Initial copy from dali-adaptor repository 31/231531/1
authorHeeyong Song <heeyong.song@samsung.com>
Wed, 22 Apr 2020 07:58:26 +0000 (16:58 +0900)
committerHeeyong Song <heeyong.song@samsung.com>
Wed, 22 Apr 2020 07:59:32 +0000 (16:59 +0900)
Change-Id: I6f0d1f7c1de5daf666ff3bb3717654ba3829ffbf

900 files changed:
LICENSE [new file with mode: 0644]
LICENSE.BSD-3-Clause [new file with mode: 0644]
README.md [new file with mode: 0644]
adaptors/scripts/dalireslog.sh [new file with mode: 0755]
adaptors/scripts/dalireslog.txt [new file with mode: 0644]
adaptors/scripts/parse.rb [new file with mode: 0755]
automated-tests/.gitignore-with-autogenerated-files [new file with mode: 0644]
automated-tests/.gitignore-without-autogenerated-files [new file with mode: 0644]
automated-tests/CMakeLists.txt [new file with mode: 0644]
automated-tests/README.md [new file with mode: 0644]
automated-tests/build.sh [new file with mode: 0755]
automated-tests/coverage.sh [new file with mode: 0755]
automated-tests/execute.sh [new file with mode: 0755]
automated-tests/images/README.md [new file with mode: 0644]
automated-tests/images/error-bits.gif [new file with mode: 0644]
automated-tests/images/error-bits.gif.buffer [new file with mode: 0644]
automated-tests/images/flag-24bpp.bmp [new file with mode: 0644]
automated-tests/images/flag-24bpp.buffer [new file with mode: 0644]
automated-tests/images/frac-32x64.png [new file with mode: 0644]
automated-tests/images/frac.24.bmp [new file with mode: 0644]
automated-tests/images/frac.jpg [new file with mode: 0644]
automated-tests/images/frac.png [new file with mode: 0644]
automated-tests/images/fractal-compressed-ETC1_RGB8_OES-45x80.ktx [new file with mode: 0644]
automated-tests/images/fractal-compressed-R11_EAC-45x80.ktx [new file with mode: 0644]
automated-tests/images/fractal-compressed-RGB8_ETC2-45x80.ktx [new file with mode: 0644]
automated-tests/images/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.astc [new file with mode: 0644]
automated-tests/images/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.ktx [new file with mode: 0644]
automated-tests/images/fractal-compressed-RGB_PVRTC_4BPPV1_IMG-32x64.ktx [new file with mode: 0644]
automated-tests/images/fractal-compressed-SRBG8_ALPHA8_ASTC_4x4_KHR-32x64.ktx [new file with mode: 0644]
automated-tests/images/interlaced.gif [new file with mode: 0644]
automated-tests/images/interlaced.gif.buffer [new file with mode: 0644]
automated-tests/images/pattern.gif [new file with mode: 0644]
automated-tests/images/pattern.gif.buffer [new file with mode: 0644]
automated-tests/images/test-image-4x4-1bpp.ico [new file with mode: 0644]
automated-tests/images/test-image-4x4-24bpp.ico [new file with mode: 0644]
automated-tests/images/test-image-4x4-32bpp.ico [new file with mode: 0644]
automated-tests/images/test-image-4x4-4bpp.ico [new file with mode: 0644]
automated-tests/images/test-image-4x4-8bpp.ico [new file with mode: 0644]
automated-tests/images/test-image.wbmp [new file with mode: 0644]
automated-tests/images/transparency.gif [new file with mode: 0644]
automated-tests/images/transparency.gif.buffer [new file with mode: 0644]
automated-tests/packaging/core-dali-adaptor-tests.spec [new file with mode: 0644]
automated-tests/packaging/core-dali-platform-abstraction-tests.spec [new file with mode: 0644]
automated-tests/patch-coverage.pl [new file with mode: 0755]
automated-tests/resources/canvas-bgnd.gif [new file with mode: 0644]
automated-tests/resources/canvas-none.gif [new file with mode: 0644]
automated-tests/resources/canvas-prev.gif [new file with mode: 0644]
automated-tests/resources/f-even-exif-1.jpg [new file with mode: 0644]
automated-tests/resources/f-even-exif-2.jpg [new file with mode: 0644]
automated-tests/resources/f-even-exif-3.jpg [new file with mode: 0644]
automated-tests/resources/f-even-exif-4.jpg [new file with mode: 0644]
automated-tests/resources/f-even-exif-5.jpg [new file with mode: 0644]
automated-tests/resources/f-even-exif-6.jpg [new file with mode: 0644]
automated-tests/resources/f-even-exif-7.jpg [new file with mode: 0644]
automated-tests/resources/f-even-exif-8.jpg [new file with mode: 0644]
automated-tests/resources/f-large-exif-3.jpg [new file with mode: 0644]
automated-tests/resources/f-odd-exif-1.jpg [new file with mode: 0644]
automated-tests/resources/f-odd-exif-2.jpg [new file with mode: 0644]
automated-tests/resources/f-odd-exif-3.jpg [new file with mode: 0644]
automated-tests/resources/f-odd-exif-4.jpg [new file with mode: 0644]
automated-tests/resources/f-odd-exif-5.jpg [new file with mode: 0644]
automated-tests/resources/f-odd-exif-6.jpg [new file with mode: 0644]
automated-tests/resources/f-odd-exif-7.jpg [new file with mode: 0644]
automated-tests/resources/f-odd-exif-8.jpg [new file with mode: 0644]
automated-tests/resources/gallery-small-1.jpg [new file with mode: 0644]
automated-tests/resources/icon-edit.png [new file with mode: 0644]
automated-tests/resources/test.txt [new file with mode: 0644]
automated-tests/scripts/add_all_smack_rule.sh [new file with mode: 0755]
automated-tests/scripts/add_smack_rule.sh [new file with mode: 0755]
automated-tests/scripts/add_style.pl [new file with mode: 0755]
automated-tests/scripts/all_smack.rule [new file with mode: 0644]
automated-tests/scripts/autocompletion.sh [new file with mode: 0755]
automated-tests/scripts/init.sh [new file with mode: 0755]
automated-tests/scripts/output_summary.pl [new file with mode: 0755]
automated-tests/scripts/retriever.sh [new file with mode: 0755]
automated-tests/scripts/summarize.pl [new file with mode: 0755]
automated-tests/scripts/tcbuild.sh [new file with mode: 0755]
automated-tests/scripts/tcheadgen.sh [new file with mode: 0755]
automated-tests/scripts/tcpackageslistsgen.sh [new file with mode: 0755]
automated-tests/scripts/tctestsgen.sh [new file with mode: 0755]
automated-tests/src/CMakeLists.txt [new file with mode: 0644]
automated-tests/src/common/assert.h [new file with mode: 0644]
automated-tests/src/common/testcase.h [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/CMakeLists.txt [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/image-loaders.cpp [new file with mode: 0755]
automated-tests/src/dali-adaptor-internal/image-loaders.h [new file with mode: 0755]
automated-tests/src/dali-adaptor-internal/tct-dali-adaptor-internal-core.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-BmpLoader.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-CommandLineOptions.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-CompressedTextures.cpp [new file with mode: 0755]
automated-tests/src/dali-adaptor-internal/utc-Dali-FontClient.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-GifLoader.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-IcoLoader.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-ImageOperations.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-Internal-PixelBuffer.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-Lifecycle-Controller.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor-internal/utc-Dali-TiltSensor.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/CMakeLists.txt [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/adaptor-test-adaptor-impl.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/adaptor-test-adaptor-impl.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/adaptor-test-application.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/dali-test-img-utils.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/dali-test-suite-utils.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/dali-test-suite-utils.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/mesh-builder.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/mesh-builder.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-actor-utils.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-actor-utils.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-compare-types.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gesture-generator.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gesture-generator.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-context-helper-abstraction.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-sync-abstraction.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-sync-abstraction.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-harness.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-harness.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-intrusive-ptr.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-native-image.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-native-image.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-platform-abstraction.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-platform-abstraction.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-render-controller.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-render-controller.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-touch-utils.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-trace-call-stack.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/dali-test-suite-utils/test-trace-call-stack.h [new file with mode: 0644]
automated-tests/src/dali-adaptor/tct-dali-adaptor-core.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-Application.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-FileLoader.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-GifLoading.cpp [new file with mode: 0755]
automated-tests/src/dali-adaptor/utc-Dali-ImageLoading.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-Key.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-KeyGrab.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-NativeImageSource.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-PixelBuffer.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-Timer.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-TtsPlayer.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-Watch-Time.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-Watch.cpp [new file with mode: 0644]
automated-tests/src/dali-adaptor/utc-Dali-Window.cpp [new file with mode: 0644]
automated-tests/src/dali-platform-abstraction/CMakeLists.txt [new file with mode: 0644]
automated-tests/src/dali-platform-abstraction/tct-dali-platform-abstraction-core.cpp [new file with mode: 0644]
automated-tests/src/dali-platform-abstraction/utc-image-fitting-modes.cpp [new file with mode: 0644]
automated-tests/src/dali-platform-abstraction/utc-image-loading-common.cpp [new file with mode: 0644]
automated-tests/src/dali-platform-abstraction/utc-image-loading-common.h [new file with mode: 0644]
automated-tests/tcbuild [new symlink]
automated-tests/templates/tct-package/README [new file with mode: 0644]
automated-tests/templates/tct-package/inst.sh [new file with mode: 0755]
build/tizen/CMakeLists.txt [new file with mode: 0644]
build/tizen/common.cmake [new file with mode: 0644]
build/tizen/dali-adaptor-integration.pc.in [new file with mode: 0644]
build/tizen/dali-adaptor.pc.in [new file with mode: 0644]
build/tizen/deps-check.cmake [new file with mode: 0644]
build/tizen/linker-test.cpp [new file with mode: 0644]
build/tizen/module-list.cmake [new file with mode: 0644]
build/tizen/plugins/CMakeLists.txt [new file with mode: 0644]
build/tizen/profiles/android-profile.cmake [new file with mode: 0644]
build/tizen/profiles/common-profile.cmake [new file with mode: 0644]
build/tizen/profiles/ivi-profile.cmake [new file with mode: 0644]
build/tizen/profiles/mobile-profile.cmake [new file with mode: 0644]
build/tizen/profiles/tizen-post-install.cmake [new file with mode: 0644]
build/tizen/profiles/tv-profile.cmake [new file with mode: 0644]
build/tizen/profiles/ubuntu-profile.cmake [new file with mode: 0644]
build/tizen/profiles/wearable-profile.cmake [new file with mode: 0644]
build/tizen/profiles/windows-profile.cmake [new file with mode: 0644]
build/tizen/rename-cov-data [new file with mode: 0755]
build/tizen/system-cache-path.in [new file with mode: 0644]
dali-adaptor.manifest [new file with mode: 0644]
dali/dali.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/accessibility-action-handler.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/accessibility-adaptor.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/accessibility-adaptor.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/accessibility-gesture-event.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/accessibility-gesture-handler.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/application-devel.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/application-devel.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/atspi-accessibility.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/bitmap-saver.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/bitmap-saver.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/clipboard-event-notifier.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/clipboard-event-notifier.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/clipboard.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/clipboard.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/color-controller-plugin.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/color-controller.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/color-controller.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/environment-variable.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/environment-variable.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/event-feeder.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/event-feeder.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/event-thread-callback.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/event-thread-callback.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/feedback-player.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/feedback-player.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/feedback-plugin.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/file-loader.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/file-loader.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/file-stream.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/file-stream.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/gif-loading.cpp [new file with mode: 0755]
dali/devel-api/adaptor-framework/gif-loading.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/image-loader-input.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/image-loader-plugin.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/image-loading.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/image-loading.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/input-method-context.cpp [new file with mode: 0755]
dali/devel-api/adaptor-framework/input-method-context.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/input-method-options.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/input-method-options.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/key-devel.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/key-devel.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/key-extension-plugin.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/keyboard.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/lifecycle-controller.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/lifecycle-controller.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/native-image-source-devel.cpp [new file with mode: 0755]
dali/devel-api/adaptor-framework/native-image-source-devel.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/native-image-source-queue.cpp [new file with mode: 0755]
dali/devel-api/adaptor-framework/native-image-source-queue.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/orientation.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/orientation.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/performance-logger.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/performance-logger.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/physical-keyboard.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/physical-keyboard.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/pixel-buffer.cpp [new file with mode: 0755]
dali/devel-api/adaptor-framework/pixel-buffer.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/sound-player.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/sound-player.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/style-monitor.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/style-monitor.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/thread-settings.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/thread-settings.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/tilt-sensor.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/tilt-sensor.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/vector-animation-renderer-plugin.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/vector-animation-renderer.cpp [new file with mode: 0755]
dali/devel-api/adaptor-framework/vector-animation-renderer.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/video-player-plugin.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/video-player.cpp [new file with mode: 0755]
dali/devel-api/adaptor-framework/video-player.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/virtual-keyboard.cpp [new file with mode: 0755]
dali/devel-api/adaptor-framework/virtual-keyboard.h [new file with mode: 0755]
dali/devel-api/adaptor-framework/web-engine-plugin.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/web-engine.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/web-engine.h [new file with mode: 0644]
dali/devel-api/adaptor-framework/window-devel.cpp [new file with mode: 0644]
dali/devel-api/adaptor-framework/window-devel.h [new file with mode: 0644]
dali/devel-api/file.list [new file with mode: 0755]
dali/devel-api/text-abstraction/bidirectional-support.cpp [new file with mode: 0755]
dali/devel-api/text-abstraction/bidirectional-support.h [new file with mode: 0755]
dali/devel-api/text-abstraction/bitmap-font.cpp [new file with mode: 0755]
dali/devel-api/text-abstraction/bitmap-font.h [new file with mode: 0755]
dali/devel-api/text-abstraction/font-client.cpp [new file with mode: 0755]
dali/devel-api/text-abstraction/font-client.h [new file with mode: 0755]
dali/devel-api/text-abstraction/font-list.cpp [new file with mode: 0644]
dali/devel-api/text-abstraction/font-list.h [new file with mode: 0755]
dali/devel-api/text-abstraction/font-metrics.cpp [new file with mode: 0755]
dali/devel-api/text-abstraction/font-metrics.h [new file with mode: 0755]
dali/devel-api/text-abstraction/glyph-info.cpp [new file with mode: 0755]
dali/devel-api/text-abstraction/glyph-info.h [new file with mode: 0755]
dali/devel-api/text-abstraction/script.cpp [new file with mode: 0644]
dali/devel-api/text-abstraction/script.h [new file with mode: 0644]
dali/devel-api/text-abstraction/segmentation.cpp [new file with mode: 0644]
dali/devel-api/text-abstraction/segmentation.h [new file with mode: 0755]
dali/devel-api/text-abstraction/shaping.cpp [new file with mode: 0644]
dali/devel-api/text-abstraction/shaping.h [new file with mode: 0644]
dali/devel-api/text-abstraction/text-abstraction-definitions.h [new file with mode: 0755]
dali/devel-api/text-abstraction/text-abstraction.h [new file with mode: 0755]
dali/devel-api/text-abstraction/text-renderer-layout-helper.cpp [new file with mode: 0755]
dali/devel-api/text-abstraction/text-renderer-layout-helper.h [new file with mode: 0755]
dali/devel-api/text-abstraction/text-renderer.cpp [new file with mode: 0755]
dali/devel-api/text-abstraction/text-renderer.h [new file with mode: 0755]
dali/file.list [new file with mode: 0644]
dali/integration-api/adaptor-framework/adaptor.h [new file with mode: 0755]
dali/integration-api/adaptor-framework/android/android-framework.cpp [new file with mode: 0644]
dali/integration-api/adaptor-framework/android/android-framework.h [new file with mode: 0644]
dali/integration-api/adaptor-framework/android/application-launcher.h [new file with mode: 0644]
dali/integration-api/adaptor-framework/android/file.list [new file with mode: 0644]
dali/integration-api/adaptor-framework/egl-interface.h [new file with mode: 0644]
dali/integration-api/adaptor-framework/log-factory-interface.h [new file with mode: 0644]
dali/integration-api/adaptor-framework/native-render-surface-factory.h [new file with mode: 0755]
dali/integration-api/adaptor-framework/native-render-surface.h [new file with mode: 0644]
dali/integration-api/adaptor-framework/render-surface-interface.h [new file with mode: 0644]
dali/integration-api/adaptor-framework/scene-holder-impl.cpp [new file with mode: 0644]
dali/integration-api/adaptor-framework/scene-holder-impl.h [new file with mode: 0644]
dali/integration-api/adaptor-framework/scene-holder.cpp [new file with mode: 0644]
dali/integration-api/adaptor-framework/scene-holder.h [new file with mode: 0644]
dali/integration-api/adaptor-framework/thread-synchronization-interface.h [new file with mode: 0644]
dali/integration-api/adaptor-framework/trigger-event-factory.h [new file with mode: 0644]
dali/integration-api/adaptor-framework/trigger-event-interface.h [new file with mode: 0644]
dali/integration-api/file.list [new file with mode: 0644]
dali/internal/accessibility/common/accessibility-adaptor-impl.cpp [new file with mode: 0644]
dali/internal/accessibility/common/accessibility-adaptor-impl.h [new file with mode: 0644]
dali/internal/accessibility/common/accessibility-gesture-detector.cpp [new file with mode: 0644]
dali/internal/accessibility/common/accessibility-gesture-detector.h [new file with mode: 0644]
dali/internal/accessibility/common/tts-player-factory.cpp [new file with mode: 0644]
dali/internal/accessibility/common/tts-player-factory.h [new file with mode: 0644]
dali/internal/accessibility/common/tts-player-impl.cpp [new file with mode: 0644]
dali/internal/accessibility/common/tts-player-impl.h [new file with mode: 0644]
dali/internal/accessibility/file.list [new file with mode: 0755]
dali/internal/accessibility/generic/accessibility-adaptor-impl-generic.cpp [new file with mode: 0644]
dali/internal/accessibility/generic/atspi-accessibility-generic.cpp [new file with mode: 0755]
dali/internal/accessibility/generic/tts-player-factory-generic.cpp [new file with mode: 0644]
dali/internal/accessibility/generic/tts-player-impl-generic.cpp [new file with mode: 0644]
dali/internal/accessibility/generic/tts-player-impl-generic.h [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/accessibility-common.h [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/accessibility-impl.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/accessibility-impl.h [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/accessibility-optional.h [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/accessibility.h [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/accessible.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/atspi-accessibility-tizen.cpp [new file with mode: 0755]
dali/internal/accessibility/tizen-wayland/atspi/bridge-accessible.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-accessible.h [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-action.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-action.h [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-base.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-base.h [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-collection.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-collection.h [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-component.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-component.h [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-editable-text.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-editable-text.h [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-impl.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-object.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-object.h [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-text.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-text.h [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-value.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/bridge-value.h [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/component.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/dbus-locators.h [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/dbus-tizen.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/atspi/dbus.h [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/tizen-common/accessibility-adaptor-impl-tizen.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/tizen-ivi/accessibility-adaptor-impl-ivi.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/tizen-mobile/accessibility-adaptor-impl-mobile.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/tizen-mobile/accessibility-adaptor-impl-mobile.h [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/tizen-tv/accessibility-adaptor-impl-tv.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/tizen-wearable/accessibility-adaptor-impl-wearable.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/tts-player-factory-tizen.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/tts-player-impl-tizen.cpp [new file with mode: 0644]
dali/internal/accessibility/tizen-wayland/tts-player-impl-tizen.h [new file with mode: 0644]
dali/internal/adaptor-framework/android/file-loader-impl-android.cpp [new file with mode: 0644]
dali/internal/adaptor-framework/android/file-stream-impl-android.cpp [new file with mode: 0644]
dali/internal/adaptor-framework/common/file-loader-impl.h [new file with mode: 0644]
dali/internal/adaptor-framework/common/file-stream-impl.h [new file with mode: 0644]
dali/internal/adaptor-framework/file.list [new file with mode: 0644]
dali/internal/adaptor-framework/generic/file-loader-impl-generic.cpp [new file with mode: 0644]
dali/internal/adaptor-framework/generic/file-stream-impl-generic.cpp [new file with mode: 0644]
dali/internal/adaptor/android/android-framework-impl.cpp [new file with mode: 0644]
dali/internal/adaptor/android/android-framework-impl.h [new file with mode: 0644]
dali/internal/adaptor/android/framework-android.cpp [new file with mode: 0644]
dali/internal/adaptor/androidjni/framework-androidjni.cpp [new file with mode: 0644]
dali/internal/adaptor/common/adaptor-builder-impl.cpp [new file with mode: 0644]
dali/internal/adaptor/common/adaptor-builder-impl.h [new file with mode: 0644]
dali/internal/adaptor/common/adaptor-impl.cpp [new file with mode: 0755]
dali/internal/adaptor/common/adaptor-impl.h [new file with mode: 0755]
dali/internal/adaptor/common/adaptor-internal-services.h [new file with mode: 0644]
dali/internal/adaptor/common/adaptor.cpp [new file with mode: 0755]
dali/internal/adaptor/common/application-impl.cpp [new file with mode: 0755]
dali/internal/adaptor/common/application-impl.h [new file with mode: 0755]
dali/internal/adaptor/common/combined-update-render-controller-debug.h [new file with mode: 0755]
dali/internal/adaptor/common/combined-update-render-controller.cpp [new file with mode: 0644]
dali/internal/adaptor/common/combined-update-render-controller.h [new file with mode: 0644]
dali/internal/adaptor/common/framework.h [new file with mode: 0644]
dali/internal/adaptor/common/lifecycle-controller-impl.cpp [new file with mode: 0644]
dali/internal/adaptor/common/lifecycle-controller-impl.h [new file with mode: 0644]
dali/internal/adaptor/common/lifecycle-observer.h [new file with mode: 0644]
dali/internal/adaptor/common/thread-controller-interface.h [new file with mode: 0644]
dali/internal/adaptor/common/threading-mode.h [new file with mode: 0644]
dali/internal/adaptor/file.list [new file with mode: 0644]
dali/internal/adaptor/generic/adaptor-impl-generic.cpp [new file with mode: 0644]
dali/internal/adaptor/tizen-wayland/adaptor-impl-tizen.cpp [new file with mode: 0755]
dali/internal/adaptor/tizen-wayland/dali-ecore-wayland.h [new file with mode: 0644]
dali/internal/adaptor/tizen-wayland/dali-ecore-wl2.h [new file with mode: 0644]
dali/internal/adaptor/tizen-wayland/framework-tizen.cpp [new file with mode: 0644]
dali/internal/adaptor/tizen-wayland/tizen-wearable/watch-application-impl.cpp [new file with mode: 0644]
dali/internal/adaptor/tizen-wayland/tizen-wearable/watch-application-impl.h [new file with mode: 0644]
dali/internal/adaptor/tizen-wayland/tizen-wearable/watch-application.cpp [new file with mode: 0644]
dali/internal/adaptor/ubuntu/framework-ubuntu.cpp [new file with mode: 0644]
dali/internal/adaptor/windows/framework-win.cpp [new file with mode: 0755]
dali/internal/clipboard/common/clipboard-event-notifier-impl.cpp [new file with mode: 0644]
dali/internal/clipboard/common/clipboard-event-notifier-impl.h [new file with mode: 0755]
dali/internal/clipboard/common/clipboard-impl.h [new file with mode: 0644]
dali/internal/clipboard/file.list [new file with mode: 0644]
dali/internal/clipboard/generic/clipboard-impl-generic.cpp [new file with mode: 0755]
dali/internal/clipboard/tizen-wayland/clipboard-impl-ecore-wl.cpp [new file with mode: 0755]
dali/internal/clipboard/ubuntu-x11/clipboard-impl-x.cpp [new file with mode: 0644]
dali/internal/graphics/android/egl-image-extensions-android.cpp [new file with mode: 0644]
dali/internal/graphics/common/egl-image-extensions.h [new file with mode: 0644]
dali/internal/graphics/common/egl-include.h [new file with mode: 0644]
dali/internal/graphics/common/graphics-factory-interface.h [new file with mode: 0644]
dali/internal/graphics/common/graphics-interface.h [new file with mode: 0644]
dali/internal/graphics/file.list [new file with mode: 0644]
dali/internal/graphics/generic/egl-image-extensions-generic.cpp [new file with mode: 0644]
dali/internal/graphics/gles/egl-context-helper-implementation.cpp [new file with mode: 0644]
dali/internal/graphics/gles/egl-context-helper-implementation.h [new file with mode: 0644]
dali/internal/graphics/gles/egl-debug.cpp [new file with mode: 0644]
dali/internal/graphics/gles/egl-debug.h [new file with mode: 0644]
dali/internal/graphics/gles/egl-factory-interface.h [new file with mode: 0644]
dali/internal/graphics/gles/egl-graphics-factory.cpp [new file with mode: 0644]
dali/internal/graphics/gles/egl-graphics-factory.h [new file with mode: 0644]
dali/internal/graphics/gles/egl-graphics.cpp [new file with mode: 0644]
dali/internal/graphics/gles/egl-graphics.h [new file with mode: 0644]
dali/internal/graphics/gles/egl-implementation.cpp [new file with mode: 0755]
dali/internal/graphics/gles/egl-implementation.h [new file with mode: 0644]
dali/internal/graphics/gles/egl-sync-implementation.cpp [new file with mode: 0644]
dali/internal/graphics/gles/egl-sync-implementation.h [new file with mode: 0644]
dali/internal/graphics/gles/gl-extensions.cpp [new file with mode: 0644]
dali/internal/graphics/gles/gl-extensions.h [new file with mode: 0644]
dali/internal/graphics/gles/gl-implementation.h [new file with mode: 0644]
dali/internal/graphics/gles/gl-proxy-implementation.cpp [new file with mode: 0644]
dali/internal/graphics/gles/gl-proxy-implementation.h [new file with mode: 0644]
dali/internal/graphics/gles/gles-abstraction.h [new file with mode: 0644]
dali/internal/graphics/gles/gles2-implementation.h [new file with mode: 0644]
dali/internal/graphics/gles/gles3-implementation.h [new file with mode: 0644]
dali/internal/graphics/tizen/egl-image-extensions-tizen.cpp [new file with mode: 0644]
dali/internal/graphics/windows-gl/egl-image-extensions.cpp [new file with mode: 0755]
dali/internal/haptics/common/feedback-player-impl.cpp [new file with mode: 0644]
dali/internal/haptics/common/feedback-player-impl.h [new file with mode: 0644]
dali/internal/haptics/common/feedback-plugin-proxy.cpp [new file with mode: 0644]
dali/internal/haptics/common/feedback-plugin-proxy.h [new file with mode: 0644]
dali/internal/haptics/file.list [new file with mode: 0644]
dali/internal/imaging/android/native-image-source-factory-android.cpp [new file with mode: 0644]
dali/internal/imaging/android/native-image-source-factory-android.h [new file with mode: 0644]
dali/internal/imaging/android/native-image-source-impl-android.cpp [new file with mode: 0755]
dali/internal/imaging/android/native-image-source-impl-android.h [new file with mode: 0755]
dali/internal/imaging/android/native-image-source-queue-impl-android.cpp [new file with mode: 0644]
dali/internal/imaging/android/native-image-source-queue-impl-android.h [new file with mode: 0644]
dali/internal/imaging/common/alpha-mask.cpp [new file with mode: 0644]
dali/internal/imaging/common/alpha-mask.h [new file with mode: 0644]
dali/internal/imaging/common/file-download.cpp [new file with mode: 0755]
dali/internal/imaging/common/file-download.h [new file with mode: 0755]
dali/internal/imaging/common/gaussian-blur.cpp [new file with mode: 0644]
dali/internal/imaging/common/gaussian-blur.h [new file with mode: 0644]
dali/internal/imaging/common/http-utils.cpp [new file with mode: 0644]
dali/internal/imaging/common/http-utils.h [new file with mode: 0644]
dali/internal/imaging/common/image-loader-plugin-proxy.cpp [new file with mode: 0755]
dali/internal/imaging/common/image-loader-plugin-proxy.h [new file with mode: 0755]
dali/internal/imaging/common/image-loader.cpp [new file with mode: 0755]
dali/internal/imaging/common/image-loader.h [new file with mode: 0644]
dali/internal/imaging/common/image-operations.cpp [new file with mode: 0755]
dali/internal/imaging/common/image-operations.h [new file with mode: 0755]
dali/internal/imaging/common/loader-astc.cpp [new file with mode: 0755]
dali/internal/imaging/common/loader-astc.h [new file with mode: 0755]
dali/internal/imaging/common/loader-bmp.cpp [new file with mode: 0755]
dali/internal/imaging/common/loader-bmp.h [new file with mode: 0755]
dali/internal/imaging/common/loader-gif.cpp [new file with mode: 0755]
dali/internal/imaging/common/loader-gif.h [new file with mode: 0755]
dali/internal/imaging/common/loader-ico.cpp [new file with mode: 0755]
dali/internal/imaging/common/loader-ico.h [new file with mode: 0755]
dali/internal/imaging/common/loader-jpeg-turbo.cpp [new file with mode: 0755]
dali/internal/imaging/common/loader-jpeg.h [new file with mode: 0755]
dali/internal/imaging/common/loader-ktx.cpp [new file with mode: 0755]
dali/internal/imaging/common/loader-ktx.h [new file with mode: 0755]
dali/internal/imaging/common/loader-png.cpp [new file with mode: 0755]
dali/internal/imaging/common/loader-png.h [new file with mode: 0755]
dali/internal/imaging/common/loader-wbmp.cpp [new file with mode: 0755]
dali/internal/imaging/common/loader-wbmp.h [new file with mode: 0755]
dali/internal/imaging/common/native-bitmap-buffer-impl.cpp [new file with mode: 0644]
dali/internal/imaging/common/native-bitmap-buffer-impl.h [new file with mode: 0644]
dali/internal/imaging/common/native-image-source-factory.h [new file with mode: 0644]
dali/internal/imaging/common/native-image-source-impl.h [new file with mode: 0755]
dali/internal/imaging/common/native-image-source-queue-impl.h [new file with mode: 0755]
dali/internal/imaging/common/pixel-buffer-impl.cpp [new file with mode: 0755]
dali/internal/imaging/common/pixel-buffer-impl.h [new file with mode: 0755]
dali/internal/imaging/common/pixel-manipulation.cpp [new file with mode: 0644]
dali/internal/imaging/common/pixel-manipulation.h [new file with mode: 0644]
dali/internal/imaging/file.list [new file with mode: 0644]
dali/internal/imaging/tizen/native-image-source-factory-tizen.cpp [new file with mode: 0644]
dali/internal/imaging/tizen/native-image-source-factory-tizen.h [new file with mode: 0644]
dali/internal/imaging/tizen/native-image-source-impl-tizen.cpp [new file with mode: 0755]
dali/internal/imaging/tizen/native-image-source-impl-tizen.h [new file with mode: 0755]
dali/internal/imaging/tizen/native-image-source-queue-impl-tizen.cpp [new file with mode: 0644]
dali/internal/imaging/tizen/native-image-source-queue-impl-tizen.h [new file with mode: 0755]
dali/internal/imaging/ubuntu-x11/native-image-source-factory-x.cpp [new file with mode: 0644]
dali/internal/imaging/ubuntu-x11/native-image-source-factory-x.h [new file with mode: 0644]
dali/internal/imaging/ubuntu-x11/native-image-source-impl-x.cpp [new file with mode: 0755]
dali/internal/imaging/ubuntu-x11/native-image-source-impl-x.h [new file with mode: 0755]
dali/internal/imaging/ubuntu-x11/native-image-source-queue-impl-x.cpp [new file with mode: 0644]
dali/internal/imaging/ubuntu-x11/native-image-source-queue-impl-x.h [new file with mode: 0755]
dali/internal/imaging/windows/curl-environment-win.cpp [new file with mode: 0755]
dali/internal/imaging/windows/file-download-win.cpp [new file with mode: 0755]
dali/internal/imaging/windows/native-image-source-factory-win.cpp [new file with mode: 0755]
dali/internal/imaging/windows/native-image-source-factory-win.h [new file with mode: 0755]
dali/internal/imaging/windows/native-image-source-impl-win.cpp [new file with mode: 0755]
dali/internal/imaging/windows/native-image-source-impl-win.h [new file with mode: 0755]
dali/internal/input/common/input-method-context-factory.h [new file with mode: 0755]
dali/internal/input/common/input-method-context-impl.cpp [new file with mode: 0755]
dali/internal/input/common/input-method-context-impl.h [new file with mode: 0755]
dali/internal/input/common/key-grab.cpp [new file with mode: 0644]
dali/internal/input/common/key-impl.cpp [new file with mode: 0644]
dali/internal/input/common/key-impl.h [new file with mode: 0644]
dali/internal/input/common/keyboard.cpp [new file with mode: 0644]
dali/internal/input/common/physical-keyboard-impl.cpp [new file with mode: 0644]
dali/internal/input/common/physical-keyboard-impl.h [new file with mode: 0644]
dali/internal/input/common/virtual-keyboard-impl.h [new file with mode: 0755]
dali/internal/input/file.list [new file with mode: 0644]
dali/internal/input/generic/input-method-context-factory-generic.cpp [new file with mode: 0644]
dali/internal/input/generic/input-method-context-impl-generic.cpp [new file with mode: 0644]
dali/internal/input/generic/input-method-context-impl-generic.h [new file with mode: 0644]
dali/internal/input/generic/key-mapping-generic.cpp [new file with mode: 0644]
dali/internal/input/generic/virtual-keyboard-impl-generic.cpp [new file with mode: 0644]
dali/internal/input/linux/dali-ecore-imf.h [new file with mode: 0644]
dali/internal/input/tizen-wayland/ecore-virtual-keyboard.cpp [new file with mode: 0755]
dali/internal/input/tizen-wayland/ecore-virtual-keyboard.h [new file with mode: 0644]
dali/internal/input/tizen-wayland/input-method-context-factory-ecore-wl.cpp [new file with mode: 0755]
dali/internal/input/tizen-wayland/input-method-context-impl-ecore-wl.cpp [new file with mode: 0755]
dali/internal/input/tizen-wayland/input-method-context-impl-ecore-wl.h [new file with mode: 0755]
dali/internal/input/tizen-wayland/key-mapping-ecore-wl.cpp [new file with mode: 0644]
dali/internal/input/tizen-wayland/virtual-keyboard-impl-ecore-wl.cpp [new file with mode: 0755]
dali/internal/input/ubuntu-x11/dali-ecore-input.h [new file with mode: 0644]
dali/internal/input/ubuntu-x11/input-method-context-factory-x.cpp [new file with mode: 0755]
dali/internal/input/ubuntu-x11/input-method-context-impl-x.cpp [new file with mode: 0755]
dali/internal/input/ubuntu-x11/input-method-context-impl-x.h [new file with mode: 0755]
dali/internal/input/ubuntu-x11/key-mapping-x.cpp [new file with mode: 0644]
dali/internal/input/ubuntu-x11/virtual-keyboard-impl-x.cpp [new file with mode: 0755]
dali/internal/input/windows/input-method-context-factory-win.cpp [new file with mode: 0755]
dali/internal/input/windows/input-method-context-impl-win.cpp [new file with mode: 0755]
dali/internal/input/windows/input-method-context-impl-win.h [new file with mode: 0755]
dali/internal/input/windows/key-mapping-win.cpp [new file with mode: 0755]
dali/internal/input/windows/virtual-keyboard-impl-win.cpp [new file with mode: 0755]
dali/internal/legacy/common/tizen-platform-abstraction.cpp [new file with mode: 0644]
dali/internal/legacy/common/tizen-platform-abstraction.h [new file with mode: 0644]
dali/internal/legacy/file.list [new file with mode: 0644]
dali/internal/legacy/tizen/data-compression.cpp [new file with mode: 0644]
dali/internal/legacy/tizen/data-compression.h [new file with mode: 0644]
dali/internal/legacy/tizen/image-encoder.h [new file with mode: 0644]
dali/internal/legacy/tizen/platform-capabilities.h [new file with mode: 0644]
dali/internal/network/common/automation.cpp [new file with mode: 0644]
dali/internal/network/common/automation.h [new file with mode: 0644]
dali/internal/network/common/client-send-data-interface.h [new file with mode: 0644]
dali/internal/network/common/network-performance-client.cpp [new file with mode: 0644]
dali/internal/network/common/network-performance-client.h [new file with mode: 0644]
dali/internal/network/common/network-performance-protocol.cpp [new file with mode: 0644]
dali/internal/network/common/network-performance-protocol.h [new file with mode: 0644]
dali/internal/network/common/network-performance-server.cpp [new file with mode: 0644]
dali/internal/network/common/network-performance-server.h [new file with mode: 0644]
dali/internal/network/common/socket-factory-interface.h [new file with mode: 0644]
dali/internal/network/common/socket-factory.cpp [new file with mode: 0644]
dali/internal/network/common/socket-factory.h [new file with mode: 0644]
dali/internal/network/common/socket-impl.cpp [new file with mode: 0644]
dali/internal/network/common/socket-impl.h [new file with mode: 0644]
dali/internal/network/common/socket-interface.h [new file with mode: 0644]
dali/internal/network/common/trace-interface.h [new file with mode: 0644]
dali/internal/network/file.list [new file with mode: 0644]
dali/internal/sensor/common/tilt-sensor-factory.cpp [new file with mode: 0644]
dali/internal/sensor/common/tilt-sensor-factory.h [new file with mode: 0644]
dali/internal/sensor/common/tilt-sensor-impl.cpp [new file with mode: 0644]
dali/internal/sensor/common/tilt-sensor-impl.h [new file with mode: 0644]
dali/internal/sensor/file.list [new file with mode: 0644]
dali/internal/sensor/tizen/tilt-sensor-factory-tizen.cpp [new file with mode: 0644]
dali/internal/sensor/tizen/tilt-sensor-impl-tizen.cpp [new file with mode: 0644]
dali/internal/sensor/tizen/tilt-sensor-impl-tizen.h [new file with mode: 0644]
dali/internal/sensor/ubuntu/tilt-sensor-factory-ubuntu.cpp [new file with mode: 0644]
dali/internal/sensor/ubuntu/tilt-sensor-impl-ubuntu.cpp [new file with mode: 0644]
dali/internal/sensor/ubuntu/tilt-sensor-impl-ubuntu.h [new file with mode: 0644]
dali/internal/styling/common/style-monitor-impl.cpp [new file with mode: 0644]
dali/internal/styling/common/style-monitor-impl.h [new file with mode: 0644]
dali/internal/styling/file.list [new file with mode: 0644]
dali/internal/system/android/callback-manager-android.cpp [new file with mode: 0644]
dali/internal/system/android/callback-manager-android.h [new file with mode: 0644]
dali/internal/system/android/file-descriptor-monitor-android.cpp [new file with mode: 0644]
dali/internal/system/android/logging-android.cpp [new file with mode: 0644]
dali/internal/system/android/shared-file-operations-android.cpp [new file with mode: 0644]
dali/internal/system/android/system-settings-android.cpp [new file with mode: 0644]
dali/internal/system/android/timer-impl-android.cpp [new file with mode: 0644]
dali/internal/system/android/widget-application-impl-android.cpp [new file with mode: 0644]
dali/internal/system/android/widget-application-impl-android.h [new file with mode: 0644]
dali/internal/system/common/abort-handler.cpp [new file with mode: 0644]
dali/internal/system/common/abort-handler.h [new file with mode: 0755]
dali/internal/system/common/atomics.h [new file with mode: 0644]
dali/internal/system/common/callback-manager.h [new file with mode: 0644]
dali/internal/system/common/color-controller-impl.cpp [new file with mode: 0644]
dali/internal/system/common/color-controller-impl.h [new file with mode: 0644]
dali/internal/system/common/command-line-options.cpp [new file with mode: 0644]
dali/internal/system/common/command-line-options.h [new file with mode: 0644]
dali/internal/system/common/configuration-manager.cpp [new file with mode: 0644]
dali/internal/system/common/configuration-manager.h [new file with mode: 0644]
dali/internal/system/common/core-event-interface.h [new file with mode: 0644]
dali/internal/system/common/environment-options.cpp [new file with mode: 0644]
dali/internal/system/common/environment-options.h [new file with mode: 0644]
dali/internal/system/common/environment-variables.h [new file with mode: 0644]
dali/internal/system/common/file-closer.h [new file with mode: 0755]
dali/internal/system/common/file-descriptor-monitor.h [new file with mode: 0644]
dali/internal/system/common/file-reader.h [new file with mode: 0644]
dali/internal/system/common/file-writer.h [new file with mode: 0644]
dali/internal/system/common/fps-tracker.cpp [new file with mode: 0644]
dali/internal/system/common/fps-tracker.h [new file with mode: 0644]
dali/internal/system/common/frame-time-stamp.cpp [new file with mode: 0644]
dali/internal/system/common/frame-time-stamp.h [new file with mode: 0644]
dali/internal/system/common/frame-time-stats.cpp [new file with mode: 0644]
dali/internal/system/common/frame-time-stats.h [new file with mode: 0644]
dali/internal/system/common/kernel-trace.cpp [new file with mode: 0644]
dali/internal/system/common/kernel-trace.h [new file with mode: 0644]
dali/internal/system/common/locale-utils.cpp [new file with mode: 0755]
dali/internal/system/common/locale-utils.h [new file with mode: 0644]
dali/internal/system/common/logging.h [new file with mode: 0644]
dali/internal/system/common/object-profiler.cpp [new file with mode: 0644]
dali/internal/system/common/object-profiler.h [new file with mode: 0644]
dali/internal/system/common/performance-interface-factory.cpp [new file with mode: 0644]
dali/internal/system/common/performance-interface-factory.h [new file with mode: 0644]
dali/internal/system/common/performance-interface.h [new file with mode: 0644]
dali/internal/system/common/performance-logger-impl.cpp [new file with mode: 0644]
dali/internal/system/common/performance-logger-impl.h [new file with mode: 0644]
dali/internal/system/common/performance-marker.cpp [new file with mode: 0644]
dali/internal/system/common/performance-marker.h [new file with mode: 0644]
dali/internal/system/common/performance-server.cpp [new file with mode: 0644]
dali/internal/system/common/performance-server.h [new file with mode: 0644]
dali/internal/system/common/shared-file.cpp [new file with mode: 0644]
dali/internal/system/common/shared-file.h [new file with mode: 0644]
dali/internal/system/common/sound-player-impl.cpp [new file with mode: 0644]
dali/internal/system/common/sound-player-impl.h [new file with mode: 0644]
dali/internal/system/common/stat-context-log-interface.h [new file with mode: 0644]
dali/internal/system/common/stat-context-manager.cpp [new file with mode: 0644]
dali/internal/system/common/stat-context-manager.h [new file with mode: 0644]
dali/internal/system/common/stat-context.cpp [new file with mode: 0644]
dali/internal/system/common/stat-context.h [new file with mode: 0644]
dali/internal/system/common/system-settings.h [new file with mode: 0644]
dali/internal/system/common/system-trace.cpp [new file with mode: 0644]
dali/internal/system/common/system-trace.h [new file with mode: 0644]
dali/internal/system/common/thread-controller.cpp [new file with mode: 0644]
dali/internal/system/common/thread-controller.h [new file with mode: 0644]
dali/internal/system/common/time-service.cpp [new file with mode: 0644]
dali/internal/system/common/time-service.h [new file with mode: 0644]
dali/internal/system/common/timer-impl.h [new file with mode: 0644]
dali/internal/system/common/timer-interface.h [new file with mode: 0644]
dali/internal/system/common/trigger-event-factory.cpp [new file with mode: 0644]
dali/internal/system/common/trigger-event.cpp [new file with mode: 0644]
dali/internal/system/common/trigger-event.h [new file with mode: 0644]
dali/internal/system/common/update-status-logger.cpp [new file with mode: 0644]
dali/internal/system/common/update-status-logger.h [new file with mode: 0644]
dali/internal/system/common/widget-application-impl.cpp [new file with mode: 0644]
dali/internal/system/common/widget-application-impl.h [new file with mode: 0644]
dali/internal/system/common/widget-controller.h [new file with mode: 0644]
dali/internal/system/file.list [new file with mode: 0644]
dali/internal/system/generic/shared-file-operations-generic.cpp [new file with mode: 0644]
dali/internal/system/linux/callback-manager-ecore.cpp [new file with mode: 0644]
dali/internal/system/linux/callback-manager-ecore.h [new file with mode: 0644]
dali/internal/system/linux/dali-ecore-x.h [new file with mode: 0644]
dali/internal/system/linux/dali-ecore.h [new file with mode: 0644]
dali/internal/system/linux/dali-elementary.h [new file with mode: 0644]
dali/internal/system/linux/file-descriptor-monitor-ecore.cpp [new file with mode: 0644]
dali/internal/system/linux/timer-impl-ecore.cpp [new file with mode: 0644]
dali/internal/system/tizen-wayland/logging-tizen.cpp [new file with mode: 0644]
dali/internal/system/tizen-wayland/system-settings-tizen.cpp [new file with mode: 0644]
dali/internal/system/tizen-wayland/tizen-wearable/capture-impl-tizen.cpp [new file with mode: 0755]
dali/internal/system/tizen-wayland/tizen-wearable/capture-impl.h [new file with mode: 0755]
dali/internal/system/tizen-wayland/tizen-wearable/capture.cpp [new file with mode: 0644]
dali/internal/system/tizen-wayland/tizen-wearable/watch-time.cpp [new file with mode: 0644]
dali/internal/system/tizen-wayland/widget-application-impl-tizen.cpp [new file with mode: 0644]
dali/internal/system/tizen-wayland/widget-application-impl-tizen.h [new file with mode: 0644]
dali/internal/system/tizen-wayland/widget-controller-tizen.cpp [new file with mode: 0644]
dali/internal/system/tizen-wayland/widget-controller-tizen.h [new file with mode: 0644]
dali/internal/system/ubuntu-x11/logging-x.cpp [new file with mode: 0644]
dali/internal/system/ubuntu-x11/system-settings-x.cpp [new file with mode: 0644]
dali/internal/system/ubuntu-x11/widget-application-impl-x.cpp [new file with mode: 0644]
dali/internal/system/ubuntu-x11/widget-application-impl-x.h [new file with mode: 0644]
dali/internal/system/ubuntu-x11/widget-controller-x.cpp [new file with mode: 0644]
dali/internal/system/ubuntu-x11/widget-controller-x.h [new file with mode: 0644]
dali/internal/system/windows/callback-manager-win.cpp [new file with mode: 0755]
dali/internal/system/windows/callback-manager-win.h [new file with mode: 0755]
dali/internal/system/windows/logging-win.cpp [new file with mode: 0644]
dali/internal/system/windows/system-settings-win.cpp [new file with mode: 0755]
dali/internal/system/windows/timer-impl-win.cpp [new file with mode: 0755]
dali/internal/system/windows/trigger-event-factory.cpp [new file with mode: 0755]
dali/internal/system/windows/trigger-event.cpp [new file with mode: 0755]
dali/internal/system/windows/trigger-event.h [new file with mode: 0755]
dali/internal/system/windows/widget-application-impl-win.cpp [new file with mode: 0755]
dali/internal/system/windows/widget-application-impl-win.h [new file with mode: 0755]
dali/internal/system/windows/widget-controller-win.cpp [new file with mode: 0755]
dali/internal/system/windows/widget-controller-win.h [new file with mode: 0755]
dali/internal/text/file.list [new file with mode: 0644]
dali/internal/text/text-abstraction/bidirectional-support-impl.cpp [new file with mode: 0755]
dali/internal/text/text-abstraction/bidirectional-support-impl.h [new file with mode: 0755]
dali/internal/text/text-abstraction/cairo-renderer.cpp [new file with mode: 0755]
dali/internal/text/text-abstraction/cairo-renderer.h [new file with mode: 0755]
dali/internal/text/text-abstraction/font-client-helper.cpp [new file with mode: 0644]
dali/internal/text/text-abstraction/font-client-helper.h [new file with mode: 0644]
dali/internal/text/text-abstraction/font-client-impl.cpp [new file with mode: 0755]
dali/internal/text/text-abstraction/font-client-impl.h [new file with mode: 0755]
dali/internal/text/text-abstraction/font-client-plugin-impl.cpp [new file with mode: 0755]
dali/internal/text/text-abstraction/font-client-plugin-impl.h [new file with mode: 0755]
dali/internal/text/text-abstraction/segmentation-impl.cpp [new file with mode: 0644]
dali/internal/text/text-abstraction/segmentation-impl.h [new file with mode: 0644]
dali/internal/text/text-abstraction/shaping-impl.cpp [new file with mode: 0755]
dali/internal/text/text-abstraction/shaping-impl.h [new file with mode: 0644]
dali/internal/text/text-abstraction/text-renderer-impl.cpp [new file with mode: 0755]
dali/internal/text/text-abstraction/text-renderer-impl.h [new file with mode: 0755]
dali/internal/text/ubuntu/vector-font-cache.cpp [new file with mode: 0644]
dali/internal/thread/common/thread-settings-impl.cpp [new file with mode: 0644]
dali/internal/thread/common/thread-settings-impl.h [new file with mode: 0644]
dali/internal/thread/file.list [new file with mode: 0644]
dali/internal/trace/android/trace-factory-android.cpp [new file with mode: 0644]
dali/internal/trace/android/trace-manager-impl-android.cpp [new file with mode: 0644]
dali/internal/trace/android/trace-manager-impl-android.h [new file with mode: 0644]
dali/internal/trace/common/trace-factory.cpp [new file with mode: 0644]
dali/internal/trace/common/trace-factory.h [new file with mode: 0644]
dali/internal/trace/common/trace-manager-impl.cpp [new file with mode: 0644]
dali/internal/trace/common/trace-manager-impl.h [new file with mode: 0644]
dali/internal/trace/file.list [new file with mode: 0644]
dali/internal/trace/generic/trace-factory-generic.cpp [new file with mode: 0644]
dali/internal/trace/generic/trace-manager-impl-generic.cpp [new file with mode: 0644]
dali/internal/trace/generic/trace-manager-impl-generic.h [new file with mode: 0644]
dali/internal/trace/tizen/trace-factory-tizen.cpp [new file with mode: 0644]
dali/internal/trace/tizen/trace-manager-impl-tizen.cpp [new file with mode: 0644]
dali/internal/trace/tizen/trace-manager-impl-tizen.h [new file with mode: 0644]
dali/internal/vector-animation/common/vector-animation-renderer-impl.cpp [new file with mode: 0644]
dali/internal/vector-animation/common/vector-animation-renderer-impl.h [new file with mode: 0755]
dali/internal/vector-animation/common/vector-animation-renderer-plugin-proxy.cpp [new file with mode: 0644]
dali/internal/vector-animation/common/vector-animation-renderer-plugin-proxy.h [new file with mode: 0644]
dali/internal/vector-animation/file.list [new file with mode: 0644]
dali/internal/video/common/video-player-impl.cpp [new file with mode: 0755]
dali/internal/video/common/video-player-impl.h [new file with mode: 0755]
dali/internal/video/file.list [new file with mode: 0644]
dali/internal/web-engine/common/web-engine-impl.cpp [new file with mode: 0644]
dali/internal/web-engine/common/web-engine-impl.h [new file with mode: 0644]
dali/internal/web-engine/file.list [new file with mode: 0644]
dali/internal/window-system/android/display-connection-factory-android.cpp [new file with mode: 0644]
dali/internal/window-system/android/display-connection-factory-android.h [new file with mode: 0644]
dali/internal/window-system/android/display-connection-impl-android.cpp [new file with mode: 0644]
dali/internal/window-system/android/display-connection-impl-android.h [new file with mode: 0644]
dali/internal/window-system/android/render-surface-factory-android.cpp [new file with mode: 0644]
dali/internal/window-system/android/render-surface-factory-android.h [new file with mode: 0644]
dali/internal/window-system/android/window-base-android.cpp [new file with mode: 0644]
dali/internal/window-system/android/window-base-android.h [new file with mode: 0644]
dali/internal/window-system/android/window-factory-android.cpp [new file with mode: 0644]
dali/internal/window-system/android/window-factory-android.h [new file with mode: 0644]
dali/internal/window-system/android/window-system-android.cpp [new file with mode: 0644]
dali/internal/window-system/common/damage-observer.h [new file with mode: 0644]
dali/internal/window-system/common/display-connection-factory.h [new file with mode: 0644]
dali/internal/window-system/common/display-connection-impl.h [new file with mode: 0644]
dali/internal/window-system/common/display-connection.cpp [new file with mode: 0644]
dali/internal/window-system/common/display-connection.h [new file with mode: 0644]
dali/internal/window-system/common/display-utils.h [new file with mode: 0644]
dali/internal/window-system/common/event-handler.cpp [new file with mode: 0755]
dali/internal/window-system/common/event-handler.h [new file with mode: 0755]
dali/internal/window-system/common/native-render-surface-factory.cpp [new file with mode: 0644]
dali/internal/window-system/common/orientation-impl.cpp [new file with mode: 0644]
dali/internal/window-system/common/orientation-impl.h [new file with mode: 0644]
dali/internal/window-system/common/pixmap-render-surface.h [new file with mode: 0644]
dali/internal/window-system/common/render-surface-factory.h [new file with mode: 0644]
dali/internal/window-system/common/rotation-event.h [new file with mode: 0644]
dali/internal/window-system/common/window-base.cpp [new file with mode: 0644]
dali/internal/window-system/common/window-base.h [new file with mode: 0644]
dali/internal/window-system/common/window-event-interface.h [new file with mode: 0644]
dali/internal/window-system/common/window-factory.h [new file with mode: 0644]
dali/internal/window-system/common/window-impl.cpp [new file with mode: 0644]
dali/internal/window-system/common/window-impl.h [new file with mode: 0644]
dali/internal/window-system/common/window-render-surface.cpp [new file with mode: 0644]
dali/internal/window-system/common/window-render-surface.h [new file with mode: 0644]
dali/internal/window-system/common/window-system.h [new file with mode: 0644]
dali/internal/window-system/common/window-visibility-observer.h [new file with mode: 0644]
dali/internal/window-system/file.list [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/display-connection-factory-ecore-wl.cpp [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/display-connection-factory-ecore-wl.h [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/display-connection-impl-ecore-wl.cpp [new file with mode: 0755]
dali/internal/window-system/tizen-wayland/display-connection-impl-ecore-wl.h [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/ecore-wl/render-surface-factory-ecore-wl.cpp [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/ecore-wl/render-surface-factory-ecore-wl.h [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/ecore-wl/window-base-ecore-wl.cpp [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/ecore-wl/window-base-ecore-wl.h [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/ecore-wl/window-factory-ecore-wl.cpp [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/ecore-wl/window-factory-ecore-wl.h [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/ecore-wl/window-system-ecore-wl.cpp [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/ecore-wl2/render-surface-factory-ecore-wl2.cpp [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/ecore-wl2/render-surface-factory-ecore-wl2.h [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/ecore-wl2/window-base-ecore-wl2.cpp [new file with mode: 0755]
dali/internal/window-system/tizen-wayland/ecore-wl2/window-base-ecore-wl2.h [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/ecore-wl2/window-factory-ecore-wl2.cpp [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/ecore-wl2/window-factory-ecore-wl2.h [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/ecore-wl2/window-system-ecore-wl2.cpp [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/native-render-surface-ecore-wl.cpp [new file with mode: 0644]
dali/internal/window-system/tizen-wayland/native-render-surface-ecore-wl.h [new file with mode: 0644]
dali/internal/window-system/ubuntu-x11/display-connection-factory-x.cpp [new file with mode: 0644]
dali/internal/window-system/ubuntu-x11/display-connection-factory-x.h [new file with mode: 0644]
dali/internal/window-system/ubuntu-x11/display-connection-impl-x.cpp [new file with mode: 0644]
dali/internal/window-system/ubuntu-x11/display-connection-impl-x.h [new file with mode: 0644]
dali/internal/window-system/ubuntu-x11/ecore-x-types.h [new file with mode: 0644]
dali/internal/window-system/ubuntu-x11/pixmap-render-surface-ecore-x.cpp [new file with mode: 0644]
dali/internal/window-system/ubuntu-x11/pixmap-render-surface-ecore-x.h [new file with mode: 0644]
dali/internal/window-system/ubuntu-x11/render-surface-factory-ecore-x.cpp [new file with mode: 0644]
dali/internal/window-system/ubuntu-x11/render-surface-factory-ecore-x.h [new file with mode: 0644]
dali/internal/window-system/ubuntu-x11/window-base-ecore-x.cpp [new file with mode: 0755]
dali/internal/window-system/ubuntu-x11/window-base-ecore-x.h [new file with mode: 0644]
dali/internal/window-system/ubuntu-x11/window-factory-ecore-x.cpp [new file with mode: 0644]
dali/internal/window-system/ubuntu-x11/window-factory-ecore-x.h [new file with mode: 0644]
dali/internal/window-system/ubuntu-x11/window-interface-ecore-x.cpp [new file with mode: 0644]
dali/internal/window-system/ubuntu-x11/window-interface-ecore-x.h [new file with mode: 0644]
dali/internal/window-system/ubuntu-x11/window-system-ecore-x.cpp [new file with mode: 0644]
dali/internal/window-system/windows/display-connection-factory-win.cpp [new file with mode: 0755]
dali/internal/window-system/windows/display-connection-factory-win.h [new file with mode: 0755]
dali/internal/window-system/windows/display-connection-impl-win.cpp [new file with mode: 0755]
dali/internal/window-system/windows/display-connection-impl-win.h [new file with mode: 0755]
dali/internal/window-system/windows/event-system-win.h [new file with mode: 0755]
dali/internal/window-system/windows/platform-implement-win.cpp [new file with mode: 0755]
dali/internal/window-system/windows/platform-implement-win.h [new file with mode: 0755]
dali/internal/window-system/windows/render-surface-factory-win.cpp [new file with mode: 0755]
dali/internal/window-system/windows/render-surface-factory-win.h [new file with mode: 0755]
dali/internal/window-system/windows/window-base-win.cpp [new file with mode: 0755]
dali/internal/window-system/windows/window-base-win.h [new file with mode: 0755]
dali/internal/window-system/windows/window-factory-win.cpp [new file with mode: 0755]
dali/internal/window-system/windows/window-factory-win.h [new file with mode: 0755]
dali/internal/window-system/windows/window-system-win.cpp [new file with mode: 0755]
dali/public-api/adaptor-framework/application-configuration.h [new file with mode: 0644]
dali/public-api/adaptor-framework/application.cpp [new file with mode: 0644]
dali/public-api/adaptor-framework/application.h [new file with mode: 0644]
dali/public-api/adaptor-framework/device-status.h [new file with mode: 0644]
dali/public-api/adaptor-framework/input-method.h [new file with mode: 0644]
dali/public-api/adaptor-framework/key-grab.h [new file with mode: 0755]
dali/public-api/adaptor-framework/key.cpp [new file with mode: 0644]
dali/public-api/adaptor-framework/key.h [new file with mode: 0755]
dali/public-api/adaptor-framework/native-image-source.cpp [new file with mode: 0755]
dali/public-api/adaptor-framework/native-image-source.h [new file with mode: 0755]
dali/public-api/adaptor-framework/style-change.h [new file with mode: 0644]
dali/public-api/adaptor-framework/timer.cpp [new file with mode: 0644]
dali/public-api/adaptor-framework/timer.h [new file with mode: 0755]
dali/public-api/adaptor-framework/tts-player.cpp [new file with mode: 0644]
dali/public-api/adaptor-framework/tts-player.h [new file with mode: 0755]
dali/public-api/adaptor-framework/widget-application.cpp [new file with mode: 0644]
dali/public-api/adaptor-framework/widget-application.h [new file with mode: 0644]
dali/public-api/adaptor-framework/widget-impl.cpp [new file with mode: 0644]
dali/public-api/adaptor-framework/widget-impl.h [new file with mode: 0644]
dali/public-api/adaptor-framework/widget.cpp [new file with mode: 0644]
dali/public-api/adaptor-framework/widget.h [new file with mode: 0755]
dali/public-api/adaptor-framework/window.cpp [new file with mode: 0644]
dali/public-api/adaptor-framework/window.h [new file with mode: 0755]
dali/public-api/capture/capture.h [new file with mode: 0755]
dali/public-api/dali-adaptor-common.h [new file with mode: 0755]
dali/public-api/dali-adaptor-version.cpp [new file with mode: 0644]
dali/public-api/dali-adaptor-version.h [new file with mode: 0755]
dali/public-api/file.list [new file with mode: 0644]
dali/public-api/watch/dali-wearable.h [new file with mode: 0644]
dali/public-api/watch/watch-application.h [new file with mode: 0755]
dali/public-api/watch/watch-time.h [new file with mode: 0755]
doc/dali-adaptor-doc.h [new file with mode: 0644]
doc/file.list [new file with mode: 0644]
packaging/dali-adaptor.spec [new file with mode: 0644]
plugins/dali-feedback.cpp [new file with mode: 0644]
plugins/dali-feedback.h [new file with mode: 0644]
plugins/file.list [new file with mode: 0644]
plugins/sounds/file.list [new file with mode: 0644]
plugins/sounds/touch.wav [new file with mode: 0644]
third-party/file.list [new file with mode: 0644]
third-party/glyphy/glyphy-arc-bezier.hh [new file with mode: 0644]
third-party/glyphy/glyphy-arcs-bezier.hh [new file with mode: 0644]
third-party/glyphy/glyphy-arcs.cc [new file with mode: 0644]
third-party/glyphy/glyphy-blob-impl.cc [new file with mode: 0644]
third-party/glyphy/glyphy-common.hh [new file with mode: 0644]
third-party/glyphy/glyphy-extents.cc [new file with mode: 0644]
third-party/glyphy/glyphy-freetype.h [new file with mode: 0644]
third-party/glyphy/glyphy-geometry.hh [new file with mode: 0644]
third-party/glyphy/glyphy-outline.cc [new file with mode: 0644]
third-party/glyphy/glyphy-sdf.cc [new file with mode: 0644]
third-party/glyphy/glyphy.h [new file with mode: 0644]
third-party/glyphy/vector-font-cache.cpp [new file with mode: 0644]
third-party/glyphy/vector-font-cache.h [new file with mode: 0644]
third-party/libunibreak/AUTHORS [new file with mode: 0644]
third-party/libunibreak/LICENCE [new file with mode: 0644]
third-party/libunibreak/README.md [new file with mode: 0644]
third-party/libunibreak/linebreak.c [new file with mode: 0644]
third-party/libunibreak/linebreak.h [new file with mode: 0644]
third-party/libunibreak/linebreakdata.c [new file with mode: 0644]
third-party/libunibreak/linebreakdef.c [new file with mode: 0644]
third-party/libunibreak/linebreakdef.h [new file with mode: 0644]
third-party/libunibreak/unibreakbase.c [new file with mode: 0755]
third-party/libunibreak/unibreakbase.h [new file with mode: 0755]
third-party/libunibreak/unibreakdef.c [new file with mode: 0755]
third-party/libunibreak/unibreakdef.h [new file with mode: 0755]
third-party/libunibreak/wordbreak.c [new file with mode: 0644]
third-party/libunibreak/wordbreak.h [new file with mode: 0644]
third-party/libunibreak/wordbreakdata.c [new file with mode: 0644]
third-party/libunibreak/wordbreakdef.h [new file with mode: 0644]
third-party/resampler/resampler.cpp [new file with mode: 0644]
third-party/resampler/resampler.h [new file with mode: 0644]
third-party/windows-platform/Win32File/CustomFile.cpp [new file with mode: 0644]
third-party/windows-platform/Win32File/CustomFile.h [new file with mode: 0644]
third-party/windows-platform/Win32File/MemFile.cpp [new file with mode: 0644]
third-party/windows-platform/Win32File/OriginalFile.cpp [new file with mode: 0644]
third-party/windows-platform/dirent.h [new file with mode: 0644]
third-party/windows-platform/dlfcn.cpp [new file with mode: 0644]
third-party/windows-platform/dlfcn.h [new file with mode: 0644]
third-party/windows-platform/environment.cpp [new file with mode: 0644]
third-party/windows-platform/extern-definitions.h [new file with mode: 0644]
third-party/windows-platform/netinet/in.h [new file with mode: 0644]
third-party/windows-platform/network.cpp [new file with mode: 0644]
third-party/windows-platform/preprocessor-definitions.h [new file with mode: 0644]
third-party/windows-platform/sys/mman.h [new file with mode: 0644]
third-party/windows-platform/sys/prctl.h [new file with mode: 0644]
third-party/windows-platform/sys/socket.h [new file with mode: 0644]
third-party/windows-platform/sys/time.h [new file with mode: 0644]
third-party/windows-platform/thread.cpp [new file with mode: 0644]
third-party/windows-platform/unistd.h [new file with mode: 0644]

diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..dc0510e
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,70 @@
+Apache License
+
+Version 2.0, January 2004
+
+http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+
+"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+
+"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+
+"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
+
+"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
+
+"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
+
+"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
+
+"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+
+"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
+
+"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
+
+You must give any other recipients of the Work or Derivative Works a copy of this License; and
+You must cause any modified files to carry prominent notices stating that You changed the files; and
+You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
+If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
+
+You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
+5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+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.
\ No newline at end of file
diff --git a/LICENSE.BSD-3-Clause b/LICENSE.BSD-3-Clause
new file mode 100644 (file)
index 0000000..bd25463
--- /dev/null
@@ -0,0 +1,12 @@
+
+Copyright (c) 2017 Samsung Electronics Co, Ltd. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..99a47a6
--- /dev/null
+++ b/README.md
@@ -0,0 +1,106 @@
+<img src="https://dalihub.github.io/images/DaliLogo320x200.png">
+
+# Table of Contents
+
+   * [Build Instructions](#build-instructions)
+      * [1. Building for Ubuntu desktop](#1-building-for-ubuntu-desktop)
+         * [Minimum Requirements](#minimum-requirements)
+         * [Building the Repository](#building-the-repository)
+         * [Build target options](#build-target-options)
+         * [Building and executing test cases](#building-and-executing-test-cases)
+      * [2. GBS Builds](#2-gbs-builds)
+         * [DEBUG Builds](#debug-builds)
+      * [3. Building for MS Windows](#3-building-for-ms-windows)
+         * Build with the Visual Studio project.
+         * Build with CMake.
+
+# Build Instructions
+
+## 1. Building for Ubuntu desktop
+
+### Minimum Requirements
+
+ - Ubuntu 14.04 or later
+ - Environment created using dali_env script in dali-core repository
+ - GCC version 6
+
+DALi requires a compiler supporting C++11 features.
+Ubuntu 16.04 is the first version to offer this by default (GCC v5.4.0).
+
+GCC version 6 is recommended since it has fixes for issues in version 5
+e.g. it avoids spurious 'defined but not used' warnings in header files.
+
+### Building the Repository
+
+To build the repository enter the 'build/tizen' folder:
+
+         $ cd dali-adaptor/build/tizen
+
+Then run the following command to set up the build:
+
+         $ cmake -DCMAKE_INSTALL_PREFIX=$DESKTOP_PREFIX .
+
+If a Debug build is required, then add -DCMAKE_BUILD_TYPE=Debug
+
+To build run:
+
+         $ make install -j8
+
+### Building and executing test cases
+
+See the README.md in dali-adaptor/automated-tests.
+
+## 2. GBS Builds
+
+         $ gbs build -A [TARGET_ARCH]
+
+### DEBUG Builds
+
+         $ gbs build -A [TARGET_ARCH] --define "%enable_debug 1"
+
+
+## 3. Building for MS Windows
+
+Third party dependencies are built using vcpkg. Instructions on how to install vcpkg can be found in the
+vcpkg-script folder in the windows-dependencies repository.
+
+- Download the windows-dependencies repository from DaliHub
+
+         $ git clone https://github.com/dalihub/windows-dependencies.git
+
+- Read the windows-dependencies/vcpkg-script/Readme.md file for more instructions on how to build and install the third-party dependencies.
+
+### Build with the Visual Studio project
+  Read the windows-dependencies/README.md file for more instructions on how to build and run DALi for MS Windows.
+
+### Build with CMake
+
+  * Requirements
+    It's required the version 3.12.2 of CMake and a Git Bash Shell.
+
+  * Notes and troubleshoting:
+    It should be possible to use the MS Visual studio Developer Command Prompt (https://docs.microsoft.com/en-us/dotnet/framework/tools/developer-command-prompt-for-vs) to build DALi from the command line.
+    However, the CMake version installed with MS Visual Studio 2017 is a bit out of date and some VCPKG modules require a higher version.
+    This instructions have been tested with CMake 3.12.2 on a Git Bash shell.
+
+  * Define an environment variable to set the path to the VCPKG folder
+
+    $ export VCPKG_FOLDER=C:/Users/username/Workspace/VCPKG_TOOL
+
+  * Define an environment variable to set the path where DALi is going to be installed.
+
+    $ export DALI_ENV_FOLDER=C:/Users/username/Workspace/dali-env
+
+  * Execute the following commands to create the makefiles, build and install DALi.
+
+    $ cmake -g Ninja . -DCMAKE_TOOLCHAIN_FILE=$VCPKG_FOLDER/vcpkg/scripts/buildsystems/vcpkg.cmake -DENABLE_PKG_CONFIGURE=OFF -DENABLE_LINK_TEST=OFF -DCMAKE_INSTALL_PREFIX=$DALI_ENV_FOLDER -DINSTALL_CMAKE_MODULES=ON -DPROFILE_LCASE=windows
+    $ cmake --build . --target install
+
+  * Options:
+    - CMAKE_TOOLCHAIN_FILE  ---> Needed to find packages installed by VCPKG.
+    - ENABLE_PKG_CONFIGURE  ---> Whether to install pkg configure files (not currently working on MS Windows. CMake modules used instead).
+    - ENABLE_LINK_TEST      ---> Whether to enable the link test (not currently working on MS Windows).
+    - CMAKE_INSTALL_PREFIX  ---> Were DALi is installed.
+    - INSTALL_CMAKE_MODULES ---> Whether to install the CMake modules (Used by the CMake command find_package() to find previously installed libraries).
+    - PROFILE_LCASE         ---> The platform (must be windows).
+    - ENABLE_DEBUG          ---> Whether to build with debug enabled.
diff --git a/adaptors/scripts/dalireslog.sh b/adaptors/scripts/dalireslog.sh
new file mode 100755 (executable)
index 0000000..ae86a9e
--- /dev/null
@@ -0,0 +1,749 @@
+#!/bin/bash
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+# Log resource analyser tool for Dali
+# Monitors resource usage of last run Dali app
+# Shows memory uploaded to GPU or normal RAM
+# Texture atlas usage usually reflects used Font atlases
+
+set -u
+
+#global variables
+TERM_W=0       # latest width of terminal window
+TERM_H=0       # latest height of terminal window
+SEPARATOR_H=5  # 5 lines in info bar
+CURPAGE=0      # current page number
+MAXFILENO=0    # maximum lines to display from resourcelist
+MAXP=0         # number of pages
+
+DLOGTEMPFILE=/tmp/dalidlog.txt
+DLOGUTIL=/usr/bin/dlogutil
+USING_DLOG=
+INPUTFILE=""
+
+
+
+#possible states
+# ID| Desc                             | Color     | Tags
+#---+----------------------------------+-----------+-------
+# 0.| loaded in CPU memory             |  [CPU]    | [LOAD]
+# 1.| present in both memories         |  [CPUGPU] | [LOAD] [UPLOAD]
+# 2.| GPU memory only, buffer discarded|  [GPU]    | [UPLOAD] [DELBUF]
+# 3.| loaded but discarded later on    |  [DISC]   | [LOAD] [DELBUF] or [DELBUF] [DELTEXTURE]
+
+#colors for marking resource state
+COLOR_CPU=5
+COLOR_CPUGPU=1
+COLOR_GPU=2
+COLOR_DISC=6
+
+declare -a COLORS=( $COLOR_CPU $COLOR_CPUGPU $COLOR_GPU $COLOR_DISC )
+
+declare -a FILENAMES_G=( )
+declare -a BITMAPS_G=( )
+declare -a TEXTURES_G=( )
+declare -a STATES_G=( )
+declare -a SIZES_G=( )
+declare -a SIZE_DETAILS_G=( )
+
+ATLASMEM=0
+ATLAS_NO=0
+
+CPUMEM=0
+GPUMEM=0
+
+#process ID of last running Dali app
+PID_G=0
+
+#distinguish texture atlases from framebuffer textures
+BITMAP_ID_ATLAS=0
+BITMAP_ID_FB_TEXTURE="-"
+
+###################################string formatting, command line and error handling
+function error
+{
+  echo "Error: $1"
+  cleanup
+  exit 1
+}
+
+function usage
+{
+    echo "usage: ./dalireslog.sh [FILE]"
+    echo "if FILE isn't specified script will try to use dlogutil"
+}
+
+function getTermSize
+{
+    TERM_W=$(tput cols)
+    TERM_H=$(tput lines)
+
+    let MAXFILENO=$(($TERM_H-$SEPARATOR_H-2)) #leave space for keyboard shortcuts and separator itself
+    let MAXP=${#FILENAMES_G[@]}/$MAXFILENO
+
+    # don't show empty page if list just fits on screen
+    local rmd=0
+    let rmd=${#FILENAMES_G[@]}%$MAXFILENO
+    if [ $rmd -eq 0 ]
+    then
+        let MAXP-=1;
+    fi
+}
+
+# print string, notifying user if it doesn't fit in one line. takes one parameter
+function printString
+{
+    echo -n ${1:0:$TERM_W}
+    if [[ $TERM_W -lt ${#1} ]]
+    then
+        tput cub 1;
+        tput setab 1; tput smso; echo -n '>'; tput el; tput rmso
+        return 1
+    else
+        tput el
+        return 0
+    fi
+}
+
+# print string, clear until end of line, print newline. takes one parameter
+function printLine
+{
+    printString "$1"
+    local RET=$?
+    printf '\n'
+    return $RET
+}
+
+function parseCmdLine
+{
+    if [[ $# -lt 1 ]]
+    then
+        # try using dlogutil
+        if [[ ! -e "$DLOGUTIL" ]]
+        then
+            echo "dlogutil not installed"
+            usage
+            exit 1
+        fi
+
+        INPUTFILE="$DLOGTEMPFILE"
+        USING_DLOG=true
+    else
+        # check if help is requested
+        if [[ $1 == '-h' || $1 == '--help' ]]
+        then
+            usage
+            exit 0
+        # try reading from file
+        else
+            INPUTFILE=$1
+            if [[ ! -e "$INPUTFILE" ]]
+            then
+                echo cannot read file "$INPUTFILE"
+                usage
+                exit 1
+            fi
+        fi
+    fi
+}
+
+# print filename or basename or "..." depending on terminal size, takes one parameter
+function printPath
+{
+    if [ -z "$1" ]
+    then
+        echo "ERROR in printPath";
+        cleanup; exit 1
+    fi
+
+    FILENAME="$1"
+    FBASENAME=$(basename $FILENAME)
+    if [[ ${#FILENAME} -lt $TERM_W ]]
+    then
+        printLine "$FILENAME"
+    else
+        if [[ ${#FBASENAME} -lt $TERM_W ]]
+        then
+            printLine "$FBASENAME"
+        else
+            printLine ...
+        fi
+    fi
+}
+
+###################################memory query functions
+function getGpuMemUsage
+{
+  GPUMEM=0
+  local i=0
+  for state in ${STATES_G[@]}
+  do
+    if [[ $state == 1 || $state == 2 ]]
+    then
+      let GPUMEM+=${SIZES_G[$i]}
+    fi
+    let i+=1
+  done
+  return $GPUMEM
+}
+
+function getCpuMemUsage
+{
+  CPUMEM=0
+  local i=0
+  for state in ${STATES_G[@]}
+  do
+    if [[ $state == 0 || $state == 1 ]]
+    then
+      let CPUMEM+=${SIZES_G[$i]}
+    fi
+    let i+=1
+  done
+  return $CPUMEM
+}
+
+function getAtlasNumber
+{
+  ATLAS_NO=0
+  local i=0
+  for bitmap in ${BITMAPS_G[@]}
+  do
+    if [[ $bitmap == 0 && ${STATES_G[$i]} == 2 ]]
+    then
+      let ATLAS_NO+=1
+    fi
+    let i+=1
+  done
+  return $ATLAS_NO
+}
+
+function getAtlasMemUsage
+{
+  ATLASMEM=0
+  local i=0
+  for bitmap in ${BITMAPS_G[@]}
+  do
+    if [[ $bitmap == 0 && ${STATES_G[$i]} == 2 ]]
+    then
+      let ATLASMEM+=${SIZES_G[$i]}
+    fi
+    let i+=1
+  done
+  return $ATLASMEM
+}
+
+##################################global arrays manipulation
+#adds record to resource list
+#params: filename, bitmap, texture, state, size, size detail
+function addRecord
+{
+  if [ $# -ne 6 ]
+  then
+    error "addRecord - number of arguments is $#"
+  fi
+  FILENAMES_G+=("$1")
+  BITMAPS_G+=("$2")
+  TEXTURES_G+=("$3")
+  STATES_G+=("$4")
+  SIZES_G+=("$5")
+  SIZE_DETAILS_G+=("$6")
+}
+
+#adds image resource to list
+#params: filename, bitmap, size, size detail
+function fileLoaded
+{
+  if [ $# -ne 4 ]
+  then
+    error "fileLoaded"
+  fi
+  FILENAMES_G+=("$1")
+  BITMAPS_G+=("$2")
+  SIZES_G+=("$3")
+  SIZE_DETAILS_G+=("$4")
+  TEXTURES_G+=(0)
+  STATES_G+=(0)
+}
+
+#params: texture, size, size detail
+function atlasUploaded
+{
+  FILENAMES_G+=("-")
+  BITMAPS_G+=("$BITMAP_ID_ATLAS")
+  TEXTURES_G+=("$1")
+  STATES_G+=(2)
+  SIZES_G+=("$2")
+  SIZE_DETAILS_G+=("$3")
+}
+
+#params: size, size detail
+function frameBufUploaded
+{
+  FILENAMES_G+=("$1")
+  BITMAPS_G+=("$BITMAP_ID_FB_TEXTURE")
+  TEXTURES_G+=("$2")
+  STATES_G+=(2)
+  SIZES_G+=("$3")
+  SIZE_DETAILS_G+=("$4")
+}
+
+
+##################################log parsing functions
+function checkLoaded
+{
+  if [[ "$1" =~ .*DALI.*[LOAD].*file\ (.*)\ to\ Bitmap\ (.*)\ -\ size\ ([[:digit:]]*)\ bytes\ (.*) ]]
+  then
+    local FILENAME="${BASH_REMATCH[1]}"
+    local BITMAP="${BASH_REMATCH[2]}"
+    local SIZE="${BASH_REMATCH[3]}"
+    local SIZE_DETAILS="${BASH_REMATCH[4]}"
+
+    local found=0
+
+    #check if file was loaded before with same size
+    local i=0
+    if [ ${#FILENAMES_G[@]} -ne 0 ]
+    then
+
+    for filenameIter in ${FILENAMES_G[@]}
+    do
+      if [[ "$filenameIter" == "$FILENAME" ]]
+      then
+        if [[ ${SIZES_G[$i]} == "$SIZE" && ${SIZE_DETAILS_G[$i]} == "$SIZE_DETAILS" ]]
+        then
+          found=1
+          case ${STATES_G[$i]} in
+            0) #CPU
+              BITMAPS_G[$i]="$BITMAP"
+              ;;
+            1) #CPUGPU
+              BITMAPS_G[$i]="$BITMAP"
+              ;;
+            2) #GPU
+              STATES_G[$i]=1 #GPU->CPUGPU  loaded into memory again
+              BITMAPS_G[$i]="$BITMAP"
+              ;;
+            3) #DISC
+              #previously discarded, load again
+              STATES_G[$i]=0
+              BITMAPS_G[$i]="$BITMAP"
+              ;;
+            *)
+              error "checkLoaded - unknown state"
+              ;;
+          esac
+        else
+          #filename is same, but its loaded in different size
+          :
+        fi
+      fi
+      let i+=1
+    done
+    fi
+
+    if [ $found -ne 1 ]
+    then
+      fileLoaded "$FILENAME" "$BITMAP" "$SIZE" "$SIZE_DETAILS"
+    fi
+
+    return 0
+  else
+    error "checkLoaded"
+  fi
+}
+
+function checkUploaded
+{
+  if [[ "$1" =~ .*DALI.*[UPLOAD].*Bitmap\ (.*)\ to\ Texture\ (.*)\ -\ size\ ([[:digit:]]*)\ bytes\ (.*) ]]
+  then
+    local BITMAP="${BASH_REMATCH[1]}"
+    local TEXTURE="${BASH_REMATCH[2]}"
+    local SIZE="${BASH_REMATCH[3]}"
+    local SIZE_DETAILS="${BASH_REMATCH[4]}"
+
+    local i=0
+    local lastIdx=-1
+
+    if [[ "$BITMAP" =~ \(nil\) ]]
+    then
+      atlasUploaded $TEXTURE $SIZE "$SIZE_DETAILS"
+      return 0
+    else
+      #not a texture atlas
+      if [ ${#BITMAPS_G[@]} -ne $BITMAP_ID_ATLAS ]
+      then
+        for bitmap in ${BITMAPS_G[@]}
+        do
+          if [ $bitmap == $BITMAP ]
+          then
+            lastIdx=$i
+          fi
+        let i+=1
+        done
+      fi
+    fi
+
+    if [ $lastIdx != -1 ]
+    then
+      #Bitmap found
+      if [[ ${TEXTURES_G[$lastIdx]} == 0 && ${STATES_G[$lastIdx]} == 0 ]]
+      then
+        #File loaded in memory -> upload to GPU
+        TEXTURES_G[$lastIdx]="$TEXTURE"
+        STATES_G[$lastIdx]=1
+      elif [[ ${FILENAMES_G[$lastIdx]} == "-" && ${STATES_G[$lastIdx]} == 1 ]]
+      then
+        #BufferImage already in memory and GPU mem. -> updated
+        SIZES_G[$lastIdx]=$SIZE
+        SIZE_DETAILS_G[$lastIdx]="$SIZE_DETAILS"
+      else
+        #bitmap uploaded to new texture
+        addRecord ${FILENAMES_G[$lastIdx]} $BITMAP $TEXTURE 1 $SIZE "$SIZE_DETAILS"
+      fi
+    else
+      #bitmapImage - not loaded from file
+      #newly added
+      addRecord "-" $BITMAP $TEXTURE 1 $SIZE "$SIZE_DETAILS"
+    fi
+    return 0
+  elif [[ "$1" =~ .*DALI.*[UPLOAD].*FrameBufferTexture\ (.*)\ GL\ Texture\ (.*)\ -\ size\ ([[:digit:]]*)\ bytes\ (.*) ]]
+  then
+    local FBTEXTURE="${BASH_REMATCH[1]}"
+    local TEXTURE="${BASH_REMATCH[2]}"
+    local SIZE="${BASH_REMATCH[3]}"
+    local SIZE_DETAILS="${BASH_REMATCH[4]}"
+    frameBufUploaded "$FBTEXTURE" "$TEXTURE" "$SIZE" "$SIZE_DETAILS"
+    return 0
+  else
+    echo "$1"
+    error "checkUploaded"
+  fi
+}
+
+function checkDeletedBuf
+{
+  if [[ "$1" =~ .*DALI.*[DELBUF].*Bitmap\ (.*)\ -\ .*size\ (.*) ]]
+  then
+    local BITMAP=${BASH_REMATCH[1]}
+    local i=0
+
+    for bitmap in ${BITMAPS_G[@]}
+    do
+      if [ $bitmap == "$BITMAP" ]
+      then
+        case ${STATES_G[$i]} in
+        0)
+            STATES_G[$i]=3 #CPU->DISC
+            ;;
+        1)
+            STATES_G[$i]=2 #CPUGPU->GPU
+            ;;
+        2)
+            #GPU->?
+            #probably previously freed bitmap buffer but memory is reused since
+            ;;
+        3)
+            #DISC->?
+            #probably previously freed but memory is reused since
+            ;;
+        *)
+            error "checkDeletedBuf - unkown state"
+            ;;
+        esac
+      fi
+    let i+=1
+    done
+
+    return 0
+  else
+    echo "$1"
+    error "checkDeletedBuf"
+  fi
+}
+
+function checkDeletedTexture
+{
+  if [[ "$1" =~ .*DALI.*[DELTEXTURE].*Texture\ (.*)\ -\ size\ (.*) ]]
+  then
+    local TEXTURE="${BASH_REMATCH[1]}"
+    local i=0
+    local lastIdx=-1
+
+    for texture in ${TEXTURES_G[@]}
+    do
+      if [ $texture == $TEXTURE ]
+      then
+        lastIdx=$i
+      fi
+    let i+=1
+    done
+
+    if [ $lastIdx != -1 ]
+    then
+      case ${STATES_G[$lastIdx]} in
+      0)
+          #CPU->?
+          echo "$1"
+          error "checkDeletedTexture - state CPU"
+          ;;
+      1)
+          STATES_G[$lastIdx]=0 #CPUGPU->CPU
+          ;;
+      2)
+          STATES_G[$lastIdx]=3 #GPU->DISC
+          ;;
+      3)
+          #DISC->?
+          echo "$1"
+          error "checkDeletedTexture - state DISC"
+          ;;
+      *)
+          error "checkDeletedTexture - unkown state"
+          ;;
+      esac
+    else
+      echo "$1"
+      error "checkDeletedTexture - texture not uploaded"
+    fi
+    return 0
+  else
+    echo "$1"
+    error "checkDeletedTexture"
+  fi
+}
+
+function processLine
+{
+  if [[ "$1" =~ .*DALI.*\ \[(.*)\].* ]]
+  then
+    RESCMD=${BASH_REMATCH[1]}
+    case "$RESCMD" in
+    LOAD)
+        checkLoaded "$1"
+        ;;
+    UPLOAD)
+        checkUploaded "$1"
+        ;;
+    DELBUF)
+        checkDeletedBuf "$1"
+        ;;
+    DELTEXTURE)
+        checkDeletedTexture "$1"
+        ;;
+    INIT)
+        ;;
+    FIN)
+        return 1 #end of last log session
+        ;;
+    *)
+        error "Unkown command $RESCMD"
+        ;;
+    esac
+  fi
+  return 0
+}
+
+function parseFile
+{
+  if [ -z "$1" ]
+  then
+    echo "ERROR in parseFile";
+    cleanup; exit 1
+  fi
+
+  #return if file does not contain dali resource log
+  if ! grep -q -m 1 -E "DALI.*\[INIT\]" $1
+  then
+    return 1
+  fi
+
+  #find last resource log session
+  local LOGBUFFER=$(sed -n 'H; /DALI.*\[INIT\]/h; ${g;p;}' $1)
+
+  while read -r line
+  do
+    #show PID of last process
+    PID_G=$(echo "$line" | sed 's/[^0-9]*\([0-9]*\).*/\1/')
+    if [ ! -z "$PID_G" ]
+    then
+      break
+    fi
+  done <<< "$LOGBUFFER"
+
+  while read -r line
+  do
+    if ! processLine "$line" #stop parsing at the end of last session
+    then
+      break
+    fi
+  done <<< "$LOGBUFFER"
+}
+
+##################################draw and main functions
+function redraw
+{
+  tput cup 0 0 #move cursor to top left
+
+  # print info (4 lines)
+  tput bold
+  printLine "PID: $PID_G"
+  printLine "MEM 3D: $GPUMEM"
+  printLine "MEM Atlas: $ATLASMEM";
+  printLine "MEM CPU: $CPUMEM"
+  printLine "Number of atlases: $ATLAS_NO";
+  tput sgr0
+
+  # separator bar (colored bar with (actual/number of files) count)
+  tput cup $SEPARATOR_H 0
+  local PAGEIND="$(expr $CURPAGE + 1)/$(expr $MAXP + 1)"
+  local FILL_W=0
+  let FILL_W=$TERM_W-${#PAGEIND}
+  tput setab 4; printf $PAGEIND%"$FILL_W"s; printf '\n'; tput sgr0
+
+  # print filenames
+  local count=0
+  local index=0
+  let index=$CURPAGE*$MAXFILENO
+
+  filecount=${#FILENAMES_G[@]}
+
+  tput setaf 252
+
+  while [[ $count -lt $MAXFILENO ]]
+  do
+    if [[ $index -lt $filecount ]]
+    then
+      tput setab ${COLORS[${STATES_G[$index]}]}
+#     printPath "${FILENAMES_G[$count]}"
+      printLine "${FILENAMES_G[$index]} ${SIZES_G[$index]} ${SIZE_DETAILS_G[$index]}"
+    else
+      tput sgr0
+      printLine "" #clear remaining lines to fill screen
+    fi
+    let count+=1
+    let index+=1
+  done
+
+  # print keyboard shortcuts
+  tput setab 4; tput bold
+  IFS= printString "  |  n: next page  |  p: previous page  |  ^C: exit  |  Resource state: "
+  # print color codes
+  if [[ $TERM_W -gt 100 ]]
+  then
+    tput setab ${COLORS[0]}
+    echo -n " CPU "
+    tput setab ${COLORS[1]}
+    echo -n " CPUGPU "
+    tput setab ${COLORS[2]}
+    echo -n " GPU "
+    tput setab ${COLORS[3]}
+    echo -n " DISCARDED "
+  fi
+
+  tput sgr0
+}
+
+function readInput
+{
+    local key
+    read -n1 -t 0.3 key
+
+    case "$key" in
+        'p')
+            if [[ $CURPAGE -ne 0 ]]
+            then
+              let CURPAGE-=1
+            fi
+            ;;
+        'n')
+            if [[ $CURPAGE -lt $MAXP ]]
+            then
+              let CURPAGE+=1
+            fi
+            ;;
+    esac
+}
+
+function initVars
+{
+  FILENAMES_G=( )
+  BITMAPS_G=( )
+  TEXTURES_G=( )
+  SIZES_G=( )
+  SIZE_DETAILS_G=( )
+  STATES_G=( )
+}
+
+function cleanup
+{
+  tput cup 9999 0 #go to bottom of screen
+  tput cnorm #show cursor
+  tput sgr0
+  if [ -f "$DLOGTEMPFILE" ]
+  then
+    rm "$DLOGTEMPFILE"
+  fi
+}
+
+function update
+{
+  initVars
+  if [ -n "$USING_DLOG" ]
+  then
+    if [ -f "$DLOGTEMPFILE" ]
+    then
+      rm "$DLOGTEMPFILE"
+    fi
+    "$DLOGUTIL" DALI:I -d -f "$DLOGTEMPFILE" 2>/dev/null
+  fi
+
+  if [ ! -e "$INPUTFILE" ]
+  then
+    return 1
+  fi
+
+  parseFile "$INPUTFILE"
+
+  if [[ $? -gt 0 || ${#STATES_G[@]} -lt 1 ]]
+  then
+    return 1
+  fi
+
+  getCpuMemUsage
+  getGpuMemUsage
+  getAtlasMemUsage
+  getAtlasNumber
+
+  getTermSize
+  readInput
+  redraw
+}
+
+function main
+{
+  parseCmdLine $@
+
+  if [ -z "$INPUTFILE" ]
+  then
+    echo No input file specified;
+    cleanup
+    exit 1
+  fi
+
+  tput civis #hide cursor
+  tput clear #clear screen
+
+  echo "waiting for log..."
+
+  while [ 1 ]
+  do
+    update
+#    sleep 0.3  # we are now reading input for 0.3
+  done
+
+  cleanup
+}
+
+trap "cleanup; exit 0" SIGINT SIGTERM  #reset terminal when ^C is pressed
+# trap "getTermSize" SIGWINCH            #handle window resize
+
+main $@
diff --git a/adaptors/scripts/dalireslog.txt b/adaptors/scripts/dalireslog.txt
new file mode 100644 (file)
index 0000000..cce06af
--- /dev/null
@@ -0,0 +1,23 @@
+Resource log analyzer tool for dali applications
+
+USAGE:
+./dalireslog.sh [FILE]
+if FILE isn't specified script will try to use dlogutil
+
+Example:
+
+sh-4.1$ ./dalireslog.sh
+on a separate terminal:
+sh-4.1$ DALI_ENABLE_LOG=RESOURCE_LOG /opt/apps/com.samsung.dali-demo/bin/album.example
+
+Displayed information:
+3D        - amount of GPU memory used by application
+MEM Atlas - amount of GPU memory used by texture atlases. Usually this means font atlases.
+Number of atlases - how many texture atlases are present in memory
+
+A list of files is displayed in the main view, with different color codes representing different states.
+
+CPU       - resource is in memory, but hasn't been uploaded to a GL texture
+GPU       - resource has been uploaded to a GL texture, bitmap buffer discarded
+CPUGPU    - resource has been uploaded to a GL texture, but still present in CPU memory as well
+DISCARDED - resource has been discarded, memory freed up
diff --git a/adaptors/scripts/parse.rb b/adaptors/scripts/parse.rb
new file mode 100755 (executable)
index 0000000..ee34ea2
--- /dev/null
@@ -0,0 +1,49 @@
+#!/usr/bin/env ruby
+# To use type parse.rb in the same folder as gl-abstraction.h
+# and pipe the output to a file
+#
+# Assemble the gl function call
+#
+# turns this: GLBoolean BlendEquation(GLEnum mode);
+#
+# into an inline function like this:
+#
+# GLBoolean BlendEquation(GLEnum mode)
+# {
+#    return glBlendEquation(mode);
+# }
+
+f = File.new("x11-gles.h")
+#scan each line in the file
+f.each do |x|
+
+  # x is original line, y is the new gl function call
+  y = String.new(x)
+
+  y.lstrip!                 # strip leading white spaces
+  returns = y.index("void"); # see if the function returns void
+  y.gsub!'void',' '          # delete the return types ...
+  y.gsub!(/GL[a-z]*/, '')    # remove GL types such as GLenum
+  y.gsub!('const','')        # remove const, *
+  y.gsub!('char','')         # remove char
+  y.gsub!('*','')            # remove pointer *
+  y.gsub!(/\s+/,"")          # remove all spaces
+  y.insert(0,'  gl')         # add gl to function name
+
+  if (returns != 0)          # insert a return if the function returns
+   y.lstrip!
+   y.insert(0,'  return ')
+  end
+
+  # print the function out
+  y << "\n"
+  x.lstrip!
+  x.gsub!(';','')
+  print x
+  print "{\n"
+  print y
+  print "}\n\n"
+end
+
+
+
diff --git a/automated-tests/.gitignore-with-autogenerated-files b/automated-tests/.gitignore-with-autogenerated-files
new file mode 100644 (file)
index 0000000..f039d8a
--- /dev/null
@@ -0,0 +1,4 @@
+*.xml
+build
+build.log
+tct*core.h
diff --git a/automated-tests/.gitignore-without-autogenerated-files b/automated-tests/.gitignore-without-autogenerated-files
new file mode 100644 (file)
index 0000000..8f3f9e2
--- /dev/null
@@ -0,0 +1,3 @@
+*.xml
+build
+build.log
diff --git a/automated-tests/CMakeLists.txt b/automated-tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5b1729a
--- /dev/null
@@ -0,0 +1,13 @@
+include(CheckIncludeFileCXX)
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+PROJECT(tct_coreapi_utc)
+
+INCLUDE(FindPkgConfig)
+SET(BIN_DIR "/opt/usr/bin")
+
+INCLUDE_DIRECTORIES(
+       src/common
+)
+
+ADD_SUBDIRECTORY(src)
diff --git a/automated-tests/README.md b/automated-tests/README.md
new file mode 100644 (file)
index 0000000..25376f7
--- /dev/null
@@ -0,0 +1,254 @@
+Testing environment   {#auto_testing}
+===================
+
+The new test environment from Tizen is the Web-TCT test suite. This was written for testing web components, but can easily be used for testing Dali.
+
+Each of the DALi repositories, **dali-core**, **dali-adaptor** and **dali-toolkit**, have their own test suites under the `automated-tests` folder. Within the src folder are a number of secondary folders - these correspond to 'API' tests  and internal (for desktop testing only)
+
+Installation
+------------
+
+There are usage instructions and installation instructions on the Tizen.org website [here](http://download.tizen.org/tct/2.2.1/Manual/Web_TCT_2.2.1_User_Guide_v1.0.pdf)
+
+These are device specific instructions, however, installing the test suite will also provide the relevant packages for running tests on Ubuntu ( follow the first block of quickstart instructions below ).
+
+If you are planning on running tests on device, then flash your handset with latest image, or turn off ssh: `set_usb_debug.sh --mtp-sdb` and plug it in, then follow the quickstart instructions repeated below.
+
+Quickstart
+----------
+
+For target or desktop testing:
+
+    cd ~/Packages
+    wget http://download.tizen.org/tct/2.2.1/2.2.1_r1/web-tct_2.2.1_r1.tar.gz
+    sudo tar xzf web-tct_2.2.1_r1.tar.gz
+    cd web-tct_2.2.1_r1/tools
+    sudo -E ./tct-config-host.sh
+
+
+If you are planning on running tests on device, then plug in your freshly flashed device and run the following commands:
+
+    sudo apt-get install sdb
+    ./tct-config-device.sh
+
+**NOTE:** After flashing a handset, you will need to run this step of the installation again.
+
+Testing on desktop
+==================
+
+Building libraries with coverage options
+----------------------------------------
+
+Building dali adaptor:
+
+    cd dali-adaptor  # the location of your dali-adaptor repository
+    cd build/tizen
+    export CC=gcc
+    export CXX=g++
+    git clean -fxd . # Only do this in the build folder
+    CXXFLAGS='-g -O0 --coverage' LDFLAGS='--coverage' cmake -DCMAKE_INSTALL_PREFIX=$DESKTOP_PREFIX -DCMAKE_BUILD_TYPE=Debug
+    make -j8 install
+
+Note, you __must__ use a local build and not a distributed build, and you __must__ also build with debug enabled to allow *DALI_ASSERT_DEBUG* to trigger on wrong behaviour ( Which should always be a test case failure! )
+
+Further note that, for the following, your gcov version must match the version of the compiler.
+
+Building the tests
+------------------
+
+Run the following commands:
+
+    cd automated-tests
+    ./build.sh
+
+This will build dali-adaptor, dali-adaptor-internal and dali-platform-abstraction test sets.
+
+Test sets can be built individually:
+
+    ./build.sh dali-adaptor
+
+They can also be built without regenerating test case scripts (Useful for quicker rebuilds)
+
+    ./build.sh -n dali-adaptor
+
+Or without cleaning down the build area (Useful for fast build/run/debug cycles)
+
+    ./build.sh -n -r dali-adaptor
+
+
+Executing the tests
+-------------------
+
+To see a list of all of the options:
+
+    ./execute.sh -h
+
+To execute tests, cd into automated-tests and run
+
+    ./execute.sh
+
+This will execute dali and dali-internal test sets. Note that the output summary for the first will be printed before running the second.
+
+By default the tests execute in parallel, which is faster but does not produce any test case output files.  Use this to execute the tests in series and log test output to stdout/err
+
+    ./execute.sh -S
+
+To use test kit lite, (which is very slow),
+
+    ./execute.sh -s
+
+To see the test kit lite results, copy the style folder from web-tct_2.2.1_r1/tools/tct-mgr/style into automated-tests and run
+
+    firefox --new-window summary.xml
+
+To execute a subset of tests, you can run individual test sets, e.g.
+
+    ./execute.sh dali-adaptor
+
+To get coverage output (you need to first build dali libraries with
+--coverage), run
+
+    ./coverage.sh
+
+
+Testing on target
+=================
+
+To build for target, first build and install dali-core, dali-adaptor and dali-toolkit, then build dali-capi without --keep-packs option.
+
+You will need to install libconfig-tiny-perl:
+
+sudo apt-get install libconfig-tiny-perl
+
+If you use a non-standard `GBS_ROOT` then you will need to edit the tcbuild script to match your configuration - change line 96 and add a -B option with your GBS-ROOT path (line 96 = `gbs build -A armv7l --spec core-$1-tests.spec --include-all --keep-packs` ).
+To install on device from a non-standard GBS_ROOT, also modify line 28 (`RPM_DIR="$HOME/GBS-ROOT/local/repos/$PROFILE/armv7l/RPMS"`).
+
+For Dali Adaptor, cd into automated-tests, and use:
+
+    sudo ./tcbuild build dali-adaptor
+    sudo ./tcbuild build dali-adaptor-internal
+    sudo ./tcbuild build dali-platform-abstraction
+    ./tcbuild install dali-adaptor
+    ./tcbuild install dali-adaptor-internal
+    ./tcbuild install dali-platform-abstraction
+
+Ensure your handset's filesystem is writable:
+
+    sdb shell su -c "change-booting-mode.sh --update"
+
+To execute tests, cd into automated-tests and run
+
+    tct-mgr
+
+This will bring up the java test suite program. You should see the Plan pane with a list of all tests in. Select the tct-dali-core-tests. and you will be offered a dialog to choose a test plan: either create a new one or use temp.
+Select dali test suite, and click Run, then "Create a new plan", and call it "Dali-Core" or some such. It will now run the dali-test suite.
+
+You can find the output files under /opt/tct/manager/result/
+
+
+Adding tests
+============
+
+To Managed API
+--------------
+
+If you are adding test cases for new or existing managed API (CAPI), you need to add your changes to the src/dali mirror, and copy your change to the managed test suite in core-api. You need to inform HQ of your update.
+
+For internal API
+----------------
+
+If you are adding tests for internal API, then this will only work on desktop, and you should add your tests to the src/dali-adaptor-internal test suite.
+
+General
+-------
+
+If you are adding test cases to existing files, then all you need to do is create functions with the method signature
+
+    int UtcTestcase(void)
+    {
+      TestApplication application;
+      ...
+      END_TEST;
+    }
+
+Note that **the parentheses in the method signature must not be empty** (i.e., it must violate our coding convention and follow __exactly__ this pattern: `int UtcDaliMyTestcaseName(void)`), as it's parsed by an awk script to auto-generate the testcase arrays in the main header file. Neither may any comments on the same line contain empty parentheses.
+
+You can contine to use the TET api, e.g. `tet_infoline`, `tet_result` and our test check methods `DALI_TEST_CHECK`, `DALI_TEST_EQUALS`, etc.
+
+If you need any non-test methods or variables, ensure they are wrapped in an anonymous namespace.
+
+If you are adding new test files, then you need to add the filename to the SET(TC_SOURCES...
+section of CMakeLists.txt (this is also parsed by an awk script prior to building)
+
+Good Practices
+--------------
+Use DALI_TEST_EQUALS to test actual value against expected value, like this:
+
+    DALI_TEST_EQUALS( actor.GetProperty< float >( Actor::Property::COLOR_ALPHA ), 0.9f, TEST_LOCATION );
+
+This will speed up debugging in case the test some day fails. There is also a variant to test that value is greater than expected:
+
+    DALI_TEST_GREATER( textureBindIndex[1], textureBindIndex[2], TEST_LOCATION );
+
+When doing negative tests where your code uses DALI_ASSERT_ALWAYS, use the DALI_TEST_ASSERTION macro, like below:
+
+    DALI_TEST_ASSERTION(
+    {
+        animation.AnimateTo( Property( actor, Actor::Property::PARENT_ORIGIN ), targetParentOrigin );
+    }, "IsPropertyAnimatable( index )" );
+
+This macro will catch the DALi Exception and check that the correct assert message was included. It will also fail the test in case the assert did not occur. It also reduces the amount of false positive error logging whilst the  is being thrown making it easier to see the real errors.
+
+Note, DALI_ASSERT_DEBUG cannot be tested as tests execute against release version of the code.
+
+Use additional scope to control the life of stack allocated objects, such as DALi handles
+
+    // try reparenting an orphaned child
+    {
+        Actor temporaryParent = Actor::New();
+        temporaryParent.Add( child );
+        DALI_TEST_EQUALS( parent2.GetChildCount(), 0u, TEST_LOCATION );
+    }
+    // temporaryParent has now died, reparent the orphaned child
+    parent2.Add( child );
+    DALI_TEST_EQUALS( parent2.GetChildCount(), 1u, TEST_LOCATION );
+
+Always test the output of your test by making your code fail!!!
+
+Debugging
+=========
+
+On desktop, you can debug the tests by running gdb on the test program:
+
+    $ cd automated-tests
+    $ gdb build/src/dali-adaptor/tct-dali-adaptor-core
+    gdb> r <TestCase>
+
+replace `<TestCase>` with the name of the failing testcase.
+
+For example, using testcase UtcDaliLoadCompletion from the dali-platform-abstraction test suite:
+
+    $ gdb build/src/dali-platform-abstraction/tct-dali-platform-abstraction-core
+    gdb> r UtcDaliLoadCompletion
+
+
+On target, you can re-install the test RPM and associated debug RPMs manually using
+
+    sdb push <test-package>.rpm /tmp
+
+After installing the rpm and it's debug RPMs, you can find the executable in /opt/usr/bin/tct-dali-core. First ensure you have smack permissions set:
+
+    chsmack -e "^" /usr/bin/gdb
+    chsmack -e "^" /opt/usr/bin/tct-dali-adaptor-core/tct-dali-adaptor-core
+
+then run it under gdb as above.
+
+
+Troubleshooting
+===============
+
+If when running tct-mgr tests, if "Health-Check get" fails and leaves a white screen on the device, you will need to run `tct-config-device.sh` from your `web-tct/tools` directory (wherever you untarred it) and power cycle your handset. If that still fails, you can work-around the issue by running "`mkdir –p /opt/usr/media/Documents/tct/`" on target – you may also need to kill the getCapabilities app from App Manager on the handset)
+
+If the test results show that the test cases fail with "Undefined reference to XXX", it means you have probably failed to update the dali packages on target.
+
+If all the tests are failing then make sure that you have enabled the engineering mode on the target with the 'change-booting-mode.sh --update' command in sdb shell, as the tests may not have installed correctly.
diff --git a/automated-tests/build.sh b/automated-tests/build.sh
new file mode 100755 (executable)
index 0000000..2f92135
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/bash
+
+
+TEMP=`getopt -o rn --long rebuild,no-gen \
+     -n 'genmake' -- "$@"`
+
+if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
+
+# Note the quotes around `$TEMP': they are essential!
+eval set -- "$TEMP"
+
+opt_rebuild=false
+opt_generate=true
+
+while true ; do
+    case "$1" in
+        -r|--rebuild) opt_rebuild=true ; shift ;;
+        -n|--no-gen)  opt_generate=false ; shift ;;
+        --) shift ; break ;;
+        *) shift ;;   # Ignore
+    esac
+done
+
+if [ false == $opt_rebuild -o ! -d "build" ] ; then
+    rm -rf build
+    mkdir build
+fi
+
+function build
+{
+    if [ $opt_generate == true -o $opt_rebuild == false ] ; then
+        (cd src/$1; ../../scripts/tcheadgen.sh tct-$1-core.h)
+        if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+    fi
+    (cd build ; cmake .. -DMODULE=$1 ; make -j7 )
+}
+
+if [ -n "$1" ] ; then
+  echo BUILDING ONLY $1
+  build $1
+else
+  for mod in `ls -1 src/ | grep -v CMakeList `
+  do
+    if [ $mod != 'common' ] && [ $mod != 'manual' ]; then
+        echo BUILDING $mod
+        build $mod
+        if [ $? -ne 0 ]; then echo "Build failed" ; exit 1; fi
+    fi
+  done
+fi
+
+echo "Build succeeded"
+exit 0
diff --git a/automated-tests/coverage.sh b/automated-tests/coverage.sh
new file mode 100755 (executable)
index 0000000..c5fbed7
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+( cd ../build/tizen ; make cov_data )
+
+# From lcov version 1.10 onwards, branch coverage is off by default and earlier versions do not support the rc option
+LCOV_OPTS=`if [ \`printf "\\\`lcov --version | cut -d' ' -f4\\\`\n1.10\n" | sort -V | head -n 1\` = 1.10 ] ; then echo "--rc lcov_branch_coverage=1" ; fi`
+
+for i in `find . -name "*.dir"` ; do
+    (
+        cd $i
+        echo `pwd`
+        covs=( `ls *.gcda 2>/dev/null` )
+        if [[ $? -eq 0 ]]
+        then
+            lcov $LCOV_OPTS --directory . -c -o dali.info
+            lcov $LCOV_OPTS --remove dali.info "/usr/include/*" "*/automated-tests/*" "*/dali-env/*" -o dali.info
+            if [ ! -s dali.info ]
+            then
+              rm -f dali.info
+            fi
+        fi
+    )
+done
+
+(
+    cd .. ;
+    genhtml $LCOV_OPTS -o build/tizen/doc/coverage `find . -name dali.info`
+)
+
+echo "Coverage output: ../build/tizen/doc/coverage/index.html"
diff --git a/automated-tests/execute.sh b/automated-tests/execute.sh
new file mode 100755 (executable)
index 0000000..902ba11
--- /dev/null
@@ -0,0 +1,162 @@
+#!/bin/bash
+
+TEMP=`getopt -o dhsSmf --long debug,help,failnorerun,serial,tct,modules -n 'execute.sh' -- "$@"`
+
+if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
+
+# Note the quotes around `$TEMP': they are essential!
+eval set -- "$TEMP"
+
+function usage
+{
+    echo -e "Usage: execute.sh [-d][-s|-S|-r] [module|testcase]"
+    echo -e "       execute.sh\t\tExecute test cases from all modules in parallel"
+    echo -e "       execute.sh -f \tExecute test cases from all modules in parallel without rerunning failed test cases"
+    echo -e "       execute.sh -d <testcase>\tDebug testcase"
+    echo -e "       execute.sh [module]\tExecute test cases from the given module in parallel"
+    echo -e "       execute.sh -s [module]\t\tExecute test cases in serial using Testkit-Lite"
+    echo -e "       execute.sh -S [module]\t\tExecute test cases in serial"
+    echo -e "       execute.sh <testcase>\tFind and execute the given test case"
+    exit 2
+}
+
+opt_tct=0
+opt_serial=""
+opt_modules=0
+opt_debug=0
+opt_noFailedRerun="";
+while true ; do
+    case "$1" in
+        -h|--help)     usage ;;
+        -d|--debug)    opt_debug=1 ; shift ;;
+        -s|--tct)      opt_tct=1 ; shift ;;
+        -f|--nofailedrerun) opt_noFailedRerun="-f" ; shift ;;
+        -S|--serial)   opt_serial="-s" ; shift ;;
+        -m|--modules)  opt_modules=1 ; shift ;;
+        --) shift; break;;
+        *) echo "Internal error $1!" ; exit 1 ;;
+    esac
+done
+
+function execute_tct
+{
+    scripts/tctestsgen.sh $1 `pwd` desktop $2
+    testkit-lite -f `pwd`/tests.xml -o tct-${1}-core-tests.xml  -A --comm localhost
+    scripts/add_style.pl $1
+}
+
+function summary_start
+{
+    start=`date +"%Y-%m-%d_%H_%M_%S"`
+    cat > summary.xml <<EOF
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="./style/summary.xsl"?>
+<result_summary plan_name="Core">
+  <other xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string" />
+  <summary test_plan_name="Dali">
+    <start_at>$start</start_at>
+    <end_at>$start</end_at>
+  </summary>
+EOF
+}
+
+function summary_end
+{
+    cat >> summary.xml <<EOF
+</result_summary>
+EOF
+}
+
+if [ $opt_modules == 1 ] ; then
+    modules= get_modules
+    echo $modules
+    exit 0
+fi
+
+# Clean up old test results
+rm -f tct*core-tests.xml
+
+# Clean up old coverage data
+if [ -d ../build/tizen ] ; then
+    rm -f ../build/tizen/dali/.libs/*.gcda
+fi
+
+find build \( -name "*.gcda" \) -exec rm '{}' \;
+
+ASCII_BOLD="\e[1m"
+ASCII_RESET="\e[0m"
+
+modules=`ls -1 src/ | grep -v CMakeList | grep -v common | grep -v manual`
+if [ -f summary.xml ] ; then unlink summary.xml ; fi
+
+if [ $opt_tct == 1 ] ; then
+    # Use Test-kit lite
+    # Run all test case executables serially, create XML output
+    if [ -n "$1" ] ; then
+        execute_tct $1 $*
+    else
+        for mod in $modules
+        do
+            if [ $mod != 'common' ] && [ $mod != 'manual' ]; then
+
+                echo -ne "$ASCII_BOLD"
+                echo -e "Executing $mod$ASCII_RESET"
+                execute_tct $mod $*
+            fi
+        done
+    fi
+
+    scripts/summarize.pl
+
+else
+    # Execute test cases using own test harness
+
+    if [ -z "$1" ] ; then
+        # No arguments:
+        # Execute each test executable in turn (by default, runs tests in parallel)
+        summary_start
+        for mod in $modules
+        do
+            echo -e "$ASCII_BOLD"
+            echo -e "Executing $mod$ASCII_RESET"
+            build/src/$mod/tct-$mod-core $opt_serial $opt_noFailedRerun
+        done
+        summary_end
+
+    elif [ -f "build/src/$1/tct-$1-core" ] ; then
+        # First argument is an executable filename - execute only that with any
+        # remaining arguments
+        summary_start
+        module=$1
+        shift;
+        build/src/$module/tct-$module-core $opt_serial $opt_noFailedRerun $*
+        summary_end
+
+    else
+        # First argument is not an executable. Is it a test case name?
+        # Try executing each executable with the test case name until success/known failure
+        for mod in $modules
+        do
+            output=`build/src/$mod/tct-$mod-core $1`
+            ret=$?
+            if [ $ret -ne 6 ] ; then
+                if [ $opt_debug -ne 0 ] ; then
+                    echo DEBUGGING:
+                    gdb --args build/src/$mod/tct-$mod-core $1
+
+                else
+                    echo $output
+                    if [ $ret -eq 0 ] ; then echo -e "\nPassed" ; fi
+                fi
+                exit $ret
+            fi
+        done
+        echo $1 not found
+    fi
+fi
+
+if [ -f summary.xml ] ; then
+    scripts/output_summary.pl
+fi
+
+exit $?
diff --git a/automated-tests/images/README.md b/automated-tests/images/README.md
new file mode 100644 (file)
index 0000000..3a9d7a3
--- /dev/null
@@ -0,0 +1,17 @@
+% Images for Dali Adaptor Automated Testing
+
+Images used in automated tests for the dali-adaptor project.
+These images include broken files to test error handling as well as valid
+images.
+
+Truncated files are an interesting case and are a plausible consequence of IO
+errors such as network disconnection during downloading of an image by an
+application.
+Some image codecs can sometimes deliver a partial image for such a truncated
+file.
+It is thus a policy decision for us whether to return an image like this to the
+application, to show some junk to the user, or suppress it as a failed load,
+and these tests should demonstrate that that policy is applied for all relevant
+formats.
+
+
diff --git a/automated-tests/images/error-bits.gif b/automated-tests/images/error-bits.gif
new file mode 100644 (file)
index 0000000..02d3df2
Binary files /dev/null and b/automated-tests/images/error-bits.gif differ
diff --git a/automated-tests/images/error-bits.gif.buffer b/automated-tests/images/error-bits.gif.buffer
new file mode 100644 (file)
index 0000000..3c25f9d
--- /dev/null
@@ -0,0 +1,131 @@
+ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½¼¼½@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÛÚÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéutsutsutsutsutsutsutsutsutsutsutsutsutsYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvob¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©utsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{vobvobvobvobvobvobvobvobvobvobvobvobvob\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMvobvobvobvobvobvobvobvobvobvobvobvobvobutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cK\94cKØ\84\84\84\84\84\84\84\84\84\84\84\84\84kÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚøâÚØ\84\84\84\84\84\84\84\84\84\84\84\84\84\99\99\99\99\99\99\99\99\99\99\99\99\99\99futsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsvobvobvobvobvobvobvobvobvobvobvobvobvobvobÍ1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 Í1 æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91æ°\91ÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81\84\84\81ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQâ \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13â \13µ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{Pµ{PE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©vobvobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQvI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µ·¶µdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^vobvobvobvobvobvobvobvobvobvobvobvobvobdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c2\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\162\1f\16! "! "! "! "! "! "! "! "! "! "! "! "! "! "6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fputsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84z\90\84zg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\97\e\13\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZW@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;\9ec;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;³P;Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\Ùu\y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^ùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87£\93\87OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM333333333333333333333333333333333333333ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÈÁ¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQ\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\0\0g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fy3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15y3\15g\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ fg\e\ f\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©°®©     \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b               \b       \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\0\0]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsuts{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿutsutsutsutsutsutsutsutsutsutsutsutsuts\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+!\10
+]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1ctO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>tO>\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333! "! "! "! "! "! "! "! "! "! "! "! "! "! "\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85\8f\8d\85ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#! "! "! "! "! "! "! "! "! "! "! "! "! "\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12\ e\10\12]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c]3\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^utsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsutsuts`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "utsutsutsutsutsutsutsutsutsutsutsutsutsÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<*0<6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\17\1c#\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d\92\93\9d#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)1#)16:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "3333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@QRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fp`fpdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "vobvobvobvobvobvobvobvobvobvobvobvobvobÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÞÉÂÒ³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95Ò³\95\94\94\94\94\94\94\94\94\94\94\94\94\94\94c wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZI\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWdd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^dd^YZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWYZWQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "! "\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóùõóÙ¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©Ù¾©\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94\94c @B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1vI1E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "! "333333333333333333333333333333333333333@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓêÛÓ\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3\99f3oZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIoZIQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQQRQE4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17! "! "! "! "! "! "! "! "! "! "! "! "! "))&))&))&))&))&))&))&))&))&))&))&))&))&6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@JJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJMJJM@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&ëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéëêéÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ333333333333333333333333333333333333333E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ333333333333333333333333333333333333333E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?333333333333333333333333333333333333333333333333333333333333333333333333333333333))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&))&\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99\99ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ333333333333333333333333333333333333333E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(E4(OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:OG:wG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1cwG\1c\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17\16\19\17))&))&))&))&))&))&))&))&))&))&))&))&))&3333333333333333333333333333333333333333336:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?6:?@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@@B@6:?6:?6:?6:?6:?6:?6:?6:?
\ No newline at end of file
diff --git a/automated-tests/images/flag-24bpp.bmp b/automated-tests/images/flag-24bpp.bmp
new file mode 100644 (file)
index 0000000..bbc1518
Binary files /dev/null and b/automated-tests/images/flag-24bpp.bmp differ
diff --git a/automated-tests/images/flag-24bpp.buffer b/automated-tests/images/flag-24bpp.buffer
new file mode 100644 (file)
index 0000000..9af4726
Binary files /dev/null and b/automated-tests/images/flag-24bpp.buffer differ
diff --git a/automated-tests/images/frac-32x64.png b/automated-tests/images/frac-32x64.png
new file mode 100644 (file)
index 0000000..847b0d5
Binary files /dev/null and b/automated-tests/images/frac-32x64.png differ
diff --git a/automated-tests/images/frac.24.bmp b/automated-tests/images/frac.24.bmp
new file mode 100644 (file)
index 0000000..92d81b4
Binary files /dev/null and b/automated-tests/images/frac.24.bmp differ
diff --git a/automated-tests/images/frac.jpg b/automated-tests/images/frac.jpg
new file mode 100644 (file)
index 0000000..336427d
Binary files /dev/null and b/automated-tests/images/frac.jpg differ
diff --git a/automated-tests/images/frac.png b/automated-tests/images/frac.png
new file mode 100644 (file)
index 0000000..307e83b
Binary files /dev/null and b/automated-tests/images/frac.png differ
diff --git a/automated-tests/images/fractal-compressed-ETC1_RGB8_OES-45x80.ktx b/automated-tests/images/fractal-compressed-ETC1_RGB8_OES-45x80.ktx
new file mode 100644 (file)
index 0000000..07256f5
Binary files /dev/null and b/automated-tests/images/fractal-compressed-ETC1_RGB8_OES-45x80.ktx differ
diff --git a/automated-tests/images/fractal-compressed-R11_EAC-45x80.ktx b/automated-tests/images/fractal-compressed-R11_EAC-45x80.ktx
new file mode 100644 (file)
index 0000000..980e57b
Binary files /dev/null and b/automated-tests/images/fractal-compressed-R11_EAC-45x80.ktx differ
diff --git a/automated-tests/images/fractal-compressed-RGB8_ETC2-45x80.ktx b/automated-tests/images/fractal-compressed-RGB8_ETC2-45x80.ktx
new file mode 100644 (file)
index 0000000..5824896
Binary files /dev/null and b/automated-tests/images/fractal-compressed-RGB8_ETC2-45x80.ktx differ
diff --git a/automated-tests/images/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.astc b/automated-tests/images/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.astc
new file mode 100644 (file)
index 0000000..78b370b
Binary files /dev/null and b/automated-tests/images/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.astc differ
diff --git a/automated-tests/images/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.ktx b/automated-tests/images/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.ktx
new file mode 100644 (file)
index 0000000..27234b5
Binary files /dev/null and b/automated-tests/images/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.ktx differ
diff --git a/automated-tests/images/fractal-compressed-RGB_PVRTC_4BPPV1_IMG-32x64.ktx b/automated-tests/images/fractal-compressed-RGB_PVRTC_4BPPV1_IMG-32x64.ktx
new file mode 100644 (file)
index 0000000..a8b7e24
Binary files /dev/null and b/automated-tests/images/fractal-compressed-RGB_PVRTC_4BPPV1_IMG-32x64.ktx differ
diff --git a/automated-tests/images/fractal-compressed-SRBG8_ALPHA8_ASTC_4x4_KHR-32x64.ktx b/automated-tests/images/fractal-compressed-SRBG8_ALPHA8_ASTC_4x4_KHR-32x64.ktx
new file mode 100644 (file)
index 0000000..27234b5
Binary files /dev/null and b/automated-tests/images/fractal-compressed-SRBG8_ALPHA8_ASTC_4x4_KHR-32x64.ktx differ
diff --git a/automated-tests/images/interlaced.gif b/automated-tests/images/interlaced.gif
new file mode 100644 (file)
index 0000000..42b5323
Binary files /dev/null and b/automated-tests/images/interlaced.gif differ
diff --git a/automated-tests/images/interlaced.gif.buffer b/automated-tests/images/interlaced.gif.buffer
new file mode 100644 (file)
index 0000000..dd26e81
Binary files /dev/null and b/automated-tests/images/interlaced.gif.buffer differ
diff --git a/automated-tests/images/pattern.gif b/automated-tests/images/pattern.gif
new file mode 100644 (file)
index 0000000..4e0032a
Binary files /dev/null and b/automated-tests/images/pattern.gif differ
diff --git a/automated-tests/images/pattern.gif.buffer b/automated-tests/images/pattern.gif.buffer
new file mode 100644 (file)
index 0000000..a94cba8
Binary files /dev/null and b/automated-tests/images/pattern.gif.buffer differ
diff --git a/automated-tests/images/test-image-4x4-1bpp.ico b/automated-tests/images/test-image-4x4-1bpp.ico
new file mode 100644 (file)
index 0000000..bb4c9be
Binary files /dev/null and b/automated-tests/images/test-image-4x4-1bpp.ico differ
diff --git a/automated-tests/images/test-image-4x4-24bpp.ico b/automated-tests/images/test-image-4x4-24bpp.ico
new file mode 100644 (file)
index 0000000..0ff3cab
Binary files /dev/null and b/automated-tests/images/test-image-4x4-24bpp.ico differ
diff --git a/automated-tests/images/test-image-4x4-32bpp.ico b/automated-tests/images/test-image-4x4-32bpp.ico
new file mode 100644 (file)
index 0000000..bc742cf
Binary files /dev/null and b/automated-tests/images/test-image-4x4-32bpp.ico differ
diff --git a/automated-tests/images/test-image-4x4-4bpp.ico b/automated-tests/images/test-image-4x4-4bpp.ico
new file mode 100644 (file)
index 0000000..d5eccb4
Binary files /dev/null and b/automated-tests/images/test-image-4x4-4bpp.ico differ
diff --git a/automated-tests/images/test-image-4x4-8bpp.ico b/automated-tests/images/test-image-4x4-8bpp.ico
new file mode 100644 (file)
index 0000000..bd10e2f
Binary files /dev/null and b/automated-tests/images/test-image-4x4-8bpp.ico differ
diff --git a/automated-tests/images/test-image.wbmp b/automated-tests/images/test-image.wbmp
new file mode 100644 (file)
index 0000000..8ec84ae
Binary files /dev/null and b/automated-tests/images/test-image.wbmp differ
diff --git a/automated-tests/images/transparency.gif b/automated-tests/images/transparency.gif
new file mode 100644 (file)
index 0000000..007c50e
Binary files /dev/null and b/automated-tests/images/transparency.gif differ
diff --git a/automated-tests/images/transparency.gif.buffer b/automated-tests/images/transparency.gif.buffer
new file mode 100644 (file)
index 0000000..77ef454
--- /dev/null
@@ -0,0 +1 @@
+U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0U\1fÿ\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\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\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*\1f\0*\1f\0*\1f\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\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U\1f\0\7f?\0ª_\0Ô_UÔ\7f\0Ô\7f\7f\7f\0Ô\7f\9f\7f\7f\0\7f_UU\1f\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0\7f\1f\0ª?\0Ô_UÔ_\0Ô_UÔ\7f\0Ô_UÔ\7f\0Ô\7f\7f\0Ô\7fUÿ\9f\0Ô\7fUÿ\9f\0Ô\9fUÿ\9f\9f\9fUª_U*?\0\0\0\0\0\0\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0U\1f\0\7f?\0Ô?\0ª_UÔ_\0Ô_\0Ô_\0Ô_UÔ\7f\0Ô\7f\0Ô_UÔ\7f\0Ô\7fUÿ\7f\7f\9f\7fUÿ\9f\9fUÿ\9f\9fUÿ¿UÔ\9f\7fUU\1f\0\0\0\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0U\1f\0ª?\0ª?\0Ô?UÔ_\0Ô?\0ª_\0Ô_Uª_\0Ô_\0Ô_UÔ\7f\0Ô\7f\7f\0Ô\7f\7f\0Ô\9f\0ÿ\7f\9f\0ÿ\9f\9fUÿ\9f\0Ô\9fUÿ\9fUÔ¿Uÿ\9f\9fU\7f_\0*\1f\0\0\0\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0*\0\0\7f\1f\0ª?\0ª?UÔ?\0ª_\0Ô?\0ª_UÔ_\0Ô_\0Ô_UÔ\7f\0Ô_UÔ\7f\0Ô\7f\7f\0Ô\7fUÿ\7f\9f\9fUÿ\9f\9f\9fUÿ\9fUÔ¿Uÿ\9fUÿ\9fUÔ¿Uÿ\9fUÿ¿Uª\7fUU?\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0U\1f\0ª\1f\0ª\1fUª?\0Ô?\0Ô?\0Ô_Uª?\0Ô_\0Ô?UÔ_\0Ô_\0Ô_UÔ\7f\0Ô_UÔ\7f\0Ô\7f\7f\0Ô\7fUÿ\7f\0Ô\9f\7f\0ÿ\9f\9f\0ÿ\9f\9fUÿ¿UÔ\9fUÿ\9fUÔ¿Uÿ\9fUÿ¿UÔ\9fUU?U\0\0\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0*\0\0\7f\1f\0ª\1f\0ª?\0ª\1f\0Ô?\0ª?Uª?\0Ô_\0Ô?\0Ô_\0ª_\0Ô_UÔ_\0Ô_\0Ô\7fUÔ_\0Ô\7f\7f\0Ô\7f\9f\0Ô\7fUÿ\9f\9fUÿ\9f\9fUÿ\9f\9fUÿ\9fUÔ¿Uÿ\9fUÔ¿Uÿ\9f\9fUÿ\9fUÔ¿U\7f_\0*\1f\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0*\0\0\7f\1f\0ª\1fUª?\0ª\1f\1f\0ª?\0Ô?\0Ô?\0ª?UÔ_\0ª?UÔ_\0Ô_\0ª_UÔ_\0Ô_\0Ô\7f\7f\0Ô\7f\7f\0ÿ\7f\7f\0Ô\7f\9f\0ÿ\7f\9fUÿ\9f\9fUÿ¿Uÿ\9fUÔ¿Uÿ\9f\9fUÿ¿UÔ\9fUÿ\9f\9fU\7f_U*\0\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U\1fÿ\0\0\0\0\0\0U\1f\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª?\0ª\1fUÔ?\0ª?UÔ?\0ª_\0Ô?\0Ô_\0Ô?UÔ_\0Ô_\0Ô_UÔ\7f\0Ô_\0Ô\7f\7f\0Ô\7f\7f\9f\0ÿ\7f\9f\9f\0ÿ\9f\9f\0ÿ\9f\9fUÿ\9f\9fUÿ¿Uÿ\9fUÔ¿Uÿ\9fUÿ\9f\9f\9fU\7f?\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\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\0U\1f\0ª\1f\0ª\1f\1f\0ª?UÔ\1f\0ª\1f\0ª\1f\0ª?\0ª?\0Ô?UÔ?\0ª_UÔ?\0ª_\0Ô_UÔ_\0ª_\0Ô_UÔ\7f\0Ô_UÔ\7f\0Ô\7fUÿ\7f\0Ô\7f\7f\0ÿ\9f\7f\9fUÿ\9f\9fUÿ\9f\0Ô\9fUÿ\9f\9f\0ÿ\9f\9fUÿ\9fUÔ¿\0ÿ\9f\9f\9fUU?\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0\80\80\80ª\9fªÿûðU_U\0\0\0\0\0\0\0\0\0U\1f\0ª\1f\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª?Uª\1f\0ª?UÔ\1f\0ª?\0ª?\0Ô_\0Ô?\0ª_\0Ô?\0Ô_\0Ô_UÔ_\0Ô_\0Ô\7fUÔ_\0Ô\7f\7f\0Ô\7f\7f\9f\7f\0ÿ\9f\9f\0Ô\9fUÿ\9f\9fUÿ\9f\9fUÿ¿UÔ\9fUÿ\9f\9fUÿ\9f\9fUÿ\9f\0Ô\7f\7fUU\1f\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U?U\80\80\80ÀÜÀÿßÿÿûðÿßÿÀÜÀU?U\0\0\0\0\0\0U\1f\0ª\1f\0ª\1f\1f\0ª\1fUª?\0ª\1f\0ª\1f\0ª\1f\0ª\1f\0ª?UÔ\1f\0ª?UÔ?\0ª_UÔ?\0Ô_Uª_\0Ô_\0Ô_UÔ_\0Ô\7f\0Ô_UÔ\7f\0Ô\7f\7f\0Ô\7f\0ÿ\7f\7f\7f\0ÿ\9f\7f\9f\0ÿ\9f\9f\9f\0ÿ\9f\9fUÿ\9f\0Ô\9f\9fUÿ\9f\9fUÿ\9f\0Ô\7fU\7f_\0*\1f\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U_Uª\9fªÿûðÿûðÿßÿÿûðÿÿÿÿûðÀÜÀU?U\0\0\0\0\0\0U\1f\0ª\1f\0ª\1fUª?\0ª\1f\0ª\1f\0ª\1fUª?\0Ô\1fUª?\0ª\1f\0ª\1f\0ª?\0Ô?\0ª?\0Ô_\0Ô?\0ª?\0Ô_UÔ_\0ª_\0Ô_UÔ_\0Ô\7f\0Ô_UÔ\7f\0Ô\7f\7f\0Ô\7f\9f\0Ô\7f\9fUÿ\7f\0Ô\9f\9fUÿ\9f\9fUÿ\9f\9f\9fUÿ\9f\9f\0Ô\7f\7f\0Ô\9fUÿ\7f\7fUU?\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*?U\80\80\80ÀÜÀÿßÿÿÿÿÿûðÿßÿÿûðÿûðÿßÿÿûðÔ¿ªU?U\0\0\0*\1f\0U\1f\0ª\1f\1f\0ª\1f\0ª\1f\0ª?Uª\1f\0ª?\0ª\1f\0ª\1f\0ª\1fUª?\0Ô\1fUª?\0ª?UÔ?\0ª?UÔ_\0Ô?\0Ô_\0Ô?UÔ_\0Ô_\0Ô_UÔ_\0Ô\7fUÔ_\0Ô\7f\7f\0ÿ\7f\7fUÿ\7f\0Ô\7f\9fUÿ\7f\0Ô\7f\7f\0ÿ\9f\7f\0Ô\9fUÿ\7f\0Ô\9fUÿ\7f\9f\0ÿ\7f\7f\7f\0Ô\7fUª_\0*\1f\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U_U  ¤ÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðª\9fª*?U\0\0\0\0\0\0\80\80\80ª\7f\1f\0ª?\0ª\1fUª?\0ª\1f\0Ô\1f\0ª\1fUª?\0ª\1f\0Ô?\0ª\1f\0ª\1f\0ª\1f\0Ô?\0ª?\0Ô?\0ª_UÔ?\0ª_\0Ô_\0ª_UÔ_\0Ô_\0Ô_UÔ\7f\0Ô_\0Ô\7f\7f\0Ô\7f\7f\0Ô\7f\7f\0Ô\7f\7fUÿ\9f\0Ô\7f\9f\7fUÿ\9f\0Ô\7f\9f\0Ô\7f\9f\7f\0Ô\9f\7f\0Ô\7f\7f\0\7f?U\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*?U\7f_UÀÜÀÿßÿÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿ  ¤*\1fU\0\0\0*\1f\0  ¤ÌÌÿÔ\7f\1f\1f\0ª?\0ª\1f\0ª\1fUª?\0ª\1f\0ª\1f\0ª\1f\1f\0ª?Uª\1f\0ª?Uª\1f\0Ô?Uª?\0Ô_\0Ô?\0ª?UÔ_\0Ô_\0Ô_Uª_\0Ô_\0Ô_UÔ\7f\0Ô_UÔ\7f\0Ô\7f\7f\0Ô\7fUÿ\7f\0Ô\7f\9f\0Ô\7f\7f\0ÿ\7f\9f\0Ô\7f\7fUÿ\7f\7f\0ÿ\7f\7fUÿ\7f\0Ô\7f\7f\0Ô\7fUª_\0U\1f\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U?U  ¤ÀÜÀÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿßÿÿûð  ¤*?\0\0\0\0*\1fU  ¤ÀÜÀÔßÿÔ\7f\1f\0ª?\0ª\1f\1f\0Ô?\0ª\1f\0ª\1fUÔ?\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª?\0ª\1f\0ª?\0Ô?\0ª?UÔ_\0Ô?\0ª?\0Ô_UÔ_\0Ô_\0Ô_UÔ_\0Ô_\0Ô\7fUÔ_\0Ô_\0Ô\7f\7f\0Ô\7f\7f\0Ô\7fUÿ\7f\7f\0Ô\7f\7fUÿ\7f\0Ô\7f\9f\0Ô\7f\7f\0Ô\7f\7f\0Ô\7f\7f\0Ô\7fUÔ_\0U?\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0\80\80\80ª\9fªÔßÿÿûðÿßÿÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÔßÿÿûðÿûðÿßÿÿûðÔßÿÿûð\80\80\80\0\0\0\0\0\0*?U  ¤ÀÜÀÔ¿ÿÿûðÔ\7f\1f\1f\0ª?\0ª\1f\0ª\1fUª?\0ª\1f\0ª\1f\0ª?Uª\1f\0Ô\1fUª?\0ª\1f\1f\0ª?UÔ?\0ª?\0Ô_\0ª?UÔ_\0ª?\0Ô_\0ª_UÔ_\0ª_\0Ô_UÔ_\0Ô\7f\7f\0Ô_UÔ\7f\0Ô\7f\7f\0Ô\7f\7f\0Ô\7f\7f\0Ô\7f\9f\0Ô\7f\7f\0Ô\7f\7f\0Ô\7f\7f\0Ô\7fUÔ_\0Ô\7fUÔ_\0ª_U*\1f\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U?U\80\80\80ÀÜÀÿßÿÿûðÿûðÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÔÿÿÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿûð\80\80\80*\1f\0\0\0\0U?U  ¤ÀÜÀÿßÿÔߪÿßÿª\9fªª\1f\0ª?\0ª\1f\1f\0ª\1f\0ª\1f\0ª?Uª\1f\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª?\0ª\1f\0ª?\0ª?\0Ô?Uª?\0Ô_\0Ô?\0Ô_UÔ?\0Ô_\0Ô_\0Ô_UÔ_\0Ô_\0Ô_\0Ô_UÔ\7f\0Ô_\0Ô\7fUÔ_\0Ô\7f\7f\0Ô\7f\7f\0Ô\7f\7f\0Ô\7f\7f\0ÿ\7f\7f\0Ô\7fUÔ_\0Ô\7fUÔ_\0Ô\7f\0Ô_UÔ_\0U\1f\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U_Uª\9fªÿûðÿûðÿÿÿÿßÿÿûðÿÿÿÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿßÿÀÜÀ\80\80\80\0\0\0\0\0\0U?Uª¿ªÔßÿÔߪÿßÿÿûðÿûðÔ\7f\1f\0ª\1f\0ª?\0ª\1f\0ª?Uª\1f\0ª\1f\0Ô?\0ª\1f\1f\0ª?Uª\1f\0ª\1f\1f\0ª\1f\1f\0Ô?\0ª?\0Ô?Uª_\0Ô?\0ª?\0Ô_Uª?\0Ô_\0Ô_\0ª_UÔ_\0Ô_\0Ô\7fUÔ_\0Ô\7fUÔ_\0Ô\7f\0Ô_UÔ\7f\0Ô\7f\7f\0Ô_UÔ\7f\0Ô_UÔ\7f\0Ô_UÔ\7f\0Ô_\0Ô\7fUÔ_\0Ô_UÔ_\0Ô_\0\7f?\0*\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*?U\80\80\80ÀÜÀÿßÿÿÿÿÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿßÿÀÜÀ\80\80\80\0\0\0\0\0\0U_Uª¿ªÔßÿÿߪÔßÿÿûðÔßÿÿûðÔ\9fªª\1f\0ª?UÔ\1f\0ª\1f\1f\0ª?\0ª\1f\1f\0ª?\0ª\1f\0Ô\1f\0ª\1f\0ª?\0Ô\1f\0ª?\0ª\1f\0ª?UÔ?\0ª?\0Ô?\0ª_UÔ?\0Ô_\0Ô?\0ª_UÔ_\0Ô_\0Ô_UÔ_\0Ô_\0Ô_UÔ_\0Ô\7fUÔ_\0Ô\7fUÔ_\0Ô_\0Ô\7fUÔ_\0Ô\7fUÔ_\0Ô\7f\0Ô_UÔ\7f\0Ô_UÔ_\0Ô_\0Ô_\0Ô_UÔ_\0ª?U*\1f\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U_U  ¤ÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÔßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÔßÿÿûðU_U\0\0\0\0\0\0\7f_U¦ÊðÿÌÿÀÜÀÿßÿÿûðÿûðÿûðÿÿÿÔ\9fªª?Uª\1f\0ª\1f\0ª?\0ª\1f\0Ô\1f\0ª?\0ª\1f\0ª\1f\1f\0ª?Uª\1f\0ª\1fUª?\0ª\1f\1f\0ª\1f\0ª?\0Ô?Uª?\0Ô?\0ª_\0Ô?Uª_\0Ô?\0Ô_Uª_\0Ô_\0ª_UÔ_\0Ô_\0Ô_\0Ô_\0Ô_UÔ_\0Ô\7fUÔ_\0Ô\7f\0Ô_UÔ_\0Ô\7fUÔ_\0Ô_\0Ô_UÔ_\0Ô_\0Ô_UÔ_\0ª_\0Ô_\0ª_\0U\1f\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*?U\80\80\80Ô¿ªÔßÿÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿßÿÿûðÿßÿÿûðÔÿÿÿûðÿûðÿûðÿûðÿßÿÿûðÔÿÿÿßÿÿûðÔ¿ªU?U\0\0\0\0\0\0U_UÀÜÀÔßÿÿߪÔÿÿÿûðÔßÿÿÿÿÿÿÿÿÿÿÔ\9fªÔ?\0ª?\0ª\1f\1f\0ª?Uª\1f\0ª\1fUª?\0Ô\1f\0ª?\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª?\0Ô\1f\0ª?Uª\1f\0ª?\0Ô?\0ª?UÔ_\0Ô?\0Ô_\0ª?\0Ô?\0Ô_UÔ_\0Ô_\0Ô_Uª_\0Ô_UÔ_\0Ô\7f\0Ô_\0Ô_\0Ô_UÔ_\0Ô_\0Ô_\0Ô_\0Ô_UÔ_\0Ô_\0Ô_UÔ_\0ª_\0Ô_UÔ_\0Ô_UÔ?\0\7f?\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U?U  ¤ÀÜÀÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿûðÿßÿÿûðÔßÿÿûðÿûðÿûðÔßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÀÜÀU?U\0\0\0*\1f\0\7f_UÔ¿ªÿßÿÔßÿÿûðÿßÿÿûðÿÿÿÿÿÿÿÿÿÿûðÔ¿ªÔ_Uª\1f\0ª?\0ª\1f\0Ô\1f\0ª?\0ª\1f\0ª\1f\0ª\1f\1f\0ª\1f\1f\0ª?Uª\1f\0ª\1f\1f\0ª\1f\0ª\1f\0ª?Uª?\0Ô?\0ª?\0Ô?Uª_\0Ô?Uª_\0Ô?\0ª?\0Ô_UÔ_\0Ô_\0Ô_\0ª_UÔ_\0Ô_UÔ_\0Ô_\0Ô_UÔ_\0Ô_UÔ_\0Ô_\0ª_UÔ_\0ª_\0Ô_UÔ_\0Ô_\0ª?\0Ô?\0ª_U\7f?\0*\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0\80\80\80ª¿ªÔßÿÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÔÿÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÔ¿ªU?U\0\0\0\0\0\0\7f_UÔ¿UÿßÿÀÜÀÿûðÿûðÿûðÿÿÿÿûðÿÿÿÿûðÿÿÿÀÜÀÔ_Uª?Uª\1f\0ª\1fUª?\0ª\1f\1f\0ª?\0ª\1f\0ª?\0ª\1f\0ª?\0ª\1f\0ª\1f\0Ô?\0ª\1f\0ª?Uª\1f\0Ô\1f\0ª\1f\0ª?UÔ?\0ª?\0Ô?\0Ô_\0Ô?\0ª_UÔ?\0ª?\0Ô?\0ª_UÔ?\0Ô_\0Ô_Uª_\0Ô_Uª_\0Ô_\0ª_UÔ_\0ª_UÔ_\0Ô_\0Ô_UÔ_\0Ô_\0ª?\0Ô_Uª?\0Ô_\0Ô?\0ª?\0U\1f\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U?U\80\80\80ÀÜÀÿßÿÿÿÿÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÔßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÔÿÿÿßÿ  ¤*\1fU\0\0\0*\1f\0\7f_Uÿ\9fUÿ¿UÀÜÀÿûðÿßÿÿûðÿÿÿÿÿÿÿÿÿÿÿÿÔÿÿÿßÿÿßÿÔ\7f\1f\0ª\1f\0ª?\0ª\1f\0ª\1f\0Ô?Uª\1f\0ª\1fUÔ?\0ª\1f\1f\0ª?Uª\1f\0ª\1fUª?\0ª\1f\0ª?\0ª\1fUª?\0ª\1f\0ª?\0Ô?Uª?\0ª?UÔ_\0Ô?\0Ô_\0Ô_Uª?\0Ô_\0ª?\0Ô_Uª?\0Ô_\0Ô?\0Ô_UÔ_\0Ô_\0Ô_\0Ô_\0Ô_Uª?\0Ô_\0ª?\0Ô?UÔ_\0ª?\0Ô_UÔ?\0ª_Uª?\0U\1f\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U_Uª¿ªÿßÿÿûðÿÿÿÿÿÿÿûðÿßÿÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÔßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿûðÔßÿÿûðÿûðÿûðÿßÿÿûð  ¤*?\0\0\0\0*\1f\0ª\7fUÿ\9fUÔ¿Uÿ¿ªÿߪÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÔÿÿÿûðÿûðÿûðÔßÿÔ\9fªª\1f\0ª?UÔ\1f\0ª\1fUª?\0ª\1f\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª\1f\0Ô\1f\0ª?\0ª\1f\0ª\1f\0Ô\1f\1f\0ª\1f\0ª\1f\0ª\1f\1f\0ª?\0Ô?\0ª?\0ª?\0Ô?Uª?\0Ô_\0Ô?\0Ô?UÔ_\0ª?\0Ô_\0Ô?Uª_\0Ô?\0ª?\0Ô?Uª?\0Ô?\0ª?\0Ô_\0Ô?UÔ_\0ª?\0Ô_\0Ô?\0ª?\0Ô_\0ª?\0Ô?UU\1f\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0U?U\80\80\80ÀÜÀÿßÿÿÿÿÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÔÿÿÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÔÿÿÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûð\80\80\80*\1fU\0\0\0*\1f\0ª\7f\9fUÿ¿UÔ\9fUÿ¿UÿßÿÿûðÿÿÿÿÿÿÿûðÿûðÿßÿÿûðÔßÿÿûðÀÜÀÔ\9fªÔ?Uª\1f\0ª?\0ª\1f\0ª\1f\0ª?Uª\1f\0ª\1f\1f\0ª?Uª\1f\0ª?Uª\1f\0ª\1fUª?\0ª\1f\0ª?\0ª\1fUÔ?\0ª?\0ª\1f\0ª\1f\1f\0Ô?Uª?\0Ô?\0ª?\0Ô?Uª_\0ª?\0Ô_\0Ô?Uª?\0Ô_\0ª?\0Ô_UÔ?\0ª_\0Ô_\0Ô?Uª_\0Ô?\0ª_\0Ô?\0Ô_Uª?\0Ô_Uª?\0Ô?Uª?\0ª?\0U\1f\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U_Uª\9fªÔßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿûðÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÔßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿûðÿßÿÿûðÿûðÔßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÔßÿ\80\80\80*\1f\0\0\0\0U?\0ª\7fUÿ\9fUÔ¿Uÿ\9fUÿ¿UÔ¿UÿߪÿÿÿÿÿÿÿÿÿÔßÿÿûðÔÿÿÿûðÔßÿÿûðÿßÿÔ¿ªª_Uª?\0ª\1f\0ª\1fUÔ?\0ª\1f\0ª\1f\0Ô?\0ª\1f\0ª?\0Ô\1f\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª?Uª\1f\0ª\1f\0ª\1f\0ª\1fUª?\0Ô\1f\0ª?\0ª\1f\0ª\1f\0ª?UÔ?\0ª?\0Ô?\0ª?UÔ?\0ª_\0Ô?\0Ô?UÔ_\0ª?\0Ô_\0Ô?Uª?\0Ô_\0Ô?Uª_\0Ô?Uª?\0Ô?\0ª?\0ª?\0Ô?\0ª?\0ª\1f\0Ô\1fUU\1f\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*?U\80\80\80Ô¿ªÔßÿÿßÿÿûðÿûðÿûðÿßÿÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿßÿÿûðÔßÿÿûðÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÔßÿÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÔßÿ\80\80\80*\1f\0\0\0\0U?Uª\7fUÿ¿UÔ\9fUÿ\9fUÔ¿Uÿ\9f\9fªÿߪÿÿÿÿÿÿÿûðÿûðÿûðÔßÿÿûðÀÜÀÿßÿÀÜÀÔߪÔ\7f\1f\1f\0ª?\0ª\1f\0ª\1fUª?\0ª\1f\1f\0ª\1fUª?\0ª\1f\1f\0Ô?Uª\1f\0ª\1f\0Ô?\0ª\1fUª?\0ª\1f\0ª\1f\0ª\1f\1f\0ª?Uª\1f\0ª\1f\0ª?\0ª?Uª?\0Ô?\0ª?\0Ô?Uª?\0ª?\0Ô?\0ª?UÔ?\0ª_\0Ô?\0ª?\0Ô?\0ª?\0Ô?\0ª?\0ª?UÔ?\0ª?Uª\1f\0ª\1fUª?\0ª\1f\0*\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*\1f\0U?U  ¤ÀÜÀÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÔßÿÿûðÿûðÿûðÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÔßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÿûðÿßÿÀÜÀ\80\80\80*\0\0\0\0\0U?\0ª\7fUÿ\9fUÔ¿Uÿ\9fUÿ¿UÔ\9fUÿ\9fUÿ\9fUÔߪÿÿÿÿßÿÔÿÿÿßÿÔßÿÿߪÔßÿÿûðÀÜÀÿÌÿÀÜÀÔ\7fªª?\0Ô\1f\0ª\1fUª?\0ª\1f\0ª\1f\0ª?\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª?\0ª\1f\0ª\1f\0ª?Uª\1f\0ª\1f\0ª\1f\0Ô?Uª\1f\0ª?\0ª\1f\0ª\1f\0ª?\0ª\1f\1f\0Ô\1f\0ª\1f\0ª?Uª\1f\0ª?\0Ô?\0ª?UÔ?\0ª?\0ª?\0Ô?Uª?\0ª?UÔ?\0ª?Uª?\0Ô?\0ª?\0ª\1f\0ª\1f\0ª?\0Ô\1f\0ª\1f\0\7f\1f\0U\1f\0\0\0\0\0\0\0U\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿU\1fÿ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0*?U\7f_Uª¿ªÿßÿÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿûðÿûðÿßÿÿûðÿûðÿûðÿßÿÿûðÔÿÿÿûðÿûðÿûðÿßÿÿûðÿßÿÿûðÿûðÿßÿÿûðÿûðÿßÿÿûðÔßÿÿû
\ No newline at end of file
diff --git a/automated-tests/packaging/core-dali-adaptor-tests.spec b/automated-tests/packaging/core-dali-adaptor-tests.spec
new file mode 100644 (file)
index 0000000..ba56a0f
--- /dev/null
@@ -0,0 +1,51 @@
+%define MODULE_NAME dali-adaptor
+%define MODULE_LIBNAME dali-adaptor
+Name:       core-%{MODULE_NAME}-tests
+Summary:    Core API unit TC (%{name})
+Version:    0.1
+Release:    0
+Group:      Development/Tools
+License:    Apache-2.0
+Source0:    %{name}-%{version}.tar.gz
+Requires: dali-adaptor
+Requires: dali
+BuildRequires:  dali-integration-devel
+BuildRequires:  pkgconfig(dali-core)
+BuildRequires:  pkgconfig(dali)
+BuildRequires:  cmake
+BuildRequires:  pkgconfig(ecore)
+
+%description
+Core API unit TC (%{name})
+
+%prep
+%setup -q
+
+%build
+
+%define PREFIX "%{_libdir}/%{name}"
+
+export LDFLAGS+="-Wl,--rpath=%{PREFIX} -Wl,--as-needed"
+cd automated-tests
+cmake . -DMODULE="%{MODULE_NAME}" -DCMAKE_INSTALL_PREFIX=%{_prefix}
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+cd automated-tests
+%make_install
+mkdir -p %{buildroot}/tmp/
+cp %{_builddir}/%{name}-%{version}/automated-tests/scripts/add_all_smack_rule.sh %{buildroot}/tmp/
+cp %{_builddir}/%{name}-%{version}/automated-tests/scripts/all_smack.rule %{buildroot}/tmp/
+
+%post
+
+%postun
+
+
+%files
+/opt/usr/bin/*
+/tmp/add_all_smack_rule.sh
+/tmp/all_smack.rule
+%license LICENSE
\ No newline at end of file
diff --git a/automated-tests/packaging/core-dali-platform-abstraction-tests.spec b/automated-tests/packaging/core-dali-platform-abstraction-tests.spec
new file mode 100644 (file)
index 0000000..497d5b1
--- /dev/null
@@ -0,0 +1,51 @@
+%define MODULE_NAME dali-platform-abstraction
+%define MODULE_LIBNAME dali-platform-abstraction
+Name:       core-%{MODULE_NAME}-tests
+Summary:    Core API unit TC (%{name})
+Version:    0.1
+Release:    0
+Group:      Development/Tools
+License:    Apache-2.0
+Source0:    %{name}-%{version}.tar.gz
+Requires: dali-adaptor
+Requires: dali
+BuildRequires:  dali-integration-devel
+BuildRequires:  pkgconfig(dali-core)
+BuildRequires:  pkgconfig(dali)
+BuildRequires:  cmake
+
+
+%description
+Core API unit TC (%{name})
+
+%prep
+%setup -q
+
+%build
+
+%define PREFIX "%{_libdir}/%{name}"
+
+export LDFLAGS+="-Wl,--rpath=%{PREFIX} -Wl,--as-needed"
+cd automated-tests
+cmake . -DMODULE="%{MODULE_NAME}" -DCMAKE_INSTALL_PREFIX=%{_prefix}
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+cd automated-tests
+%make_install
+mkdir -p %{buildroot}/tmp/
+cp %{_builddir}/%{name}-%{version}/automated-tests/scripts/add_all_smack_rule.sh %{buildroot}/tmp/
+cp %{_builddir}/%{name}-%{version}/automated-tests/scripts/all_smack.rule %{buildroot}/tmp/
+
+%post
+
+%postun
+
+
+%files
+/opt/usr/bin/*
+/tmp/add_all_smack_rule.sh
+/tmp/all_smack.rule
+%license LICENSE
diff --git a/automated-tests/patch-coverage.pl b/automated-tests/patch-coverage.pl
new file mode 100755 (executable)
index 0000000..c5d9083
--- /dev/null
@@ -0,0 +1,758 @@
+#!/usr/bin/perl
+#
+# Copyright (c) 2020 Samsung Electronics Co., Ltd.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+use strict;
+use Git;
+use Getopt::Long;
+use Error qw(:try);
+use HTML::Element;
+use Pod::Usage;
+use File::Basename;
+#use Data::Dumper;
+use File::stat;
+use Scalar::Util qw /looks_like_number/;
+use Cwd qw /getcwd/;
+use Term::ANSIColor qw(:constants);
+
+# Program to run gcov on files in patch (that are in source dirs - needs to be dali-aware).
+
+# A) Get patch
+# B) Remove uninteresting files
+# C) Find matching gcno/gcda files
+# D) Copy and rename them to match source prefix (i.e. strip library name off front)
+# E) Generate patch output with covered/uncovered lines marked in green/red
+# F) Generate coverage data for changed lines
+# G) Exit status should be 0 for high coverage (90% line coverage for all new/changed lines)
+#    or 1 for low coverage
+
+# Sources for conversion of gcno/gcda files:
+# ~/bin/lcov
+# Python git-coverage (From http://stef.thewalter.net/git-coverage-useful-code-coverage.html)
+
+our $repo = Git->repository();
+our $debug=0;
+our $pd_debug=0;
+our $opt_cached;
+our $opt_help;
+our $opt_output;
+our $opt_quiet;
+our $opt_verbose;
+
+my %options = (
+    "cached"       => { "optvar"=>\$opt_cached, "desc"=>"Use index" },
+    "output:s"     => { "optvar"=>\$opt_output, "desc"=>"Generate html output"},
+    "help"         => { "optvar"=>\$opt_help, "desc"=>""},
+    "quiet"        => { "optvar"=>\$opt_quiet, "desc"=>""},
+    "verbose"      => { "optvar"=>\$opt_verbose, "desc"=>"" });
+
+my %longOptions = map { $_ => $options{$_}->{"optvar"} } keys(%options);
+GetOptions( %longOptions ) or pod2usage(2);
+pod2usage(1) if $opt_help;
+
+
+## Format per file, repeated, no linebreak
+# <diffcmd>
+# index c1..c2 c3
+# --- a/<left-hand-side-file>
+# +++ b/<right-hand-side-file>
+# <diff hunks>
+
+# Format of each diff hunk, repeated, no linebreak
+# @@ <ranges> @@ line
+# 3 lines of context
+# [-|+]lines removed on left, added on right
+# 3 lines of context
+#
+# output:
+sub parse_diff
+{
+    my $patchref = shift;
+    my $file="";
+    my @checklines=();
+    my %b_lines=();
+    my $state = 0;
+    my $store_line=-1;
+    my %files=();
+
+    print "Patch size: ".scalar(@$patchref)."\n" if $pd_debug;
+    for my $line (@$patchref)
+    {
+        if($state == 0)
+        {
+            print "State: $state  $line  \n" if $pd_debug;
+            # Search for a line matching "+++ b/<filename>"
+            if( $line =~ m!^\+\+\+ b/([\w-_\./]*)!)
+            {
+                $file = $1;
+                $state = 1 ;
+                print "Found File: $file\n" if $pd_debug;
+            }
+        }
+        else #elsif($state == 1)
+        {
+            # If we find a line starting with diff, the previous
+            # file's diffs have finished, store them.
+            if( $line =~ /^diff/)
+            {
+                print "State: $state  $line  \n" if $pd_debug;
+                $state = 0;
+                # if the file had changes, store the new/modified line numbers
+                if( $file && scalar(@checklines))
+                {
+                    $files{$file}->{"patch"} = [@checklines];
+                    $files{$file}->{"b_lines"} = {%b_lines};
+                    @checklines=();
+                    %b_lines=();
+                }
+                print("\n\n") if $pd_debug;
+            }
+            # If we find a line starting with @@, it tells us the line numbers
+            # of the old file and new file for this hunk.
+            elsif( $line =~ /^@@/)
+            {
+                print "State: $state  $line  \n" if $pd_debug;
+
+                # Find the lines in the new file (of the form "+<start>[,<length>])
+                my($start,$space,$length) = ($line =~ /\+([0-9]+)(,| )([0-9]+)?/);
+                if($length || $space eq " ")
+                {
+                    if( $space eq " " )
+                    {
+                        $length=1;
+                    }
+                    push(@checklines, [$start, $length]);
+                    $store_line=$start;
+                }
+                else
+                {
+                    $store_line = -1;
+                }
+                if($pd_debug)
+                {
+                    my $last = scalar(@checklines)-1;
+                    if( $last >= 0 )
+                    {
+                        print "Checkline:" . $checklines[$last]->[0] . ", " . $checklines[$last]->[1] . "\n";
+                    }
+                }
+            }
+            # If we find a line starting with "+", it belongs to the new file's patch
+            elsif( $line =~ /^\+/)
+            {
+               if($store_line >= 0)
+               {
+                   chomp;
+                   $line = substr($line, 1); # Remove leading +
+                   $b_lines{$store_line} = $line;
+                   $store_line++;
+               }
+            }
+        }
+    }
+    # Store the final entry
+    $files{$file}->{"patch"} = [@checklines];
+    $files{$file}->{"b_lines"} = {%b_lines};
+
+    my %filter = map { $_ => $files{$_} } grep {m!^dali(-toolkit)?/!} (keys(%files));;
+
+    if($pd_debug)
+    {
+        print("Filtered files:\n");
+        foreach my $file (keys(%filter))
+        {
+            print("$file: ");
+            $patchref = $filter{$file}->{"patch"};
+            foreach my $lineblock (@$patchref)
+            {
+                print "$lineblock->[0]($lineblock->[1]) "
+            }
+            print ( "\n");
+        }
+    }
+
+    return {%filter};
+}
+
+sub show_patch_lines
+{
+    my $filesref = shift;
+    print "\nNumber of files: " . scalar(keys(%$filesref)) . "\n";
+    for my $file (keys(%$filesref))
+    {
+        print("$file:");
+        my $clref = $filesref->{$file}->{"patch"};
+        for my $cl (@$clref)
+        {
+            print("($cl->[0],$cl->[1]) ");
+        }
+        print("\n");
+    }
+}
+
+sub get_gcno_file
+{
+    # Assumes test cases have been run, and "make rename_cov_data" has been executed
+
+    my $file = shift;
+    my ($name, $path, $suffix) = fileparse($file, (".c", ".cpp", ".h"));
+    my $gcno_file = $repo->wc_path() . "/build/tizen/.cov/$name.gcno";
+
+    # Note, will translate headers to their source's object, which
+    # may miss execution code in the headers (e.g. inlines are usually
+    # not all used in the implementation, and require getting coverage
+    # from test cases.
+
+    if( -f $gcno_file )
+    {
+        my $gcno_st = stat($gcno_file);
+        my $fq_file = $repo->wc_path() . $file;
+        my $src_st = stat($fq_file);
+        if($gcno_st->ctime < $src_st->mtime)
+        {
+            print "WARNING: GCNO $gcno_file older than SRC $fq_file\n";
+            $gcno_file="";
+        }
+
+    }
+    else
+    {
+        print("WARNING: No equivalent gcno file for $file\n");
+    }
+    return $gcno_file;
+}
+
+our %gcovfiles=();
+sub get_coverage
+{
+    my $file = shift;
+    my $filesref = shift;
+    print("get_coverage($file)\n") if $debug;
+
+    my $gcno_file = get_gcno_file($file);
+    my @gcov_files = ();
+    my $gcovfile;
+    if( $gcno_file )
+    {
+        print "Running gcov on $gcno_file:\n" if $debug;
+        open( my $fh,  "gcov --preserve-paths $gcno_file |") || die "Can't run gcov:$!\n";
+        while( <$fh> )
+        {
+            print $_ if $debug>=3;
+            chomp;
+            if( m!'(.*\.gcov)'$! )
+            {
+                my $coverage_file = $1; # File has / replaced with # and .. replaced with ^
+                my $source_file = $coverage_file;
+                $source_file =~ s!\^!..!g;  # Change ^ to ..
+                $source_file =~ s!\#!/!g;   # change #'s to /s
+                $source_file =~ s!.gcov$!!; # Strip off .gcov suffix
+
+                print "Matching $file against $source_file\n" if $debug >= 3;
+                # Only want the coverage files matching source file:
+                if(index( $source_file, $file ) > 0 )
+                {
+                    $gcovfile = $coverage_file;
+                    # Some header files do not produce an equivalent gcov file so we shouldn't parse them
+                    if(($source_file =~ /\.h$/) && (! -e $gcovfile))
+                    {
+                        print "Omitting Header: $source_file\n" if $debug;
+                        $gcovfile = ""
+                    }
+                    last;
+                }
+            }
+        }
+        close($fh);
+
+        if($gcovfile)
+        {
+            if($gcovfiles{$gcovfile} == undef)
+            {
+                # Only parse a gcov file once
+                $gcovfiles{$gcovfile}->{"seen"}=1;
+
+                print "Getting coverage data from $gcovfile\n" if $debug;
+
+                open( FH, "< $gcovfile" ) || die "Can't open $gcovfile for reading:$!\n";
+                while(<FH>)
+                {
+                    my ($cov, $line, @code ) = split( /:/, $_ );
+                    $cov =~ s/^\s+//; # Strip leading space
+                    $line =~ s/^\s+//;
+                    my $code=join(":", @code);
+                    if($cov =~ /\#/)
+                    {
+                        # There is no coverage data for these executable lines
+                        $gcovfiles{$gcovfile}->{"uncovered"}->{$line}++;
+                        $gcovfiles{$gcovfile}->{"src"}->{$line}=$code;
+                    }
+                    elsif( $cov ne "-" && looks_like_number($cov) && $cov > 0 )
+                    {
+                        $gcovfiles{$gcovfile}->{"covered"}->{$line}=$cov;
+                        $gcovfiles{$gcovfile}->{"src"}->{$line}=$code;
+                    }
+                    else
+                    {
+                        # All other lines are not executable.
+                        $gcovfiles{$gcovfile}->{"src"}->{$line}=$code;
+                    }
+                }
+                close( FH );
+            }
+            $filesref->{$file}->{"coverage"} = $gcovfiles{$gcovfile}; # store hashref
+        }
+        else
+        {
+            # No gcov output - the gcno file produced no coverage of the source/header
+            # Probably means that there is no coverage for the file (with the given
+            # test case - there may be some somewhere, but for the sake of speed, don't
+            # check (yet).
+        }
+    }
+}
+
+# Run the git diff command to get the patch, then check the coverage
+# output for the patch.
+sub run_diff
+{
+    #print "run_diff(" . join(" ", @_) . ")\n";
+    my ($fh, $c) = $repo->command_output_pipe(@_);
+    our @patch=();
+    while(<$fh>)
+    {
+        chomp;
+        push @patch, $_;
+    }
+    $repo->command_close_pipe($fh, $c);
+
+    print "Patch size: " . scalar(@patch) . "\n" if $debug;
+
+    # @patch has slurped diff for all files...
+    my $filesref = parse_diff ( \@patch );
+    show_patch_lines($filesref) if $debug;
+
+    print "Checking coverage:\n" if $debug;
+
+    my $cwd=getcwd();
+    chdir ".cov" || die "Can't find $cwd/.cov:$!\n";
+
+    for my $file (keys(%$filesref))
+    {
+        my ($name, $path, $suffix) = fileparse($file, qr{\.[^.]*$});
+        next if($path !~ /^dali/);
+        if($suffix eq ".cpp" || $suffix eq ".c" || $suffix eq ".h")
+        {
+            get_coverage($file, $filesref);
+        }
+    }
+    chdir $cwd;
+    return $filesref;
+}
+
+sub calc_patch_coverage_percentage
+{
+    my $filesref = shift;
+    my $total_covered_lines = 0;
+    my $total_uncovered_lines = 0;
+
+    foreach my $file (keys(%$filesref))
+    {
+        my ($name, $path, $suffix) = fileparse($file, qr{\.[^.]*$});
+        next if($path !~ /^dali/);
+
+        my $covered_lines = 0;
+        my $uncovered_lines = 0;
+
+        my $patchref = $filesref->{$file}->{"patch"};
+        my $coverage_ref = $filesref->{$file}->{"coverage"};
+        if( $coverage_ref )
+        {
+            for my $patch (@$patchref)
+            {
+                for(my $i = 0; $i < $patch->[1]; $i++ )
+                {
+                    my $line = $i + $patch->[0];
+                    if($coverage_ref->{"covered"}->{$line})
+                    {
+                        $covered_lines++;
+                        $total_covered_lines++;
+                    }
+                    if($coverage_ref->{"uncovered"}->{$line})
+                    {
+                        $uncovered_lines++;
+                        $total_uncovered_lines++;
+                    }
+                }
+            }
+            $coverage_ref->{"covered_lines"} = $covered_lines;
+            $coverage_ref->{"uncovered_lines"} = $uncovered_lines;
+            my $total = $covered_lines + $uncovered_lines;
+            my $percent = 0;
+            if($total > 0)
+            {
+                $percent = $covered_lines / $total;
+            }
+            $coverage_ref->{"percent_covered"} = 100 * $percent;
+        }
+    }
+    my $total_exec = $total_covered_lines + $total_uncovered_lines;
+    my $percent = 0;
+    if($total_exec > 0) { $percent = 100 * $total_covered_lines / $total_exec; }
+
+    return [ $total_exec, $percent ];
+}
+
+sub patch_output
+{
+    my $filesref = shift;
+    foreach my $file (keys(%$filesref))
+    {
+        my ($name, $path, $suffix) = fileparse($file, qr{\.[^.]*$});
+        next if($path !~ /^dali/);
+
+        my $patchref = $filesref->{$file}->{"patch"};
+        my $b_lines_ref = $filesref->{$file}->{"b_lines"};
+        my $coverage_ref = $filesref->{$file}->{"coverage"};
+        print BOLD, "$file  ";
+
+        if($coverage_ref)
+        {
+            if( $coverage_ref->{"covered_lines"} > 0
+                ||
+                $coverage_ref->{"uncovered_lines"} > 0 )
+            {
+                print GREEN, "Covered: " . $coverage_ref->{"covered_lines"}, RED, " Uncovered: " . $coverage_ref->{"uncovered_lines"}, RESET;
+            }
+        }
+        else
+        {
+            if($suffix eq ".cpp" || $suffix eq ".c" || $suffix eq ".h")
+            {
+                print RED;
+            }
+            print "No coverage found";
+        }
+        print RESET "\n";
+
+        for my $patch (@$patchref)
+        {
+            my $hunkstr="Hunk: " . $patch->[0];
+            if( $patch->[1] > 1 )
+            {
+                $hunkstr .= " - " . ($patch->[0]+$patch->[1]-1);
+            }
+            print BOLD, "$hunkstr\n",  RESET;
+            for(my $i = 0; $i < $patch->[1]; $i++ )
+            {
+                my $line = $i + $patch->[0];
+                printf "%-6s  ", $line;
+
+                if($coverage_ref)
+                {
+                    my $color;
+                    if($coverage_ref->{"covered"}->{$line})
+                    {
+                        $color=GREEN;
+                    }
+                    elsif($coverage_ref->{"uncovered"}->{$line})
+                    {
+                        $color=BOLD . RED;
+                    }
+                    else
+                    {
+                        $color=BLACK;
+                    }
+                    my $src=$coverage_ref->{"src"}->{$line};
+                    chomp($src);
+                    print $color, "$src\n", RESET;
+                }
+                else
+                {
+                    # We don't have coverage data, so print it from the patch instead.
+                    my $src = $b_lines_ref->{$line};
+                    print "$src\n";
+                }
+            }
+        }
+    }
+}
+
+
+sub patch_html_output
+{
+    my $filesref = shift;
+
+    my $html = HTML::Element->new('html');
+    my $head = HTML::Element->new('head');
+    my $title = HTML::Element->new('title');
+    $title->push_content("Patch Coverage");
+    $head->push_content($title, "\n");
+    $html->push_content($head, "\n");
+
+    my $body = HTML::Element->new('body');
+    $body->attr('bgcolor', "white");
+
+    foreach my $file (sort(keys(%$filesref)))
+    {
+        my ($name, $path, $suffix) = fileparse($file, qr{\.[^.]*$});
+        next if($path !~ /^dali/);
+
+        my $patchref = $filesref->{$file}->{"patch"};
+        my $b_lines_ref = $filesref->{$file}->{"b_lines"};
+        my $coverage_ref = $filesref->{$file}->{"coverage"};
+
+        my $header = HTML::Element->new('h2');
+        $header->push_content($file);
+        $body->push_content($header);
+        $body->push_content("\n");
+        if($coverage_ref)
+        {
+            if( $coverage_ref->{"covered_lines"} > 0
+                ||
+                $coverage_ref->{"uncovered_lines"} > 0 )
+            {
+                my $para = HTML::Element->new('p');
+                my $covered = HTML::Element->new('span');
+                $covered->attr('style', "color:green;");
+                $covered->push_content("Covered: " . $coverage_ref->{"covered_lines"} );
+                $para->push_content($covered);
+
+                my $para2 = HTML::Element->new('p');
+                my $uncovered = HTML::Element->new('span');
+                $uncovered->attr('style', "color:red;");
+                $uncovered->push_content("Uncovered: " . $coverage_ref->{"uncovered_lines"} );
+                $para2->push_content($uncovered);
+                $body->push_content($para, $para2);
+            }
+            else
+            {
+                #print "coverage ref exists for $file:\n" . Data::Dumper::Dumper($coverage_ref) . "\n";
+            }
+        }
+        else
+        {
+            my $para = HTML::Element->new('p');
+            my $span = HTML::Element->new('span');
+            if($suffix eq ".cpp" || $suffix eq ".c" || $suffix eq ".h")
+            {
+                $span->attr('style', "color:red;");
+            }
+            $span->push_content("No coverage found");
+            $para->push_content($span);
+            $body->push_content($para);
+        }
+
+        for my $patch (@$patchref)
+        {
+            my $hunkstr="Hunk: " . $patch->[0];
+            if( $patch->[1] > 1 )
+            {
+                $hunkstr .= " - " . ($patch->[0]+$patch->[1]-1);
+            }
+
+            my $para = HTML::Element->new('p');
+            my $span = HTML::Element->new('span');
+            $span->attr('style', "font-weight:bold;");
+            $span->push_content($hunkstr);
+            $para->push_content($span);
+            $body->push_content($para);
+
+            my $codeHunk = HTML::Element->new('pre');
+            for(my $i = 0; $i < $patch->[1]; $i++ )
+            {
+                my $line = $i + $patch->[0];
+                my $num_line_digits=log($line)/log(10);
+                for $i (0..(6-$num_line_digits-1))
+                {
+                    $codeHunk->push_content(" ");
+                }
+
+                $codeHunk->push_content("$line  ");
+
+                my $srcLine = HTML::Element->new('span');
+                if($coverage_ref)
+                {
+                    my $color;
+
+                    if($coverage_ref->{"covered"}->{$line})
+                    {
+                        $srcLine->attr('style', "color:green;");
+                    }
+                    elsif($coverage_ref->{"uncovered"}->{$line})
+                    {
+                        $srcLine->attr('style', "color:red;font-weight:bold;");
+                    }
+                    else
+                    {
+                        $srcLine->attr('style', "color:black;font-weight:normal;");
+                    }
+                    my $src=$coverage_ref->{"src"}->{$line};
+                    chomp($src);
+                    $srcLine->push_content($src);
+                }
+                else
+                {
+                    # We don't have coverage data, so print it from the patch instead.
+                    my $src = $b_lines_ref->{$line};
+                    $srcLine->attr('style', "color:black;font-weight:normal;");
+                    $srcLine->push_content($src);
+                }
+                $codeHunk->push_content($srcLine, "\n");
+            }
+            $body->push_content($codeHunk, "\n");
+        }
+    }
+    $body->push_content(HTML::Element->new('hr'));
+    $html->push_content($body, "\n");
+
+    open( my $filehandle, ">", $opt_output ) || die "Can't open $opt_output for writing:$!\n";
+
+    print $filehandle <<EOH;
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
+"http://www.w3.org/TR/REC-html40/loose.dtd">
+EOH
+;
+    print $filehandle $html->as_HTML();
+    close $filehandle;
+}
+
+
+################################################################################
+##                                    MAIN                                    ##
+################################################################################
+
+my $cwd = getcwd();
+chdir $repo->wc_path();
+chdir "build/tizen";
+`make rename_cov_data`;
+
+my @cmd=('--no-pager','diff','--no-ext-diff','-U0','--no-color');
+
+my $status = $repo->command("status", "-s");
+if( $status eq "" && !scalar(@ARGV))
+{
+    # There are no changes in the index or working tree, and
+    # no diff arguments to append. Use the last patch instead.
+    push @cmd, ('HEAD~1','HEAD');
+}
+else
+{
+    # detect if there are only cached changes or only working tree changes
+    my $cached = 0;
+    my $working = 0;
+    for my $fstat ( split(/\n/, $status) )
+    {
+        if(substr( $fstat, 0, 1 ) ne " "){ $cached++; }
+        if(substr( $fstat, 1, 1 ) ne " "){ $working++; }
+    }
+    if($cached > 0 )
+    {
+        if($working == 0)
+        {
+            push @cmd, "--cached";
+        }
+        else
+        {
+            die "Both cached & working files - cannot get correct patch from git\n";
+            # Would have to diff from separate clone.
+        }
+    }
+}
+
+push @cmd, @ARGV;
+my $filesref = run_diff(@cmd);
+
+chdir $cwd;
+
+# Check how many actual source files there are in the patch
+my $filecount = 0;
+foreach my $file (keys(%$filesref))
+{
+    my ($name, $path, $suffix) = fileparse($file, qr{\.[^.]*$});
+    next if($path !~ /^dali/);
+    next if($suffix ne ".cpp" && $suffix ne ".c" && $suffix ne ".h");
+    $filecount++;
+}
+if( $filecount == 0 )
+{
+    print "No source files found\n";
+    exit 0;    # Exit with no error.
+}
+
+my $percentref = calc_patch_coverage_percentage($filesref);
+if($percentref->[0] == 0)
+{
+    print "No coverable lines found\n";
+    exit 0;
+}
+my $percent = $percentref->[1];
+
+my $color=BOLD RED;
+if($opt_output)
+{
+    print "Outputing to $opt_output\n" if $debug;
+    patch_html_output($filesref);
+}
+elsif( ! $opt_quiet )
+{
+    patch_output($filesref);
+    if($percent>=90)
+    {
+        $color=GREEN;
+    }
+    print RESET;
+}
+
+printf("Percentage of change covered: %5.2f%\n", $percent);
+
+exit($percent<90);
+
+
+__END__
+
+=head1 NAME
+
+patch-coverage
+
+=head1 SYNOPSIS
+
+patch-coverage.pl - Determine if patch coverage is below 90%
+
+=head1 DESCRIPTION
+Calculates how well the most recent patch is covered (either the
+patch that is in the index+working directory, or HEAD).
+
+=head1 OPTIONS
+
+=over 28
+
+=item B<-c|--cached>
+Use index files if there is nothing in the working tree
+
+=item B<   --help>
+This help
+
+=item B<-q|--quiet>
+Don't generate any output
+
+=head1 RETURN STATUS
+0 if the coverage of source files is > 90%, otherwise 1
+
+=head1 EXAMPLES
+
+
+=cut
diff --git a/automated-tests/resources/canvas-bgnd.gif b/automated-tests/resources/canvas-bgnd.gif
new file mode 100644 (file)
index 0000000..99d8ea4
Binary files /dev/null and b/automated-tests/resources/canvas-bgnd.gif differ
diff --git a/automated-tests/resources/canvas-none.gif b/automated-tests/resources/canvas-none.gif
new file mode 100644 (file)
index 0000000..11bedf8
Binary files /dev/null and b/automated-tests/resources/canvas-none.gif differ
diff --git a/automated-tests/resources/canvas-prev.gif b/automated-tests/resources/canvas-prev.gif
new file mode 100644 (file)
index 0000000..8d3ad98
Binary files /dev/null and b/automated-tests/resources/canvas-prev.gif differ
diff --git a/automated-tests/resources/f-even-exif-1.jpg b/automated-tests/resources/f-even-exif-1.jpg
new file mode 100644 (file)
index 0000000..713919f
Binary files /dev/null and b/automated-tests/resources/f-even-exif-1.jpg differ
diff --git a/automated-tests/resources/f-even-exif-2.jpg b/automated-tests/resources/f-even-exif-2.jpg
new file mode 100644 (file)
index 0000000..e1cf3e1
Binary files /dev/null and b/automated-tests/resources/f-even-exif-2.jpg differ
diff --git a/automated-tests/resources/f-even-exif-3.jpg b/automated-tests/resources/f-even-exif-3.jpg
new file mode 100644 (file)
index 0000000..5bb8918
Binary files /dev/null and b/automated-tests/resources/f-even-exif-3.jpg differ
diff --git a/automated-tests/resources/f-even-exif-4.jpg b/automated-tests/resources/f-even-exif-4.jpg
new file mode 100644 (file)
index 0000000..6d8c5f1
Binary files /dev/null and b/automated-tests/resources/f-even-exif-4.jpg differ
diff --git a/automated-tests/resources/f-even-exif-5.jpg b/automated-tests/resources/f-even-exif-5.jpg
new file mode 100644 (file)
index 0000000..5cd39b6
Binary files /dev/null and b/automated-tests/resources/f-even-exif-5.jpg differ
diff --git a/automated-tests/resources/f-even-exif-6.jpg b/automated-tests/resources/f-even-exif-6.jpg
new file mode 100644 (file)
index 0000000..ce6cd02
Binary files /dev/null and b/automated-tests/resources/f-even-exif-6.jpg differ
diff --git a/automated-tests/resources/f-even-exif-7.jpg b/automated-tests/resources/f-even-exif-7.jpg
new file mode 100644 (file)
index 0000000..d2252e2
Binary files /dev/null and b/automated-tests/resources/f-even-exif-7.jpg differ
diff --git a/automated-tests/resources/f-even-exif-8.jpg b/automated-tests/resources/f-even-exif-8.jpg
new file mode 100644 (file)
index 0000000..2ebb1c3
Binary files /dev/null and b/automated-tests/resources/f-even-exif-8.jpg differ
diff --git a/automated-tests/resources/f-large-exif-3.jpg b/automated-tests/resources/f-large-exif-3.jpg
new file mode 100644 (file)
index 0000000..929c7fc
Binary files /dev/null and b/automated-tests/resources/f-large-exif-3.jpg differ
diff --git a/automated-tests/resources/f-odd-exif-1.jpg b/automated-tests/resources/f-odd-exif-1.jpg
new file mode 100644 (file)
index 0000000..67ff806
Binary files /dev/null and b/automated-tests/resources/f-odd-exif-1.jpg differ
diff --git a/automated-tests/resources/f-odd-exif-2.jpg b/automated-tests/resources/f-odd-exif-2.jpg
new file mode 100644 (file)
index 0000000..f92e297
Binary files /dev/null and b/automated-tests/resources/f-odd-exif-2.jpg differ
diff --git a/automated-tests/resources/f-odd-exif-3.jpg b/automated-tests/resources/f-odd-exif-3.jpg
new file mode 100644 (file)
index 0000000..a39af5d
Binary files /dev/null and b/automated-tests/resources/f-odd-exif-3.jpg differ
diff --git a/automated-tests/resources/f-odd-exif-4.jpg b/automated-tests/resources/f-odd-exif-4.jpg
new file mode 100644 (file)
index 0000000..057359b
Binary files /dev/null and b/automated-tests/resources/f-odd-exif-4.jpg differ
diff --git a/automated-tests/resources/f-odd-exif-5.jpg b/automated-tests/resources/f-odd-exif-5.jpg
new file mode 100644 (file)
index 0000000..f41cffc
Binary files /dev/null and b/automated-tests/resources/f-odd-exif-5.jpg differ
diff --git a/automated-tests/resources/f-odd-exif-6.jpg b/automated-tests/resources/f-odd-exif-6.jpg
new file mode 100644 (file)
index 0000000..d347ce3
Binary files /dev/null and b/automated-tests/resources/f-odd-exif-6.jpg differ
diff --git a/automated-tests/resources/f-odd-exif-7.jpg b/automated-tests/resources/f-odd-exif-7.jpg
new file mode 100644 (file)
index 0000000..a9ef6a3
Binary files /dev/null and b/automated-tests/resources/f-odd-exif-7.jpg differ
diff --git a/automated-tests/resources/f-odd-exif-8.jpg b/automated-tests/resources/f-odd-exif-8.jpg
new file mode 100644 (file)
index 0000000..48070bb
Binary files /dev/null and b/automated-tests/resources/f-odd-exif-8.jpg differ
diff --git a/automated-tests/resources/gallery-small-1.jpg b/automated-tests/resources/gallery-small-1.jpg
new file mode 100644 (file)
index 0000000..9292310
Binary files /dev/null and b/automated-tests/resources/gallery-small-1.jpg differ
diff --git a/automated-tests/resources/icon-edit.png b/automated-tests/resources/icon-edit.png
new file mode 100644 (file)
index 0000000..ce3e327
Binary files /dev/null and b/automated-tests/resources/icon-edit.png differ
diff --git a/automated-tests/resources/test.txt b/automated-tests/resources/test.txt
new file mode 100644 (file)
index 0000000..524acff
--- /dev/null
@@ -0,0 +1 @@
+Test file
diff --git a/automated-tests/scripts/add_all_smack_rule.sh b/automated-tests/scripts/add_all_smack_rule.sh
new file mode 100755 (executable)
index 0000000..8efb158
--- /dev/null
@@ -0,0 +1,26 @@
+#!/bin/sh
+
+SCRIPTDIR=`dirname $(readlink -f $0)`
+SMACK_FILE=$SCRIPTDIR/all_smack.rule
+       
+echo ""
+echo "Add smack rule in $SMACK_FILE"
+echo "==================================================="
+echo ""
+
+while read rule; do
+       NO_BLANK=$(echo $rule | sed 's/ //g' | sed 's/  //g')
+       if [ ${#NO_BLANK} -lt 1 ]; then
+               echo "Blank"
+               continue
+       elif [ `echo $NO_BLANK|cut -c1-1` = '#' ]; then
+               echo "Comment"
+               continue
+       fi
+
+       echo "echo \"$rule\" > /smack/load2"
+       echo "$rule" > /smack/load2
+done < $SMACK_FILE
+
+echo "==================================================="
+echo ""
diff --git a/automated-tests/scripts/add_smack_rule.sh b/automated-tests/scripts/add_smack_rule.sh
new file mode 100755 (executable)
index 0000000..22fe5ee
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+SCRIPTDIR=`dirname $(readlink -f $0)`
+SMACK_FILE=$SCRIPTDIR/all_smack.rule
+       
+echo ""
+echo "Add smack rule in $SMACK_FILE"
+echo "==================================================="
+
+echo "sdb root on"
+sdb root on
+
+while read rule; do
+       NO_BLANK=$(echo $rule | sed 's/ //g' | sed 's/  //g')
+       if [ ${#NO_BLANK} -lt 1 ]; then
+               #echo "Blank"
+               continue
+       elif [ `echo $NO_BLANK|cut -c1-1` = '#' ]; then
+               #echo "Comment"
+               continue
+       fi
+
+       echo "sdb shell \"echo $rule > /smack/load2\""
+       sdb shell "echo $rule > /smack/load2"
+done < $SMACK_FILE
+
+echo "==================================================="
+echo ""
diff --git a/automated-tests/scripts/add_style.pl b/automated-tests/scripts/add_style.pl
new file mode 100755 (executable)
index 0000000..e958842
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/perl
+
+use strict;
+use Encode;
+use Getopt::Long;
+use Cwd;
+
+my $pwd = getcwd;
+my $MOD_NAME = $ARGV[0];
+my $results_xml = "tct-$MOD_NAME-core-tests.xml";
+my $results_out = "results_xml.$$";
+
+# Copy $results_xml, writing new stylesheet line:
+# Write <?xml-stylesheet type="text/xsl" href="./style/testresult.xsl"?> as second line
+open RESULTS, "<$results_xml" || die "Can't open $results_xml for reading:$!\n";
+open RESULTS_OUT, ">$results_out" || die "Can't open $results_out for writing:$!\n";
+my $fline = readline RESULTS;
+print RESULTS_OUT $fline;
+print RESULTS_OUT "<?xml-stylesheet type=\"text/xsl\" href=\"./style/testresult.xsl\"?>\n";
+while(<RESULTS>)
+{
+    if( ! /xml-stylesheet/ )
+    {
+        print RESULTS_OUT $_;
+    }
+}
+close RESULTS_OUT;
+close RESULTS;
+unlink $results_xml;
+print `mv $results_out $results_xml`;
diff --git a/automated-tests/scripts/all_smack.rule b/automated-tests/scripts/all_smack.rule
new file mode 100644 (file)
index 0000000..93f2b67
--- /dev/null
@@ -0,0 +1,28 @@
+# calendar-service
+_ calendar-service::svc rwx
+
+# capi-appfw-application
+_ alarm-server::alarm rw
+_ aul::launch x
+_ aul::terminate x
+
+# capi-network-bluetooth
+_ bt-service::admin w
+_ bt-service::manager w
+_ bt-service::gap w
+_ bt-service::spp w
+_ bt:service::opp w
+
+# capi-network-nfc
+_ nfc-manager rwx
+_ nfc-manager::tag rwx
+_ nfc-manager::p2p rwx
+_ nfc-manager::admin rwx
+_ nfc-manager::common rwx
+
+# capi-location-*
+_ location::maps rw
+_ location::client rw
+
+# libmdm
+_ mdm-server::eas rw
diff --git a/automated-tests/scripts/autocompletion.sh b/automated-tests/scripts/autocompletion.sh
new file mode 100755 (executable)
index 0000000..d952c73
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/bash
+if [ -z "$TC_PROJECT_DIR" ]; then
+    echo "CoreAPI project directory can't be found. `basename $0` exitting..."
+    exit 1
+fi
+
+_tcbuild () {
+    local cur
+    cur=${COMP_WORDS[$COMP_CWORD]}
+    if [ $COMP_CWORD -eq 1 ]; then
+        COMPREPLY=( $( compgen -W "addmod build install rmmod" -- $cur ) )
+    else #if [ $COMP_CWORD -eq 2 ]; then
+        COMPREPLY=( $( cd $TC_PROJECT_DIR/src; compgen -d -X "common" -- $cur ) )
+    fi
+    return 0
+}
+
+complete -F _tcbuild tcbuild
diff --git a/automated-tests/scripts/init.sh b/automated-tests/scripts/init.sh
new file mode 100755 (executable)
index 0000000..1ccd9ea
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+PROJECT_DIR="$(cd "$(dirname $0)" && cd .. && pwd)"
+
+ln -s $PROJECT_DIR/scripts/tcbuild.sh $PROJECT_DIR/tcbuild
+
+echo "" >> $HOME/.bashrc
+echo "# CoreAPI-tests convenience helpers" >> $HOME/.bashrc
+echo "export TC_PROJECT_DIR=\"$PROJECT_DIR\"" >> $HOME/.bashrc
+echo "source $PROJECT_DIR/scripts/autocompletion.sh" >> $HOME/.bashrc
diff --git a/automated-tests/scripts/output_summary.pl b/automated-tests/scripts/output_summary.pl
new file mode 100755 (executable)
index 0000000..dec392d
--- /dev/null
@@ -0,0 +1,78 @@
+#!/usr/bin/perl
+
+# Reads summary.xml and produces human readable output
+
+use strict;
+use XML::Parser;
+use Encode;
+use Getopt::Long;
+use Cwd;
+
+my $pwd = getcwd;
+my $text = "";
+my $module="";
+my %modules=();
+
+sub handle_start
+{
+    my ($p, $elt, %attrs) = @_;
+
+    if($elt =~ /suite/)
+    {
+        $module=$attrs{"name"};
+    }
+    if($elt =~ /_case/)
+    {
+        $text = "";
+    }
+}
+
+sub handle_end
+{
+  my ($p, $elt) = @_;
+  if($elt =~ /pass_case/)
+  {
+      $modules{$module}->{"pass"}=$text;
+      $text="";
+  }
+  elsif($elt =~ /fail_case/)
+  {
+      $modules{$module}->{"fail"}=$text;
+      $text="";
+  }
+}
+
+sub handle_char
+{
+  my ($p, $str) = @_;
+  $text .= $str;
+}
+
+my($parser) = new XML::Parser(Handlers => {Start => \&handle_start,
+                                           End   => \&handle_end,
+                                           Char  => \&handle_char});
+$parser->parsefile("summary.xml");
+
+my $RED_COLOR="\e[1;31m";
+my $GREEN_COLOR="\e[1;32m";
+my $ASCII_RESET="\e[0m";
+my $ASCII_BOLD="\e[1m";
+
+print "\n";
+my $totalFailures=0;
+foreach $module (keys(%modules))
+{
+    my $result_colour = $GREEN_COLOR;
+    if( $modules{$module}->{"fail"} )
+    {
+        $result_colour = $RED_COLOR;
+    }
+    my $numPasses = $modules{$module}->{"pass"};
+    my $numFailures = $modules{$module}->{"fail"};
+    $totalFailures += $numFailures;
+    print( "$ASCII_BOLD$module results:$ASCII_RESET\n" );
+    printf("Number of test passes:   %s%4d (%5.2f%%)%s\n", $ASCII_BOLD, $numPasses, 100.0 * $numPasses / ($numPasses+$numFailures),  $ASCII_RESET);
+    printf("%sNumber of test failures:%s %s%4d%s\n\n", $result_colour, $ASCII_RESET, $ASCII_BOLD, $numFailures, $ASCII_RESET);
+}
+
+exit $totalFailures == 0;
diff --git a/automated-tests/scripts/retriever.sh b/automated-tests/scripts/retriever.sh
new file mode 100755 (executable)
index 0000000..c1d466d
--- /dev/null
@@ -0,0 +1,212 @@
+#!/bin/bash
+
+USAGE=$(cat <<EOF
+Usage note: retriever.sh [option] [directory]
+Options:
+  none    retrieve TC names with corresponding startup and cleanup functions
+  -f      retrieveve TC name with corresponding "set" and "purpose" clauses
+  -anum   retrieve automatic TC number
+  -mnum   retrieve manual TC number
+
+In case of TC in form of "int tc_name()" script will abort.
+("int tc_name(void)" is a proper function signature)
+EOF
+)
+
+function get_tc_files {
+    CMAKE_FILE="$DIR/CMakeLists.txt"
+    if [ ! -e $CMAKE_FILE ]; then
+        echo "File $CMAKE_FILE not found. Aborting..."
+        exit 1
+    fi
+
+    TC_FILES=$(cat $CMAKE_FILE | awk -vDIR="$DIR" '
+    BEGIN {
+        flag = 0;
+        files = "";
+    }
+    /^SET\(TC_SOURCES/ {
+        flag = 1;
+        next;
+    }
+    /\)/ {
+        if (flag == 1)
+            exit;
+    }
+    !/^ *#/ {
+        if (flag == 1) {
+            if (files == "")
+                files = DIR "/" $1;
+            else
+                files = files " " DIR "/" $1;
+        }
+    }
+    END {
+        print files;
+    }')
+}
+
+function tc_names {
+    if [[ -z "$1" ]]; then
+        exit
+    fi
+
+    awk '
+    BEGIN {
+        OFS = ",";
+        start_fun = "NULL";
+        clean_fun = "NULL";
+        err_flag = 0;
+        tc_list = "";
+    }
+    /^void .*startup\(void\)/ {
+        gsub(/^void /, "");
+        gsub(/\(void\)$/,"");
+        start_fun = $0
+    }
+    /^void .*cleanup\(void\)/ {
+        gsub(/^void /, "");
+        gsub(/\(void\)$/,"");
+        clean_fun = $0
+    }
+    /^int .*\(\)/ {
+        print "Warning: function with empty argument list -- \"" $0 "\" in " FILENAME ":" FNR;
+        err_flag = 1;
+    }
+    /^int .*\(void\)/ {
+        gsub(/^int /, "");
+        gsub(/\(void\).*/,"");
+        if (tc_list != "") tc_list = tc_list "\n";
+        tc_list = tc_list $0 OFS start_fun OFS clean_fun
+    }
+    END {
+        if (err_flag) {
+            exit 1
+        } else {
+            print tc_list
+        }
+    }
+    ' $*
+}
+
+function tc_anum {
+    awk '
+    BEGIN {
+        count = 0;
+        err_flag = 0;
+    }
+    /^int .*\(\)/ {
+        print "Warning: function with empty argument list -- \"" $0 "\" in " FILENAME ":" FNR;
+        err_flag = 1;
+    }
+    /^int .*\(void\)$/ {
+        count++;
+    }
+    END {
+        if (err_flag) {
+            exit 1
+        } else {
+            print count
+        }
+    }
+    ' $*
+}
+
+function tc_mnum {
+    # TODO: fix this hardcoded value
+    echo 0
+}
+
+function tc_fullinfo {
+    awk '
+    BEGIN {
+        OFS=",";
+        purpose = "";
+        set = "default";
+        err_flag = 0;
+        tc_list = "";
+    }
+    /^\/\/& set:/ {
+        set = $3;
+        next;
+    }
+    /^\/\/& purpose:/ {
+        purpose = $3;
+        for (i = 4; i <= NF; i++) {
+            purpose = purpose " " $i;
+        }
+        next;
+    }
+    /^int .*\(\)/ {
+        print "Warning: function with empty argument list -- \"" $0 "\" in " FILENAME ":" FNR;
+        err_flag = 1;
+    }
+    /^int .*\(void\)$/ {
+        gsub(/^int /, "");
+        gsub(/\(void\)$/,"");
+        if (tc_list != "") tc_list = tc_list "\n";
+        tc_list = tc_list $0 OFS set OFS purpose;
+        purpose = "";
+        next
+    }
+    END {
+        if (err_flag) {
+            exit 1
+        } else {
+            print tc_list
+        }
+    }
+    ' $*
+}
+
+
+# usage note and exit:
+# - argument begin with '-' but is not recognised or number of arguments is > 3,
+# - argument doesn't begin with '-' and number of arguments is > 2
+if [[ ( "$1" == -* && ( ! "$1" =~ ^-(anum|mnum|f)$ || $# > 3 ) ) || ( "$1" != -* && $# > 2 ) ]]; then
+    echo -e "$USAGE"
+    exit 1
+fi
+
+# get directory from last argument (or assume current one)
+if [[ ! "$1" =~ ^-(anum|mnum|f)$ ]]; then
+    DIR=${1:-.}
+else
+    DIR=${2:-.}
+fi
+
+# get filename from last argument
+if [[ $# == 3 && -f $DIR/$3 ]] ; then
+    FILE=$3
+elif [[ $# == 2 && -f $DIR/$2 ]] ; then
+    FILE=$2
+fi
+
+#echo "Dir: $DIR  File: $FILE" >& 2
+
+
+# populate $TC_FILES with files declared in CMakeLists.txt
+if [[ -z $FILE ]]; then
+    get_tc_files $DIR
+    if [ $? != 0 ]; then
+        exit 1
+    fi
+    echo "Got all files" >& 2
+else
+    TC_FILES="$DIR/$FILE"
+    echo "TC_FILES: $TC_FILES" >& 2
+fi
+
+
+
+# run appropriate subcommand
+case "$1" in
+    -anum)
+        tc_anum $TC_FILES ;;
+    -mnum)
+        tc_mnum $TC_FILES ;;
+    -f)
+        tc_fullinfo $TC_FILES ;;
+    *)
+        tc_names $TC_FILES ;;
+esac
diff --git a/automated-tests/scripts/summarize.pl b/automated-tests/scripts/summarize.pl
new file mode 100755 (executable)
index 0000000..8270376
--- /dev/null
@@ -0,0 +1,111 @@
+#!/usr/bin/perl
+
+# Generates an XML summary of test cases from Test-kit lite output XML.
+
+use strict;
+use XML::Parser;
+use Encode;
+use Getopt::Long;
+use Cwd;
+
+my $pwd = getcwd;
+my $num_tests=0;
+my $num_passes=0;
+my $num_actual_passes=0;
+my $text = "";
+
+sub handle_start
+{
+    my ($p, $elt, %attrs) = @_;
+
+    if($elt =~ /testcase/)
+    {
+        $num_tests++;
+        if($attrs{"result"} eq "PASS")
+        {
+            $num_passes++;
+        }
+    }
+    if($elt =~ /actual_result/)
+    {
+        $text = "";
+    }
+}
+
+sub handle_end
+{
+  my ($p, $elt) = @_;
+  if($elt =~ /actual_result/)
+  {
+      if($text eq "PASS")
+      {
+          $num_actual_passes++;
+      }
+      $text = "";
+  }
+}
+
+sub handle_char
+{
+  my ($p, $str) = @_;
+  $text .= $str;
+}
+
+my($parser) = new XML::Parser(Handlers => {Start => \&handle_start,
+                                           End   => \&handle_end,
+                                           Char  => \&handle_char});
+
+
+# Write summary.xml:
+open SUMMARY, ">summary.xml" || die "Can't open summary.xml for writing:$!\n";
+print SUMMARY << "EOS";
+<?xml version="1.0" encoding="UTF-8"?>
+<?xml-stylesheet type="text/xsl" href="./style/summary.xsl"?>
+<result_summary plan_name="Core">
+  <other xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string" />
+  <summary test_plan_name="Empty test_plan_name">
+    <start_at>2014-03-21_18_52_41</start_at>
+    <end_at>2014-03-21_18_57_54</end_at>
+  </summary>
+EOS
+
+print "\n\nSummary of all tests:\n";
+my $output_files = `ls tct*core-tests.xml`;
+my $file;
+foreach $file (split /\s+/, $output_files )
+{
+    $num_tests=0;
+    $num_passes=0;
+    $num_actual_passes=0;
+    $text = "";
+
+    $parser->parsefile($file);
+
+    my $pass_rate = sprintf("%5.2f", $num_passes * 100.0 / $num_tests);
+    my $num_fails = $num_tests - $num_passes;
+    my $fail_rate = sprintf("%5.2f", $num_fails * 100.0 / $num_tests);
+
+    my $suite_name = $file;
+    $suite_name =~ s/\.xml$//;
+
+    print "$suite_name: $num_passes tests passed out of $num_tests ( $pass_rate% )\n";
+
+print SUMMARY << "EOS2";
+  <suite name="$suite_name">
+    <total_case>$num_tests</total_case>
+    <pass_case>$num_passes</pass_case>
+    <pass_rate>$pass_rate</pass_rate>
+    <fail_case>$num_fails</fail_case>
+    <fail_rate>$fail_rate</fail_rate>
+    <block_case>0</block_case>
+    <block_rate>0.00</block_rate>
+    <na_case>0</na_case>
+    <na_rate>0.00</na_rate>
+  </suite>
+EOS2
+}
+
+print SUMMARY "</result_summary>\n";
+close SUMMARY;
+
+print "Summary of results written to summary.xml\n";
diff --git a/automated-tests/scripts/tcbuild.sh b/automated-tests/scripts/tcbuild.sh
new file mode 100755 (executable)
index 0000000..b604675
--- /dev/null
@@ -0,0 +1,215 @@
+#!/bin/bash
+
+#---------- DEBUG_BEGIN ----------
+#ARG="-d" # debug-on flag, might be set as $1
+# keyprompt "introductory message" -- wait until any key pressed
+function keyprompt { echo -ne "\n\e[1;31m$1 -- " && read -n 1 && echo -e "\n\e[0m"; }
+# d_bp -- breakpoint at which user need to press any key to proceed
+function d_bp { if [[ "$ARG" == "-d" ]]; then keyprompt "d >> Press any key"; fi }
+# d_showVar VARNAME -- print bash variable name
+function d_showVar { if [ "$ARG" == "-d" -a -n "$1" ]; then echo "d >> ${1} = ${!1}"; fi }
+# d_print "message" -- print a debug message
+function d_print { if [ "$ARG" == "-d" -a -n "$1" ]; then echo -e "d >> $1"; fi }
+#----------  DEBUG_END  ----------
+
+PROJECT_DIR="$(cd "$(dirname $0)" && pwd)"
+d_showVar PROJECT_DIR
+
+function gbs_profile {
+perl -e "
+use Config::Tiny;
+my \$Config = Config::Tiny->read( \"\$ENV{HOME}/.gbs.conf\" );
+my \$profile = \$Config->{general}->{profile};
+\$profile =~ s/profile.//;
+print \$profile;"
+}
+
+PROFILE=`gbs_profile`
+RPM_DIR="$HOME/GBS-ROOT/local/repos/$PROFILE/armv7l/RPMS"
+d_showVar RPM_DIR
+
+function add_module {
+    # argument check
+    if [ -z "$1" ]; then echo "Usage: `basename $0` addmod <module_name> [module_lib_name]"; exit 1; fi
+
+    MODULE_NAME=$1
+    d_showVar MODULE_NAME
+    MODULE_NAME_C=$(echo $MODULE_NAME | sed -e 's/-\([a-z]\)/\U\1/' -e 's/^\([a-z]\)/\U\1/')
+    d_showVar MODULE_NAME_C
+    MODULE_NAME_U=$(echo $MODULE_NAME | sed -e 's/-/_/')
+    d_showVar MODULE_NAME_U
+#    MODULE_LIBNAME=${2:-capi-$MODULE_NAME}
+    MODULE_LIBNAME=$1
+    d_showVar MODULE_LIBNAME
+
+    echo "Adding $MODULE_NAME module to project..."
+    d_bp
+    cd $PROJECT_DIR
+    # prepare .spec file
+    echo "-- Generating packaging/core-$MODULE_NAME-tests.spec file"
+    if [ ! -d packaging ]; then mkdir packaging; fi
+    sed -e "s:\[MODULE_NAME\]:$MODULE_NAME:g" -e "s:\[MODULE_LIBNAME\]:$MODULE_LIBNAME:g" \
+        templates/core-\[module_name\]-tests.spec > packaging/core-$MODULE_NAME-tests.spec
+    # prepare src directory
+    mkdir src/$MODULE_NAME
+    echo "-- Generating src/$MODULE_NAME/CMakeLists.txt file"
+    sed -e "s:%{MODULE_NAME}:$MODULE_NAME:g" -e "s:%{MODULE_LIBNAME}:$MODULE_LIBNAME:g" \
+        templates/src-directory/CMakeLists.txt > src/$MODULE_NAME/CMakeLists.txt
+    echo "-- Generating src/$MODULE_NAME/tct-$MODULE_NAME-core.c file"
+    sed -e "s:%{MODULE_NAME}:$MODULE_NAME:g" \
+        templates/src-directory/tct-\[module_name\]-core.c > src/$MODULE_NAME/tct-$MODULE_NAME-core.c
+    echo "-- Generating src/$MODULE_NAME/utc-$MODULE_NAME.c file"
+    sed -e "s:%{MODULE_NAME_U}:$MODULE_NAME_U:g" -e "s:%{MODULE_NAME_C}:$MODULE_NAME_C:g" \
+        templates/src-directory/utc-\[module_name\].c > src/$MODULE_NAME/utc-$MODULE_NAME.c
+    echo "Task finished successfully"
+}
+
+function rm_module {
+    # argument check
+    if [ -z "$1" ]; then echo "Usage: `basename $0` rmmod <module_name>"; exit 1; fi
+
+    MODULE_NAME=$1
+    d_showVar MODULE_NAME
+
+    echo "Removing $MODULE_NAME module from project..."
+    d_bp
+    echo "---- Updating /opt/tct/packages/package_list.xml"
+    scripts/tcpackageslistsgen.sh $MODULE_NAME /opt/tct/packages/package_list.xml 1
+    if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+   # echo "---- Updating test plans"
+   # scripts/tcpackageslistsgen.sh $MODULE_NAME /opt/tct/manager/plan/*.xml 1
+   # if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+
+    cd $PROJECT_DIR
+    echo "-- Removing packaging/core-$MODULE_NAME-tests.spec file"
+    rm packaging/core-$MODULE_NAME-tests.spec
+    echo "-- Removing src/$MODULE_NAME directory"
+    rm -r src/$MODULE_NAME
+    echo "Task finished successfully"
+}
+
+function build {
+    if [ -n "$1" ]; then
+        (cd src/$1; ../../scripts/tcheadgen.sh tct-$1-core.h)
+        if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+        cp packaging/core-$1-tests.spec ../packaging
+        cp .gitignore-without-autogenerated-files .gitignore
+        gbs build -A armv7l --spec core-$1-tests.spec --include-all --keep-packs | \
+            tee build.log | stdbuf -o0 sed -e 's/error:/\x1b[1;91m&\x1b[0m/' \
+                                           -e 's/warning:/\x1b[93m&\x1b[0m/'
+        rm ../packaging/core-$1-tests.spec
+        cp .gitignore-with-autogenerated-files .gitignore
+    else
+        echo "Build requires a module name"
+        exit 1
+    fi
+}
+
+function inst {
+    if [ -z "$1" ]
+    then
+        for mod in `ls -1 src/ | grep -v CMakeLists`
+        do
+
+       if [ $mod != 'common' ] && [ $mod != 'manual' ]; then
+
+            PKG_NAME="core-$mod-tests"
+            d_showVar PKG_NAME
+            VER=$(cat packaging/$PKG_NAME.spec | awk '/^Version:/ { print $2; exit; }')
+            d_showVar VER
+            PKG_VNAME="$PKG_NAME-$VER"
+            d_showVar PKG_VNAME
+            PKG_FNAME="$PKG_VNAME-0.armv7l.rpm"
+            d_showVar PKG_FNAME
+
+            if [ -f "$RPM_DIR/$PKG_FNAME" ]
+            then
+                inst $mod
+                echo ""
+            fi
+       fi
+        done
+    else
+        cd $PROJECT_DIR
+        # setting variables
+        MOD_NAME="$1"
+        d_showVar MOD_NAME
+        PKG_NAME="core-$MOD_NAME-tests"
+        d_showVar PKG_NAME
+        VER=$(cat packaging/$PKG_NAME.spec | awk '/^Version:/ { print $2; exit; }')
+        d_showVar VER
+        PKG_VNAME="$PKG_NAME-$VER"
+        d_showVar PKG_VNAME
+        PKG_FNAME="$PKG_VNAME-0.armv7l.rpm"
+        d_showVar PKG_FNAME
+        TCT_DIR="opt/tct-$MOD_NAME-core-tests"
+        d_showVar TCT_DIR
+
+        echo "Deploying $MOD_NAME suite to tct-mgr..."
+        d_bp
+        # prepare tct directory and files
+        echo "-- Preparing suite .zip file..."
+        echo "---- Creating /tmp/$TCT_DIR directory"
+        rm -r /tmp/opt > /dev/null 2>&1
+        mkdir -p /tmp/$TCT_DIR
+        # README
+        echo "---- Copying /tmp/$TCT_DIR"
+        cp templates/tct-package/README /tmp/$TCT_DIR
+        # rpm
+        echo "---- Copying /tmp/$TCT_DIR package"
+        cp $RPM_DIR/$PKG_FNAME /tmp/$TCT_DIR
+        if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+        # inst.sh
+        echo "---- Generating /tmp/$TCT_DIR/inst.sh file"
+        sed -e "s:%{PKG_NAME}:\"$PKG_NAME\":g" -e "s:%{PKG_FULLNAME}:\"$PKG_FNAME\":g" \
+            -e "s:%{PKG_DIR}:\"/opt/usr/media/tct/$TCT_DIR\":g" \
+            templates/tct-package/inst.sh > /tmp/$TCT_DIR/inst.sh
+        chmod a+x /tmp/$TCT_DIR/inst.sh
+        # tests.xml
+        echo "---- Generating /tmp/$TCT_DIR"
+        scripts/tctestsgen.sh $MOD_NAME /tmp/$TCT_DIR target
+        if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+        # zip
+        echo "---- Preparing /tmp/tct/packages/tct-$MOD_NAME-core-tests-2.2.1-1.zip file"
+        # clear old zips
+        rm -r /tmp/tct/packages > /dev/null 2>&1
+        mkdir -p /tmp/tct/packages
+        # create new zip
+        ( cd /tmp; zip -r /tmp/tct/packages/tct-$MOD_NAME-core-tests-2.2.1-1.zip opt > /dev/null 2>&1; )
+        # deployment
+        echo "-- Suite deployment..."
+        echo "---- Copying /opt/tct/packages/tct-$MOD_NAME-core-tests-2.2.1-1.zip"
+        cp /tmp/tct/packages/tct-$MOD_NAME-core-tests-2.2.1-1.zip /opt/tct/packages/
+        echo "---- Updating /opt/tct/packages/package_list.xml"
+        scripts/tcpackageslistsgen.sh $MOD_NAME /opt/tct/packages/package_list.xml 0
+        if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+       # echo "---- Updating test plans"
+       # for file in `grep -r tct-$MOD_NAME-core-tests /opt/tct/manager/plan/ | cut -d: -f1 | uniq`
+       # do
+       #     scripts/tcpackageslistsgen.sh $MOD_NAME $file
+       # done
+       # scripts/tcpackageslistsgen.sh $MOD_NAME /opt/tct/manager/plan/Full_test.xml
+       # if [ $? -ne 0 ]; then echo "Aborting..."; exit 1; fi
+        echo "Task finished successfully"
+    fi
+}
+
+if [ -z "$1" ]; then
+    # usage note
+    echo "Usage: `basename $0` <addmod|rmmod|build|install> <module_name> [module_lib_name]"
+    exit 1
+elif [ "addmod" == "$1" ]; then
+    # add new module
+    add_module $2 $3
+elif [ "rmmod" == "$1" ]; then
+    # remove module
+    rm_module $2
+elif [ "build" == "$1" ]; then
+    # build the binary
+    build $2
+elif [ "install" == "$1" ]; then
+    # install
+    inst $2
+else
+    echo "Invalid subcommand: $1"
+fi
diff --git a/automated-tests/scripts/tcheadgen.sh b/automated-tests/scripts/tcheadgen.sh
new file mode 100755 (executable)
index 0000000..c8cd679
--- /dev/null
@@ -0,0 +1,73 @@
+#!/bin/bash
+
+if [[ -z $1 ]]; then
+    echo "Usage note: tcheadgen.sh <header_filename.h>"
+    exit 1
+fi
+
+FILE="$PWD/$1"
+TFILE="/tmp/retr.csv$$"
+HEADER_NAME=$(echo $1 | tr '[:lower:]' '[:upper:]' | sed -e 's/-/_/g' -e 's/\./_/')
+SCRIPT_DIR="$(cd "$(dirname $0)" && pwd)"
+
+$SCRIPT_DIR/retriever.sh > $TFILE
+if [ $? -ne 0 ]; then cat $TFILE; exit 1; fi
+awk -F',' -v HEADER_NAME="$HEADER_NAME" '
+    BEGIN {
+        OFS = ", ";
+
+        startup_counter = 0;
+        startup_list[0] = "";
+
+        cleanup_counter = 0;
+        cleanup_list[0] = "";
+
+        testcase_counter = 0;
+        testcase_list[0] = "";
+
+        tc_array_counter = 0;
+        tc_array_list[0] = "";
+
+print "#ifndef " HEADER_NAME
+print "#define " HEADER_NAME
+print ""
+print "#include \"testcase.h\""
+print ""
+    }
+    {
+        testcase_list[testcase_counter++] = $1;
+
+        if (startup_counter == 0 || startup_list[startup_counter-1] != $2)
+            startup_list[startup_counter++] = $2;
+
+        if (startup_counter == 0 || cleanup_list[cleanup_counter-1] != $3)
+            cleanup_list[cleanup_counter++] = $3;
+
+        tc_array_list[tc_array_counter++] = "\"" $1 "\", " $1 ", " $2 ", " $3;
+    }
+    END {
+        sc_count = (startup_counter > cleanup_counter) ? startup_counter : cleanup_counter;
+        for (i = 0; i < sc_count; i++) {
+            if (i < startup_counter && startup_list[i] != "NULL")
+print "extern void " startup_list[i] "(void);"
+            if (i < cleanup_counter && cleanup_list[i] != "NULL")
+print "extern void " cleanup_list[i] "(void);"
+        }
+
+print ""
+        for (i = 0; i < testcase_counter; i++)
+print "extern int " testcase_list[i] "(void);"
+
+print ""
+print "testcase tc_array[] = {"
+
+        for (i = 0; i < tc_array_counter; i++)
+print "    {" tc_array_list[i] "},"
+
+print "    {NULL, NULL}"
+print "};"
+print ""
+print "#endif // " HEADER_NAME
+}' $TFILE > $FILE
+unlink $TFILE
+
diff --git a/automated-tests/scripts/tcpackageslistsgen.sh b/automated-tests/scripts/tcpackageslistsgen.sh
new file mode 100755 (executable)
index 0000000..15ea51f
--- /dev/null
@@ -0,0 +1,72 @@
+#!/bin/bash
+
+if [ -z $1 -o -z $2 ]; then
+    echo "Usage note: tcpackageslistsgen.sh <module_name> <output_file.xml>"
+    exit 1
+fi
+
+MODULE_NAME=$1
+FILE=$2
+if [ ! -f $FILE ]; then
+    echo "No such file: $2"
+    exit
+fi
+SCRIPT_DIR="$(cd "$(dirname $0)" && pwd)"
+AUTO_NUM=$(cd $SCRIPT_DIR/..; scripts/retriever.sh -anum src/$MODULE_NAME)
+if [ $? -ne 0 ]; then echo $AUTO_NUM; exit 1; fi
+MAN_NUM=$(cd $SCRIPT_DIR/..; scripts/retriever.sh -mnum src/$MODULE_NAME)
+if [ $? -ne 0 ]; then echo $MAN_NUM; exit 1; fi
+
+TFILE="/tmp/tempfile.xml"
+if [ -f $TFILE ]; then
+    rm $TFILE
+fi
+
+function regen {
+    awk -v RS='\r\n' -v ORS='\r\n' -v MODULE_NAME=$MODULE_NAME -v AUTO_NUM=$AUTO_NUM -v MAN_NUM=$MAN_NUM '    
+    BEGIN {
+        found = 0;
+        replaced = 0;
+    }
+    $0 ~ "<suite name=\"tct-" MODULE_NAME "-core-tests\" category=\"Core APIs\">" {
+        found = 1;
+        next
+    }
+    /<\/suite>/ {
+        if (found == 1) {
+print "  <suite name=\"tct-" MODULE_NAME "-core-tests\" category=\"Core APIs\">";
+print "    <auto_tcn>" AUTO_NUM "</auto_tcn>";
+print "    <manual_tcn>" MAN_NUM "</manual_tcn>";
+print "    <total_tcn>" AUTO_NUM+MAN_NUM "</total_tcn>";
+print "    <pkg_name>tct-" MODULE_NAME "-core-tests-2.2.1-1.zip</pkg_name>";
+print "  </suite>";
+            found = 0;
+            replaced = 1;
+        } else {
+            print $0;
+        }
+        next
+    }
+    /<\/ns3:testplan>/ {
+        if (replaced == 0) {
+print "  <suite name=\"tct-" MODULE_NAME "-core-tests\" category=\"Core APIs\">";
+print "    <auto_tcn>" AUTO_NUM "</auto_tcn>";
+print "    <manual_tcn>" MAN_NUM "</manual_tcn>";
+print "    <total_tcn>" AUTO_NUM+MAN_NUM "</total_tcn>";
+print "    <pkg_name>tct-" MODULE_NAME "-core-tests-2.2.1-1.zip</pkg_name>";
+print "  </suite>";
+print $0
+        } else {
+            print $0
+        }
+        next
+    }
+    {
+        if (found == 0) {
+            print $0;
+        }
+    }' $FILE > $TFILE
+    cat $TFILE > $FILE
+}
+
+regen
diff --git a/automated-tests/scripts/tctestsgen.sh b/automated-tests/scripts/tctestsgen.sh
new file mode 100755 (executable)
index 0000000..1881668
--- /dev/null
@@ -0,0 +1,66 @@
+#!/bin/bash
+
+if [[ -z $1 ]]; then
+    echo "Usage note: tctestsgen.sh <module_name>"
+    exit 1
+fi
+
+MODULE_NAME=$1
+MODULE_NAME_C=$(echo $MODULE_NAME | sed -e 's/-\([a-z]\)/\U\1/' -e 's/^\([a-z]\)/\U\1/')
+SCRIPT_DIR="$(cd "$(dirname $0)" && pwd)"
+TC_DIR="/opt/usr/bin/tct-$1-core"
+if [[ $3 == "desktop" ]] ; then
+  TC_DIR="build/src/$1"
+fi
+
+FILE="$2/tests.xml"
+if [ -a $FILE ]; then
+    rm $FILE
+fi
+TFILE="/tmp/tcs.csv"
+if [ -a $TFILE ]; then
+    rm $TFILE
+fi
+
+function gen {
+    awk -F',' -v MODULE_NAME=$MODULE_NAME -v MODULE_NAME_C=$MODULE_NAME_C -v TC_DIR=$TC_DIR '
+    BEGIN {
+        set = ""
+print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
+print "    <?xml-stylesheet type=\"text/xsl\" href=\"./testcase.xsl\"?>";
+print "<test_definition>";
+print "  <suite name=\"tct-"MODULE_NAME"-core-tests\" category=\"Core APIs\">";
+    }
+    {
+        if (set != "" && set != $2) {
+print "    </set>"
+        }
+
+        if (set != $2) {
+            set = $2;
+print "    <set name=\"" set "\">";
+        }
+
+        tcname = $1;
+        tcpurpose = $3
+
+print "      <testcase component=\"CoreAPI/" MODULE_NAME_C "/" set "\" execution_type=\"auto\" id=\"" tcname "\" purpose=\"" tcpurpose "\">";
+print "        <description>";
+
+print "          <test_script_entry test_script_expected_result=\"0\">" TC_DIR "/tct-" MODULE_NAME "-core " tcname "</test_script_entry>";
+print "        </description>";
+print "      </testcase>";
+    }
+    END {
+        if (set != "") {
+print "    </set>"
+        }
+print "  </suite>"
+print "</test_definition>"
+    }' $TFILE > $FILE
+}
+
+(cd $SCRIPT_DIR/..; scripts/retriever.sh -f src/$MODULE_NAME $4 > ${TFILE}_pre)
+if [ $? -ne 0 ]; then cat ${TFILE}_pre; exit 1; fi
+cat ${TFILE}_pre | sort -t',' -k2,2 -s > $TFILE
+gen
diff --git a/automated-tests/src/CMakeLists.txt b/automated-tests/src/CMakeLists.txt
new file mode 100644 (file)
index 0000000..e4f0a2b
--- /dev/null
@@ -0,0 +1,6 @@
+IF( DEFINED MODULE )
+    MESSAGE(STATUS "Building: ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}")
+    ADD_SUBDIRECTORY(${MODULE})
+ELSE( DEFINED MODULE )
+    MESSAGE(FATAL_ERROR "No module selected to build. Aborting...")
+ENDIF( DEFINED MODULE )
diff --git a/automated-tests/src/common/assert.h b/automated-tests/src/common/assert.h
new file mode 100644 (file)
index 0000000..a5d6cff
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef _ASSERT_H_
+#define _ASSERT_H_
+#include <stdio.h>
+#include <stdlib.h>
+
+#define assert(exp) \
+    if (!(exp)) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Following expression is not true:\n" \
+                "%s\n", #exp); \
+        return 1; \
+    }
+
+#define assert_eq(var, ref) \
+    if (var != ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Values \"%s\" and \"%s\" are not equal:\n" \
+                "%s == %d, %s == %d\n", \
+            #var, #ref, #var, (int)var, #ref, (int)ref); \
+        return 1; \
+    }
+
+#define assert_neq(var, ref) \
+    if (var == ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Values \"%s\" and \"%s\" are equal:\n" \
+                "%s == %s == %d\n", \
+            #var, #ref, #var, #ref, (int)ref); \
+        return 1; \
+    }
+
+#define assert_gt(var, ref) \
+    if (var <= ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Value \"%s\" is not greater than \"%s\":\n" \
+                "%s == %d, %s == %d\n", \
+            #var, #ref, #var, var, #ref, ref); \
+        return 1; \
+    }
+
+#define assert_geq(var, ref) \
+    if (var < ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Value \"%s\" is not greater or equal to \"%s\":\n" \
+                "%s == %d, %s == %d\n", \
+            #var, #ref, #var, var, #ref, ref); \
+        return 1; \
+    }
+
+#define assert_lt(var, ref) \
+    if (var >= ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Value \"%s\" is not lower than \"%s\":\n" \
+                "%s == %d, %s == %d\n", \
+            #var, #ref, #var, var, #ref, ref); \
+        return 1; \
+    }
+
+#define assert_leq(var, ref) \
+    if (var > ref) { \
+        fprintf(stderr, \
+            "Assert fail in %s:%d\n", __FILE__, __LINE__); \
+        fprintf(stderr, \
+            "Value \"%s\" is not lower or equal to \"%s\":\n" \
+                "%s == %d, %s == %d\n", \
+            #var, #ref, #var, var, #ref, ref); \
+        return 1; \
+    }
+
+#endif //  _ASSERT_H_
diff --git a/automated-tests/src/common/testcase.h b/automated-tests/src/common/testcase.h
new file mode 100644 (file)
index 0000000..011a452
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _TESTCASE_H_
+#define _TESTCASE_H_
+
+/* pointer to startup/cleanup functions */
+typedef void (*void_fun_ptr)(void);
+
+/* pointer to testcase functions */
+typedef int (*tc_fun_ptr)(void);
+
+/* struct describing specific testcase */
+typedef struct testcase_s {
+    const char* name;
+    tc_fun_ptr function;
+    void_fun_ptr startup;
+    void_fun_ptr cleanup;
+} testcase;
+
+#endif // _TESTCASE_H_
diff --git a/automated-tests/src/dali-adaptor-internal/CMakeLists.txt b/automated-tests/src/dali-adaptor-internal/CMakeLists.txt
new file mode 100644 (file)
index 0000000..4b0039e
--- /dev/null
@@ -0,0 +1,72 @@
+SET(PKG_NAME "dali-adaptor-internal")
+
+SET(EXEC_NAME "tct-${PKG_NAME}-core")
+SET(RPM_NAME "core-${PKG_NAME}-tests")
+
+SET(CAPI_LIB "dali-adaptor-internal")
+
+SET(TC_SOURCES
+    utc-Dali-CommandLineOptions.cpp
+    utc-Dali-CompressedTextures.cpp
+    utc-Dali-FontClient.cpp
+    utc-Dali-GifLoader.cpp
+    utc-Dali-IcoLoader.cpp
+    utc-Dali-BmpLoader.cpp
+    utc-Dali-ImageOperations.cpp
+    utc-Dali-Internal-PixelBuffer.cpp
+    utc-Dali-Lifecycle-Controller.cpp
+    utc-Dali-TiltSensor.cpp
+)
+
+LIST(APPEND TC_SOURCES
+    image-loaders.cpp
+    ../dali-adaptor/dali-test-suite-utils/mesh-builder.cpp
+    ../dali-adaptor/dali-test-suite-utils/dali-test-suite-utils.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-actor-utils.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-harness.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-application.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-gl-abstraction.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-gl-sync-abstraction.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-native-image.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-platform-abstraction.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-render-controller.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-trace-call-stack.cpp
+    ../dali-adaptor/dali-test-suite-utils/adaptor-test-adaptor-impl.cpp
+)
+
+PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED
+    dali-core
+    dali-adaptor
+    ecore
+)
+
+ADD_COMPILE_OPTIONS( -O0 -ggdb --coverage -Wall -Werror )
+ADD_COMPILE_OPTIONS( ${${CAPI_LIB}_CFLAGS_OTHER} )
+
+# Shouldn't have to do this!
+# But CMake's new auto-escape quote policy doesn't work right.
+CMAKE_POLICY(SET CMP0005 OLD)
+ADD_DEFINITIONS(-DTEST_IMAGE_DIR=\"\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../images\\\"\" )
+
+
+FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
+    SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}")
+ENDFOREACH(directory ${CAPI_LIB_LIBRARY_DIRS})
+
+# Adaptor directories are included in order of most-specific to least specific:
+INCLUDE_DIRECTORIES(
+    ../../../
+    ../../../third-party/image-resampler
+    ${${CAPI_LIB}_INCLUDE_DIRS}
+    ../dali-adaptor/dali-test-suite-utils
+)
+
+ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp ${TC_SOURCES})
+TARGET_LINK_LIBRARIES(${EXEC_NAME}
+    ${${CAPI_LIB}_LIBRARIES}
+    -lpthread --coverage
+)
+
+INSTALL(PROGRAMS ${EXEC_NAME}
+    DESTINATION ${BIN_DIR}/${EXEC_NAME}
+)
diff --git a/automated-tests/src/dali-adaptor-internal/image-loaders.cpp b/automated-tests/src/dali-adaptor-internal/image-loaders.cpp
new file mode 100755 (executable)
index 0000000..3b8821c
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2018 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-loaders.h"
+#include <dali-test-suite-utils.h>
+#include <dali/internal/imaging/common/pixel-buffer-impl.h>
+
+AutoCloseFile::AutoCloseFile( FILE *fp )
+: filePtr( fp )
+{
+}
+
+AutoCloseFile::~AutoCloseFile()
+{
+  if ( filePtr )
+  {
+    fclose( filePtr );
+  }
+}
+
+
+ImageDetails::ImageDetails( const char * const _name, unsigned int _width, unsigned int _height )
+: name( _name ),
+  width( _width ),
+  height( _height ),
+  reportedWidth( _width ),
+  reportedHeight( _height ),
+  refBufferSize( 0u ),
+  refBuffer( nullptr )
+{
+  LoadBuffer();
+}
+
+ImageDetails::ImageDetails( const char * const _name, unsigned int _width, unsigned int _height, unsigned int _reportedWidth, unsigned int _reportedHeight )
+: name( _name ),
+  width( _width ),
+  height( _height ),
+  reportedWidth( _reportedWidth ),
+  reportedHeight( _reportedHeight ),
+  refBufferSize( 0u ),
+  refBuffer( nullptr )
+{
+  LoadBuffer();
+}
+
+ImageDetails::~ImageDetails()
+{
+  if( refBuffer )
+  {
+    delete[] refBuffer;
+  }
+}
+
+void ImageDetails::LoadBuffer()
+{
+  // Load the reference buffer from the buffer file
+  std::string refBufferFilename( name + ".buffer" );
+  FILE *fp = fopen ( refBufferFilename.c_str(), "rb" );
+  AutoCloseFile autoCloseBufferFile( fp );
+
+  if ( fp )
+  {
+    fseek( fp, 0, SEEK_END );
+    refBufferSize = ftell( fp );
+    fseek( fp, 0, SEEK_SET );
+    refBuffer = reinterpret_cast<Dali::PixelBuffer*>( malloc( refBufferSize ) );
+    fread( refBuffer, sizeof( Dali::PixelBuffer ), refBufferSize, fp );
+  }
+}
+
+
+LoadFunctions::LoadFunctions( LoadBitmapHeaderFunction _header, LoadBitmapFunction _loader )
+: header( _header ),
+  loader( _loader )
+{
+}
+
+void TestImageLoading( const ImageDetails& image, const LoadFunctions& functions, Dali::Integration::Bitmap::Profile bitmapProfile )
+{
+  FILE* fp = fopen( image.name.c_str() , "rb" );
+  AutoCloseFile autoClose( fp );
+  DALI_TEST_CHECK( fp != NULL );
+
+  // Check the header file.
+
+  unsigned int width(0), height(0);
+  const Dali::ImageLoader::Input input( fp );
+  DALI_TEST_CHECK( functions.header( input, width, height ) );
+
+  DALI_TEST_EQUALS( width,  image.reportedWidth,  TEST_LOCATION );
+  DALI_TEST_EQUALS( height, image.reportedHeight, TEST_LOCATION );
+
+  // Loading the header moves the pointer within the file so reset to start of file.
+  fseek( fp, 0, 0 );
+
+  Dali::Devel::PixelBuffer bitmap;
+
+  // Load Bitmap and check its return values.
+  DALI_TEST_CHECK( functions.loader( input, bitmap ) );
+  DALI_TEST_EQUALS( image.width,  bitmap.GetWidth(),  TEST_LOCATION );
+  DALI_TEST_EQUALS( image.height, bitmap.GetHeight(), TEST_LOCATION );
+
+  // Compare buffer generated with reference buffer.
+  Dali::PixelBuffer* bufferPtr( bitmap.GetBuffer() );
+  Dali::PixelBuffer* refBufferPtr( image.refBuffer );
+  for ( unsigned int i = 0; i < image.refBufferSize; ++i, ++bufferPtr, ++refBufferPtr )
+  {
+    if( *bufferPtr != *refBufferPtr )
+    {
+      tet_result( TET_FAIL );
+      tet_printf("%s Failed in %s at line %d\n", __PRETTY_FUNCTION__, __FILE__, __LINE__);
+      break;
+    }
+  }
+}
+
+void CompareLoadedImageData( const ImageDetails& image, const LoadFunctions& functions, const uint32_t* master )
+{
+  FILE* filePointer = fopen( image.name.c_str() , "rb" );
+  AutoCloseFile autoClose( filePointer );
+  DALI_TEST_CHECK( filePointer != NULL );
+
+  // Check the header file.
+  unsigned int width = 0, height = 0;
+  const Dali::ImageLoader::Input input( filePointer );
+  DALI_TEST_CHECK( functions.header( input, width, height ) );
+
+  DALI_TEST_EQUALS( width,  image.reportedWidth,  TEST_LOCATION );
+  DALI_TEST_EQUALS( height, image.reportedHeight, TEST_LOCATION );
+
+  // Loading the header moves the pointer within the file so reset to start of file.
+  fseek( filePointer, 0, SEEK_SET );
+
+  Dali::Devel::PixelBuffer bitmap;
+
+  // Load Bitmap and check its return values.
+  DALI_TEST_CHECK( functions.loader( input, bitmap ) );
+  DALI_TEST_EQUALS( image.width,  bitmap.GetWidth(),  TEST_LOCATION );
+  DALI_TEST_EQUALS( image.height, bitmap.GetHeight(), TEST_LOCATION );
+
+  // Check the bytes per pixel.
+  const Pixel::Format pixelFormat = bitmap.GetPixelFormat();
+  const unsigned int bytesPerPixel = Pixel::GetBytesPerPixel( pixelFormat );
+
+  // Compare buffer generated with reference buffer.
+  Dali::PixelBuffer* pBitmapData( bitmap.GetBuffer() );
+  const uint32_t* pMaster( master );
+
+  // Loop through each pixel in the bitmap.
+  for ( unsigned int i = 0; i < image.refBufferSize; ++i, ++pMaster )
+  {
+    unsigned int color = 0;
+    // Loop through each byte per pixel, to build up a color value for that pixel.
+    for( unsigned int j = 0; j < bytesPerPixel; ++j, ++pBitmapData )
+    {
+      color = ( color << 8 ) | *pBitmapData;
+    }
+
+    // Check the color value is what we expect.
+    DALI_TEST_EQUALS( color, *pMaster, TEST_LOCATION );
+  }
+}
+
+void DumpImageBufferToTempFile( std::string filename, std::string targetFilename, const LoadFunctions& functions )
+{
+  FILE* fp = fopen( filename.c_str() , "rb" );
+  AutoCloseFile autoClose( fp );
+
+  Dali::Devel::PixelBuffer bitmap;
+  const Dali::ImageLoader::Input input( fp );
+
+  DALI_TEST_CHECK( functions.loader( input, bitmap ) );
+
+  Dali::PixelBuffer* bufferPtr( bitmap.GetBuffer() );
+
+  FILE* writeFp = fopen( targetFilename.c_str(), "wb" );
+  AutoCloseFile autoCloseWrite( writeFp );
+  auto& impl = GetImplementation(bitmap);
+  fwrite( bufferPtr, 1, impl.GetBufferSize(), writeFp );
+}
diff --git a/automated-tests/src/dali-adaptor-internal/image-loaders.h b/automated-tests/src/dali-adaptor-internal/image-loaders.h
new file mode 100755 (executable)
index 0000000..65cb420
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#ifndef DALI_ADAPTOR_TET_IMAGE_LOADERS_H
+#define DALI_ADAPTOR_TET_IMAGE_LOADERS_H
+
+#include <dali/dali.h>
+#include <dali/integration-api/bitmap.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/devel-api/adaptor-framework/image-loader-input.h>
+
+// Simple structure to close the file when finished with it.
+struct AutoCloseFile
+{
+  AutoCloseFile( FILE *fp );
+  ~AutoCloseFile();
+  FILE* filePtr;
+};
+
+/// Structure to hold image details and the reference buffer.
+struct ImageDetails
+{
+  /**
+   * Normal Constructor.
+   *
+   * @param[in]  _name    The name of the image to open.  The reference buffer file should have the same name appended with ".buffer".
+   * @param[in]  _width   The width of the image.
+   * @param[in]  _height  The height of the image.
+   */
+  ImageDetails( const char * const _name, unsigned int _width, unsigned int _height );
+
+  /**
+   * Sometimes an image reports an incorrect size in the header than what it actually is. In such a
+   * scenario, this constructor should be used.
+   *
+   * @param[in]  _name            The name of the image to open.  The reference buffer file should have the same name appended with ".buffer".
+   * @param[in]  _width           The width of the image.
+   * @param[in]  _height          The height of the image.
+   * @param[in]  _reportedWidth   The reported width of the image by reading the header.
+   * @param[in]  _reportedHeight  The reported height of the image by reading the header.
+   */
+  ImageDetails( const char * const _name, unsigned int _width, unsigned int _height, unsigned int _reportedWidth, unsigned int _reportedHeight );
+
+  /**
+   * Destructor
+   */
+  ~ImageDetails();
+
+
+  std::string name;
+  unsigned int width;
+  unsigned int height;
+  unsigned int reportedWidth;
+  unsigned int reportedHeight;
+  unsigned int refBufferSize;
+  Dali::PixelBuffer* refBuffer;
+
+private:
+
+  /**
+   * Loads the reference buffer file.
+   */
+  void LoadBuffer();
+};
+
+/**
+ * A structure storing the methods that should be called when reading an image's header and when
+ * reading the bitmap from the image file.
+ */
+struct LoadFunctions
+{
+  typedef bool (*LoadBitmapFunction)( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& );
+  typedef bool (*LoadBitmapHeaderFunction)( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+  LoadFunctions( LoadBitmapHeaderFunction _header, LoadBitmapFunction _loader );
+  LoadBitmapHeaderFunction header;
+  LoadBitmapFunction loader;
+};
+
+// Helper method to test each image file.
+/**
+ * Use this method to test the header and and bitmap loading of each image.
+ * The loaded bitmap is then checked with the reference bitmap in ImageDetails.
+ *
+ * @param[in]  image         The image details.
+ * @param[in]  functions     The loader functions that need to be called.
+ * @param[in]  bitmapProfile Whether or not the bitmap is raw
+ */
+void TestImageLoading( const ImageDetails& image, const LoadFunctions& functions, Dali::Integration::Bitmap::Profile bitmapProfile = Dali::Integration::Bitmap::BITMAP_2D_PACKED_PIXELS );
+
+/**
+ * Helper method to compare the resultant loaded image data of the specified image with a golden master data.
+ *
+ * @param[in] image         The image to load
+ * @param[in] functions     The functions to use to load the image
+ * @param[in] master        Golden master data to compare the resultant loaded image with
+ */
+void CompareLoadedImageData( const ImageDetails& image, const LoadFunctions& functions, const uint32_t* master );
+
+/**
+ * Helper function which should be used when first creating a reference buffer file.
+ * Set output file to a file in the /tmp/ directory e.g:
+ *   DumpImageBufferToTempFile( "images/pattern.gif" , "/tmp/pattern.gif.buffer" );
+ *
+ * @param[in]  filename        The path of the image file.
+ * @param[in]  targetFilename  The path of where the buffer should be written to.  This should ideally be in the "/tmp" folder.
+ * @param[in]  functions       The loader functions to call.
+ */
+void DumpImageBufferToTempFile( std::string filename, std::string targetFilename, const LoadFunctions& functions );
+
+#endif // DALI_ADAPTOR_TET_IMAGE_LOADERS_H
diff --git a/automated-tests/src/dali-adaptor-internal/tct-dali-adaptor-internal-core.cpp b/automated-tests/src/dali-adaptor-internal/tct-dali-adaptor-internal-core.cpp
new file mode 100644 (file)
index 0000000..1dfb194
--- /dev/null
@@ -0,0 +1,51 @@
+#include <string.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <test-harness.h>
+#include "tct-dali-adaptor-internal-core.h"
+
+int main(int argc, char * const argv[])
+{
+  int result = TestHarness::EXIT_STATUS_BAD_ARGUMENT;
+
+  const char* optString = "sf";
+  bool optRerunFailed(true);
+  bool optRunSerially(false);
+
+  int nextOpt = 0;
+  do
+  {
+    nextOpt = getopt( argc, argv, optString );
+    switch(nextOpt)
+    {
+      case 'f':
+        optRerunFailed = false;
+        break;
+      case 's':
+        optRunSerially = true;
+        break;
+      case '?':
+        TestHarness::Usage(argv[0]);
+        exit(TestHarness::EXIT_STATUS_BAD_ARGUMENT);
+        break;
+    }
+  } while( nextOpt != -1 );
+
+  if( optind == argc ) // no testcase name in argument list
+  {
+    if( optRunSerially )
+    {
+      result = TestHarness::RunAll( argv[0], tc_array );
+    }
+    else
+    {
+      result = TestHarness::RunAllInParallel( argv[0], tc_array, optRerunFailed );
+    }
+  }
+  else
+  {
+    // optind is index of next argument - interpret as testcase name
+    result = TestHarness::FindAndRunTestCase(tc_array, argv[optind]);
+  }
+  return result;
+}
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-BmpLoader.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-BmpLoader.cpp
new file mode 100644 (file)
index 0000000..6599536
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2018 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-test-suite-utils.h>
+
+#include <dali/internal/imaging/common/loader-bmp.h>
+#include "image-loaders.h"
+
+using namespace Dali;
+
+namespace
+{
+
+static const LoadFunctions BmpLoaders( TizenPlatform::LoadBmpHeader, TizenPlatform::LoadBitmapFromBmp );
+
+} // Unnamed namespace.
+
+int UtcDaliBmp24bpp(void)
+{
+  ImageDetails image( TEST_IMAGE_DIR "/flag-24bpp.bmp", 32u, 32u );
+
+  TestImageLoading( image, BmpLoaders );
+
+  END_TEST;
+}
+
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-CommandLineOptions.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-CommandLineOptions.cpp
new file mode 100644 (file)
index 0000000..f9a9404
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * 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 <getopt.h>
+#include <dali/dali.h>
+#include <dali/internal/system/common/command-line-options.h>
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+using namespace Dali::Internal::Adaptor;
+
+
+// Called only once before first test is run.
+void command_line_options_startup(void)
+{
+  test_return_value = TET_UNDEF;
+  optind = 0; // Reset opt for test
+}
+
+// Called only once after last test is run
+void command_line_options_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliCommandLineOptionsNoArgs(void)
+{
+  optind=0;
+
+  int argc( 1 );
+  const char* argList[1] = { "program" };
+  char** argv = const_cast<char**>(argList);
+
+  CommandLineOptions options( &argc, &argv );
+
+  DALI_TEST_EQUALS( argc, 1, TEST_LOCATION );
+
+  // Check values
+  DALI_TEST_EQUALS( options.stageWidth, 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageHeight, 0, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageDPI, "", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliCommandLineOptionsDaliShortArgs(void)
+{
+  optind=0;
+
+  const char* argList[] =
+  {
+      "program",
+      "-w", "800",
+      "-h", "1000",
+      "-d", "4x5",
+  };
+  int argc( sizeof( argList ) / sizeof( argList[0] ) );
+  char** argv = const_cast<char**>(argList);
+
+  CommandLineOptions options( &argc, &argv );
+
+  // Should strip out the height and width
+  DALI_TEST_EQUALS( argc, 1, TEST_LOCATION );
+
+  // Check values
+  DALI_TEST_EQUALS( options.stageWidth, 800, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageHeight, 1000, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageDPI, "4x5", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliCommandLineOptionsDaliLongArgsEqualsSign(void)
+{
+  optind=0;
+
+  const char* argList[] =
+  {
+      "program",
+      "--width=800",
+      "--height=1000",
+      "--dpi=3x4",
+      "--help"
+  };
+  int argc( sizeof( argList ) / sizeof( argList[0] ) );
+  char** argv = const_cast<char**>(argList);
+
+  CommandLineOptions options( &argc, &argv );
+
+  // Should strip out the height and width
+  DALI_TEST_EQUALS( argc, 1, TEST_LOCATION );
+
+  // Check values
+  DALI_TEST_EQUALS( options.stageWidth, 800, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageHeight, 1000, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageDPI, "3x4", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliCommandLineOptionsDaliLongArgsSpaces(void)
+{
+  optind=0;
+
+  const char* argList[] =
+  {
+      "program",
+      "--width", "800",
+      "--height", "1000",
+      "--dpi", "3x4",
+      "--help"
+  };
+  int argc( sizeof( argList ) / sizeof( argList[0] ) );
+  char** argv = const_cast<char**>(argList);
+
+  CommandLineOptions options( &argc, &argv );
+
+  // Should strip out the height and width
+  DALI_TEST_EQUALS( argc, 1, TEST_LOCATION );
+
+  // Check values
+  DALI_TEST_EQUALS( options.stageWidth, 800, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageHeight, 1000, TEST_LOCATION );
+  DALI_TEST_EQUALS( options.stageDPI, "3x4", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliCommandLineOptionsNonDaliArgs(void)
+{
+  optind=0;
+
+  const char* argList[] =
+  {
+      "program",
+      "hello-world",
+      "-y", "600",
+  };
+  int argc( sizeof( argList ) / sizeof( argList[0] ) );
+  char** argv = const_cast<char**>(argList);
+
+  CommandLineOptions options( &argc, &argv );
+
+  // Should still be the same
+  DALI_TEST_EQUALS( argc, 4, TEST_LOCATION );
+
+  // Ensure order has not changed
+  DALI_TEST_EQUALS( argList[0], "program", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[1], "hello-world", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[2], "-y", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[3], "600", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliCommandLineOptionsMixture(void)
+{
+  optind = 0; // Reset opt for test
+
+  const char* argList[] =
+  {
+    "program",
+    "--width=800",
+    "hello-world",
+    "-y", "600",
+    "--height", "1000",
+    "-r",
+  };
+  int argc( sizeof( argList ) / sizeof( argList[0] ) );
+  char** argv = const_cast<char**>( argList );
+
+  CommandLineOptions options( &argc, &argv );
+
+  // Should still be the same
+  DALI_TEST_EQUALS( argc, 5, TEST_LOCATION );
+
+  // Ensure order of program name and unhandled options has not changed
+  DALI_TEST_EQUALS( argList[0], "program", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[1], "hello-world", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[2], "-y", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[3], "600", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[4], "-r", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliCommandLineOptionsMixtureDaliOpsAtStart(void)
+{
+  optind=0;
+
+  const char* argList[] =
+  {
+      "program",
+      "--width=800",
+      "--height", "1000",
+      "-r",
+      "hello-world",
+      "-y", "600",
+  };
+  int argc( sizeof( argList ) / sizeof( argList[0] ) );
+  char** argv = const_cast<char**>( argList );
+
+  CommandLineOptions options( &argc, &argv );
+
+  // Should still be the same
+  DALI_TEST_EQUALS( argc, 5, TEST_LOCATION );
+
+  // Ensure order of program name and unhandled options has not changed
+  DALI_TEST_EQUALS( argList[0], "program", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[1], "-r", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[2], "hello-world", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[3], "-y", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[4], "600", TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliCommandLineOptionsMixtureDaliOpsAtEnd(void)
+{
+  optind=0;
+
+  const char* argList[] =
+  {
+      "program",
+      "hello-world",
+      "-y", "600",
+      "-r",
+      "--width=800",
+      "--height", "1000",
+  };
+  int argc( sizeof( argList ) / sizeof( argList[0] ) );
+  char** argv = const_cast<char**>( argList );
+
+  CommandLineOptions options( &argc, &argv );
+
+  // Should still be the same
+  DALI_TEST_EQUALS( argc, 5, TEST_LOCATION );
+
+  // Ensure order of program name and unhandled options has not changed
+  DALI_TEST_EQUALS( argList[0], "program", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[1], "hello-world", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[2], "-y", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[3], "600", TEST_LOCATION );
+  DALI_TEST_EQUALS( argList[4], "-r", TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-CompressedTextures.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-CompressedTextures.cpp
new file mode 100755 (executable)
index 0000000..1b1eb54
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * 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 <iostream>
+#include <stdlib.h>
+#include <vector>
+#include <dali-test-suite-utils.h>
+#include <dali/internal/imaging/common/loader-ktx.h>
+#include <dali/internal/imaging/common/loader-astc.h>
+
+// INTERNAL INCLUDES
+#include "image-loaders.h"
+
+using namespace Dali;
+
+// Pre-define loader functions for each image type being tested (as they are reused in different tests).
+static const LoadFunctions KtxLoaders(  TizenPlatform::LoadKtxHeader,  TizenPlatform::LoadBitmapFromKtx  );
+static const LoadFunctions AstcLoaders( TizenPlatform::LoadAstcHeader, TizenPlatform::LoadBitmapFromAstc );
+
+/**
+ * This class encapsulates knowledge of testing compressed files.
+ * It requires a few input parameters per test to confirm if the file was read and understood.
+ * The fixture guarantees that each test performed is setup and closed individually, therefore run order does not matter.
+ */
+class KtxTestFixture
+{
+  public:
+
+    /**
+     * Constructor.
+     * Sets up the fixture.
+     */
+    KtxTestFixture( void )
+    {
+    }
+
+    /**
+     * Destructor.
+     */
+    ~KtxTestFixture()
+    {
+    }
+
+    /**
+     * This struct contains any per-test parameters.
+     * This should be added to if more properties of a file/format should be tested.
+     */
+    struct TestEntry
+    {
+        LoadFunctions loadFunctions;    ///< Used to parse the header of a given type of image.
+        std::string filename;           ///< Name of the compressed texture KTX file to load.
+        int expectedWidth;              ///< The width the texture should be.
+        int expectedHeight;             ///< The height the KTX texture should be.
+
+        TestEntry( const LoadFunctions& newLoadFunctions, std::string newFilename, int newExpectedWidth, int newExpectedHeight )
+        : loadFunctions( newLoadFunctions ),
+          filename( newFilename ),
+          expectedWidth( newExpectedWidth ),
+          expectedHeight( newExpectedHeight )
+        {
+        }
+    };
+
+  private:
+
+    typedef std::vector< TestEntry > TestContainer;
+
+  public:
+
+    /**
+     * Adds a test to be performed.
+     * @param[in] testEntry A TestEntry struct containing all the details to perform one test.
+     */
+    void AddTest( TestEntry testEntry )
+    {
+        mTests.push_back( testEntry );
+    }
+
+    /**
+     * Runs all tests created with "AddTest".
+     * This will create failures upon failing tests.
+     */
+    void RunTests()
+    {
+      for( TestContainer::iterator testIterator = mTests.begin(); testIterator != mTests.end(); ++testIterator )
+      {
+        const TestEntry& currentTest = *testIterator;
+
+        RunTest( currentTest );
+      }
+    }
+
+  private:
+
+    /**
+     * Sets up, Runs and Closes-down an individual test.
+     * @param[in] testEntry A TestEntry struct containing all the details to perform one test.
+     */
+    void RunTest( const TestEntry& testEntry )
+    {
+      FILE* fileDescriptor = fopen( testEntry.filename.c_str(), "rb" );
+      AutoCloseFile autoClose( fileDescriptor );
+      DALI_TEST_CHECK( fileDescriptor != NULL );
+
+      // Check the header file.
+      unsigned int width( 0 ), height( 0 );
+      const Dali::ImageLoader::Input input( fileDescriptor );
+
+      // Use the given loader to parse the image header.
+      DALI_TEST_CHECK( testEntry.loadFunctions.header( input, width, height ) );
+
+      DALI_TEST_EQUALS( width,  testEntry.expectedWidth,  TEST_LOCATION );
+      DALI_TEST_EQUALS( height, testEntry.expectedHeight, TEST_LOCATION );
+    }
+
+  private:
+
+    TestContainer mTests;         ///< Holds all tests to be run.
+
+};
+
+// KTX files (KTX is a wrapper, so can contain different compressed texture types):
+
+int UtcDaliKtxLoaderETC(void)
+{
+  KtxTestFixture fixture;
+
+  fixture.AddTest( KtxTestFixture::TestEntry( KtxLoaders, TEST_IMAGE_DIR "/fractal-compressed-ETC1_RGB8_OES-45x80.ktx", 45u, 80u ) );
+  fixture.AddTest( KtxTestFixture::TestEntry( KtxLoaders, TEST_IMAGE_DIR "/fractal-compressed-RGB8_ETC2-45x80.ktx", 45u, 80u ) );
+
+  fixture.RunTests();
+
+  END_TEST;
+}
+
+int UtcDaliKtxLoaderPVRTC(void)
+{
+  KtxTestFixture fixture;
+
+  fixture.AddTest( KtxTestFixture::TestEntry( KtxLoaders, TEST_IMAGE_DIR "/fractal-compressed-RGB_PVRTC_4BPPV1_IMG-32x64.ktx", 32u, 64u ) );
+
+  fixture.RunTests();
+
+  END_TEST;
+}
+
+int UtcDaliKtxLoaderEAC(void)
+{
+  KtxTestFixture fixture;
+
+  fixture.AddTest( KtxTestFixture::TestEntry( KtxLoaders, TEST_IMAGE_DIR "/fractal-compressed-R11_EAC-45x80.ktx", 45u, 80u ) );
+
+  fixture.RunTests();
+
+  END_TEST;
+}
+
+int UtcDaliKtxLoaderASTC(void)
+{
+  KtxTestFixture fixture;
+
+  fixture.AddTest( KtxTestFixture::TestEntry( KtxLoaders, TEST_IMAGE_DIR "/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.ktx", 32u, 64u ) );
+  fixture.AddTest( KtxTestFixture::TestEntry( KtxLoaders, TEST_IMAGE_DIR "/fractal-compressed-SRBG8_ALPHA8_ASTC_4x4_KHR-32x64.ktx", 32u, 64u ) );
+
+  fixture.RunTests();
+
+  END_TEST;
+}
+
+
+// ASTC (Native) files:
+int UtcDaliAstcLoader(void)
+{
+  KtxTestFixture fixture;
+
+  fixture.AddTest( KtxTestFixture::TestEntry( AstcLoaders, TEST_IMAGE_DIR "/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.astc", 32u, 64u ) );
+
+  fixture.RunTests();
+
+  END_TEST;
+}
+
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-FontClient.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-FontClient.cpp
new file mode 100644 (file)
index 0000000..3bdab67
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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 <stdint.h>
+#include <dali/dali.h>
+#include <dali-test-suite-utils.h>
+#include <dali/internal/text/text-abstraction/font-client-helper.h>
+
+using namespace Dali;
+
+int UtcDaliFontClient(void)
+{
+  const int ORDERED_VALUES[] = { -1, 50, 63, 75, 87, 100, 113, 125, 150, 200 };
+
+  const unsigned int NUM_OF_ORDERED_VALUES = sizeof( ORDERED_VALUES ) / sizeof( int );
+
+  TestApplication application;
+  int result=0;
+
+  tet_infoline("UtcDaliFontClient No table");
+  result = TextAbstraction::Internal::ValueToIndex( 100, NULL, 0u );
+  DALI_TEST_EQUALS( -1, result, TEST_LOCATION );
+
+  tet_infoline("UtcDaliFontClient Non defined values");
+  result = TextAbstraction::Internal::ValueToIndex( -1, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 0, result, TEST_LOCATION );
+  result = TextAbstraction::Internal::ValueToIndex( -3, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 0, result, TEST_LOCATION );
+
+  tet_infoline("UtcDaliFontClient Between non defined and first of range.");
+  result = TextAbstraction::Internal::ValueToIndex( 0, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 1, result, TEST_LOCATION );
+  result = TextAbstraction::Internal::ValueToIndex( 30, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 1, result, TEST_LOCATION );
+  result = TextAbstraction::Internal::ValueToIndex( 49, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 1, result, TEST_LOCATION );
+
+  tet_infoline("UtcDaliFontClient Defined in range");
+  for( unsigned int index = 1u; index < NUM_OF_ORDERED_VALUES; ++index )
+  {
+    result = TextAbstraction::Internal::ValueToIndex( ORDERED_VALUES[index], ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+    DALI_TEST_EQUALS( index, result, TEST_LOCATION );
+  }
+
+  tet_infoline("UtcDaliFontClient Non defined in range");
+  result = TextAbstraction::Internal::ValueToIndex( 51, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 1, result, TEST_LOCATION );
+  result = TextAbstraction::Internal::ValueToIndex( 55, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 1, result, TEST_LOCATION );
+  result = TextAbstraction::Internal::ValueToIndex( 62, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 2, result, TEST_LOCATION );
+  result = TextAbstraction::Internal::ValueToIndex( 64, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 2, result, TEST_LOCATION );
+  result = TextAbstraction::Internal::ValueToIndex( 151, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 8, result, TEST_LOCATION );
+  result = TextAbstraction::Internal::ValueToIndex( 175, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 9, result, TEST_LOCATION );
+  result = TextAbstraction::Internal::ValueToIndex( 176, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 9, result, TEST_LOCATION );
+  result = TextAbstraction::Internal::ValueToIndex( 199, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 9, result, TEST_LOCATION );
+
+  tet_infoline("UtcDaliFontClient above of range");
+  result = TextAbstraction::Internal::ValueToIndex( 220, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 9, result, TEST_LOCATION );
+  result = TextAbstraction::Internal::ValueToIndex( 500, ORDERED_VALUES, NUM_OF_ORDERED_VALUES - 1u );
+  DALI_TEST_EQUALS( 9, result, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-GifLoader.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-GifLoader.cpp
new file mode 100644 (file)
index 0000000..28c997a
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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-test-suite-utils.h>
+
+#include <dali/internal/imaging/common/loader-gif.h>
+#include "image-loaders.h"
+
+using namespace Dali;
+
+namespace {
+static const LoadFunctions GifLoaders( TizenPlatform::LoadGifHeader, TizenPlatform::LoadBitmapFromGif );
+}
+
+
+void gif_loader_startup(void)
+{
+}
+
+void gif_loader_cleanup(void)
+{
+}
+
+int UtcDaliGifLoaderInterlaced(void)
+{
+  ImageDetails interlaced( TEST_IMAGE_DIR "/interlaced.gif", 365u, 227u );
+  TestImageLoading( interlaced, GifLoaders );
+  END_TEST;
+}
+
+int UtcDaliGifLoaderErrorBits(void)
+{
+  ImageDetails errorBits( TEST_IMAGE_DIR "/error-bits.gif", 534u, 749u, 1280u, 1024u );
+  TestImageLoading( errorBits, GifLoaders );
+  END_TEST;
+}
+
+int UtcDaliGifLoaderPattern(void)
+{
+  ImageDetails pattern( TEST_IMAGE_DIR "/pattern.gif", 600u, 600u );
+  TestImageLoading( pattern, GifLoaders );
+  END_TEST;
+}
+
+int UtcDaliGifLoaderTransparency(void)
+{
+  ImageDetails transparency( TEST_IMAGE_DIR "/transparency.gif", 320u, 280u );
+  TestImageLoading( transparency, GifLoaders );
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-IcoLoader.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-IcoLoader.cpp
new file mode 100644 (file)
index 0000000..963a4e6
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * 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 <iostream>
+#include <stdlib.h>
+#include <dali-test-suite-utils.h>
+
+#include <dali/internal/imaging/common/loader-ico.h>
+#include "image-loaders.h"
+
+using namespace Dali;
+
+namespace
+{
+
+static const LoadFunctions IcoLoaders( TizenPlatform::LoadIcoHeader, TizenPlatform::LoadBitmapFromIco );
+
+
+// Golden master image data for each icon type:
+// Note: The bottom right corner of each image is fully transparent.
+// Note: The first 4 sets of data *happen* to be the same, but could be different depending on the image converted.
+//       In this case as the original image contains few colors, they can easily fit inside an 8bit palette, thus
+//       Causing no image degradation.
+
+uint32_t ImageCheckData_Ico4x4_32bpp_8alpha[] = {
+    0xff0000ff, 0x00ff00ff, 0x0000ffff, 0xff00ffff,
+    0xc04040ff, 0x40c040ff, 0x4040c0ff, 0xffff00ff,
+    0xa06060ff, 0x60a060ff, 0x6060a0ff, 0x00ffffff,
+    0xffffffff, 0x808080ff, 0x000000ff, 0x00000000
+};
+
+uint32_t ImageCheckData_Ico4x4_24bpp[] = {
+    0xff0000ff, 0x00ff00ff, 0x0000ffff, 0xff00ffff,
+    0xc04040ff, 0x40c040ff, 0x4040c0ff, 0xffff00ff,
+    0xa06060ff, 0x60a060ff, 0x6060a0ff, 0x00ffffff,
+    0xffffffff, 0x808080ff, 0x000000ff, 0x00000000
+};
+
+uint32_t ImageCheckData_Ico4x4_8bpp[] = {
+    0xff0000ff, 0x00ff00ff, 0x0000ffff, 0xff00ffff,
+    0xc04040ff, 0x40c040ff, 0x4040c0ff, 0xffff00ff,
+    0xa06060ff, 0x60a060ff, 0x6060a0ff, 0x00ffffff,
+    0xffffffff, 0x808080ff, 0x000000ff, 0x00000000
+};
+
+uint32_t ImageCheckData_Ico4x4_4bpp[] = {
+    0xff0000ff, 0x00ff00ff, 0x0000ffff, 0xff00ffff,
+    0xc04040ff, 0x40c040ff, 0x4040c0ff, 0xffff00ff,
+    0xa06060ff, 0x60a060ff, 0x6060a0ff, 0x00ffffff,
+    0xffffffff, 0x808080ff, 0x000000ff, 0x00000000
+};
+
+uint32_t ImageCheckData_Ico4x4_1bpp[] = {
+    0xA18783ff, 0xA18783ff, 0xA18783ff, 0xA18783ff,
+    0xA18783ff, 0xA18783ff, 0xA18783ff, 0xA18783ff,
+    0xA18783ff, 0xA18783ff, 0xA18783ff, 0xA18783ff,
+    0xA18783ff, 0xA18783ff, 0xA18783ff, 0xA1878300
+};
+
+
+} // Unnamed namespace.
+
+
+int UtcDaliIco32bpp8alpha(void)
+{
+  ImageDetails image( TEST_IMAGE_DIR "/test-image-4x4-32bpp.ico", 4u, 4u );
+
+  CompareLoadedImageData( image, IcoLoaders, ImageCheckData_Ico4x4_32bpp_8alpha );
+
+  END_TEST;
+}
+
+
+int UtcDaliIco24bpp1alpha(void)
+{
+  ImageDetails image( TEST_IMAGE_DIR "/test-image-4x4-24bpp.ico", 4u, 4u );
+
+  CompareLoadedImageData( image, IcoLoaders, ImageCheckData_Ico4x4_24bpp );
+
+  END_TEST;
+}
+
+
+int UtcDaliIco8bpp1alpha(void)
+{
+  ImageDetails image( TEST_IMAGE_DIR "/test-image-4x4-8bpp.ico", 4u, 4u );
+
+  CompareLoadedImageData( image, IcoLoaders, ImageCheckData_Ico4x4_8bpp );
+
+  END_TEST;
+}
+
+
+int UtcDaliIco4bpp1alpha(void)
+{
+  ImageDetails image( TEST_IMAGE_DIR "/test-image-4x4-4bpp.ico", 4u, 4u );
+
+  CompareLoadedImageData( image, IcoLoaders, ImageCheckData_Ico4x4_4bpp );
+
+  END_TEST;
+}
+
+
+int UtcDaliIco1bpp1alpha(void)
+{
+  ImageDetails image( TEST_IMAGE_DIR "/test-image-4x4-1bpp.ico", 4u, 4u );
+
+  CompareLoadedImageData( image, IcoLoaders, ImageCheckData_Ico4x4_1bpp );
+
+  END_TEST;
+}
+
+
+
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-ImageOperations.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-ImageOperations.cpp
new file mode 100644 (file)
index 0000000..01ec549
--- /dev/null
@@ -0,0 +1,1426 @@
+/*
+ * 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 <dali-test-suite-utils.h>
+#include <dali/internal/imaging/common/image-operations.h>
+#include <dali/devel-api/common/ref-counted-dali-vector.h>
+
+#include <sys/mman.h>
+#include <unistd.h>
+
+using namespace Dali::Internal::Platform;
+
+namespace
+{
+
+/**
+ * @brief Generate a random integer between zero and the parameter passed in.
+ **/
+uint32_t RandomInRange( uint32_t max )
+{
+  const uint32_t randToMax = lrand48() % (max + 1);
+  return randToMax;
+}
+
+/**
+ * @brief Random number representable in an 8 bit color component.
+ */
+inline uint32_t RandomComponent8()
+{
+  return RandomInRange( 255u );
+}
+
+/**
+ * @brief Random number representable in a 5 bit color component.
+ */
+inline uint32_t RandomComponent5()
+{
+  return RandomInRange( 31u );
+}
+
+/**
+ * @brief Random number representable in a 6 bit color component.
+ */
+inline uint32_t RandomComponent6()
+{
+  return RandomInRange( 63u );
+}
+
+/**
+ * @brief RGBA8888 Pixels from separate color components.
+ */
+inline uint32_t PixelRGBA8888( uint32_t r, uint32_t g, uint32_t b, uint32_t a )
+{
+  return (r << 24) + (g << 16) + (b << 8) + a;
+}
+
+/**
+ * @brief RGB565 Pixels from color components in the low bits of passed-in words.
+ */
+inline uint16_t PixelRGB565( uint32_t r, uint32_t g, uint32_t b )
+{
+  return (r << 11) + (g << 5) + b;
+}
+
+/**
+ * @brief RGBA8888 Pixels with random color components.
+ */
+inline uint32_t RandomPixelRGBA8888( )
+{
+  const uint32_t randomPixel = PixelRGBA8888( RandomComponent8(), RandomComponent8(), RandomComponent8(), RandomComponent8() );
+  return randomPixel;
+}
+
+/**
+ * @brief Return a hash over a set of pixels.
+ *
+ * Used to check a buffer of pixels is unmodified by an operation given inputs
+ * that should mean that it is not changed.
+ */
+inline uint32_t HashPixels( const uint32_t* const pixels, unsigned int numPixels )
+{
+  uint32_t hash = 5381;
+
+  for( unsigned int i = 0; i < numPixels; ++i )
+  {
+    hash = hash * 33 + pixels[i];
+  }
+
+  return hash;
+}
+
+/**
+ * @brief Build some dummy scanlines to exercise scanline averaging code on.
+ */
+void SetupScanlineForHalvingTestsRGBA8888( size_t scanlineLength, Dali::Vector<uint32_t>& scanline, Dali::Vector<uint32_t>& reference )
+{
+  scanline.Resize( scanlineLength );
+  reference.Reserve( scanlineLength / 2 + 32 );
+
+  // Prepare some random pixels:
+  srand( 19 * 23 * 47 * 53 );
+  for( size_t i = 0; i < scanlineLength / 2; ++i )
+  {
+    // Generate random colors:
+    const uint32_t red1   = RandomComponent8();
+    const uint32_t red2   = RandomComponent8();
+    const uint32_t green1 = RandomComponent8();
+    const uint32_t green2 = RandomComponent8();
+    const uint32_t blue1  = RandomComponent8();
+    const uint32_t blue2  = RandomComponent8();
+    const uint32_t alpha1 = RandomComponent8();
+    const uint32_t alpha2 = RandomComponent8();
+
+    // The average of these pixels should equal the reference:
+    scanline[i * 2]     = PixelRGBA8888( red1, green1, blue1, alpha1 );
+    scanline[i * 2 + 1] = PixelRGBA8888( red2, green2, blue2, alpha2 );
+
+    // Average the two pixels manually as a reference:
+    reference.PushBack( PixelRGBA8888( (red1 + red2) >> 1u, (green1 + green2) >> 1u, (blue1 + blue2) >> 1u, (alpha1 + alpha2) >> 1u ) );
+  }
+
+  for( size_t i = scanlineLength / 2; i < reference.Capacity(); ++i )
+  {
+    reference[i] = 0xEEEEEEEE;
+  }
+}
+
+/**
+ * @brief Build some dummy scanlines to exercise scanline averaging code on.
+ */
+void SetupScanlineForHalvingTestsRGB565( size_t scanlineLength, Dali::Vector<uint16_t>& scanline, Dali::Vector<uint16_t>& reference )
+{
+  scanline.Resize( scanlineLength );
+  reference.Reserve( scanlineLength / 2 + 32 );
+
+  // Prepare some random pixels:
+  srand48( 19 * 23 * 47 * 53 );
+  for( size_t i = 0; i < scanlineLength / 2; ++i )
+  {
+    // Generate random colors:
+    const uint32_t red1   = RandomComponent5();
+    const uint32_t red2   = RandomComponent5();
+    const uint32_t green1 = RandomComponent6();
+    const uint32_t green2 = RandomComponent6();
+    const uint32_t blue1  = RandomComponent5();
+    const uint32_t blue2  = RandomComponent5();
+
+    // The average of these pixels should equal the reference:
+    scanline[i * 2]     = PixelRGB565( red1, green1, blue1 );
+    scanline[i * 2 + 1] = PixelRGB565( red2, green2, blue2 );
+
+    // Average the two pixels manually as a reference:
+    reference.PushBack( PixelRGB565( (red1 + red2) >> 1u, (green1 + green2) >> 1u, (blue1 + blue2) >> 1u ) );
+  }
+
+  for( size_t i = scanlineLength / 2; i < reference.Capacity(); ++i )
+  {
+    reference[i] = 0xEEEE;
+  }
+}
+
+/**
+ * @brief Build some dummy scanlines to exercise scanline averaging code on.
+ */
+void SetupScanlineForHalvingTests2Bytes( size_t scanlineLength, Dali::Vector<uint8_t>& scanline, Dali::Vector<uint8_t>& reference )
+{
+  scanline.Resize( scanlineLength * 2 );
+  reference.Reserve( scanlineLength + 32 );
+
+  // Prepare some random pixels:
+  srand48( 19 * 23 * 47 * 53 * 59 );
+  for( size_t i = 0; i < scanlineLength / 2; ++i )
+  {
+    // Generate random colors:
+    const uint32_t c11   = RandomComponent8();
+    const uint32_t c12   = RandomComponent8();
+    const uint32_t c21   = RandomComponent8();
+    const uint32_t c22   = RandomComponent8();
+
+    // The average of these pixels should equal the reference:
+    scanline[i * 4]     = c11;
+    scanline[i * 4 + 1] = c12;
+    scanline[i * 4 + 2] = c21;
+    scanline[i * 4 + 3] = c22;
+
+    // Average the two pixels manually as a reference:
+    reference.PushBack( (c11 + c21) >> 1u );
+    reference.PushBack( (c12 + c22) >> 1u );
+  }
+
+  for( size_t i = scanlineLength; i < reference.Capacity(); ++i )
+  {
+    reference[i] = 0xEE;
+  }
+}
+
+/**
+ * @brief Build some dummy 1 byte per pixel scanlines to exercise scanline averaging code on.
+ */
+void SetupScanlineForHalvingTests1Byte( size_t scanlineLength, Dali::Vector<uint8_t>& scanline, Dali::Vector<uint8_t>& reference )
+{
+  scanline.Resize( scanlineLength * 2 );
+  reference.Reserve( scanlineLength + 32 );
+
+  // Prepare some random pixels:
+  srand48( 19 * 23 * 47 * 53 * 63 );
+  for( size_t i = 0; i < scanlineLength / 2; ++i )
+  {
+    // Generate random colors:
+    const uint32_t c1 = RandomComponent8();
+    const uint32_t c2 = RandomComponent8();
+
+    // The average of these pixels should equal the reference:
+    scanline[i * 2]     = c1;
+    scanline[i * 2 + 1] = c2;
+
+    // Average the two pixels manually as a reference:
+    reference.PushBack( (c1 + c2) >> 1u );
+
+  }
+
+  for( size_t i = scanlineLength; i < reference.Capacity(); ++i )
+  {
+    reference[i] = 0xEE;
+  }
+}
+
+/**
+ * @brief Build some dummy scanlines to exercise vertical averaging code on.
+ *
+ * All tested formats bar RGB565 can share this setup.
+ */
+void SetupScanlinesRGBA8888( size_t scanlineLength, Dali::Vector<uint32_t>& scanline1, Dali::Vector<uint32_t>& scanline2, Dali::Vector<uint32_t>& reference, Dali::Vector<uint32_t>& output )
+{
+  scanline1.Reserve( scanlineLength );
+  scanline2.Reserve( scanlineLength );
+  reference.Reserve( scanlineLength + 32 );
+  output.Reserve( scanlineLength + 32 );
+
+  for( size_t i = scanlineLength; i < output.Capacity(); ++i )
+  {
+    output[i]    = 0xDEADBEEF;
+    reference[i] = 0xDEADBEEF;
+  }
+
+  // Prepare some random pixels:
+  srand48( 19 * 23 * 47 );
+  for( size_t i = 0; i < scanlineLength; ++i )
+  {
+    // Generate random colors:
+    const uint32_t red1   = RandomComponent8();
+    const uint32_t red2   = RandomComponent8();
+    const uint32_t green1 = RandomComponent8();
+    const uint32_t green2 = RandomComponent8();
+    const uint32_t blue1  = RandomComponent8();
+    const uint32_t blue2  = RandomComponent8();
+    const uint32_t alpha1 = RandomComponent8();
+    const uint32_t alpha2 = RandomComponent8();
+
+    // The average of these pixels should equal the reference:
+    scanline1.PushBack( PixelRGBA8888( red1, green1, blue1, alpha1 ) );
+    scanline2.PushBack( PixelRGBA8888( red2, green2, blue2, alpha2 ) );
+
+    // Average the two pixels manually as a reference:
+    reference.PushBack( PixelRGBA8888( (red1 + red2) >> 1u, (green1 + green2) >> 1u, (blue1 + blue2) >> 1u, (alpha1 + alpha2) >> 1u ) );
+  }
+}
+
+/**
+ * @brief Compares a scanline of interest to a reference, testing each pixel is the same.
+ */
+void MatchScanlinesRGBA8888( Dali::Vector<uint32_t>& reference, Dali::Vector<uint32_t>& output, size_t& numMatches, const char * const location )
+{
+  numMatches = 0;
+  for( size_t i = 0, length = reference.Capacity(); i < length; ++i )
+  {
+    DALI_TEST_EQUALS( output[i], reference[i], location );
+    numMatches += output[i] == reference[i];
+  }
+}
+
+} //< namespace unnamed
+
+/**
+ * @brief Test component averaging code.
+ */
+int UtcDaliImageOperationsAverageComponent(void)
+{
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 0u, 0u ), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 1u, 1u ), 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 0xffffffffu >> 1u, 0xffffffffu >> 1u ), 0xffffffffu >> 1u, TEST_LOCATION );
+  const unsigned int avg3 = Dali::Internal::Platform::AverageComponent( 0xfffffffeu, 1u );
+  DALI_TEST_EQUALS( avg3, 0x7fffffffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 255u, 255u ), 255u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 512u, 0u ), 256u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 511u, 0u ), 255u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 510u, 0u ), 255u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 509u, 0u ), 254u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AverageComponent( 0u, 509u ), 254u, TEST_LOCATION );
+  END_TEST;
+}
+
+/**
+ * @brief Test Pixel averaging code.
+ */
+int UtcDaliImageOperationsAveragePixelRGBA8888(void)
+{
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGBA8888( 0u, 0u ), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGBA8888( 0x01010101, 0x01010101 ), 0x01010101u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGBA8888( 0x01010101, 0x03030303 ), 0x02020202u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGBA8888( 0xffffffff, 0xffffffff ), 0xffffffffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGBA8888( 0xffffffff, 0u ), 0x7f7f7f7fu, TEST_LOCATION );
+  END_TEST;
+}
+
+/**
+ * @brief Test RGBA565 pixel averaging function.
+ */
+int UtcDaliImageOperationsAveragePixelRGB565(void)
+{
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0u, 0u ), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0xf800u, 0xf800u ), 0xf800u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0xf800u, 0x800u ), 1u << 15, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0x7e0u, 0x7e0u ), 0x7e0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0x7e0u, 0x20u ), 1u << 10, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0x1f, 0x1f ), 0x1fu, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0x1f, 0x1 ), 1u << 4, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0xf800u, 0x7e0u ), 0x7800u + 0x3e0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( Dali::Internal::Platform::AveragePixelRGB565( 0xffff, 0xffff ), 0xffffu, TEST_LOCATION );
+  END_TEST;
+}
+
+/**
+ * @brief Build a square bitmap, downscale it and assert the resulting bitmap has the right dimensions.
+ */
+void TestDownscaledBitmapHasRightDimensionsAndFormat(
+    Pixel::Format format,
+    uint32_t sourceDimension,
+    uint32_t targetDimension,
+    uint32_t expectedDimension,
+    const char * const location )
+{
+  ImageDimensions desired( targetDimension, targetDimension );
+  FittingMode::Type fittingMode( FittingMode::SHRINK_TO_FIT );
+  SamplingMode::Type samplingMode( SamplingMode::BOX );
+
+  Dali::Devel::PixelBuffer sourceBitmap = Dali::Devel::PixelBuffer::New( sourceDimension, sourceDimension, format );
+
+  Dali::Devel::PixelBuffer downScaled = DownscaleBitmap( sourceBitmap, desired, fittingMode, samplingMode );
+
+  DALI_TEST_EQUALS( downScaled.GetWidth(), expectedDimension, location );
+  DALI_TEST_EQUALS( downScaled.GetHeight(), expectedDimension, location );
+  DALI_TEST_EQUALS( downScaled.GetPixelFormat(), format, location );
+}
+
+/**
+ * @brief Test the top-level function for reducing the dimension of a bitmap,
+ * feeding it each of the five pixel formats that are output by image loaders.
+ * Simply assert that the resulting bitmaps have the expected dimensions and
+ * formats.
+ */
+int UtcDaliImageOperationsDownscaleBitmap(void)
+{
+  // Do Scalings that are expected to work for all pixels modes and assert the resulting bitmap dimensions:
+
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGBA8888, 1024, 8, 8, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGB888, 1024, 8, 8, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGB565, 1024, 8, 8, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::LA88, 1024, 8, 8, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::L8, 1024, 8, 8, TEST_LOCATION );
+
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGBA8888, 773, 1, 1, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGB888, 787, 1, 1, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGB565, 797, 1, 1, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::LA88, 809, 1, 1, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::L8, 811, 1, 1, TEST_LOCATION );
+
+  // Do Scalings that are expected to produce a slightly larger than requested image:
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGBA8888, 47, 7, 11, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGB888, 73, 17, 18, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::RGB565, 61, 8, 15, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::LA88, 19, 5, 9, TEST_LOCATION );
+  TestDownscaledBitmapHasRightDimensionsAndFormat( Pixel::L8, 353, 23, 44, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test downscaling of RGB888 images as raw pixel arrays.
+ */
+int UtcDaliImageOperationsDownscaleInPlacePow2RGB888(void)
+{
+  unsigned outWidth = -1, outHeight = -1;
+
+  // Do downscaling to 1 x 1 so we can easily assert the value of the single pixel produced:
+
+  // Scale down a black/white checkerboard to mid-grey:
+  unsigned char check_4x4 [16 * 3] = {
+      0xff, 0xff, 0xff,  0x00, 0x00, 0x00,  0xff, 0xff, 0xff,  0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00,  0xff, 0xff, 0xff,  0x00, 0x00, 0x00,  0xff, 0xff, 0xff,
+      0xff, 0xff, 0xff,  0x00, 0x00, 0x00,  0xff, 0xff, 0xff,  0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00,  0xff, 0xff, 0xff,  0x00, 0x00, 0x00,  0xff, 0xff, 0xff
+  };
+
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(check_4x4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_EQUALS( outWidth, 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( outHeight, 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( check_4x4[0], (unsigned char)0x7f, TEST_LOCATION );
+
+  // Scale down a 16 pixel black image with a single white pixel to a 1/16th grey single pixel:
+  unsigned char single_4x4 [16 * 3] = {
+    0xff, 0xff, 0xff,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00
+  };
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_EQUALS( outWidth, 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( outHeight, 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( single_4x4[0], (unsigned char)0xf, TEST_LOCATION );
+
+  // Scale down a 16 pixel black image with a single white pixel to a 1/16th grey single pixel:
+  // (white pixel at bottom-right of image)
+  unsigned char single_4x4_2 [16 * 3] = {
+      0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,
+      0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0x00, 0x00, 0x00,  0xff, 0xff, 0xff
+    };
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888(single_4x4_2, 4, 4, 1, 1, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_EQUALS( outWidth, 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( outHeight, 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( single_4x4_2[0], (unsigned char)0xf, TEST_LOCATION );
+
+  // Build a larger ~600 x ~600 uniform magenta image for tests which only test output dimensions:
+
+  unsigned char magenta_600_x_600[608*608 * 3];
+  for( unsigned int i = 0; i < sizeof(magenta_600_x_600); i += 3 )
+  {
+    magenta_600_x_600[i] = 0xff;
+    magenta_600_x_600[i + 1] = 0;
+    magenta_600_x_600[i + 2] = 0xff;
+  }
+
+  // Scaling to 0 x 0 should stop at 1 x 1:
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 352, 352, 0, 0, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_EQUALS( outWidth, 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( outHeight, 1u, TEST_LOCATION );
+
+  // Scaling to 1 x 1 should hit 1 x 1:
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 608, 608, 1, 1, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_EQUALS( outWidth, 1u, TEST_LOCATION );
+  DALI_TEST_EQUALS( outHeight, 1u, TEST_LOCATION );
+
+  // Scaling to original dimensions should NOP:
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 384, 384, 384, 384, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_EQUALS( outWidth, 384u, TEST_LOCATION );
+  DALI_TEST_EQUALS( outHeight, 384u, TEST_LOCATION );
+
+  // More dimension tests:
+
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 352, 352, 44, 11, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_EQUALS( outWidth, 44u, TEST_LOCATION );
+  DALI_TEST_EQUALS( outHeight, 44u, TEST_LOCATION );
+
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 384, 384, 3, 48, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_EQUALS( outWidth, 48u, TEST_LOCATION );
+  DALI_TEST_EQUALS( outHeight, 48u, TEST_LOCATION );
+
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 384, 384, 3, 3, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_CHECK( outWidth == 3u && outHeight == 3u );
+
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 320, 320, 5, 5, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_CHECK( outWidth == 5u && outHeight == 5u );
+
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 448, 448, 7, 7, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_CHECK( outWidth == 7u && outHeight == 7u );
+
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB888( magenta_600_x_600, 352, 352, 11, 11, BoxDimensionTestBoth, outWidth, outHeight );
+  DALI_TEST_CHECK( outWidth == 11u && outHeight == 11u );
+
+  // Check that no pixel values were modified by the repeated averaging of identical pixels in tests above:
+  unsigned int numNonMagenta = 0u;
+  for( unsigned i = 0; i < sizeof(magenta_600_x_600); i += 3 )
+  {
+    numNonMagenta += magenta_600_x_600[i] == 0xff && magenta_600_x_600[i + 1] == 0x00 && magenta_600_x_600[i + 2] == 0xff ? 0 : 1;
+  }
+  DALI_TEST_EQUALS( numNonMagenta, 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test that resizing RGBA8888 images as raw pixel arrays produces a result of the correct dimensions.
+ */
+void TestDownscaleOutputsExpectedDimensionsRGBA8888( uint32_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char * const location )
+{
+  unsigned int resultingWidth = -1, resultingHeight = -1;
+  Dali::Internal::Platform::DownscaleInPlacePow2RGBA8888(
+      reinterpret_cast<unsigned char *> (pixels),
+      inputWidth, inputHeight,
+      desiredWidth, desiredHeight, BoxDimensionTestBoth,
+      resultingWidth, resultingHeight );
+
+  DALI_TEST_EQUALS( resultingWidth, expectedWidth, location );
+  DALI_TEST_EQUALS( resultingHeight, expectedHeight, location );
+}
+
+/**
+ * @brief Test that resizing RGB565 images as raw pixel arrays produces a result of the correct dimensions.
+ */
+void TestDownscaleOutputsExpectedDimensionsRGB565( uint16_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char * const location )
+{
+  unsigned int resultingWidth = -1, resultingHeight = -1;
+  Dali::Internal::Platform::DownscaleInPlacePow2RGB565(
+      reinterpret_cast<unsigned char *> (pixels),
+      inputWidth, inputHeight,
+      desiredWidth, desiredHeight, BoxDimensionTestBoth,
+      resultingWidth, resultingHeight );
+
+  DALI_TEST_EQUALS( resultingWidth, expectedWidth, location );
+  DALI_TEST_EQUALS( resultingHeight, expectedHeight, location );
+}
+
+/**
+ * @brief Test that resizing 2-byte-per-pixel images as raw pixel arrays produces a result of the correct dimensions.
+ */
+void TestDownscaleOutputsExpectedDimensions2ComponentPair( uint8_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char * const location )
+{
+  unsigned int resultingWidth = -1, resultingHeight = -1;
+  Dali::Internal::Platform::DownscaleInPlacePow2ComponentPair(
+      pixels,
+      inputWidth, inputHeight,
+      desiredWidth, desiredHeight, BoxDimensionTestBoth,
+      resultingWidth, resultingHeight );
+
+  DALI_TEST_EQUALS( resultingWidth, expectedWidth, location );
+  DALI_TEST_EQUALS( resultingHeight, expectedHeight, location );
+}
+
+/**
+ * @brief Test that resizing single-byte-per-pixel images as raw pixel arrays produces a result of the correct dimensions.
+ */
+void TestDownscaleOutputsExpectedDimensionsSingleComponent( uint8_t pixels[], unsigned inputWidth, unsigned inputHeight, unsigned int desiredWidth, unsigned int desiredHeight, unsigned int expectedWidth, unsigned int expectedHeight, const char * const location )
+{
+  unsigned int resultingWidth = -1, resultingHeight = -1;
+  Dali::Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel(
+      pixels,
+      inputWidth, inputHeight,
+      desiredWidth, desiredHeight, BoxDimensionTestBoth,
+      resultingWidth, resultingHeight );
+
+  DALI_TEST_EQUALS( resultingWidth, expectedWidth, location );
+  DALI_TEST_EQUALS( resultingHeight, expectedHeight, location );
+}
+
+/**
+ * @brief Test downscaling of RGBA8888 images in raw image arrays.
+ */
+int UtcDaliImageOperationsDownscaleInPlacePow2RGBA8888(void)
+{
+  uint32_t image[608*608];
+  for( unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i )
+  {
+    image[i] = 0xffffffff;
+  }
+  unsigned char* const pixels = reinterpret_cast<unsigned char *> (image);
+  unsigned int resultingWidth = -1, resultingHeight = -1;
+
+  // Test downscaling where the input size is an exact multiple of the desired size:
+  // (We expect a perfect result here)
+
+  DownscaleInPlacePow2RGBA8888( pixels, 600, 600, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 75u, TEST_LOCATION );
+  DALI_TEST_EQUALS( resultingHeight, 75u, TEST_LOCATION );
+
+  DownscaleInPlacePow2RGBA8888( pixels, 512, 512, 16, 16, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 16u, TEST_LOCATION );
+  DALI_TEST_EQUALS( resultingHeight, 16u, TEST_LOCATION );
+
+  DownscaleInPlacePow2RGBA8888( pixels, 512, 64, 16, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 16u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( resultingHeight, 2u, TEST_LOCATION );
+
+  DownscaleInPlacePow2RGBA8888( pixels, 64, 1024, 4, 64, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 4u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( resultingHeight, 64u, TEST_LOCATION );
+
+  // Test downscaling where the input size is slightly off being an exact multiple of the desired size:
+  // (We expect a perfect match at the end because of rounding-down to an even width and height at each step)
+
+  DownscaleInPlacePow2RGBA8888( pixels, 601, 603, 75, 75, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 75u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( resultingHeight, 75u, TEST_LOCATION );
+
+  DownscaleInPlacePow2RGBA8888( pixels, 736 + 1, 352 + 3, 23, 11, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 23u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( resultingHeight, 11u, TEST_LOCATION );
+
+  DownscaleInPlacePow2RGBA8888( pixels, 384 + 3, 896 + 1, 3, 7, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 3u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( resultingHeight, 7u, TEST_LOCATION );
+
+  // Test downscales with source dimensions which are under a nice power of two by one:
+
+  // The target is hit exactly due to losing spare columns or rows at each iteration:
+  DownscaleInPlacePow2RGBA8888( pixels, 63, 31, 7, 3, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 7u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( resultingHeight, 3u, TEST_LOCATION );
+
+  // Asking to downscale a bit smaller should stop at the dimensions of the last test as one more halving would go down to 3 x 1, which is too small.
+  DownscaleInPlacePow2RGBA8888( pixels, 63, 31, 4, 2, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 7u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( resultingHeight, 3u, TEST_LOCATION );
+
+  // Should stop at almost twice the requested dimensions:
+  DownscaleInPlacePow2RGBA8888( pixels, 15, 127, 4, 32, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 7u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( resultingHeight, 63u, TEST_LOCATION );
+
+  // Test downscales to 1 in one or both dimensions:
+  // Parameters:                                         input-x  input-y, desired-x, desired-y, expected-x, expected-y
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     512,     1,         1,         1,          1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     32,      16,        1,         16,         1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     32,      7,         1,         16,         1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     32,      7,         1,         16,         1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     32,      5,         1,         16,         1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     32,      3,         1,         16,         1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 32,      512,     1,         1,         1,          16,        TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 32,      512,     1,         16,        1,          16,        TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 32,      512,     1,         3,         1,          16,        TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 33,      33,      1,         1,         1,          1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 17*19,   17*19,   1,         1,         1,          1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 33,      33,      3,         1,         4,          4,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 33,      9,       3,         1,         4,          1,         TEST_LOCATION );
+
+
+
+  // Test downscales to zero in one or both dimensions:
+  // Scaling should stop when one or both dimensions reach 1.
+  // Parameters:                                         input-x  input-y, desired-x, desired-y, expected-x, expected-y
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     512,     0,         0,         1,          1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     256,     0,         0,         2,          1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     128,     0,         0,         4,          1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 512,     16,      0,         0,         32,         1,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 128,     512,     0,         0,         1,          4,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 32,      512,     0,         0,         1,          16,        TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 8,       512,     0,         0,         1,          64,        TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 2,       512,     0,         0,         1,          256,       TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test downscalings of RGBA8888 images in raw image arrays that should have no effect on the input.
+ */
+int UtcDaliImageOperationsDownscaleInPlacePow2RGBA8888Nops(void)
+{
+  uint32_t image[608*608];
+  const uint32_t numPixels = sizeof(image) / sizeof(image[0]);
+  for( unsigned i = 0; i < numPixels; ++i )
+  {
+    image[i] = RandomPixelRGBA8888();
+  }
+  const uint32_t imageHash = HashPixels( image, numPixels );
+  unsigned char* const pixels = reinterpret_cast<unsigned char *> (image);
+  unsigned int resultingWidth = -1, resultingHeight = -1;
+
+  // Test downscales to the same size:
+  // The point is just to be sure the downscale is a NOP in this case:
+
+  DownscaleInPlacePow2RGBA8888( pixels, 600, 600, 600, 600, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 600u, TEST_LOCATION );
+  DALI_TEST_EQUALS( resultingHeight, 600u, TEST_LOCATION );
+
+  DownscaleInPlacePow2RGBA8888( pixels, 512, 128, 512, 128, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 512u, TEST_LOCATION );
+  DALI_TEST_EQUALS( resultingHeight, 128u, TEST_LOCATION );
+
+  DownscaleInPlacePow2RGBA8888( pixels, 17, 1001, 17, 1001, BoxDimensionTestBoth, resultingWidth, resultingHeight );
+  DALI_TEST_EQUALS( resultingWidth, 17u, TEST_LOCATION );
+  DALI_TEST_EQUALS( resultingHeight, 1001u, TEST_LOCATION );
+
+  // Test downscales that request a larger size (we never upscale so these are NOPs too):
+  // Parameters:                                         input-x  input-y, desired-x, desired-y, expected-x, expected-y
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 300,     300,     600,       600,       300,        300,       TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 3,       127,     99,        599,       3,          127,       TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGBA8888( image, 600,     600,     999,       999,       600,        600,       TEST_LOCATION ); //< checks no out of bounds mem access in this case
+
+
+  // Make sure that none of these NOP downscalings has affected the pixels of the image:
+  DALI_TEST_EQUALS( HashPixels( image, numPixels ), imageHash, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Do additional downscaling testing using RGB565 images in raw image
+ * arrays to shake out differences relating to the pixel format.
+ */
+int UtcDaliImageOperationsDownscaleInPlacePow2RGB565(void)
+{
+  // Test that calling with null and zero parameters doesn't blow up:
+  unsigned int outWidth, outHeight;
+  DownscaleInPlacePow2RGB565( 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight );
+
+  uint16_t image[608*608];
+  for( unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i )
+  {
+    image[i] = 0xffff;
+  }
+
+  // Do a straightforward test using an exact divisor target size:
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 600, 600, 75, 75, 75, 75, TEST_LOCATION );
+  // Test that a slightly smaller than possible to achieve target results in the
+  // next-higher exact divisor output image dimensions:
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 600, 600, 71, 69, 75, 75, TEST_LOCATION );
+  // Test that resizing from a starting size that is slightly larger than an exact
+  // multiple of the desired dimensions still results in the desired ones being
+  // reached:
+  // Parameters:                                       input-x  input-y, desired-x, desired-y, expected-x, expected-y
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 600 + 1, 600 + 1, 75,        75,        75,         75,        TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 256 + 1, 512 + 1, 2,         4,         2,          4,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 512 + 1, 128 + 1, 16,        4,         16,         4,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 512 + 1, 64  + 1, 16,        2,         16,         2,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 512 + 3, 512 + 3, 16,        16,        16,         16,        TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 512 + 3, 256 + 3, 16,        8,         16,         8,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 256 + 3, 512 + 3, 4,         8,         4,          8,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 256 + 7, 512 + 7, 4,         8,         4,          8,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 256 + 7, 512 + 7, 2,         4,         2,          4,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 512 + 7, 128 + 7, 16,        4,         16,         4,         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsRGB565( image, 512 + 7, 64  + 7, 16,        2,         16,         2,         TEST_LOCATION );
+
+
+  END_TEST;
+}
+
+/**
+ * @brief Do additional downscaling testing using 2-byte-per-pixel images in
+ * raw image arrays to shake out differences relating to the pixel format.
+ */
+int UtcDaliImageOperationsDownscaleInPlacePow2ComponentPair(void)
+{
+  // Simple test that a null pointer does not get dereferenced in the function:
+  unsigned int outWidth, outHeight;
+  DownscaleInPlacePow2ComponentPair( 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight );
+
+  // Simple tests of dimensions output:
+
+  uint8_t image[608*608*2];
+  for( unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i )
+  {
+    image[i] = 0xff;
+  }
+
+  TestDownscaleOutputsExpectedDimensions2ComponentPair( image,
+                                                        600, 600, //< Input dimensions
+                                                        37, 37,   //< Requested dimensions
+                                                        37, 37,   //< Expected output dimensions
+                                                        TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensions2ComponentPair( image,
+                                                        600, 600, //< Input dimensions
+                                                        34, 35,   //< Requested dimensions to scale-down to
+                                                        37, 37,   //< Expected output dimensions achieved
+                                                        TEST_LOCATION );
+  ///@note: No need to be as comprehensive as with RGB888 and RGBA8888 as the logic is shared.
+
+  END_TEST;
+}
+
+/**
+ * @brief Do additional downscaling testing using 1-byte-per-pixel images in
+ * raw image arrays to shake out differences relating to the pixel format.
+ */
+int UtcDaliImageOperationsDownscaleInPlacePow2SingleBytePerPixel(void)
+{
+  // Simple test that a null pointer does not get dereferenced in the function:
+  unsigned int outWidth, outHeight;
+  DownscaleInPlacePow2SingleBytePerPixel( 0, 0, 0, 0, 0, BoxDimensionTestBoth, outWidth, outHeight );
+
+  // Tests of output dimensions from downscaling:
+  uint8_t image[608*608];
+  for( unsigned i = 0; i < sizeof(image) / sizeof(image[0]); ++i )
+  {
+    image[i] = 0xff;
+  }
+
+  TestDownscaleOutputsExpectedDimensionsSingleComponent( image,
+                                                         600, 300,  //< Input dimensions
+                                                         150, 75,   //< Requested dimensions to scale-down to
+                                                         150, 75,   //< Expected output dimensions achieved
+                                                         TEST_LOCATION );
+  TestDownscaleOutputsExpectedDimensionsSingleComponent( image, 577, 411, 142, 99, 144, 102, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging pairs of pixels on a scanline.
+ */
+int UtcDaliImageOperationsHalveScanlineInPlaceRGB888(void)
+{
+  // Red and cyan, averaging to grey:
+  unsigned char shortEven[] =    { 0xff, 0, 0,   0, 0xff, 0xff,   0xff, 0, 0,   0, 0xff, 0xff };
+  unsigned char shortOdd[] =     { 0xff, 0, 0,  0, 0xff, 0xff,  0xff, 0, 0,  0, 0xff, 0xff,  0xC, 0xC, 0xC };
+
+  Dali::Internal::Platform::HalveScanlineInPlaceRGB888( shortEven, 4u );
+  Dali::Internal::Platform::HalveScanlineInPlaceRGB888( shortOdd, 4u );
+  for( unsigned i = 0; i < sizeof(shortEven) >> 1u ; ++i )
+  {
+    DALI_TEST_EQUALS( unsigned(shortEven[i]), 0x7fu, TEST_LOCATION );
+    DALI_TEST_EQUALS( unsigned(shortOdd[i]), 0x7fu, TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging pairs of pixels on a scanline.
+ */
+int UtcDaliImageOperationsHalveScanlineInPlaceRGBA8888(void)
+{
+  const size_t scanlineLength = 4096u;
+  Dali::Vector<uint32_t> scanline;
+  Dali::Vector<uint32_t> reference;
+  SetupScanlineForHalvingTestsRGBA8888( scanlineLength, scanline, reference );
+
+  HalveScanlineInPlaceRGBA8888( (uint8_t *) &scanline[0], scanlineLength );
+
+  // Check that the halving matches the independently calculated reference:
+  size_t numMatches = 0;
+  for( int i = 0, length = reference.Size(); i < length; ++i )
+  {
+    DALI_TEST_EQUALS( scanline[i], reference[i], TEST_LOCATION );
+    numMatches += scanline[i] == reference[i];
+  }
+  DALI_TEST_EQUALS( numMatches, scanlineLength / 2, TEST_LOCATION );
+
+  // Test for no beyond-bounds writes:
+  for( size_t i = scanlineLength / 2; i < reference.Capacity(); ++i )
+  {
+    DALI_TEST_EQUALS( reference[i],  (uint32_t)0xEEEEEEEE, TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging pairs of pixels on a scanline.
+ */
+int UtcDaliImageOperationsHalveScanlineInPlaceRGB565(void)
+{
+  const size_t scanlineLength = 4096u;
+  Dali::Vector<uint16_t> scanline;
+  Dali::Vector<uint16_t> reference;
+  SetupScanlineForHalvingTestsRGB565( scanlineLength, scanline, reference );
+
+  HalveScanlineInPlaceRGB565( (unsigned char *) (&scanline[0]), scanlineLength );
+
+  // Check output against reference:
+  size_t numMatches = 0;
+  for( int i = 0, length = reference.Size(); i < length; ++i )
+  {
+    DALI_TEST_EQUALS( scanline[i], reference[i], TEST_LOCATION );
+    numMatches += scanline[i] == reference[i];
+  }
+  DALI_TEST_EQUALS( numMatches, scanlineLength / 2, TEST_LOCATION );
+
+  // Test for no beyond-bounds writes:
+  for( size_t i = scanlineLength / 2; i < reference.Capacity(); ++i )
+  {
+    DALI_TEST_EQUALS( reference[i],  (uint16_t)0xEEEE, TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging pairs of pixels on a scanline.
+ */
+int UtcDaliImageOperationsHalveScanlineInPlace2Bytes(void)
+{
+  const size_t scanlineLength = 4096u;
+  Dali::Vector<uint8_t> scanline;
+  Dali::Vector<uint8_t> reference;
+  SetupScanlineForHalvingTests2Bytes( scanlineLength, scanline, reference );
+
+  HalveScanlineInPlace2Bytes( &scanline[0], scanlineLength );
+
+  // Test the output against the reference (no differences):
+  size_t numMatches = 0;
+  for( int i = 0, length = reference.Size(); i < length; ++i )
+  {
+    DALI_TEST_EQUALS( 1u * scanline[i], 1u * reference[i], TEST_LOCATION );
+    numMatches += scanline[i] == reference[i];
+  }
+  // The number of matching bytes should be double the number of pixels, which happens to be the original scanline length in pixels:
+  DALI_TEST_EQUALS( numMatches, scanlineLength, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging pairs of pixels on a scanline.
+ */
+int UtcDaliImageOperationsHalveScanlineInPlace1Byte(void)
+{
+  const size_t scanlineLength = 4096u;
+  Dali::Vector<uint8_t> scanline;
+  Dali::Vector<uint8_t> reference;
+  SetupScanlineForHalvingTests1Byte( scanlineLength, scanline, reference );
+
+  HalveScanlineInPlace1Byte( &scanline[0], scanlineLength );
+
+  // Test the reference matches the output:
+  size_t numMatches = 0;
+  for( int i = 0, length = reference.Size(); i < length; ++i )
+  {
+    DALI_TEST_EQUALS( 1u * scanline[i], 1u * reference[i], TEST_LOCATION );
+    numMatches += scanline[i] == reference[i];
+  }
+  DALI_TEST_EQUALS( numMatches, scanlineLength / 2, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging vertically-adjacent pairs of single-byte-per-pixel pixels on a scanline.
+ */
+int UtcDaliImageOperationsAverageScanlines1(void)
+{
+  // Red and cyan, averaging to grey:
+  unsigned char shortEven1[] =    { 0xff, 0, 0,    0, 0xff, 0xff,  0xff, 0, 0,      0, 0xff, 0xff };
+  unsigned char shortEven2[] =    { 0, 0xff, 0xff, 0xff, 0, 0,     0, 0xff,  0xff,  0xff, 0, 0 };
+  unsigned char outputBuffer[sizeof(shortEven1)];
+
+  AverageScanlines1( shortEven1, shortEven2, outputBuffer, sizeof(shortEven1) );
+  for( unsigned i = 0; i < sizeof(shortEven1) ; ++i )
+  {
+    DALI_TEST_EQUALS( unsigned(outputBuffer[i]), 0x7fu, TEST_LOCATION );
+  }
+
+  // Longer test reusing RGBA setup/test logic:
+  const size_t scanlineLength = 4096u;
+  Dali::Vector<uint32_t> scanline1;
+  Dali::Vector<uint32_t> scanline2;
+  Dali::Vector<uint32_t> reference;
+  Dali::Vector<uint32_t> output;
+  SetupScanlinesRGBA8888( scanlineLength, scanline1, scanline2, reference, output );
+
+  AverageScanlines1( (const unsigned char*) &scanline1[0], (const unsigned char*) &scanline2[0], (unsigned char*) &output[0], scanlineLength * 4 );
+
+  // Check the output matches the independently generated reference:
+  size_t numMatches = 0;
+  MatchScanlinesRGBA8888( reference, output, numMatches, TEST_LOCATION );
+  DALI_TEST_EQUALS( numMatches, reference.Capacity(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging vertically-adjacent pairs of 2-byte-per-pixel pixels on a scanline.
+ */
+int UtcDaliImageOperationsAverageScanlines2(void)
+{
+  // Red and cyan, averaging to grey:
+  unsigned char shortEven1[] =    { 0xff, 0, 0,    0, 0xff, 0xff,  0xff, 0, 0,      0, 0xff, 0xff };
+  unsigned char shortEven2[] =    { 0, 0xff, 0xff, 0xff, 0, 0,     0, 0xff,  0xff,  0xff, 0, 0 };
+  unsigned char outputBuffer[sizeof(shortEven1)];
+
+  AverageScanlines2( shortEven1, shortEven2, outputBuffer, sizeof(shortEven1) / 2 );
+
+  for( unsigned i = 0; i < sizeof(shortEven1); ++i )
+  {
+    DALI_TEST_EQUALS( unsigned(outputBuffer[i]), 0x7fu, TEST_LOCATION );
+  }
+
+  // Longer test reusing RGBA setup/test logic:
+  const size_t scanlineLength = 4096u;
+  Dali::Vector<uint32_t> scanline1;
+  Dali::Vector<uint32_t> scanline2;
+  Dali::Vector<uint32_t> reference;
+  Dali::Vector<uint32_t> output;
+  SetupScanlinesRGBA8888( scanlineLength, scanline1, scanline2, reference, output );
+
+  AverageScanlines2( (const unsigned char*) &scanline1[0], (const unsigned char*) &scanline2[0], (unsigned char*) &output[0], scanlineLength * 2 );
+
+  // Check the output matches the independently generated reference:
+  size_t numMatches = 0;
+  MatchScanlinesRGBA8888( reference, output, numMatches, TEST_LOCATION );
+  DALI_TEST_EQUALS( numMatches, reference.Capacity(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging vertically-adjacent pairs of RGB888 pixels on a scanline.
+ */
+int UtcDaliImageOperationsAverageScanlines3(void)
+{
+  // Red and cyan, averaging to grey:
+  unsigned char shortEven1[] =    { 0xff, 0, 0,    0, 0xff, 0xff,  0xff, 0, 0,      0, 0xff, 0xff };
+  unsigned char shortEven2[] =    { 0, 0xff, 0xff, 0xff, 0, 0,     0, 0xff,  0xff,  0xff, 0, 0 };
+  unsigned char outputBuffer[sizeof(shortEven1)];
+
+  AverageScanlines3( shortEven1, shortEven2, outputBuffer, sizeof(shortEven1) / 3 );
+  for( unsigned i = 0; i < sizeof(shortEven1) ; ++i )
+  {
+    DALI_TEST_EQUALS( unsigned(outputBuffer[i]), 0x7fu, TEST_LOCATION );
+  }
+
+  // Longer test reusing RGBA setup/test logic:
+  const size_t scanlineLength = 3 * 4 * 90u;
+  Dali::Vector<uint32_t> scanline1;
+  Dali::Vector<uint32_t> scanline2;
+  Dali::Vector<uint32_t> reference;
+  Dali::Vector<uint32_t> output;
+  SetupScanlinesRGBA8888( scanlineLength, scanline1, scanline2, reference, output );
+
+  AverageScanlines3( (const unsigned char*) &scanline1[0], (const unsigned char*) &scanline2[0], (unsigned char*) &output[0], scanlineLength * 4 / 3 );
+
+  // Check the output matches the independently generated reference:
+  size_t numMatches = 0;
+  MatchScanlinesRGBA8888( reference, output, numMatches, TEST_LOCATION );
+  DALI_TEST_EQUALS( numMatches, reference.Capacity(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging vertically-adjacent pairs of RGBA8888 pixels on a scanline.
+ */
+int UtcDaliImageOperationsAverageScanlinesRGBA8888(void)
+{
+  const size_t scanlineLength = 4096u;
+  Dali::Vector<uint32_t> scanline1;
+  Dali::Vector<uint32_t> scanline2;
+  Dali::Vector<uint32_t> reference;
+  Dali::Vector<uint32_t> output;
+  SetupScanlinesRGBA8888( scanlineLength, scanline1, scanline2, reference, output );
+
+  AverageScanlinesRGBA8888( (const unsigned char*) &scanline1[0], (const unsigned char*) &scanline2[0], (unsigned char*) &output[0], scanlineLength );
+
+  // Check the output matches the independently generated reference:
+  size_t numMatches = 0;
+  MatchScanlinesRGBA8888( reference, output, numMatches, TEST_LOCATION );
+  DALI_TEST_EQUALS( numMatches, reference.Capacity(), TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the function for averaging vertically-adjacent pairs of RGB565 pixels on a scanline.
+ */
+int UtcDaliImageOperationsAverageScanlinesRGB565(void)
+{
+  // Red and cyan, averaging to grey:
+  const uint16_t shortEven1[] =    { 0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0xf800, 0xBEEF, 0xBEEF };
+  const uint16_t shortEven2[] =    { 0x7ff,  0x7ff,  0x7ff,  0x7ff,  0x7ff,  0x7ff, 0xBEEF, 0xBEEF };
+  const size_t arrayLength = sizeof(shortEven1) / sizeof(shortEven1[0]) - 2;
+  uint16_t outputBuffer[arrayLength + 2];
+  outputBuffer[arrayLength] = 0xDEAD;
+  outputBuffer[arrayLength+1] = 0xDEAD;
+
+  Dali::Internal::Platform::AverageScanlinesRGB565( (const unsigned char*) shortEven1, (const unsigned char*) shortEven2, (unsigned char*) outputBuffer,  arrayLength );
+  for( unsigned i = 0; i <  arrayLength ; ++i )
+  {
+    DALI_TEST_EQUALS( unsigned(outputBuffer[i]), 0xffff - (1u << 15) - (1u << 10) - (1u << 4), TEST_LOCATION );
+  }
+
+  // Check for buffer overrun:
+  DALI_TEST_EQUALS( outputBuffer[arrayLength], (uint16_t)0xDEAD, TEST_LOCATION );
+  DALI_TEST_EQUALS( outputBuffer[arrayLength+1], (uint16_t)0xDEAD, TEST_LOCATION );
+
+  END_TEST;
+}
+
+namespace
+{
+
+void MakeSingleColorImageRGBA8888( unsigned int width, unsigned int height, uint32_t *inputImage )
+{
+  const uint32_t inPixel = PixelRGBA8888( 255, 192, 128, 64 );
+  for( unsigned int i = 0; i < width * height; ++i )
+  {
+    inputImage[i] = inPixel;
+  }
+}
+
+/*
+ * @brief Make an image with a checkerboard pattern.
+ * @note This is an easy pattern to scan for correctness after a downscaling test.
+ */
+Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > MakeCheckerboardImageRGBA8888( unsigned int width,  unsigned int height, unsigned int checkerSize )
+{
+  const unsigned int imageWidth = width * checkerSize;
+  const unsigned int imageHeight = height * checkerSize;
+  Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > image = new Dali::RefCountedVector<uint32_t>;
+  image->GetVector().Resize( imageWidth * imageHeight );
+
+  uint32_t rowColor = 0xffffffff;
+  for( unsigned int cy = 0; cy < height; ++cy )
+  {
+    rowColor = rowColor == 0xffffffff ? 0xff000000 : 0xffffffff;
+    uint32_t checkColor = rowColor;
+    for( unsigned int cx = 0; cx < width; ++cx )
+    {
+      checkColor = checkColor == 0xffffffff ? 0xff000000 : 0xffffffff;
+      uint32_t paintedColor = checkColor;
+      // Draw 3 special case checks as r,g,b:
+      if(cx == 0 && cy == 0)
+      {
+        paintedColor = 0xff0000ff;// Red
+      }
+      else if(cx == 7 && cy == 0)
+      {
+        paintedColor = 0xff00ff00;// Green
+      }
+      else if(cx == 7 && cy == 7)
+      {
+        paintedColor = 0xffff0000;// blue
+      }
+      uint32_t * check = &image->GetVector()[ (cy * checkerSize * imageWidth) + (cx * checkerSize)];
+      for( unsigned int py = 0; py < checkerSize; ++py )
+      {
+        uint32_t * checkLine = check +  py * imageWidth;
+        for( unsigned int px = 0; px < checkerSize; ++px )
+        {
+          checkLine[px] = paintedColor;
+        }
+      }
+    }
+  }
+
+  return image;
+}
+
+}
+
+/**
+ * @brief Test the right pixels are generated when downsampling a checkerboard into a small image.
+ */
+int UtcDaliImageOperationsPointSampleCheckerboardRGBA888(void)
+{
+  Dali::IntrusivePtr<Dali::RefCountedVector<uint32_t> > image = MakeCheckerboardImageRGBA8888( 8, 8, 32 );
+  const unsigned int desiredWidth = 8;
+  const unsigned int desiredHeight = 8;
+
+  uint32_t outputImage[ desiredWidth * desiredHeight ];
+
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) &image->GetVector()[0], 256, 256, (unsigned char*) outputImage, desiredWidth, desiredHeight );
+
+  DALI_TEST_EQUALS( outputImage[0], (uint32_t)0xff0000ff, TEST_LOCATION ); // < Red corner pixel
+  DALI_TEST_EQUALS( outputImage[7], (uint32_t)0xff00ff00, TEST_LOCATION ); // < Green corner pixel
+  DALI_TEST_EQUALS( outputImage[8*8-1], (uint32_t)0xffff0000, TEST_LOCATION ); // < Blue corner pixel
+
+  DALI_TEST_EQUALS( outputImage[1], (uint32_t)0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[2], (uint32_t)0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[3], (uint32_t)0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[4], (uint32_t)0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[5], (uint32_t)0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[6], (uint32_t)0xffffffff, TEST_LOCATION ); // < white pixel
+
+  // Second scanline:
+  DALI_TEST_EQUALS( outputImage[8+0], (uint32_t)0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[8+1], (uint32_t)0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[8+2], (uint32_t)0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[8+3], (uint32_t)0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[8+4], (uint32_t)0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[8+5], (uint32_t)0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[8+6], (uint32_t)0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[8+7], (uint32_t)0xffffffff, TEST_LOCATION ); // < white pixel
+
+  // Third scanline:
+  DALI_TEST_EQUALS( outputImage[16+0], (uint32_t)0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[16+1], (uint32_t)0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[16+2], (uint32_t)0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[16+3], (uint32_t)0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[16+4], (uint32_t)0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[16+5], (uint32_t)0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[16+6], (uint32_t)0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[16+7], (uint32_t)0xff000000, TEST_LOCATION ); // < black pixel
+
+  // ... could do more scanlines (there are 8)
+
+  // Sample a few more pixels:
+
+  // Diagonals:
+  DALI_TEST_EQUALS( outputImage[24+3], (uint32_t)0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[32+4], (uint32_t)0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[40+5], (uint32_t)0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[48+6], (uint32_t)0xffffffff, TEST_LOCATION ); // < white pixel
+  DALI_TEST_EQUALS( outputImage[24+4], (uint32_t)0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[32+3], (uint32_t)0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[40+2], (uint32_t)0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[48+1], (uint32_t)0xff000000, TEST_LOCATION ); // < black pixel
+  DALI_TEST_EQUALS( outputImage[56+0], (uint32_t)0xff000000, TEST_LOCATION ); // < black pixel
+
+  END_TEST;
+}
+
+/**
+ * @brief Test that a scaling preserves input color in destination image.
+ */
+int UtcDaliImageOperationsPointSampleRGBA888PixelsCorrectColor(void)
+{
+  const unsigned int inputWidth = 137;
+  const unsigned int inputHeight = 571;
+  const unsigned int desiredWidth = 59;
+  const unsigned int desiredHeight = 257;
+
+  uint32_t inputImage[ inputWidth * inputHeight ];
+  MakeSingleColorImageRGBA8888( inputWidth, inputHeight, inputImage );
+
+  const size_t outputBufferSize = desiredWidth * desiredHeight;
+  std::vector< uint32_t > buffer;
+  buffer.resize( outputBufferSize );
+  uint32_t* outputImage = &buffer[0];
+
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage, inputWidth, inputHeight, (unsigned char*) outputImage, desiredWidth, desiredHeight );
+
+  // Check that all the output pixels are the right color:
+  const uint32_t reference = inputImage[ inputWidth * inputHeight / 2];
+  unsigned int differentColorCount = 0;
+  for( unsigned int i = 0; i < desiredWidth * desiredHeight; ++i )
+  {
+    if( outputImage[i] != reference )
+    {
+      ++differentColorCount;
+    }
+  }
+
+  DALI_TEST_EQUALS( 0U, differentColorCount, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test that scaling down to a 1x1 image works.
+ */
+int UtcDaliImageOperationsPointSampleRGBA888ScaleToSinglePixel(void)
+{
+  const unsigned int desiredWidth = 1;
+  const unsigned int desiredHeight = 1;
+
+  uint32_t inputImage[ 1024 * 1024 ];
+  MakeSingleColorImageRGBA8888( 1024, 1024, inputImage );
+  uint32_t outputImage = 0;
+
+  // Try several different starting image sizes:
+
+  // 1x1 -> 1x1:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,    1,    1, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
+  DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
+  outputImage = 0;
+
+  // Single-pixel wide tall stripe:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,    1, 1024, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
+  DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
+  outputImage = 0;
+
+  // Single-pixel tall, wide strip:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage, 1024,    1, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
+  DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
+  outputImage = 0;
+
+  // Square mid-size image:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,  103,  103, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
+  DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
+  outputImage = 0;
+
+  // Wide mid-size image:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,  313,  79, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
+  DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
+  outputImage = 0;
+
+  // Tall mid-size image:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,   53,  467, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
+  DALI_TEST_EQUALS( outputImage, inputImage[0], TEST_LOCATION );
+  outputImage = 0;
+
+  // 0 x 0 input image (make sure output not written to):
+  outputImage = 0xDEADBEEF;
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,    0,    0, (unsigned char*) &outputImage, desiredWidth, desiredHeight );
+  DALI_TEST_EQUALS( outputImage, (uint32_t)0xDEADBEEF, TEST_LOCATION );
+  outputImage = 0;
+
+  END_TEST;
+}
+
+/**
+ * @brief Test that downsampling to 0 - area images is a NOP and does not modify the destination.
+ * (edge-case)
+ */
+int UtcDaliImageOperationsPointSampleRGBA888N(void)
+{
+  uint32_t inputImage[ 128 * 128 ];
+  MakeSingleColorImageRGBA8888( 128, 128, inputImage );
+  uint32_t outputImage[ 128 * 128 ];
+  memset( outputImage, 0xaa, 128 * 128 * sizeof(uint32_t) );
+
+  // Try several different starting image sizes:
+
+  // 1x1 -> 1x1:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,   1,   1, (unsigned char*) outputImage, 0, 0 );
+  DALI_TEST_EQUALS( 0xaaaaaaaa, outputImage[0], TEST_LOCATION );
+
+  // Single-pixel wide tall stripe:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,   1, 102, (unsigned char*) outputImage, 0, 33 );
+  DALI_TEST_EQUALS( 0xaaaaaaaa, outputImage[0], TEST_LOCATION );
+
+  // Single-pixel tall, wide strip:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage, 102,   1, (unsigned char*) outputImage, 0, 67 );
+  DALI_TEST_EQUALS( 0xaaaaaaaa, outputImage[0], TEST_LOCATION );
+
+  // Square mid-size image:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage, 103, 103, (unsigned char*) outputImage, 21, 0 );
+  DALI_TEST_EQUALS( 0xaaaaaaaa, outputImage[0], TEST_LOCATION );
+
+  // Wide mid-size image to 0 height
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage, 313,  79, (unsigned char*) outputImage, 99, 0 );
+  DALI_TEST_EQUALS( 0xaaaaaaaa, outputImage[0], TEST_LOCATION );
+
+  // Tall mid-size image to 0 height, over width
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,  53,  46, (unsigned char*) outputImage, 9999, 0 );
+  DALI_TEST_EQUALS( 0xaaaaaaaa, outputImage[0], TEST_LOCATION );
+
+  // 0 x 0 input image:
+  Dali::Internal::Platform::PointSample4BPP( (const unsigned char *) inputImage,   0,   0, (unsigned char*) outputImage, 200, 99 );
+  DALI_TEST_EQUALS( 0xaaaaaaaa, outputImage[0], TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the small int (x,y) tuple.
+ */
+int UtcDaliImageOperationsUint16Pair(void)
+{
+  Uint16Pair vec1( 2, 3 );
+
+  DALI_TEST_EQUALS( vec1.GetWidth(), (uint16_t)2, TEST_LOCATION );
+  DALI_TEST_EQUALS( vec1.GetX(),     (uint16_t)2, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( vec1.GetHeight(), (uint16_t)3, TEST_LOCATION );
+  DALI_TEST_EQUALS( vec1.GetY(),      (uint16_t)3, TEST_LOCATION );
+
+  Uint16Pair vec1Copy = vec1;
+
+  DALI_TEST_EQUALS( vec1Copy.GetWidth(), (uint16_t)2, TEST_LOCATION );
+  DALI_TEST_EQUALS( vec1Copy.GetX(),     (uint16_t)2, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( vec1Copy.GetHeight(), (uint16_t)3, TEST_LOCATION );
+  DALI_TEST_EQUALS( vec1Copy.GetY(),      (uint16_t)3, TEST_LOCATION );
+
+  Uint16Pair vec2( 65535u, 65535u );
+
+  DALI_TEST_EQUALS( vec2.GetX(), (uint16_t)65535u, TEST_LOCATION );
+  DALI_TEST_EQUALS( vec2.GetY(), (uint16_t)65535u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+/**
+ * @brief Test the four-tap linear blending for single-byte modes.
+ */
+int UtcDaliImageOperationsBilinearFilter1BPP(void)
+{
+  // Zeros blend to zero:
+  DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 0, 0, 0, 0 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 0, 0, 32768, 0 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 0, 0, 65535, 0 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 0, 0, 0, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 0, 0, 0, 65535 ), TEST_LOCATION );
+
+  // Ones and zeros average to 0.5:
+  DALI_TEST_EQUALS( 127u, BilinearFilter1Component( 255, 0, 0, 255, 32768, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 127u, BilinearFilter1Component( 0, 255, 0, 255, 32768, 32768 ), TEST_LOCATION );
+
+  // Quarters ones average to 0.25:
+  DALI_TEST_EQUALS( 64u, BilinearFilter1Component( 255, 0, 0, 0, 32768, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 64u, BilinearFilter1Component( 0, 255, 0, 0, 32768, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 64u, BilinearFilter1Component( 0, 0, 255, 0, 32768, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 64u, BilinearFilter1Component( 0, 0, 0, 255, 32768, 32768 ), TEST_LOCATION );
+
+  // Horizontal blends:
+  DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 255, 0, 255, 0, 32768 ), TEST_LOCATION );
+  for( unsigned y = 0; y < 65536u; y += 256 )
+  {
+    // Vertical blends don't change result in this case as there is no vertical gradient in inputs:
+    DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 255, 0, 255, 0, y ), TEST_LOCATION );
+  }
+  DALI_TEST_EQUALS( 5u, BilinearFilter1Component( 0, 255, 0, 255, 1233, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 29u, BilinearFilter1Component( 0, 255, 0, 255, 7539, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 29u, BilinearFilter1Component( 0, 255, 0, 255, 7539, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 67u, BilinearFilter1Component( 0, 255, 0, 255, 17291, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 123u, BilinearFilter1Component( 0, 255, 0, 255, 31671, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 184u, BilinearFilter1Component( 0, 255, 0, 255, 47231, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 207u, BilinearFilter1Component( 0, 255, 0, 255, 53129, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 239u, BilinearFilter1Component( 0, 255, 0, 255, 61392, 32768 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 255u, BilinearFilter1Component( 0, 255, 0, 255, 65535, 32768 ), TEST_LOCATION );
+
+  // Vertical Blends:
+  DALI_TEST_EQUALS( 0u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 0 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 60u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 15379 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 130u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 33451 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 186u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 47836 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 244u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 62731 ), TEST_LOCATION );
+  DALI_TEST_EQUALS( 255u, BilinearFilter1Component( 0, 0, 255, 255, 32768, 65535 ), TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-Internal-PixelBuffer.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-Internal-PixelBuffer.cpp
new file mode 100644 (file)
index 0000000..1c7d294
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ * 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 <dali/internal/imaging/common/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;
+}
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-Lifecycle-Controller.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-Lifecycle-Controller.cpp
new file mode 100644 (file)
index 0000000..6511f3b
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * 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 <stdlib.h>
+#include <iostream>
+#include <dali.h>
+#include <dali-test-suite-utils.h>
+#include <dali/devel-api/adaptor-framework/lifecycle-controller.h>
+
+#include <dali/internal/adaptor/common/lifecycle-controller-impl.h>
+
+using namespace Dali;
+
+void utc_dali_lifecycle_controller_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_lifecycle_controller_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+bool g_OnInitCalled = false;
+bool g_OnTerminateCalled = false;
+bool g_OnPauseCalled = false;
+bool g_OnResumeCalled = false;
+bool g_OnResetCalled = false;
+bool g_OnResizeCalled = false;
+bool g_OnLanguageChangedCalled = false;
+
+void OnInit()
+{
+  g_OnInitCalled = true;
+}
+
+void OnTerminate()
+{
+  g_OnTerminateCalled = true;
+}
+
+void OnPause()
+{
+  g_OnPauseCalled = true;
+}
+
+void OnResume()
+{
+  g_OnResumeCalled = true;
+}
+
+void OnReset()
+{
+  g_OnResetCalled = true;
+}
+
+void OnResize()
+{
+  g_OnResizeCalled = true;
+}
+
+void OnLanguageChanged()
+{
+  g_OnLanguageChangedCalled = true;
+}
+
+} // anonymous namespace
+
+int UtcDaliLifecycleControllerGet(void)
+{
+  // Attempt to retrieve LifecycleController before creating application
+  LifecycleController lifecycleController;
+  lifecycleController = LifecycleController::Get();
+  DALI_TEST_CHECK( !lifecycleController );
+
+  TestApplication app;
+  Application application = Application::New();
+
+  lifecycleController = LifecycleController::Get();
+  DALI_TEST_CHECK( lifecycleController );
+
+  END_TEST;
+}
+
+int UtcDaliLifecycleControllerSignalInit(void)
+{
+  TestApplication app;
+  Application application = Application::New();
+
+  DALI_TEST_CHECK( !g_OnInitCalled );
+
+  LifecycleController lifecycleController = LifecycleController::Get();
+
+  lifecycleController.InitSignal().Connect( &OnInit );
+
+  GetImplementation( lifecycleController ).OnInit( application );
+
+  DALI_TEST_CHECK( g_OnInitCalled );
+
+  END_TEST;
+}
+
+int UtcDaliLifecycleControllerSignalTerminate(void)
+{
+  TestApplication app;
+  Application application = Application::New();
+
+  DALI_TEST_CHECK( !g_OnTerminateCalled );
+
+  LifecycleController lifecycleController = LifecycleController::Get();
+
+  lifecycleController.TerminateSignal().Connect( &OnTerminate );
+
+  GetImplementation( lifecycleController ).OnTerminate( application );
+
+  DALI_TEST_CHECK( g_OnTerminateCalled );
+
+  END_TEST;
+}
+
+int UtcDaliLifecycleControllerSignalPause(void)
+{
+  TestApplication app;
+  Application application = Application::New();
+
+  DALI_TEST_CHECK( !g_OnPauseCalled );
+
+  LifecycleController lifecycleController = LifecycleController::Get();
+
+  lifecycleController.PauseSignal().Connect( &OnPause );
+
+  GetImplementation( lifecycleController ).OnPause( application );
+
+  DALI_TEST_CHECK( g_OnPauseCalled );
+
+  END_TEST;
+}
+
+int UtcDaliLifecycleControllerSignalResume(void)
+{
+  TestApplication app;
+  Application application = Application::New();
+
+  DALI_TEST_CHECK( !g_OnResumeCalled );
+
+  LifecycleController lifecycleController = LifecycleController::Get();
+
+  lifecycleController.ResumeSignal().Connect( &OnResume );
+
+  GetImplementation( lifecycleController ).OnResume( application );
+
+  DALI_TEST_CHECK( g_OnResumeCalled );
+
+  END_TEST;
+}
+
+int UtcDaliLifecycleControllerSignalReset(void)
+{
+  TestApplication app;
+  Application application = Application::New();
+
+  DALI_TEST_CHECK( !g_OnResetCalled );
+
+  LifecycleController lifecycleController = LifecycleController::Get();
+
+  lifecycleController.ResetSignal().Connect( &OnReset );
+
+  GetImplementation( lifecycleController ).OnReset( application );
+
+  DALI_TEST_CHECK( g_OnResetCalled );
+
+  END_TEST;
+}
+
+int UtcDaliLifecycleControllerSignalResize(void)
+{
+  TestApplication app;
+  Application application = Application::New();
+
+  DALI_TEST_CHECK( !g_OnResizeCalled );
+
+  LifecycleController lifecycleController = LifecycleController::Get();
+
+  lifecycleController.ResizeSignal().Connect( &OnResize );
+
+  GetImplementation( lifecycleController ).OnResize( application );
+
+  DALI_TEST_CHECK( g_OnResizeCalled );
+
+  END_TEST;
+}
+
+int UtcDaliLifecycleControllerSignalLanguageChanged(void)
+{
+  TestApplication app;
+  Application application = Application::New();
+
+  DALI_TEST_CHECK( !g_OnLanguageChangedCalled );
+
+  LifecycleController lifecycleController = LifecycleController::Get();
+
+  lifecycleController.LanguageChangedSignal().Connect( &OnLanguageChanged );
+
+  GetImplementation( lifecycleController ).OnLanguageChanged( application );
+
+  DALI_TEST_CHECK( g_OnLanguageChangedCalled );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor-internal/utc-Dali-TiltSensor.cpp b/automated-tests/src/dali-adaptor-internal/utc-Dali-TiltSensor.cpp
new file mode 100644 (file)
index 0000000..acf4932
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * 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 <stdint.h>
+#include <dali/dali.h>
+#include <dali-test-suite-utils.h>
+#include <adaptor-test-application.h>
+#include <dali/internal/sensor/common/tilt-sensor-impl.h>
+#include <dali/internal/sensor/common/tilt-sensor-factory.h>
+#include <dali/internal/system/linux/dali-ecore.h>
+
+using namespace Dali;
+
+namespace
+{
+static const float ROTATION_EPSILON = 0.0001f;
+
+/**
+ * Helper to test whether timeout or tilt signal is received first
+ */
+struct SignalHelper : public ConnectionTracker
+{
+  SignalHelper()
+  : mTiltSignalReceived( false ),
+    mTimeoutOccurred( false )
+  {
+  }
+
+  void OnTilted(const TiltSensor& sensor)
+  {
+    tet_printf("tilted signal received\n");
+
+    mTiltSignalReceived = true;
+
+    // quit the main loop to continue test
+    //ecore_main_loop_quit();
+  }
+
+  bool OnTimeout()
+  {
+    tet_printf("timeout occurred\n");
+
+    mTimeoutOccurred = true;
+
+    // quit the main loop to continue test
+    //ecore_main_loop_quit();
+
+    return false;
+  }
+
+  bool mTiltSignalReceived; // True if tilted signal was received
+  bool mTimeoutOccurred;    // True if timeout occured
+};
+
+TiltSensor GetTiltSensor()
+{
+  return Dali::TiltSensor(Dali::Internal::Adaptor::TiltSensorFactory::Create());
+}
+
+bool ecore_timer_running = false;
+Ecore_Task_Cb timer_callback_func=NULL;
+const void* timer_callback_data=NULL;
+intptr_t timerId = 8; // intptr_t has the same size as a pointer and is platform independent so this can be returned as a pointer in ecore_timer_add below without compilation warnings
+}// anon namespace
+extern "C"
+{
+Ecore_Timer* ecore_timer_add(double in,
+                             Ecore_Task_Cb func,
+                             const void   *data)
+{
+  ecore_timer_running = true;
+  timer_callback_func = func;
+  timer_callback_data = data;
+  timerId+=8;
+  return (Ecore_Timer*)timerId;
+}
+
+void* ecore_timer_del(Ecore_Timer *timer)
+{
+  ecore_timer_running = false;
+  timer_callback_func = NULL;
+  return NULL;
+}
+
+}
+
+
+
+void tilt_sensor_startup(void)
+{
+}
+
+void tilt_sensor_cleanup(void)
+{
+}
+
+
+int UtcDaliTiltSensorStart(void)
+{
+  AdaptorTestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorStart");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+
+  sensor.Start();
+  DALI_TEST_CHECK( sensor.IsStarted() );
+
+  END_TEST;
+}
+
+int UtcDaliTiltSensorStop(void)
+{
+  AdaptorTestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorStop");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+
+  sensor.Start();
+  DALI_TEST_CHECK( sensor.IsStarted() );
+
+  sensor.Stop();
+  DALI_TEST_CHECK( !sensor.IsStarted() );
+  END_TEST;
+}
+
+int UtcDaliTiltSensorIsStarted(void)
+{
+  AdaptorTestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorIsStarted");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+
+  // Should be disabled by default
+  DALI_TEST_CHECK( !sensor.IsStarted() );
+  END_TEST;
+}
+
+int UtcDaliTiltSensorGetRoll(void)
+{
+  AdaptorTestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorGetRoll");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+
+  float roll = sensor.GetRoll();
+  DALI_TEST_CHECK( roll <= 1.0f && roll >= -1.0f ); // range check
+  END_TEST;
+}
+
+int UtcDaliTiltSensorGetPitch(void)
+{
+  AdaptorTestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorGetPitch");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+
+  float pitch = sensor.GetPitch();
+  DALI_TEST_CHECK( pitch <= 1.0f && pitch >= -1.0f ); // range check
+  END_TEST;
+}
+
+int UtcDaliTiltSensorGetRotation(void)
+{
+  AdaptorTestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorGetRotation");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+
+  Quaternion rotation = sensor.GetRotation();
+
+  Radian roll( sensor.GetRoll() );
+  Radian pitch( sensor.GetPitch() );
+
+  Quaternion expectedRotation = Quaternion( roll  * Math::PI * -0.5f, Vector3::YAXIS ) *
+                                Quaternion( pitch * Math::PI * -0.5f, Vector3::XAXIS );
+
+  DALI_TEST_EQUALS( rotation, expectedRotation, ROTATION_EPSILON, TEST_LOCATION );
+  END_TEST;
+}
+
+
+int UtcDaliTiltSensorSignalTilted(void)
+{
+  AdaptorTestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorSignalTilted");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+  sensor.Start();
+
+  Radian angle(Degree(-45));
+  //Setting a negative threshold for testing purpose
+  sensor.SetRotationThreshold( angle );
+
+  END_TEST;
+}
+
+int UtcDaliTiltSensorSetUpdateFrequency(void)
+{
+  AdaptorTestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorSetUpdateFrequency");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+  sensor.SetUpdateFrequency( 1.0f/*hertz*/ );
+  DALI_TEST_EQUALS( sensor.GetUpdateFrequency(), 1.0f, TEST_LOCATION );
+
+  sensor.SetUpdateFrequency( 60.0f/*hertz*/ );
+  DALI_TEST_EQUALS( sensor.GetUpdateFrequency(), 60.0f, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliTiltSensorSetRotationThreshold01(void)
+{
+  AdaptorTestApplication application;
+
+  tet_infoline("UtcDaliTiltSensorSetRotationThreshold01");
+
+  TiltSensor sensor = GetTiltSensor();
+  DALI_TEST_CHECK( sensor );
+  sensor.Start();
+
+  Radian angle(Degree(-45));
+  sensor.SetRotationThreshold( angle );
+  DALI_TEST_EQUALS( sensor.GetRotationThreshold(), angle, TEST_LOCATION );
+
+  angle = Degree(90);
+  sensor.SetRotationThreshold( angle );
+  DALI_TEST_EQUALS( sensor.GetRotationThreshold(), angle, TEST_LOCATION );
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor/CMakeLists.txt b/automated-tests/src/dali-adaptor/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2fe5be8
--- /dev/null
@@ -0,0 +1,69 @@
+SET(PKG_NAME "dali-adaptor")
+
+SET(EXEC_NAME "tct-${PKG_NAME}-core")
+SET(RPM_NAME "core-${PKG_NAME}-tests")
+
+SET(CAPI_LIB "dali-adaptor")
+SET(TC_SOURCES
+    utc-Dali-Application.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-Timer.cpp
+    utc-Dali-TtsPlayer.cpp
+    utc-Dali-Window.cpp
+    #utc-Dali-Watch.cpp
+    #utc-Dali-Watch-Time.cpp
+    #utc-Dali-KeyGrab.cpp
+)
+
+LIST(APPEND TC_SOURCES
+    dali-test-suite-utils/mesh-builder.cpp
+    dali-test-suite-utils/dali-test-suite-utils.cpp
+    dali-test-suite-utils/test-actor-utils.cpp
+    dali-test-suite-utils/test-harness.cpp
+    dali-test-suite-utils/test-application.cpp
+    dali-test-suite-utils/test-gesture-generator.cpp
+    dali-test-suite-utils/test-gl-abstraction.cpp
+    dali-test-suite-utils/test-gl-sync-abstraction.cpp
+    dali-test-suite-utils/test-native-image.cpp
+    dali-test-suite-utils/test-platform-abstraction.cpp
+    dali-test-suite-utils/test-render-controller.cpp
+    dali-test-suite-utils/test-trace-call-stack.cpp
+    dali-test-suite-utils/adaptor-test-adaptor-impl.cpp
+)
+
+PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED
+    dali-core
+    dali-adaptor
+    ecore
+    ecore-x
+)
+
+ADD_COMPILE_OPTIONS( -O0 -ggdb --coverage -Wall -Werror )
+ADD_COMPILE_OPTIONS( ${${CAPI_LIB}_CFLAGS_OTHER} )
+
+ADD_DEFINITIONS(-DTEST_RESOURCE_DIR=\"${CMAKE_CURRENT_SOURCE_DIR}/../../resources\" )
+
+FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
+    SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}")
+ENDFOREACH(directory ${CAPI_LIB_LIBRARY_DIRS})
+
+INCLUDE_DIRECTORIES(
+    ../../../
+    ${${CAPI_LIB}_INCLUDE_DIRS}
+    dali-test-suite-utils
+)
+
+ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp ${TC_SOURCES})
+TARGET_LINK_LIBRARIES(${EXEC_NAME}
+  ${${CAPI_LIB}_LIBRARIES}
+  --coverage
+)
+
+INSTALL(PROGRAMS ${EXEC_NAME}
+    DESTINATION ${BIN_DIR}/${EXEC_NAME}
+)
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/adaptor-test-adaptor-impl.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/adaptor-test-adaptor-impl.cpp
new file mode 100644 (file)
index 0000000..5b3847a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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 "adaptor-test-adaptor-impl.h"
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+bool Adaptor::mAvailable = false;
+
+bool Adaptor::IsAvailable()
+{
+  return mAvailable;
+}
+
+void Adaptor::SetAvailable()
+{
+  mAvailable = true;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/adaptor-test-adaptor-impl.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/adaptor-test-adaptor-impl.h
new file mode 100644 (file)
index 0000000..f2920b9
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef DALI_ADAPTOR_TEST_ADAPTOR_IMPL_H
+#define DALI_ADAPTOR_TEST_ADAPTOR_IMPL_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class Adaptor
+{
+public:
+  static bool IsAvailable();
+  static void SetAvailable();
+
+  Adaptor() {}
+  ~Adaptor() {}
+
+public:
+  static bool mAvailable;
+};
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
+
+#endif  // DALI_ADAPTOR_TEST_ADAPTOR_IMPL_H
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/adaptor-test-application.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/adaptor-test-application.h
new file mode 100644 (file)
index 0000000..99f24d7
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef DALI_ADAPTOR_TEST_APPLICATION_H
+#define DALI_ADAPTOR_TEST_APPLICATION_H
+
+/*
+ * Copyright (c) 2019 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 "test-application.h"
+#include "adaptor-test-adaptor-impl.h"
+
+namespace Dali
+{
+
+/**
+ * Adds some functionality on top of TestApplication that is required by the Adaptor.
+ */
+class AdaptorTestApplication : public TestApplication
+{
+public:
+
+  AdaptorTestApplication( size_t surfaceWidth  = DEFAULT_SURFACE_WIDTH,
+                          size_t surfaceHeight = DEFAULT_SURFACE_HEIGHT,
+                          float  horizontalDpi = DEFAULT_HORIZONTAL_DPI,
+                          float  verticalDpi   = DEFAULT_VERTICAL_DPI )
+  : TestApplication( surfaceWidth, surfaceHeight, horizontalDpi, verticalDpi )
+  {
+    Internal::Adaptor::Adaptor::SetAvailable();
+  }
+
+  ~AdaptorTestApplication()
+  {
+  }
+};
+
+} // namespace Dali
+
+#endif // DALI_ADAPTOR_TEST_APPLICATION_H
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/dali-test-img-utils.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/dali-test-img-utils.h
new file mode 100644 (file)
index 0000000..3c09db6
--- /dev/null
@@ -0,0 +1,141 @@
+#ifndef DALI_TEST_IMG_UTILS_H
+#define DALI_TEST_IMG_UTILS_H
+
+/*
+ * Copyright (c) 2019 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 <cstdarg>
+#include <cstdio>
+#include <iostream>
+#include <cstring>
+
+// INTERNAL INCLUDES
+#include <dali/dali.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/public-api/dali-core.h>
+
+
+using namespace Dali;
+
+namespace
+{
+
+/**
+ * Test whether two buffers are equal with tolerance value.
+ * @param[in] buffer1 The first buffer
+ * @param[in] buffer2 The second pixelbuffer
+ * @param[in] tolerance value, maximum difference to accept the similarity of buffers.
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+
+inline void DALI_TEST_EQUALS( const unsigned char* buffer1, const unsigned char* buffer2, unsigned int tolerance, long size, const char* location)
+{
+  if( !tolerance )
+  {
+    if ( memcmp( buffer1, buffer2, size) )
+    {
+      fprintf(stderr, "%s, checking buffer1 == buffer2\n", location );
+      tet_result(TET_FAIL);
+    }
+    else
+    {
+      tet_result(TET_PASS);
+    }
+  }
+  else
+  {
+    const unsigned char* buff1 = buffer1;
+    const unsigned char* buff2 = buffer2;
+    unsigned int i = 0;
+    //Create a mask to fast compare, it is expected to be similar values.
+    unsigned int maskBits = 0;
+    while( maskBits < tolerance )
+    {
+      maskBits |= (1 << i);
+      i++;
+    }
+    maskBits &= ~(1 << --i);
+    maskBits = ~maskBits;
+
+    bool equal = true;
+    for( i = 0; i < size; ++i, ++buff1, ++buff2 )
+    {
+      //Check bit difference, if exist, do more exhaustive comparison with tolerance value
+      if( (*buff1 ^ *buff2 ) & maskBits )
+      {
+        if( *buff1 < *buff2 )
+        {
+          unsigned int diff = *buff2 - *buff1;
+          if( diff  > tolerance )
+          {
+            equal = false;
+            break;
+          }
+        }
+        else
+        {
+          unsigned int diff = *buff1 - *buff2;
+          if( diff > tolerance )
+          {
+            equal = false;
+            break;
+          }
+        }
+      }
+    }
+    if ( !equal )
+    {
+      fprintf(stderr, "%s, byte %d, checking %u == %u\n", location, i, *buff1, *buff2 );
+      tet_result(TET_FAIL);
+    }
+    else
+    {
+      tet_result(TET_PASS);
+    }
+  }
+}
+
+/**
+ * Test whether two pixelbuffers are equal with tolerance value, with check of width and height.
+ * @param[in] pixelBuffer1 The first buffer
+ * @param[in] pixelBuffer2 The second pixelbuffer
+ * @param[in] tolerance value, maximum difference to accept the similarity of pixel buffers.
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+
+inline void DALI_IMAGE_TEST_EQUALS( Dali::Devel::PixelBuffer pixelBuffer1, Dali::Devel::PixelBuffer pixelBuffer2, unsigned int tolerance, const char* location)
+{
+  if( ( pixelBuffer1.GetPixelFormat() != Pixel::RGB888 ) || ( pixelBuffer2.GetPixelFormat() != Pixel::RGB888 ) )
+  {
+    fprintf(stderr, "%s, PixelFormat != Pixel::RGB888, test only support Pixel::RGB888 formats\n", location );
+    tet_result(TET_FAIL);
+  }
+  else if( ( pixelBuffer1.GetWidth() != pixelBuffer1.GetWidth() ) || ( pixelBuffer1.GetHeight() != pixelBuffer1.GetHeight() ) )
+  {
+    fprintf(stderr, "%s, Different Image sizes\n", location );
+    tet_result(TET_FAIL);
+  }
+  else
+  {
+    DALI_TEST_EQUALS( pixelBuffer1.GetBuffer(), pixelBuffer2.GetBuffer(), tolerance, pixelBuffer1.GetHeight() * pixelBuffer1.GetWidth() * 3, location);
+  }
+}
+
+}
+
+#endif // DALI_TEST_SUITE_UTILS_H
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/dali-test-suite-utils.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/dali-test-suite-utils.cpp
new file mode 100644 (file)
index 0000000..b9c8245
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include "dali-test-suite-utils.h"
+
+// EXTERNAL INCLUDES
+#include <ostream>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-core.h>
+
+using namespace Dali;
+
+int32_t test_return_value = TET_UNDEF;
+
+void tet_result(int32_t value)
+{
+  // First TET_PASS should set to zero
+  // first TET_FAIL should prevent any further TET_PASS from setting back to zero
+  // Any TET_FAIL should set to fail or leave as fail
+  if( test_return_value != 1 )
+    test_return_value = value;
+}
+
+#define END_TEST \
+  return ((test_return_value>0)?1:0)
+
+
+void tet_infoline(const char* str)
+{
+  fprintf(stderr, "%s\n", str);
+}
+
+void tet_printf(const char *format, ...)
+{
+  va_list arg;
+  va_start(arg, format);
+  vfprintf(stderr, format, arg);
+  va_end(arg);
+}
+
+bool operator==(TimePeriod a, TimePeriod b)
+{
+  return Equals(a.durationSeconds, b.durationSeconds) && Equals(a.delaySeconds, b.delaySeconds) ;
+}
+
+std::ostream& operator<<( std::ostream& ostream, TimePeriod value )
+{
+  return ostream << "( Duration:" << value.durationSeconds << " Delay:" << value.delaySeconds << ")";
+}
+
+std::ostream& operator<<( std::ostream& ostream, Radian angle )
+{
+  ostream << angle.radian;
+  return ostream;
+}
+
+std::ostream& operator<<( std::ostream& ostream, Degree angle )
+{
+  ostream << angle.degree;
+  return ostream;
+}
+
+void DALI_TEST_EQUALS( const BaseHandle& baseHandle1, const BaseHandle& baseHandle2, const char* location )
+{
+  DALI_TEST_EQUALS< const BaseHandle& >( baseHandle1, baseHandle2, location );
+}
+
+void DALI_TEST_EQUALS( const size_t value1, const uint32_t value2, const char* location )
+{
+  DALI_TEST_EQUALS< uint32_t >( ( uint32_t )( value1 ), value2, location );
+}
+
+void DALI_TEST_EQUALS( const uint32_t value1, const size_t value2, const char* location )
+{
+  DALI_TEST_EQUALS< uint32_t >( value1, ( uint32_t )( value2 ), location );
+}
+
+void DALI_TEST_EQUALS( const Matrix3& matrix1, const Matrix3& matrix2, const char* location)
+{
+  const float* m1 = matrix1.AsFloat();
+  const float* m2 = matrix2.AsFloat();
+  bool equivalent = true;
+
+  for (int32_t i=0;i<9;++i)
+  {
+    if( ! (fabsf(m1[i] - m2[i])< GetRangedEpsilon(m1[i], m2[i])) )
+    {
+      equivalent = false;
+    }
+  }
+
+  if( !equivalent )
+  {
+    // Align each float to 1234.67, i.e. 3.6 will be "   3.60"
+    fprintf( stderr, "%s, checking\n"
+               "%7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f\n"
+               "%7.2f %7.2f %7.2f == %7.2f %7.2f %7.2f\n"
+               "%7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f\n",
+               location,
+               m1[0], m1[3], m1[6],    m2[0], m2[3], m2[6],
+               m1[1], m1[4], m1[7],    m2[1], m2[4], m2[7],
+               m1[2], m1[5], m1[8],    m2[2], m2[5], m2[8] );
+
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+void DALI_TEST_EQUALS( const Matrix3& matrix1, const Matrix3& matrix2, float epsilon, const char* location)
+{
+  const float* m1 = matrix1.AsFloat();
+  const float* m2 = matrix2.AsFloat();
+  bool equivalent = true;
+
+  for (int32_t i=0;i<9;++i)
+  {
+    equivalent &= (fabsf(m1[i] - m2[i])<epsilon);
+  }
+
+  if (!equivalent)
+  {
+    // Align each float to 1234.67, i.e. 3.6 will be "   3.60"
+    fprintf( stderr, "%s, checking\n"
+               "%7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f\n"
+               "%7.2f %7.2f %7.2f == %7.2f %7.2f %7.2f\n"
+               "%7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f\n",
+               location,
+               m1[0], m1[3], m1[6],    m2[0], m2[3], m2[6],
+               m1[1], m1[4], m1[7],    m2[1], m2[4], m2[7],
+               m1[2], m1[5], m1[8],    m2[2], m2[5], m2[8] );
+
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+void DALI_TEST_EQUALS( const Matrix& matrix1, const Matrix& matrix2, const char* location)
+{
+  const float* m1 = matrix1.AsFloat();
+  const float* m2 = matrix2.AsFloat();
+  bool identical = true;
+
+  int32_t i;
+  for (i=0;i<16;++i)
+  {
+    if(m1[i] != m2[i])
+    {
+      identical = false;
+      break;
+    }
+  }
+
+  if (!identical)
+  {
+    // Align each float to 1234.67, i.e. 3.6 will be "   3.60"
+    fprintf( stderr, "%s, checking\n"
+             "%7.2f %7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f %7.2f\n"
+             "%7.2f %7.2f %7.2f %7.2f == %7.2f %7.2f %7.2f %7.2f\n"
+             "%7.2f %7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f %7.2f\n"
+             "%7.2f %7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f %7.2f\n",
+             location,
+             m1[0], m1[4], m1[8],  m1[12],    m2[0], m2[4], m2[8],  m2[12],
+             m1[1], m1[5], m1[9],  m1[13],    m2[1], m2[5], m2[9],  m2[13],
+             m1[2], m1[6], m1[10], m1[14],    m2[2], m2[6], m2[10], m2[14],
+             m1[3], m1[7], m1[11], m1[15],    m2[3], m2[7], m2[11], m2[15] );
+
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+void DALI_TEST_EQUALS( const Matrix& matrix1, const Matrix& matrix2, float epsilon, const char* location)
+{
+  const float* m1 = matrix1.AsFloat();
+  const float* m2 = matrix2.AsFloat();
+  bool equivalent = true;
+
+  for (int32_t i=0;i<16;++i)
+  {
+    equivalent &= (fabsf(m1[i] - m2[i])<epsilon);
+  }
+
+  if (!equivalent)
+  {
+    // Align each float to 1234.67, i.e. 3.6 will be "   3.60"
+    fprintf( stderr, "%s, checking\n"
+             "%7.2f %7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f %7.2f\n"
+             "%7.2f %7.2f %7.2f %7.2f == %7.2f %7.2f %7.2f %7.2f\n"
+             "%7.2f %7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f %7.2f\n"
+             "%7.2f %7.2f %7.2f %7.2f    %7.2f %7.2f %7.2f %7.2f\n",
+             location,
+             m1[0], m1[4], m1[8],  m1[12],    m2[0], m2[4], m2[8],  m2[12],
+             m1[1], m1[5], m1[9],  m1[13],    m2[1], m2[5], m2[9],  m2[13],
+             m1[2], m1[6], m1[10], m1[14],    m2[2], m2[6], m2[10], m2[14],
+             m1[3], m1[7], m1[11], m1[15],    m2[3], m2[7], m2[11], m2[15] );
+
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+
+/**
+ * Test whether two strings are equal.
+ * @param[in] str1 The first string
+ * @param[in] str2 The second string
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const std::string &str1, const char* str2, const char* location)
+{
+  DALI_TEST_EQUALS(str1.c_str(), str2, location);
+}
+
+void DALI_TEST_EQUALS( Property::Value& str1, const char* str2, const char* location)
+{
+  bool result = false;
+
+  if( str1.GetType() == Property::STRING )
+  {
+    std::string string;
+    str1.Get(string);
+    result = !string.compare(str2);
+  }
+
+  if( result )
+  {
+    tet_result(TET_PASS);
+  }
+  else
+  {
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");
+  }
+}
+
+void DALI_TEST_EQUALS( const char* str1, const std::string &str2, const char* location)
+{
+  DALI_TEST_EQUALS(str1, str2.c_str(), location);
+}
+
+void DALI_TEST_ASSERT( DaliException& e, std::string conditionSubString, const char* location )
+{
+  if( NULL == strstr( e.condition, conditionSubString.c_str() ) )
+  {
+    fprintf(stderr, "Expected substring '%s' : actual exception string '%s' : location %s\n", conditionSubString.c_str(), e.condition, location );
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+// Functor to test whether an Applied signal is emitted
+ConstraintAppliedCheck::ConstraintAppliedCheck( bool& signalReceived )
+: mSignalReceived( signalReceived )
+{
+}
+
+void ConstraintAppliedCheck::operator()( Constraint& constraint )
+{
+  mSignalReceived = true;
+}
+
+void ConstraintAppliedCheck::Reset()
+{
+  mSignalReceived = false;
+}
+
+void ConstraintAppliedCheck::CheckSignalReceived()
+{
+  if ( !mSignalReceived )
+  {
+    fprintf(stderr,  "Expected Applied signal was not received\n" );
+    tet_result( TET_FAIL );
+    throw("TET_FAIL");
+  }
+  else
+  {
+    tet_result( TET_PASS );
+  }
+}
+
+void ConstraintAppliedCheck::CheckSignalNotReceived()
+{
+  if ( mSignalReceived )
+  {
+    fprintf(stderr,  "Unexpected Applied signal was received\n" );
+    tet_result( TET_FAIL );
+    throw("TET_FAIL");
+  }
+  else
+  {
+    tet_result( TET_PASS );
+  }
+}
+
+BufferImage CreateBufferImage(int32_t width, int32_t height, const Vector4& color)
+{
+  BufferImage image = BufferImage::New(width, height, Pixel::RGBA8888);
+
+  PixelBuffer* pixbuf = image.GetBuffer();
+
+  // Using a 4x4 image gives a better blend with the GL implementation
+  // than a 3x3 image
+  for(size_t i=0; i<16; i++)
+  {
+    pixbuf[i*4+0] = color.r*255;
+    pixbuf[i*4+1] = color.g*255;
+    pixbuf[i*4+2] = color.b*255;
+    pixbuf[i*4+3] = color.a*255;
+  }
+
+  return image;
+}
+
+BufferImage CreateBufferImage()
+{
+  return CreateBufferImage(4, 4, Color::WHITE);
+}
+
+void PrepareResourceImage( TestApplication& application, uint32_t imageWidth, uint32_t imageHeight, Pixel::Format pixelFormat )
+{
+  TestPlatformAbstraction& platform = application.GetPlatform();
+  platform.SetClosestImageSize(Vector2( imageWidth, imageHeight));
+
+  Integration::Bitmap* bitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_RETAIN );
+  Integration::PixelBuffer* pixbuffer = bitmap->GetPackedPixelsProfile()->ReserveBuffer( pixelFormat, imageWidth, imageHeight, imageWidth, imageHeight );
+  uint32_t bytesPerPixel = GetBytesPerPixel(  pixelFormat );
+  uint32_t initialColor = 0xFF;
+  memset( pixbuffer, initialColor, imageHeight*imageWidth*bytesPerPixel);
+
+  Integration::ResourcePointer resourcePtr(bitmap);
+  platform.SetSynchronouslyLoadedResource( resourcePtr );
+}
+
+namespace Test
+{
+
+struct ObjectDestructionFunctor
+{
+  // Create a ObjectDestructionFunctor passing in a Dali::RefObject* to be monitored and a bool variable.
+  // Create ObjectRegistry instance and connect to the ObjectDestroyedSignal passing in the above functor for the callback.
+  // Get the ObjectPointer (Actor::GetObjectPtr) of the Actor to be checked for destruction and assign it to the Dali::RefObject*
+  // Check the bool variable which would be true when object destroyed.
+  ObjectDestructionFunctor( Dali::RefObject* objectPtr, bool& refObjectDestroyed )
+  : refObjectPointerToCheck( objectPtr ),
+    refObjectDestroyedBoolean( refObjectDestroyed )
+  {
+    refObjectDestroyed = false;
+  }
+
+  void operator()( const Dali::RefObject* objectPointer )
+  {
+    if ( refObjectPointerToCheck == objectPointer )
+    {
+      refObjectDestroyedBoolean = true;
+    }
+  }
+
+  Dali::RefObject* refObjectPointerToCheck;
+  bool& refObjectDestroyedBoolean;
+};
+
+ObjectDestructionTracker::ObjectDestructionTracker()
+  :mRefObjectDestroyed( false)
+{
+}
+
+void ObjectDestructionTracker::Start( Actor actor )
+{
+  ObjectDestructionFunctor destructionFunctor( actor.GetObjectPtr(), mRefObjectDestroyed );
+
+  ObjectRegistry objectRegistry = Stage::GetCurrent().GetObjectRegistry();
+  objectRegistry.ObjectDestroyedSignal().Connect( this, destructionFunctor );
+}
+
+bool ObjectDestructionTracker::IsDestroyed()
+{
+   return mRefObjectDestroyed;
+}
+
+} // namespace Test
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/dali-test-suite-utils.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/dali-test-suite-utils.h
new file mode 100644 (file)
index 0000000..577ca36
--- /dev/null
@@ -0,0 +1,446 @@
+#ifndef DALI_TEST_SUITE_UTILS_H
+#define DALI_TEST_SUITE_UTILS_H
+
+/*
+ * Copyright (c) 2019 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 <cstdarg>
+#include <cstdio>
+#include <iostream>
+#include <cstring>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-core.h>
+#include <test-compare-types.h>
+
+void tet_infoline(const char*str);
+void tet_printf(const char *format, ...);
+
+#include "test-application.h"
+#include "test-actor-utils.h"
+#include "test-gesture-generator.h"
+
+using namespace Dali;
+
+#define STRINGIZE_I(text) #text
+#define STRINGIZE(text) STRINGIZE_I(text)
+
+/**
+ * Inspired by https://stackoverflow.com/questions/1706346/file-macro-manipulation-handling-at-compile-time
+ * answer by Chetan Reddy
+ */
+constexpr int32_t basenameIndex( const char * const path, const int32_t index = 0, const int32_t slashIndex = -1 )
+{
+   return path[ index ]
+       ? ( path[ index ] == '/'
+           ? basenameIndex( path, index + 1, index )
+           : basenameIndex( path, index + 1, slashIndex ) )
+       : ( slashIndex + 1 );
+}
+
+#define __FILELINE__ ( { static const int32_t basenameIdx = basenameIndex( __FILE__ ); \
+                         static_assert (basenameIdx >= 0, "compile-time basename" );   \
+                         __FILE__ ":" STRINGIZE(__LINE__) + basenameIdx ; } )
+
+#define TEST_LOCATION __FILELINE__
+#define TEST_INNER_LOCATION(x) ( std::string(x) + " (" + STRINGIZE(__LINE__) + ")" ).c_str()
+
+#define TET_UNDEF 2
+#define TET_FAIL 1
+#define TET_PASS 0
+
+extern int32_t test_return_value;
+
+void tet_result(int32_t value);
+
+#define END_TEST \
+  return ((test_return_value>0)?1:0)
+
+void tet_infoline(const char* str);
+void tet_printf(const char *format, ...);
+
+/**
+ * DALI_TEST_CHECK is a wrapper for tet_result.
+ * If the condition evaluates to false, the test is stopped.
+ * @param[in] The boolean expression to check
+ */
+#define DALI_TEST_CHECK(condition)                                                        \
+if ( (condition) )                                                                        \
+{                                                                                         \
+  tet_result(TET_PASS);                                                                   \
+}                                                                                         \
+else                                                                                      \
+{                                                                                         \
+  fprintf(stderr, "Test failed in %s, condition: %s\n", __FILELINE__, #condition );       \
+  tet_result(TET_FAIL);                                                                   \
+  throw("TET_FAIL");                                                                      \
+}
+
+
+bool operator==(TimePeriod a, TimePeriod b);
+std::ostream& operator<<( std::ostream& ostream, TimePeriod value );
+std::ostream& operator<<( std::ostream& ostream, Radian angle );
+std::ostream& operator<<( std::ostream& ostream, Degree angle );
+
+/**
+ * Test whether two values are equal.
+ * @param[in] value1 The first value
+ * @param[in] value2 The second value
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+template<typename Type>
+inline void DALI_TEST_EQUALS(Type value1, Type value2, const char* location)
+{
+  if( !CompareType<Type>(value1, value2, 0.01f) )
+  {
+    std::ostringstream o;
+    o << value1 << " == " << value2 << std::endl;
+    fprintf(stderr, "Test failed in %s, checking %s", location, o.str().c_str());
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+/**
+ * Test whether two values are equal.
+ * @param[in] value1 The first value
+ * @param[in] value2 The second value
+ */
+#define DALI_TEST_EQUAL( v1, v2 ) DALI_TEST_EQUALS( v1, v2, __FILELINE__ )
+
+template<typename Type>
+inline void DALI_TEST_EQUALS(Type value1, Type value2, float epsilon, const char* location)
+{
+  if( !CompareType<Type>(value1, value2, epsilon) )
+  {
+    std::ostringstream o;
+    o << value1 << " == " << value2 << std::endl;
+    fprintf(stderr, "Test failed in %s, checking %s", location, o.str().c_str());
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+template<typename Type>
+inline void DALI_TEST_NOT_EQUALS(Type value1, Type value2, float epsilon, const char* location)
+{
+  if( CompareType<Type>(value1, value2, epsilon) )
+  {
+    std::ostringstream o;
+    o << value1 << " !=  " << value2 << std::endl;
+    fprintf(stderr, "Test failed in %s, checking %s", location, o.str().c_str());
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+
+/**
+ * Test whether two TimePeriods are within a certain distance of each other.
+ * @param[in] value1 The first value
+ * @param[in] value2 The second value
+ * @param[in] epsilon The values must be within this distance of each other
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+template<>
+inline void DALI_TEST_EQUALS<TimePeriod>( TimePeriod value1, TimePeriod value2, float epsilon, const char* location)
+{
+  if ((fabs(value1.durationSeconds - value2.durationSeconds) > epsilon))
+  {
+    fprintf(stderr, "Test failed in %s, checking durations %f == %f, epsilon %f\n", location, value1.durationSeconds, value2.durationSeconds, epsilon);
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
+  }
+  else if ((fabs(value1.delaySeconds - value2.delaySeconds) > epsilon))
+  {
+    fprintf(stderr, "Test failed in %s, checking delays %f == %f, epsilon %f\n", location, value1.delaySeconds, value2.delaySeconds, epsilon);
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+/**
+ * Test whether two base handles are equal.
+ * @param[in] baseHandle1 The first value
+ * @param[in] baseHandle2 The second value
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const BaseHandle& baseHandle1, const BaseHandle& baseHandle2, const char* location );
+
+/**
+ * Test whether a size_t value and an uint32_t are equal.
+ * @param[in] value1 The first value
+ * @param[in] value2 The second value
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const size_t value1, const uint32_t value2, const char* location );
+
+/**
+ * Test whether an uint32_t and a size_t value and are equal.
+ * @param[in] value1 The first value
+ * @param[in] value2 The second value
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const uint32_t value1, const size_t value2, const char* location );
+
+/**
+ * Test whether two Matrix3 objects are equal.
+ * @param[in] matrix1 The first object
+ * @param[in] matrix2 The second object
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const Matrix3& matrix1, const Matrix3& matrix2, const char* location);
+
+/** Test whether two Matrix3 objects are equal (fuzzy compare).
+ * @param[in] matrix1 The first object
+ * @param[in] matrix2 The second object
+ * @param[in] epsilon The epsilon to use for comparison
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const Matrix3& matrix1, const Matrix3& matrix2, float epsilon, const char* location);
+
+/**
+ * Test whether two Matrix objects are equal.
+ * @param[in] matrix1 The first object
+ * @param[in] matrix2 The second object
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const Matrix& matrix1, const Matrix& matrix2, const char* location);
+
+/**
+ * Test whether two Matrix objects are equal (fuzzy-compare).
+ * @param[in] matrix1 The first object
+ * @param[in] matrix2 The second object
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const Matrix& matrix1, const Matrix& matrix2, float epsilon, const char* location);
+
+/**
+ * Test whether two strings are equal.
+ * @param[in] str1 The first string
+ * @param[in] str2 The second string
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+template<>
+inline void DALI_TEST_EQUALS<const char*>( const char* str1, const char* str2, const char* location)
+{
+  if (strcmp(str1, str2))
+  {
+    fprintf(stderr, "Test failed in %s, checking '%s' == '%s'\n", location, str1, str2);
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+/**
+ * Test whether two strings are equal.
+ * @param[in] str1 The first string
+ * @param[in] str2 The second string
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+template<>
+inline void DALI_TEST_EQUALS<const std::string&>( const std::string &str1, const std::string &str2, const char* location)
+{
+  DALI_TEST_EQUALS(str1.c_str(), str2.c_str(), location);
+}
+
+/**
+ * Test whether two strings are equal.
+ * @param[in] str1 The first string
+ * @param[in] str2 The second string
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( Property::Value& str1, const char* str2, const char* location);
+
+/**
+ * Test whether two strings are equal.
+ * @param[in] str1 The first string
+ * @param[in] str2 The second string
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const std::string &str1, const char* str2, const char* location);
+
+/**
+ * Test whether two strings are equal.
+ * @param[in] str1 The first string
+ * @param[in] str2 The second string
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+void DALI_TEST_EQUALS( const char* str1, const std::string &str2, const char* location);
+
+/**
+ * Test whether one unsigned integer value is greater than another.
+ * Test succeeds if value1 > value2
+ * @param[in] value1 The first value
+ * @param[in] value2 The second value
+ * @param[in] location The TEST_LOCATION macro should be used here
+ */
+template< typename T >
+void DALI_TEST_GREATER( T value1, T value2, const char* location)
+{
+  if (!(value1 > value2))
+  {
+    std::cerr << "Test failed in " << location << ", checking " << value1 <<" > " << value2 << "\n";
+    tet_result(TET_FAIL);
+    throw("TET_FAIL");                                                                      \
+  }
+  else
+  {
+    tet_result(TET_PASS);
+  }
+}
+
+/**
+ * Test whether the assertion condition that failed and thus triggered the
+ * exception \b e contained a given substring.
+ * @param[in] e The exception that we expect was fired by a runtime assertion failure.
+ * @param[in] conditionSubString The text that we expect to be present in an
+ *                               assertion which triggered the exception.
+ * @param[in] location The TEST_LOCATION macro should be used here.
+ */
+void DALI_TEST_ASSERT( DaliException& e, std::string conditionSubString, const char* location );
+
+/**
+ * Print the assert
+ * @param[in] e The exception that we expect was fired by a runtime assertion failure.
+ */
+inline void DALI_TEST_PRINT_ASSERT( DaliException& e )
+{
+  tet_printf("Assertion %s failed at %s\n", e.condition, e.location );
+}
+
+/**
+ * Test that given piece of code triggers the right assertion
+ * Fails the test if the assert didn't occur.
+ * Turns off logging during the execution of the code to avoid excessive false positive log output from the assertions
+ * @param expressions code to execute
+ * @param assertstring the substring expected in the assert
+ */
+#define DALI_TEST_ASSERTION( expressions, assertstring ) \
+try \
+{ \
+  TestApplication::EnableLogging( false ); \
+  expressions; \
+  TestApplication::EnableLogging( true ); \
+  fprintf(stderr, "Test failed in %s, expected assert: '%s' didn't occur\n", __FILELINE__, assertstring ); \
+  tet_result(TET_FAIL); \
+  throw("TET_FAIL"); } \
+catch( Dali::DaliException& e ) \
+{ \
+  DALI_TEST_ASSERT( e, assertstring, TEST_LOCATION ); \
+}
+
+// Functor to test whether an Applied signal is emitted
+struct ConstraintAppliedCheck
+{
+  ConstraintAppliedCheck( bool& signalReceived );
+  void operator()( Constraint& constraint );
+  void Reset();
+  void CheckSignalReceived();
+  void CheckSignalNotReceived();
+  bool& mSignalReceived; // owned by individual tests
+};
+
+/**
+ * A Helper to test default functions
+ */
+template <typename T>
+struct DefaultFunctionCoverage
+{
+  DefaultFunctionCoverage()
+  {
+    T a;
+    T *b = new T(a);
+    DALI_TEST_CHECK(b);
+    a = *b;
+    delete b;
+  }
+};
+
+
+// Helper to Create buffer image
+BufferImage CreateBufferImage();
+BufferImage CreateBufferImage(int32_t width, int32_t height, const Vector4& color);
+
+
+// Prepare a resource image to be loaded. Should be called before creating the ResourceImage
+void PrepareResourceImage( TestApplication& application, uint32_t imageWidth, uint32_t imageHeight, Pixel::Format pixelFormat );
+
+// Test namespace to prevent pollution of Dali namespace, add Test helper functions here
+namespace Test
+{
+/**
+ *  @brief
+ *
+ *  Helper to check object destruction occurred
+ *  1) In main part of code create an ObjectDestructionTracker
+ *  2) Within sub section of main create object Actor test and call Start with Actor to test for destruction
+ *  3) Perform code which is expected to destroy Actor
+ *  4) Back in main part of code use IsDestroyed() to test if Actor was destroyed
+ */
+class ObjectDestructionTracker : public ConnectionTracker
+{
+public:
+
+  /**
+   * @brief Call in main part of code
+   */
+  ObjectDestructionTracker();
+
+  /**
+   * @brief Call in sub bock of code where the Actor being checked is still alive.
+   *
+   * @param[in] actor Actor to be checked for destruction
+   */
+  void Start( Actor actor );
+
+  /**
+   * @brief Call to check if Actor alive or destroyed.
+   *
+   * @return bool true if Actor was destroyed
+   */
+  bool IsDestroyed();
+
+private:
+  bool mRefObjectDestroyed;
+};
+
+} // namespace Test
+
+#endif // DALI_TEST_SUITE_UTILS_H
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/mesh-builder.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/mesh-builder.cpp
new file mode 100644 (file)
index 0000000..48bc26b
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "mesh-builder.h"
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/images/texture-set-image.h>
+
+namespace Dali
+{
+
+Shader CreateShader()
+{
+  return Shader::New( "vertexSrc", "fragmentSrc" );
+}
+
+TextureSet CreateTextureSet()
+{
+  return TextureSet::New();
+}
+
+TextureSet CreateTextureSet( Image image )
+{
+  TextureSet textureSet = TextureSet::New();
+  TextureSetImage( textureSet, 0u, image );
+  return textureSet;
+}
+
+PropertyBuffer CreatePropertyBuffer()
+{
+  Property::Map texturedQuadVertexFormat;
+  texturedQuadVertexFormat["aPosition"] = Property::VECTOR2;
+  texturedQuadVertexFormat["aVertexCoord"] = Property::VECTOR2;
+
+  PropertyBuffer vertexData = PropertyBuffer::New( texturedQuadVertexFormat );
+  return vertexData;
+}
+
+Geometry CreateQuadGeometry(void)
+{
+  PropertyBuffer vertexData = CreatePropertyBuffer();
+  const float halfQuadSize = .5f;
+  struct TexturedQuadVertex { Vector2 position; Vector2 textureCoordinates; };
+  TexturedQuadVertex texturedQuadVertexData[4] = {
+    { Vector2(-halfQuadSize, -halfQuadSize), Vector2(0.f, 0.f) },
+    { Vector2( halfQuadSize, -halfQuadSize), Vector2(1.f, 0.f) },
+    { Vector2(-halfQuadSize,  halfQuadSize), Vector2(0.f, 1.f) },
+    { Vector2( halfQuadSize,  halfQuadSize), Vector2(1.f, 1.f) } };
+  vertexData.SetData(texturedQuadVertexData, 4);
+
+  unsigned short indexData[6] = { 0, 3, 1, 0, 2, 3 };
+
+  Geometry geometry = Geometry::New();
+  geometry.AddVertexBuffer( vertexData );
+  geometry.SetIndexBuffer( indexData, sizeof(indexData)/sizeof(indexData[0]) );
+
+  return geometry;
+}
+
+
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/mesh-builder.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/mesh-builder.h
new file mode 100644 (file)
index 0000000..d22f9c8
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef MESH_BUILDER_H
+#define MESH_BUILDER_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>
+
+namespace Dali
+{
+
+Shader CreateShader();
+TextureSet CreateTextureSet();
+TextureSet CreateTextureSet( Image image );
+Geometry CreateQuadGeometry();
+PropertyBuffer CreatePropertyBuffer();
+
+}
+
+#endif // MESH_BUILDER_H
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-actor-utils.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-actor-utils.cpp
new file mode 100644 (file)
index 0000000..38eb0b2
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include "test-actor-utils.h"
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/dali-core.h>
+#include <dali/devel-api/images/texture-set-image.h>
+
+// INTERNAL INCLUDES
+#include "mesh-builder.h"
+
+namespace Dali
+{
+
+namespace
+{
+
+const char* VERTEX_SHADER = DALI_COMPOSE_SHADER(
+  attribute mediump vec2 aPosition;\n
+  uniform mediump mat4 uMvpMatrix;\n
+  uniform mediump vec3 uSize;\n
+  \n
+  void main()\n
+  {\n
+    mediump vec4 vertexPosition = vec4(aPosition, 0.0, 1.0);\n
+    vertexPosition.xyz *= uSize;\n
+    gl_Position = uMvpMatrix * vertexPosition;\n
+  }\n
+);
+
+const char* FRAGMENT_SHADER = DALI_COMPOSE_SHADER(
+  uniform lowp vec4 uColor;\n
+  \n
+  void main()\n
+  {\n
+    gl_FragColor = uColor;\n
+  }\n
+);
+
+} // unnamed namespace
+
+Actor CreateRenderableActor()
+{
+  return CreateRenderableActor( Image(), VERTEX_SHADER, FRAGMENT_SHADER );
+}
+
+Actor CreateRenderableActor( Image texture )
+{
+  return CreateRenderableActor( texture, VERTEX_SHADER, FRAGMENT_SHADER );
+}
+
+Actor CreateRenderableActor( Image texture, const std::string& vertexShader, const std::string& fragmentShader )
+{
+  // Create the geometry
+  Geometry geometry = CreateQuadGeometry();
+
+  // Create Shader
+  Shader shader = Shader::New( vertexShader, fragmentShader );
+
+  // Create renderer from geometry and material
+  Renderer renderer = Renderer::New( geometry, shader );
+
+  // Create actor and set renderer
+  Actor actor = Actor::New();
+  actor.AddRenderer( renderer );
+
+  // If we a texture, then create a texture-set and add to renderer
+  if( texture )
+  {
+    TextureSet textureSet = TextureSet::New();
+    TextureSetImage( textureSet, 0u, texture );
+    renderer.SetTextures( textureSet );
+
+    // Set actor to the size of the texture if set
+    actor.SetSize( texture.GetWidth(), texture.GetHeight() );
+  }
+
+  return actor;
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-actor-utils.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-actor-utils.h
new file mode 100644 (file)
index 0000000..a62dcca
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef DALI_TEST_ACTOR_UTILS_H
+#define DALI_TEST_ACTOR_UTILS_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 <string>
+
+namespace Dali
+{
+
+class Actor;
+class Image;
+
+/**
+ * @brief Creates a simple renderable-actor with solid colored quad.
+ * @return An actor with a renderer.
+ */
+Actor CreateRenderableActor();
+
+/**
+ * @brief Creates a renderable-actor with a texture.
+ * @param[in] texture Texture to set.
+ * @return An actor with a renderer.
+ */
+Actor CreateRenderableActor( Image texture );
+
+/**
+ * @brief Creates a renderable-actor with a texture and custom shaders.
+ * @param[in] texture Texture to set.
+ * @param[in] vertexShader The vertex-shader.
+ * @param[in] fragmentShader The fragment-shader.
+ * @return An actor with a renderer.
+ */
+Actor CreateRenderableActor( Image texture, const std::string& vertexShader, const std::string& fragmentShader );
+
+} // namespace Dali
+
+#endif // DALI_TEST_ACTOR_UTILS_H
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.cpp
new file mode 100644 (file)
index 0000000..f85f14d
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test-application.h"
+
+namespace Dali
+{
+
+bool TestApplication::mLoggingEnabled = true;
+
+TestApplication::TestApplication( uint32_t surfaceWidth,
+                                  uint32_t surfaceHeight,
+                                  uint32_t  horizontalDpi,
+                                  uint32_t  verticalDpi,
+                                  bool initialize )
+: mCore( NULL ),
+  mSurfaceWidth( surfaceWidth ),
+  mSurfaceHeight( surfaceHeight ),
+  mFrame( 0u ),
+  mDpi{ horizontalDpi, verticalDpi },
+  mLastVSyncTime(0u)
+{
+  if( initialize )
+  {
+    Initialize();
+  }
+}
+
+void TestApplication::Initialize()
+{
+  CreateCore();
+  CreateScene();
+  InitializeCore();
+}
+
+void TestApplication::CreateCore()
+{
+  // We always need the first update!
+  mStatus.keepUpdating = Integration::KeepUpdating::STAGE_KEEP_RENDERING;
+
+  mCore = Dali::Integration::Core::New( mRenderController,
+                                        mPlatformAbstraction,
+                                        mGlAbstraction,
+                                        mGlSyncAbstraction,
+                                        mGlContextHelperAbstraction,
+                                        Integration::RenderToFrameBuffer::FALSE,
+                                        Integration::DepthBufferAvailable::TRUE,
+                                        Integration::StencilBufferAvailable::TRUE );
+
+  mCore->ContextCreated();
+
+  Dali::Integration::Log::LogFunction logFunction(&TestApplication::LogMessage);
+  Dali::Integration::Log::InstallLogFunction(logFunction);
+
+  Dali::Integration::Trace::LogContextFunction logContextFunction(&TestApplication::LogContext);
+  Dali::Integration::Trace::InstallLogContextFunction( logContextFunction );
+
+  Dali::Integration::Trace::LogContext( true, "Test" );
+}
+
+void TestApplication::CreateScene()
+{
+  mScene = Dali::Integration::Scene::New( Size( static_cast<float>( mSurfaceWidth ), static_cast<float>( mSurfaceHeight ) ) );
+  mScene.SetDpi( Vector2( static_cast<float>( mDpi.x ), static_cast<float>( mDpi.y ) ) );
+}
+
+void TestApplication::InitializeCore()
+{
+  mCore->SceneCreated();
+  mCore->Initialize();
+}
+
+TestApplication::~TestApplication()
+{
+  Dali::Integration::Log::UninstallLogFunction();
+  delete mCore;
+}
+
+void TestApplication::LogContext( bool start, const char* tag )
+{
+  if( start )
+  {
+    fprintf(stderr, "INFO: Trace Start: %s\n", tag);
+  }
+  else
+  {
+    fprintf(stderr, "INFO: Trace End: %s\n", tag);
+  }
+}
+
+void TestApplication::LogMessage(Dali::Integration::Log::DebugPriority level, std::string& message)
+{
+  if( mLoggingEnabled )
+  {
+    switch(level)
+    {
+      case Dali::Integration::Log::DebugInfo:
+        fprintf(stderr, "INFO: %s", message.c_str());
+        break;
+      case Dali::Integration::Log::DebugWarning:
+        fprintf(stderr, "WARN: %s", message.c_str());
+        break;
+      case Dali::Integration::Log::DebugError:
+        fprintf(stderr, "ERROR: %s", message.c_str());
+        break;
+      default:
+        fprintf(stderr, "DEFAULT: %s", message.c_str());
+        break;
+    }
+  }
+}
+
+Dali::Integration::Core& TestApplication::GetCore()
+{
+  return *mCore;
+}
+
+TestPlatformAbstraction& TestApplication::GetPlatform()
+{
+  return mPlatformAbstraction;
+}
+
+TestRenderController& TestApplication::GetRenderController()
+{
+  return mRenderController;
+}
+
+TestGlAbstraction& TestApplication::GetGlAbstraction()
+{
+  return mGlAbstraction;
+}
+
+TestGlSyncAbstraction& TestApplication::GetGlSyncAbstraction()
+{
+  return mGlSyncAbstraction;
+}
+
+TestGlContextHelperAbstraction& TestApplication::GetGlContextHelperAbstraction()
+{
+  return mGlContextHelperAbstraction;
+}
+
+void TestApplication::ProcessEvent(const Integration::Event& event)
+{
+  mCore->QueueEvent(event);
+  mCore->ProcessEvents();
+}
+
+void TestApplication::SendNotification()
+{
+  mCore->ProcessEvents();
+}
+
+void TestApplication::DoUpdate( uint32_t intervalMilliseconds, const char* location )
+{
+  if( GetUpdateStatus() == 0 &&
+      mRenderStatus.NeedsUpdate() == false &&
+      ! GetRenderController().WasCalled(TestRenderController::RequestUpdateFunc) )
+  {
+    fprintf(stderr, "WARNING - Update not required :%s\n", location==NULL?"NULL":location);
+  }
+
+  uint32_t nextVSyncTime = mLastVSyncTime + intervalMilliseconds;
+  float elapsedSeconds = static_cast<float>( intervalMilliseconds ) * 0.001f;
+
+  mCore->Update( elapsedSeconds, mLastVSyncTime, nextVSyncTime, mStatus, false, false );
+
+  GetRenderController().Initialize();
+
+  mLastVSyncTime = nextVSyncTime;
+}
+
+bool TestApplication::Render( uint32_t intervalMilliseconds, const char* location )
+{
+  DoUpdate( intervalMilliseconds, location );
+
+  mCore->PreRender( mRenderStatus, false /*do not force clear*/, false /*do not skip rendering*/ );
+  mCore->RenderScene( mScene, true /*render the off-screen buffers*/);
+  mCore->RenderScene( mScene, false /*render the surface*/);
+  mCore->PostRender( false /*do not skip rendering*/ );
+
+  mFrame++;
+
+  return mStatus.KeepUpdating() || mRenderStatus.NeedsUpdate();
+}
+
+uint32_t TestApplication::GetUpdateStatus()
+{
+  return mStatus.KeepUpdating();
+}
+
+bool TestApplication::UpdateOnly( uint32_t intervalMilliseconds  )
+{
+  DoUpdate( intervalMilliseconds );
+  return mStatus.KeepUpdating();
+}
+
+bool TestApplication::GetRenderNeedsUpdate()
+{
+  return mRenderStatus.NeedsUpdate();
+}
+
+bool TestApplication::RenderOnly( )
+{
+  // Update Time values
+  mCore->PreRender( mRenderStatus, false /*do not force clear*/, false /*do not skip rendering*/ );
+  mCore->RenderScene( mScene, true /*render the off-screen buffers*/);
+  mCore->RenderScene( mScene, false /*render the surface*/);
+  mCore->PostRender( false /*do not skip rendering*/ );
+
+  mFrame++;
+
+  return mRenderStatus.NeedsUpdate();
+}
+
+void TestApplication::ResetContext()
+{
+  mCore->ContextDestroyed();
+  mGlAbstraction.Initialize();
+  mCore->ContextCreated();
+}
+
+uint32_t TestApplication::Wait( uint32_t durationToWait )
+{
+  int time = 0;
+
+  for(uint32_t i = 0; i <= ( durationToWait / RENDER_FRAME_INTERVAL); i++)
+  {
+    SendNotification();
+    Render(RENDER_FRAME_INTERVAL);
+    time += RENDER_FRAME_INTERVAL;
+  }
+  return time;
+}
+
+} // Namespace dali
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-application.h
new file mode 100644 (file)
index 0000000..a922e23
--- /dev/null
@@ -0,0 +1,115 @@
+#ifndef DALI_TEST_APPLICATION_H
+#define DALI_TEST_APPLICATION_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <test-platform-abstraction.h>
+#include "test-gl-sync-abstraction.h"
+#include "test-gl-abstraction.h"
+#include "test-gl-context-helper-abstraction.h"
+#include "test-render-controller.h"
+#include <dali/public-api/common/dali-common.h>
+#include <dali/integration-api/resource-policies.h>
+#include <dali/integration-api/trace.h>
+#include <dali/integration-api/scene.h>
+
+namespace Dali
+{
+
+class DALI_CORE_API TestApplication : public ConnectionTracker
+{
+public:
+
+  // Default values derived from H2 device.
+  static const uint32_t DEFAULT_SURFACE_WIDTH = 480;
+  static const uint32_t DEFAULT_SURFACE_HEIGHT = 800;
+
+  static constexpr uint32_t DEFAULT_HORIZONTAL_DPI = 220;
+  static constexpr uint32_t DEFAULT_VERTICAL_DPI   = 217;
+
+  static const uint32_t DEFAULT_RENDER_INTERVAL = 1;
+
+  static const uint32_t RENDER_FRAME_INTERVAL = 16;
+
+  TestApplication( uint32_t surfaceWidth  = DEFAULT_SURFACE_WIDTH,
+                   uint32_t surfaceHeight = DEFAULT_SURFACE_HEIGHT,
+                   uint32_t horizontalDpi = DEFAULT_HORIZONTAL_DPI,
+                   uint32_t verticalDpi   = DEFAULT_VERTICAL_DPI,
+                   bool initialize = true );
+
+  void Initialize();
+  void CreateCore();
+  void CreateScene();
+  void InitializeCore();
+  virtual ~TestApplication();
+  static void LogMessage( Dali::Integration::Log::DebugPriority level, std::string& message );
+  static void LogContext( bool start, const char* tag );
+  Dali::Integration::Core& GetCore();
+  TestPlatformAbstraction& GetPlatform();
+  TestRenderController& GetRenderController();
+  TestGlAbstraction& GetGlAbstraction();
+  TestGlSyncAbstraction& GetGlSyncAbstraction();
+  TestGlContextHelperAbstraction& GetGlContextHelperAbstraction();
+  void ProcessEvent(const Integration::Event& event);
+  void SendNotification();
+  bool Render( uint32_t intervalMilliseconds = DEFAULT_RENDER_INTERVAL, const char* location=NULL );
+  uint32_t GetUpdateStatus();
+  bool UpdateOnly( uint32_t intervalMilliseconds = DEFAULT_RENDER_INTERVAL );
+  bool RenderOnly( );
+  void ResetContext();
+  bool GetRenderNeedsUpdate();
+  uint32_t Wait( uint32_t durationToWait );
+  static void EnableLogging( bool enabled )
+  {
+    mLoggingEnabled = enabled;
+  }
+
+  Integration::Scene GetScene() const
+  {
+    return mScene;
+  }
+
+private:
+  void DoUpdate( uint32_t intervalMilliseconds, const char* location=NULL );
+
+protected:
+  TestPlatformAbstraction   mPlatformAbstraction;
+  TestRenderController      mRenderController;
+  TestGlAbstraction         mGlAbstraction;
+  TestGlSyncAbstraction     mGlSyncAbstraction;
+  TestGlContextHelperAbstraction mGlContextHelperAbstraction;
+
+  Integration::UpdateStatus mStatus;
+  Integration::RenderStatus mRenderStatus;
+
+  Integration::Core* mCore;
+  Dali::Integration::Scene mScene;
+
+  uint32_t mSurfaceWidth;
+  uint32_t mSurfaceHeight;
+  uint32_t mFrame;
+
+  struct { uint32_t x; uint32_t y; } mDpi;
+  uint32_t mLastVSyncTime;
+  static bool mLoggingEnabled;
+};
+
+} // Dali
+
+#endif // DALI_TEST_APPLICATION_H
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-compare-types.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-compare-types.h
new file mode 100644 (file)
index 0000000..5870028
--- /dev/null
@@ -0,0 +1,223 @@
+#ifndef DALI_TEST_COMPARE_TYPES_H
+#define DALI_TEST_COMPARE_TYPES_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/dali-core.h>
+using namespace Dali;
+
+
+template <typename Type>
+inline bool CompareType(Type value1, Type value2, float epsilon)
+{
+  return value1 == value2;
+}
+
+/**
+ * A helper for fuzzy-comparing Vector2 objects
+ * @param[in] vector1 the first object
+ * @param[in] vector2 the second object
+ * @param[in] epsilon difference threshold
+ * @returns true if difference is smaller than epsilon threshold, false otherwise
+ */
+template <>
+inline bool CompareType<float>(float value1, float value2, float epsilon)
+{
+  return fabsf(value1 - value2) < epsilon;
+}
+
+/**
+ * A helper for fuzzy-comparing Vector2 objects
+ * @param[in] vector1 the first object
+ * @param[in] vector2 the second object
+ * @param[in] epsilon difference threshold
+ * @returns true if difference is smaller than epsilon threshold, false otherwise
+ */
+template <>
+inline bool CompareType<Vector2>(Vector2 vector1, Vector2 vector2, float epsilon)
+{
+  return fabsf(vector1.x - vector2.x)<epsilon && fabsf(vector1.y - vector2.y)<epsilon;
+}
+
+/**
+ * A helper for fuzzy-comparing Vector3 objects
+ * @param[in] vector1 the first object
+ * @param[in] vector2 the second object
+ * @param[in] epsilon difference threshold
+ * @returns true if difference is smaller than epsilon threshold, false otherwise
+ */
+template <>
+inline bool CompareType<Vector3>(Vector3 vector1, Vector3 vector2, float epsilon)
+{
+  return fabsf(vector1.x - vector2.x)<epsilon &&
+         fabsf(vector1.y - vector2.y)<epsilon &&
+         fabsf(vector1.z - vector2.z)<epsilon;
+}
+
+
+/**
+ * A helper for fuzzy-comparing Vector4 objects
+ * @param[in] vector1 the first object
+ * @param[in] vector2 the second object
+ * @param[in] epsilon difference threshold
+ * @returns true if difference is smaller than epsilon threshold, false otherwise
+ */
+template <>
+inline bool CompareType<Vector4>(Vector4 vector1, Vector4 vector2, float epsilon)
+{
+  return fabsf(vector1.x - vector2.x)<epsilon &&
+         fabsf(vector1.y - vector2.y)<epsilon &&
+         fabsf(vector1.z - vector2.z)<epsilon &&
+         fabsf(vector1.w - vector2.w)<epsilon;
+}
+
+template <>
+inline bool CompareType<Quaternion>(Quaternion q1, Quaternion q2, float epsilon)
+{
+  Quaternion q2N = -q2; // These quaternions represent the same rotation
+  return CompareType<Vector4>(q1.mVector, q2.mVector, epsilon) || CompareType<Vector4>(q1.mVector, q2N.mVector, epsilon);
+}
+
+template <>
+inline bool CompareType<Radian>(Radian q1, Radian q2, float epsilon)
+{
+  return CompareType<float>(q1.radian, q2.radian, epsilon);
+}
+
+template <>
+inline bool CompareType<Degree>(Degree q1, Degree q2, float epsilon)
+{
+  return CompareType<float>(q1.degree, q2.degree, epsilon);
+}
+
+template <>
+inline bool CompareType<Extents>(Extents extents1, Extents extents2, float epsilon)
+{
+  return (extents1.start == extents2.start) &&
+         (extents1.end == extents2.end) &&
+         (extents1.top == extents2.top) &&
+         (extents1.bottom == extents2.bottom);
+}
+
+template <>
+inline bool CompareType<Property::Value>(Property::Value q1, Property::Value q2, float epsilon)
+{
+  Property::Type type = q1.GetType();
+  if( type != q2.GetType() )
+  {
+    return false;
+  }
+
+  bool result = false;
+  switch(type)
+  {
+    case Property::BOOLEAN:
+    {
+      bool a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result =  a == b;
+      break;
+    }
+    case Property::INTEGER:
+    {
+      int a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result =  a == b;
+      break;
+    }
+    case Property::FLOAT:
+    {
+      float a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result =  CompareType<float>(a, b, epsilon);
+      break;
+    }
+    case Property::VECTOR2:
+    {
+      Vector2 a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result = CompareType<Vector2>(a, b, epsilon);
+      break;
+    }
+    case Property::VECTOR3:
+    {
+      Vector3 a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result = CompareType<Vector3>(a, b, epsilon);
+      break;
+    }
+    case Property::RECTANGLE:
+    case Property::VECTOR4:
+    {
+      Vector4 a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result = CompareType<Vector4>(a, b, epsilon);
+      break;
+    }
+    case Property::ROTATION:
+    {
+      Quaternion a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result = CompareType<Quaternion>(a, b, epsilon);
+      break;
+    }
+    case Property::STRING:
+    {
+      std::string a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result = (a.compare(b) == 0);
+      break;
+    }
+    case Property::MATRIX:
+    case Property::MATRIX3:
+    case Property::ARRAY:
+    case Property::MAP:
+    {
+      //TODO: Implement this?
+      DALI_ASSERT_ALWAYS( 0 && "Not implemented");
+      result = false;
+      break;
+    }
+    case Property::EXTENTS:
+    {
+      Extents a, b;
+      q1.Get(a);
+      q2.Get(b);
+      result = CompareType<Extents>( a, b, epsilon );
+      break;
+    }
+    case Property::NONE:
+    {
+      result = false;
+      break;
+    }
+  }
+
+  return result;
+}
+
+
+
+#endif
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gesture-generator.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gesture-generator.cpp
new file mode 100644 (file)
index 0000000..c0b55ce
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test-gesture-generator.h"
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/events/touch-event-integ.h>
+
+namespace
+{
+const uint32_t RENDER_FRAME_INTERVAL = 16;                           ///< Duration of each frame in ms. (at approx 60FPS)
+
+Integration::TouchEvent GenerateSingleTouch( PointState::Type state, const Vector2& screenPosition, uint32_t time )
+{
+  Integration::TouchEvent touchEvent;
+  Integration::Point point;
+  point.SetState( state );
+  point.SetDeviceId(4);
+  point.SetScreenPosition( screenPosition );
+  point.SetDeviceClass( Device::Class::TOUCH );
+  point.SetDeviceSubclass( Device::Subclass::NONE );
+  touchEvent.points.push_back( point );
+  touchEvent.time = time;
+  return touchEvent;
+}
+
+Integration::TouchEvent GenerateDoubleTouch( PointState::Type stateA, const Vector2& screenPositionA, PointState::Type stateB, const Vector2& screenPositionB, uint32_t time )
+{
+  Integration::TouchEvent touchEvent;
+  Integration::Point point;
+  point.SetState( stateA );
+  point.SetDeviceId(4);
+  point.SetScreenPosition( screenPositionA );
+  point.SetDeviceClass( Device::Class::TOUCH );
+  point.SetDeviceSubclass( Device::Subclass::NONE );
+  touchEvent.points.push_back( point );
+  point.SetScreenPosition( screenPositionB );
+  point.SetState( stateB);
+  point.SetDeviceId(7);
+  touchEvent.points.push_back( point );
+  touchEvent.time = time;
+  return touchEvent;
+}
+} // namespace
+
+namespace Dali
+{
+uint32_t TestGetFrameInterval()
+{
+  return RENDER_FRAME_INTERVAL;
+}
+
+void TestStartLongPress( TestApplication& application, float x, float y, uint32_t time )
+{
+  application.ProcessEvent( GenerateSingleTouch( PointState::DOWN, Vector2( x, y ), time ) );
+}
+
+void TestTriggerLongPress( TestApplication& application )
+{
+  application.GetPlatform().TriggerTimer();
+}
+
+void TestGenerateLongPress( TestApplication& application, float x, float y, uint32_t time )
+{
+  TestStartLongPress( application, x, y, time );
+  TestTriggerLongPress( application );
+}
+
+void TestEndLongPress( TestApplication& application, float x, float y, uint32_t time )
+{
+  application.ProcessEvent( GenerateSingleTouch( PointState::UP, Vector2( x, y ), time ) );
+}
+
+void TestGeneratePinch( TestApplication& application)
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::DOWN, Vector2( 20.0f, 20.0f ), PointState::DOWN, Vector2( 20.0f, 90.0f ), 150 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 28.0f ), PointState::MOTION, Vector2( 20.0f, 82.0f ), 160 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 37.0f ), PointState::MOTION, Vector2( 20.0f, 74.0f ), 170 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 46.0f ), PointState::MOTION, Vector2( 20.0f, 66.0f ), 180 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 55.0f ), PointState::MOTION, Vector2( 20.0f, 58.0f ), 190 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::UP, Vector2( 20.0f, 55.0f ), PointState::UP, Vector2( 20.0f, 58.0f ), 200 ) );
+}
+
+void TestStartPinch( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time )
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::DOWN, a1, PointState::DOWN, b1, time ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 50 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 100 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 150 ) );
+}
+
+void TestContinuePinch( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time )
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a1, PointState::MOTION, b1, time ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a1, PointState::MOTION, b1, time + 50 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 100 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time +150 ) );
+}
+
+void TestEndPinch( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time )
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a1, PointState::MOTION, b1, time ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::UP, a2, PointState::UP, b2, time +50 ) );
+}
+
+void TestGenerateMiniPan( TestApplication& application)
+{
+  application.ProcessEvent( GenerateSingleTouch( PointState::DOWN, Vector2( 20.0f, 20.0f ), 250 ) );
+  application.ProcessEvent( GenerateSingleTouch( PointState::MOTION, Vector2( 20.0f, 40.0f ), 251 ) );
+  application.ProcessEvent( GenerateSingleTouch( PointState::UP, Vector2( 20.0f, 40.0f ), 255 ) );
+}
+
+void TestStartPan( TestApplication& application, Vector2 start, Vector2 end, uint32_t& time )
+{
+  application.ProcessEvent( GenerateSingleTouch( PointState::DOWN, start, time ) );
+
+  time += RENDER_FRAME_INTERVAL;
+
+  application.ProcessEvent( GenerateSingleTouch( PointState::MOTION, end, time ) );
+
+  time += RENDER_FRAME_INTERVAL;
+
+  application.ProcessEvent( GenerateSingleTouch( PointState::MOTION, end, time ) );
+
+  time += RENDER_FRAME_INTERVAL;
+}
+
+void TestMovePan( TestApplication& application, Vector2 pos, uint32_t time )
+{
+  application.ProcessEvent( GenerateSingleTouch( PointState::MOTION, pos, time ) );
+}
+
+void TestEndPan( TestApplication& application, Vector2 pos, uint32_t time )
+{
+  application.ProcessEvent( GenerateSingleTouch( PointState::UP, pos, time ) );
+}
+
+void TestGenerateTap( TestApplication& application, float x, float y, uint32_t time_down )
+{
+  application.ProcessEvent( GenerateSingleTouch( PointState::DOWN, Vector2( x, y ), time_down ) );
+  application.ProcessEvent( GenerateSingleTouch( PointState::UP, Vector2( x, y ), time_down + 20 ) );
+}
+
+void TestGenerateTwoPointTap( TestApplication& application, float x1, float y1, float x2, float y2, uint32_t time_down )
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::DOWN, Vector2( x1, y1 ), PointState::DOWN, Vector2( x2, y2 ), time_down ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::UP, Vector2( x1, y1 ), PointState::UP, Vector2( x2, y2 ), time_down + 20 ) );
+}
+
+void TestGenerateRotation( TestApplication& application )
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::DOWN, Vector2( 20.0f, 20.0f ), PointState::DOWN, Vector2( 20.0f, 90.0f ), 150 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 20.0f ), PointState::MOTION, Vector2( 25.0f, 95.0f ), 160 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 20.0f ), PointState::MOTION, Vector2( 30.0f, 100.0f ), 170 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 20.0f ), PointState::MOTION, Vector2( 35.0f, 105.0f ), 180 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, Vector2( 20.0f, 20.0f ), PointState::MOTION, Vector2( 40.0f, 110.0f ), 190 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::UP, Vector2( 20.0f, 20.0f ), PointState::UP, Vector2( 45.0f, 115.0f ), 200 ) );
+}
+
+void TestStartRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time )
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::DOWN, a1, PointState::DOWN, b1, time ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 50 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 100 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 150 ) );
+}
+
+void TestContinueRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time )
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a1, PointState::MOTION, b1, time ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a1, PointState::MOTION, b1, time + 50 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time + 100 ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a2, PointState::MOTION, b2, time +150 ) );
+}
+
+void TestEndRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time )
+{
+  application.ProcessEvent( GenerateDoubleTouch( PointState::MOTION, a1, PointState::MOTION, b1, time ) );
+  application.ProcessEvent( GenerateDoubleTouch( PointState::UP, a2, PointState::UP, b2, time +50 ) );
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gesture-generator.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gesture-generator.h
new file mode 100644 (file)
index 0000000..18051cf
--- /dev/null
@@ -0,0 +1,128 @@
+#ifndef DALI_TEST_GESTURE_GENERATOR_H
+#define DALI_TEST_GESTURE_GENERATOR_H
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test-application.h"
+
+namespace Dali
+{
+/**
+ * These functions use touch events to trigger a gesture, assuming the default gesture parameters are used
+ */
+
+/**
+ * Returns the frame interval used in ms
+ */
+uint32_t TestGetFrameInterval();
+
+/**
+ * Produces the initial touch of a long press
+ */
+void TestStartLongPress( TestApplication& application, float x = 20.0f, float y = 20.0f, uint32_t time = 450 );
+
+/**
+ * Triggers the timer to begin a long press gesture
+ */
+void TestTriggerLongPress( TestApplication& application );
+
+/**
+ * Produces the initial press and triggers the timer to begin a long press gesture
+ */
+void TestGenerateLongPress( TestApplication& application, float x = 20.0f, float y = 20.0f, uint32_t time = 450 );
+
+/**
+ * End a long press by lifting the touch
+ */
+void TestEndLongPress( TestApplication& application, float x = 20.0f, float y = 20.0f, uint32_t time = 450 );
+
+/**
+ * Produces a vertical pinch gesture between (20,20) and (20,90)
+ */
+void TestGeneratePinch( TestApplication& application );
+
+/**
+ * Produces the gesture started event of a pinch, using 4 touches, 50ms apart, starting with 1, ending at 2
+ */
+void TestStartPinch( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time );
+
+/**
+ * Produces a gesture continuing event of a pinch, using 4 touches, 50ms apart, starting with 1, ending at 2
+ */
+void TestContinuePinch( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time );
+
+/**
+ * Produces a gesture finished event of a pinch, using 2 touches, 50ms apart
+ */
+void TestEndPinch( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time );
+
+/**
+ * Produces a pan gesture from (20,20) to (20,40)
+ */
+void TestGenerateMiniPan( TestApplication& application );
+
+/**
+ * Produces the start event of a pan gesture, assuming minimum distance moved between start and end is greater than 15
+ * in either direction or 11 in both (x&y). Time will be incremented using the standard frame interval per touch movement
+ */
+void TestStartPan( TestApplication& application, Vector2 start, Vector2 end, uint32_t& time );
+
+/**
+ * Continues a pan event by creating a single touch at pos.
+ * N.B This does not increment the time
+ */
+void TestMovePan( TestApplication& application, Vector2 pos, uint32_t time = 400);
+
+/**
+ * End a pan gesture at position pos
+ */
+void TestEndPan( TestApplication& application, Vector2 pos, uint32_t time = 500);
+
+/**
+ * Produces a single point tap gesture with a 20ms interval
+ */
+void TestGenerateTap( TestApplication& application, float x = 20.0f, float y = 20.0f, uint32_t time_down = 100 );
+
+/**
+ * Produce a tap gesture with two touch points and a 20ms interval
+ */
+void TestGenerateTwoPointTap( TestApplication& application, float x1, float y1, float x2, float y2, uint32_t time_down );
+
+/**
+ * Produces a rotation gesture.
+ */
+void TestGenerateRotation( TestApplication& application );
+
+/**
+ * Produces the gesture started event of a rotation, using 4 touches, 50ms apart, starting with 1, ending at 2
+ */
+void TestStartRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time );
+
+/**
+ * Produces a gesture continuing event of a rotation, using 4 touches, 50ms apart, starting with 1, ending at 2
+ */
+void TestContinueRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time );
+
+/**
+ * Produces a gesture finished event of a rotation, using 2 touches, 50ms apart
+ */
+void TestEndRotation( TestApplication& application, Vector2 a1, Vector2 b1, Vector2 a2, Vector2 b2, uint32_t time );
+
+} // namespace Dali
+
+#endif // DALI_TEST_GESTURE_GENERATOR_H
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.cpp
new file mode 100644 (file)
index 0000000..98a2fa5
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test-gl-abstraction.h"
+
+namespace Dali
+{
+
+TestGlAbstraction::TestGlAbstraction()
+{
+  Initialize();
+}
+
+TestGlAbstraction::~TestGlAbstraction() {}
+
+void TestGlAbstraction::Initialize()
+{
+  mCurrentProgram = 0;
+  mCompileStatus = GL_TRUE;
+  mLinkStatus = GL_TRUE;
+  mNumberOfActiveUniforms = 0;
+  mGetAttribLocationResult = 0;
+  mGetErrorResult = 0;
+  mGetStringResult = NULL;
+  mIsBufferResult = 0;
+  mIsEnabledResult = 0;
+  mIsFramebufferResult = 0;
+  mIsProgramResult = 0;
+  mIsRenderbufferResult = 0;
+  mIsShaderResult = 0;
+  mIsTextureResult = 0;
+  mActiveTextureUnit = 0;
+  mCheckFramebufferStatusResult = 0;
+  mFramebufferStatus = 0;
+  mFramebufferDepthAttached = 0;
+  mFramebufferStencilAttached = 0;
+  mFramebufferColorAttachmentCount = 0;
+  mFrameBufferColorStatus = 0;
+  mNumBinaryFormats = 0;
+  mBinaryFormats = 0;
+  mProgramBinaryLength = 0;
+
+  mVertexAttribArrayChanged = false;
+  mGetProgramBinaryCalled = false;
+
+  mLastShaderCompiled = 0;
+  mLastClearBitMask = 0;
+  mLastClearColor = Color::TRANSPARENT;
+  mClearCount = 0;
+
+  mLastBlendEquationRgb   = 0;
+  mLastBlendEquationAlpha = 0;
+  mLastBlendFuncSrcRgb    = 0;
+  mLastBlendFuncDstRgb    = 0;
+  mLastBlendFuncSrcAlpha  = 0;
+  mLastBlendFuncDstAlpha  = 0;
+  mLastAutoTextureIdUsed = 0;
+  mNumGeneratedTextures = 0;
+  mLastShaderIdUsed = 0;
+  mLastProgramIdUsed = 0;
+  mLastUniformIdUsed = 0;
+  mLastDepthMask = false;
+
+  mUniforms.clear();
+  mProgramUniforms1i.clear();
+  mProgramUniforms1f.clear();
+  mProgramUniforms2f.clear();
+  mProgramUniforms3f.clear();
+  mProgramUniforms4f.clear();
+
+  mCullFaceTrace.Reset();
+  mDepthFunctionTrace.Reset();
+  mEnableDisableTrace.Reset();
+  mShaderTrace.Reset();
+  mStencilFunctionTrace.Reset();
+  mScissorTrace.Reset();
+  mTextureTrace.Reset();
+  mTexParamaterTrace.Reset();
+  mDrawTrace.Reset();
+
+  for( unsigned int i=0; i<MAX_ATTRIBUTE_CACHE_SIZE; ++i )
+  {
+    mVertexAttribArrayState[i] = false;
+  }
+}
+
+void TestGlAbstraction::PreRender()
+{
+}
+
+void TestGlAbstraction::PostRender()
+{
+}
+
+bool TestGlAbstraction::IsSurfacelessContextSupported() const
+{
+  return true;
+}
+
+bool TestGlAbstraction::TextureRequiresConverting( const GLenum imageGlFormat, const GLenum textureGlFormat, const bool isSubImage ) const
+{
+  return ( ( imageGlFormat == GL_RGB ) && ( textureGlFormat == GL_RGBA ) );
+}
+
+} // Namespace dali
+
+bool BlendEnabled(const Dali::TraceCallStack& callStack)
+{
+  std::stringstream out;
+  out << GL_BLEND;
+  bool blendEnabled = callStack.FindMethodAndParams( "Enable", out.str() );
+  return blendEnabled;
+}
+
+bool BlendDisabled(const Dali::TraceCallStack& callStack)
+{
+  std::stringstream out;
+  out << GL_BLEND;
+  bool blendEnabled = callStack.FindMethodAndParams( "Disable", out.str() );
+  return blendEnabled;
+}
+
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-abstraction.h
new file mode 100644 (file)
index 0000000..9f458fc
--- /dev/null
@@ -0,0 +1,2417 @@
+#ifndef TEST_GL_ABSTRACTION_H
+#define TEST_GL_ABSTRACTION_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <string>
+#include <cstring>
+#include <map>
+#include <cstdio>
+#include <cstring> // for strcmp
+#include <typeinfo>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-core.h>
+#include <dali/devel-api/rendering/frame-buffer-devel.h>
+#include <dali/integration-api/core.h>
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/integration-api/gl-defines.h>
+#include <test-trace-call-stack.h>
+#include <test-compare-types.h>
+
+namespace Dali
+{
+
+static const unsigned int MAX_ATTRIBUTE_CACHE_SIZE = 64;
+static const char *mStdAttribs[MAX_ATTRIBUTE_CACHE_SIZE] =
+{
+    "aPosition",    // ATTRIB_POSITION
+    "aNormal",      // ATTRIB_NORMAL
+    "aTexCoord",    // ATTRIB_TEXCOORD
+    "aColor",       // ATTRIB_COLOR
+    "aBoneWeights", // ATTRIB_BONE_WEIGHTS
+    "aBoneIndices"  // ATTRIB_BONE_INDICES
+};
+
+class DALI_CORE_API TestGlAbstraction: public Dali::Integration::GlAbstraction
+{
+public:
+  TestGlAbstraction();
+  ~TestGlAbstraction();
+  void Initialize();
+
+  void PreRender();
+  void PostRender();
+
+  bool IsSurfacelessContextSupported() const;
+
+  bool TextureRequiresConverting( const GLenum imageGlFormat, const GLenum textureGlFormat, const bool isSubImage ) const;
+
+  /* OpenGL ES 2.0 */
+
+  inline void ActiveTexture( GLenum textureUnit )
+  {
+    mActiveTextureUnit = textureUnit - GL_TEXTURE0;
+  }
+
+  inline GLenum GetActiveTextureUnit() const
+  {
+    return mActiveTextureUnit + GL_TEXTURE0;
+  }
+
+  inline void AttachShader( GLuint program, GLuint shader )
+  {
+    std::stringstream out;
+    out << program << ", " << shader;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["program"] = ToString(program);
+    namedParams["shader"] = ToString(shader);
+    mShaderTrace.PushCall("AttachShader", out.str(), namedParams);
+  }
+
+  inline void BindAttribLocation( GLuint program, GLuint index, const char* name )
+  {
+  }
+
+  inline void BindBuffer( GLenum target, GLuint buffer )
+  {
+  }
+
+  inline void BindFramebuffer( GLenum target, GLuint framebuffer )
+  {
+    //Add 010 bit;
+    mFramebufferStatus |= 2;
+  }
+
+  inline void BindRenderbuffer( GLenum target, GLuint renderbuffer )
+  {
+  }
+
+  /**
+   * This method can be used by test cases, to query the texture IDs that have been bound by BindTexture.
+   * @return A vector containing the IDs that were bound.
+   */
+  inline const std::vector<GLuint>& GetBoundTextures() const
+  {
+    return mBoundTextures;
+  }
+
+  /**
+   * Query the texture IDs that have been bound with BindTexture, with a specific active texture unit.
+   * @param[in] activeTextureUnit The specific active texture unit.
+   * @return A vector containing the IDs that were bound.
+   */
+  inline const std::vector<GLuint>& GetBoundTextures( GLuint activeTextureUnit ) const
+  {
+    return mActiveTextures[ activeTextureUnit - GL_TEXTURE0 ].mBoundTextures;
+  }
+
+  /**
+   * This method can be used by test cases, to clear the record of texture IDs that have been bound by BindTexture.
+   */
+  inline void ClearBoundTextures()
+  {
+    mBoundTextures.clear();
+
+    for( unsigned int i=0; i<MIN_TEXTURE_UNIT_LIMIT; ++i )
+    {
+      mActiveTextures[ i ].mBoundTextures.clear();
+    }
+  }
+
+  inline void BindTexture( GLenum target, GLuint texture )
+  {
+    // Record the bound textures for future checks
+    if( texture )
+    {
+      mBoundTextures.push_back( texture );
+
+      if( mActiveTextureUnit < MIN_TEXTURE_UNIT_LIMIT )
+      {
+        mActiveTextures[ mActiveTextureUnit ].mBoundTextures.push_back( texture );
+      }
+    }
+
+    std::stringstream out;
+    out << target << ", " << texture;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["texture"] = ToString(texture);
+
+    mTextureTrace.PushCall("BindTexture", out.str(), namedParams);
+  }
+
+  inline void BlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+  {
+    mLastBlendColor.r = red;
+    mLastBlendColor.g = green;
+    mLastBlendColor.b = blue;
+    mLastBlendColor.a = alpha;
+  }
+
+  inline const Vector4& GetLastBlendColor() const
+  {
+    return mLastBlendColor;
+  }
+
+  inline void BlendEquation( GLenum mode )
+  {
+    mLastBlendEquationRgb   = mode;
+    mLastBlendEquationAlpha = mode;
+  }
+
+  inline void BlendEquationSeparate( GLenum modeRgb, GLenum modeAlpha )
+  {
+    mLastBlendEquationRgb   = modeRgb;
+    mLastBlendEquationAlpha = modeAlpha;
+  }
+
+  inline GLenum GetLastBlendEquationRgb() const
+  {
+    return mLastBlendEquationRgb;
+  }
+
+  inline GLenum GetLastBlendEquationAlpha() const
+  {
+    return mLastBlendEquationAlpha;
+  }
+
+  inline void BlendFunc(GLenum sfactor, GLenum dfactor)
+  {
+    mLastBlendFuncSrcRgb = sfactor;
+    mLastBlendFuncDstRgb = dfactor;
+    mLastBlendFuncSrcAlpha = sfactor;
+    mLastBlendFuncDstAlpha = dfactor;
+  }
+
+  inline void BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
+  {
+    mLastBlendFuncSrcRgb = srcRGB;
+    mLastBlendFuncDstRgb = dstRGB;
+    mLastBlendFuncSrcAlpha = srcAlpha;
+    mLastBlendFuncDstAlpha = dstAlpha;
+  }
+
+  inline GLenum GetLastBlendFuncSrcRgb() const
+  {
+    return mLastBlendFuncSrcRgb;
+  }
+
+  inline GLenum GetLastBlendFuncDstRgb() const
+  {
+    return mLastBlendFuncDstRgb;
+  }
+
+  inline GLenum GetLastBlendFuncSrcAlpha() const
+  {
+    return mLastBlendFuncSrcAlpha;
+  }
+
+  inline GLenum GetLastBlendFuncDstAlpha() const
+  {
+    return mLastBlendFuncDstAlpha;
+  }
+
+  inline void BufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage)
+  {
+     mBufferDataCalls.push_back(size);
+  }
+
+  inline void BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data)
+  {
+     mBufferSubDataCalls.push_back(size);
+  }
+
+  inline GLenum CheckFramebufferStatus(GLenum target)
+  {
+    //If it has the three last bits set to 1 - 111, then the three minimum functions to create a
+    //Framebuffer texture have been called
+    if( mFramebufferStatus == 7 )
+    {
+      return GL_FRAMEBUFFER_COMPLETE;
+    }
+
+    return mCheckFramebufferStatusResult;
+  }
+
+  inline GLuint CheckFramebufferColorAttachmentCount()
+  {
+    return mFramebufferColorAttachmentCount;
+  }
+
+  inline GLenum CheckFramebufferDepthAttachment()
+  {
+    return mFramebufferDepthAttached;
+  }
+
+  inline GLenum CheckFramebufferStencilAttachment()
+  {
+    return mFramebufferStencilAttached;
+  }
+
+  inline void Clear(GLbitfield mask)
+  {
+    mClearCount++;
+    mLastClearBitMask = mask;
+  }
+
+  inline void ClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+  {
+    mLastClearColor.r = red;
+    mLastClearColor.g = green;
+    mLastClearColor.b = blue;
+    mLastClearColor.a = alpha;
+  }
+
+  inline const Vector4& GetLastClearColor() const
+  {
+    return mLastClearColor;
+  }
+
+  inline void ClearDepthf(GLclampf depth)
+  {
+  }
+
+  inline void ClearStencil(GLint s)
+  {
+    std::stringstream out;
+    out << s;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["s"] = ToString( s );
+
+    mStencilFunctionTrace.PushCall( "ClearStencil", out.str(), namedParams );
+  }
+
+  inline void ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+  {
+    mColorMaskParams.red = red;
+    mColorMaskParams.green = green;
+    mColorMaskParams.blue = blue;
+    mColorMaskParams.alpha = alpha;
+  }
+
+  inline void CompileShader(GLuint shader)
+  {
+    std::stringstream out;
+    out << shader;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["shader"] = ToString(shader);
+
+    mShaderTrace.PushCall("CompileShader", out.str(), namedParams);
+  }
+
+  inline void CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data)
+  {
+    std::stringstream out;
+    out << target<<", "<<level<<", "<<width << ", " << height;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["level"] = ToString(level);
+    namedParams["internalformat"] = ToString(internalformat);
+    namedParams["width"] = ToString(width);
+    namedParams["height"] = ToString(height);
+    namedParams["border"] = ToString(border);
+    namedParams["size"] = ToString(imageSize);
+
+    mTextureTrace.PushCall("CompressedTexImage2D", out.str(), namedParams);
+  }
+
+  inline void CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data)
+  {
+    std::stringstream out;
+    out << target << ", "<<level <<", " << xoffset << ", " << yoffset << ", " << width << ", " << height;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["level"] = ToString(level);
+    namedParams["xoffset"] = ToString(xoffset);
+    namedParams["yoffset"] = ToString(yoffset);
+    namedParams["width"] = ToString(width);
+    namedParams["height"] = ToString(height);
+    mTextureTrace.PushCall("CompressedTexSubImage2D", out.str(), namedParams);
+  }
+
+  inline void CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+  {
+  }
+
+  inline void CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline GLuint CreateProgram(void)
+  {
+    mShaderTrace.PushCall("CreateProgram", "");
+
+    ++mLastProgramIdUsed;
+    mUniforms[mLastProgramIdUsed] = UniformIDMap();
+    return mLastProgramIdUsed;
+  }
+
+  inline GLuint CreateShader(GLenum type)
+  {
+    std::stringstream out;
+    out << type;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["type"] = ToString(type);
+    mShaderTrace.PushCall("CreateShader", out.str(), namedParams);
+
+    return ++mLastShaderIdUsed;
+  }
+
+  inline void CullFace(GLenum mode)
+  {
+    std::stringstream out;
+    out << mode;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["program"] = ToString(mode);
+
+    mCullFaceTrace.PushCall("CullFace", out.str(), namedParams);
+  }
+
+  inline void DeleteBuffers(GLsizei n, const GLuint* buffers)
+  {
+  }
+
+  inline void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
+  {
+  }
+
+  inline void DeleteProgram(GLuint program)
+  {
+    std::stringstream out;
+    out << program;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["program"] = ToString(program);
+
+    mShaderTrace.PushCall("DeleteProgram", out.str(), namedParams);
+  }
+
+  inline void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
+  {
+  }
+
+  inline void DeleteShader(GLuint shader)
+  {
+    std::stringstream out;
+    out << shader;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["shader"] = ToString(shader);
+
+    mShaderTrace.PushCall("DeleteShader", out.str(), namedParams);
+  }
+
+  inline void DeleteTextures(GLsizei n, const GLuint* textures)
+  {
+    std::stringstream out;
+    out << n << ", " << textures << " = [";
+
+    TraceCallStack::NamedParams namedParams;
+
+    for(GLsizei i=0; i<n; i++)
+    {
+      out << textures[i] << ", ";
+      std::stringstream paramName;
+      paramName<<"texture["<<i<<"]";
+      namedParams[paramName.str()] = ToString(textures[i]);
+      mDeletedTextureIds.push_back(textures[i]);
+      mNumGeneratedTextures--;
+    }
+    out << "]";
+
+    mTextureTrace.PushCall("DeleteTextures", out.str(), namedParams);
+  }
+
+  inline bool CheckNoTexturesDeleted()
+  {
+    return mDeletedTextureIds.size() == 0;
+  }
+
+  inline bool CheckTextureDeleted( GLuint textureId )
+  {
+    bool found = false;
+
+    for(std::vector<GLuint>::iterator iter=mDeletedTextureIds.begin(); iter != mDeletedTextureIds.end(); ++iter)
+    {
+      if(*iter == textureId)
+      {
+        found = true;
+        break;
+      }
+    }
+    return found;
+  }
+
+  inline void ClearDeletedTextures()
+  {
+    mDeletedTextureIds.clear();
+  }
+
+  inline void DepthFunc(GLenum func)
+  {
+    std::stringstream out;
+    out << func;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["func"] = ToString(func);
+
+    mDepthFunctionTrace.PushCall("DepthFunc", out.str(), namedParams);
+  }
+
+  inline void DepthMask(GLboolean flag)
+  {
+    mLastDepthMask = flag;
+  }
+
+  inline bool GetLastDepthMask() const
+  {
+    return mLastDepthMask;
+  }
+
+  inline void DepthRangef(GLclampf zNear, GLclampf zFar)
+  {
+  }
+
+  inline void DetachShader(GLuint program, GLuint shader)
+  {
+    std::stringstream out;
+    out << program << ", " << shader;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["program"] = ToString(program);
+    namedParams["shader"] = ToString(shader);
+    mShaderTrace.PushCall("DetachShader", out.str(), namedParams);
+  }
+
+  inline void Disable(GLenum cap)
+  {
+    std::stringstream out;
+    out << cap;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["cap"] = ToString(cap);
+    mEnableDisableTrace.PushCall("Disable", out.str(), namedParams);
+  }
+
+  inline void DisableVertexAttribArray(GLuint index)
+  {
+    SetVertexAttribArray( index, false );
+  }
+
+  inline void DrawArrays(GLenum mode, GLint first, GLsizei count)
+  {
+    std::stringstream out;
+    out << mode << ", " << first << ", " << count;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["mode"] = ToString(mode);
+    namedParams["first"] = ToString(first);
+    namedParams["count"] = ToString(count);
+    mDrawTrace.PushCall("DrawArrays", out.str(), namedParams);
+  }
+
+  inline void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices)
+  {
+    std::stringstream out;
+    out << mode << ", " << count << ", " << type << ", indices";
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["mode"] = ToString(mode);
+    namedParams["count"] = ToString(count);
+    namedParams["type"] = ToString(type);
+    // Skip void pointers - are they of any use?
+    mDrawTrace.PushCall("DrawElements", out.str(), namedParams);
+  }
+
+  inline void Enable(GLenum cap)
+  {
+    std::stringstream out;
+    out << cap;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["cap"] = ToString(cap);
+    mEnableDisableTrace.PushCall("Enable", out.str(), namedParams);
+  }
+
+  inline void EnableVertexAttribArray(GLuint index)
+  {
+    SetVertexAttribArray( index, true);
+  }
+
+  inline void Finish(void)
+  {
+  }
+
+  inline void Flush(void)
+  {
+  }
+
+  inline void FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+  {
+    if (attachment == GL_DEPTH_ATTACHMENT)
+    {
+      mFramebufferDepthAttached = true;
+    }
+    else if (attachment == GL_STENCIL_ATTACHMENT)
+    {
+      mFramebufferStencilAttached = true;
+    }
+  }
+
+  inline void FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+  {
+    //Add 100 bit;
+    mFramebufferStatus |= 4;
+
+    //We check 4 attachment colors
+    if ((attachment >= GL_COLOR_ATTACHMENT0) && (attachment < GL_COLOR_ATTACHMENT0 + Dali::DevelFrameBuffer::MAX_COLOR_ATTACHMENTS))
+    {
+      uint8_t mask = 1 << (attachment - GL_COLOR_ATTACHMENT0);
+      if ((mFrameBufferColorStatus & mask) == 0)
+      {
+        mFrameBufferColorStatus |= mask;
+        ++mFramebufferColorAttachmentCount;
+      }
+    }
+  }
+
+  inline void FrontFace(GLenum mode)
+  {
+  }
+
+  inline void GenBuffers(GLsizei n, GLuint* buffers)
+  {
+    // avoids an assert in GpuBuffers
+    *buffers = 1u;
+  }
+
+  inline void GenerateMipmap(GLenum target)
+  {
+    std::stringstream out;
+    out<<target;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+
+    mTextureTrace.PushCall("GenerateMipmap", out.str(), namedParams);
+  }
+
+  inline void GenFramebuffers(GLsizei n, GLuint* framebuffers)
+  {
+    for( int i = 0; i < n; i++ )
+    {
+      framebuffers[i] = i + 1;
+    }
+
+    //Add 001 bit, this function needs to be called the first one in the chain
+    mFramebufferStatus = 1;
+  }
+
+  inline void GenRenderbuffers(GLsizei n, GLuint* renderbuffers)
+  {
+    for( int i = 0; i < n; i++ )
+    {
+      renderbuffers[i] = i + 1;
+    }
+  }
+
+  /**
+   * This method can be used by test cases, to manipulate the texture IDs generated by GenTextures.
+   * @param[in] ids A vector containing the next IDs to be generated
+   */
+  inline void SetNextTextureIds( const std::vector<GLuint>& ids )
+  {
+    mNextTextureIds = ids;
+  }
+
+  inline const std::vector<GLuint>& GetNextTextureIds()
+  {
+    return mNextTextureIds;
+  }
+
+  inline void GenTextures(GLsizei count, GLuint* textures)
+  {
+    for( int i=0; i<count; ++i )
+    {
+      if( !mNextTextureIds.empty() )
+      {
+        *(textures+i) = mNextTextureIds[0];
+        mNextTextureIds.erase( mNextTextureIds.begin() );
+      }
+      else
+      {
+        *(textures+i) = ++mLastAutoTextureIdUsed;
+      }
+      mNumGeneratedTextures++;
+    }
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["count"] = ToString(count);
+
+    std::stringstream out;
+    for(int i=0; i<count; i++)
+    {
+      out << textures[i];
+      if(i<count-1)
+      {
+        out << ", ";
+      }
+      std::ostringstream oss;
+      oss<<"indices["<<i<<"]";
+      namedParams[oss.str()] = ToString(textures[i]);
+    }
+
+    mTextureTrace.PushCall("GenTextures", out.str(), namedParams);
+  }
+
+  inline GLuint GetLastGenTextureId()
+  {
+    return mLastAutoTextureIdUsed;
+  }
+  inline GLuint GetNumGeneratedTextures()
+  {
+    return mNumGeneratedTextures;
+  }
+
+  inline void GetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+  {
+  }
+
+  inline void GetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
+  {
+    switch(index)
+    {
+      case 0:
+        *length = snprintf(name, bufsize, "sTexture");
+        *type = GL_SAMPLER_2D;
+        *size = 1;
+        break;
+      case 1:
+        *length = snprintf(name, bufsize, "sEffect");
+        *type = GL_SAMPLER_2D;
+        *size = 1;
+        break;
+      case 2:
+        *length = snprintf(name, bufsize, "sGloss");
+        *type = GL_SAMPLER_2D;
+        *size = 1;
+        break;
+      default:
+        break;
+    }
+  }
+
+  inline void GetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
+  {
+  }
+
+  inline int  GetAttribLocation(GLuint program, const char* name)
+  {
+    std::string attribName(name);
+
+    for( unsigned int i = 0; i < ATTRIB_TYPE_LAST; ++i )
+    {
+      if( mStdAttribs[i] == attribName )
+      {
+        return i;
+      }
+    }
+
+    // 0 is a valid location
+    return 0;
+  }
+
+  inline void GetBooleanv(GLenum pname, GLboolean* params)
+  {
+  }
+
+  inline void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params)
+  {
+  }
+
+  inline GLenum GetError(void)
+  {
+    return mGetErrorResult;
+  }
+
+  inline void GetFloatv(GLenum pname, GLfloat* params)
+  {
+  }
+
+  inline void GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetIntegerv(GLenum pname, GLint* params)
+  {
+    switch( pname )
+    {
+      case GL_MAX_TEXTURE_SIZE:
+        *params = 2048;
+        break;
+      case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+        *params = 8;
+        break;
+      case GL_NUM_PROGRAM_BINARY_FORMATS_OES:
+        *params = mNumBinaryFormats;
+        break;
+      case GL_PROGRAM_BINARY_FORMATS_OES:
+        *params = mBinaryFormats;
+        break;
+    }
+  }
+
+  inline void GetProgramiv(GLuint program, GLenum pname, GLint* params)
+  {
+    switch( pname )
+    {
+      case GL_LINK_STATUS:
+        *params = mLinkStatus;
+        break;
+      case GL_PROGRAM_BINARY_LENGTH_OES:
+        *params = mProgramBinaryLength;
+        break;
+      case GL_ACTIVE_UNIFORMS:
+        *params = mNumberOfActiveUniforms;
+        break;
+      case GL_ACTIVE_UNIFORM_MAX_LENGTH:
+        *params = 100;
+        break;
+    }
+  }
+
+  inline void GetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog)
+  {
+  }
+
+  inline void GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetShaderiv(GLuint shader, GLenum pname, GLint* params)
+  {
+    switch( pname ) {
+      case GL_COMPILE_STATUS:
+        *params = mCompileStatus;
+        break;
+    }
+  }
+
+  inline void GetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog)
+  {
+  }
+
+  inline void GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+  {
+  }
+
+  inline const GLubyte* GetString(GLenum name)
+  {
+    return mGetStringResult;
+  }
+
+  inline void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
+  {
+  }
+
+  inline void GetTexParameteriv(GLenum target, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetUniformfv(GLuint program, GLint location, GLfloat* params)
+  {
+  }
+
+  inline void GetUniformiv(GLuint program, GLint location, GLint* params)
+  {
+  }
+
+  inline GLint GetUniformLocation(GLuint program, const char* name)
+  {
+    ProgramUniformMap::iterator it = mUniforms.find(program);
+    if( it == mUniforms.end() )
+    {
+      // Not a valid program ID
+      mGetErrorResult = GL_INVALID_OPERATION;
+      return -1;
+    }
+
+    UniformIDMap& uniformIDs = it->second;
+    UniformIDMap::iterator it2 = uniformIDs.find( name );
+    if( it2 == uniformIDs.end() )
+    {
+      // Uniform not found, so add it...
+      uniformIDs[name] = ++mLastUniformIdUsed;
+      return mLastUniformIdUsed;
+    }
+
+    return it2->second;
+  }
+
+  inline void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
+  {
+  }
+
+  inline void GetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer)
+  {
+  }
+
+  inline void Hint(GLenum target, GLenum mode)
+  {
+  }
+
+  inline GLboolean IsBuffer(GLuint buffer)
+  {
+    return mIsBufferResult;
+  }
+
+  inline GLboolean IsEnabled(GLenum cap)
+  {
+    return mIsEnabledResult;
+  }
+
+  inline GLboolean IsFramebuffer(GLuint framebuffer)
+  {
+    return mIsFramebufferResult;
+  }
+
+  inline GLboolean IsProgram(GLuint program)
+  {
+    return mIsProgramResult;
+  }
+
+  inline GLboolean IsRenderbuffer(GLuint renderbuffer)
+  {
+    return mIsRenderbufferResult;
+  }
+
+  inline GLboolean IsShader(GLuint shader)
+  {
+    return mIsShaderResult;
+  }
+
+  inline GLboolean IsTexture(GLuint texture)
+  {
+    return mIsTextureResult;
+  }
+
+  inline void LineWidth(GLfloat width)
+  {
+  }
+
+  inline void LinkProgram(GLuint program)
+  {
+    std::stringstream out;
+    out << program;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["program"] = ToString(program);
+    mShaderTrace.PushCall("LinkProgram", out.str(), namedParams);
+
+    mNumberOfActiveUniforms=3;
+    GetUniformLocation(program, "sTexture");
+    GetUniformLocation(program, "sEffect");
+    GetUniformLocation(program, "sGloss");
+  }
+
+  inline void PixelStorei(GLenum pname, GLint param)
+  {
+  }
+
+  inline void PolygonOffset(GLfloat factor, GLfloat units)
+  {
+  }
+
+  inline void ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels)
+  {
+  }
+
+  inline void ReleaseShaderCompiler(void)
+  {
+  }
+
+  inline void RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline void SampleCoverage(GLclampf value, GLboolean invert)
+  {
+  }
+
+  inline void Scissor(GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+    mScissorParams.x = x;
+    mScissorParams.y = y;
+    mScissorParams.width = width;
+    mScissorParams.height = height;
+
+    std::stringstream out;
+    out << x << ", " << y << ", " << width << ", " << height;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["x"] = ToString( x );
+    namedParams["y"] = ToString( y );
+    namedParams["width"] = ToString( width );
+    namedParams["height"] = ToString( height );
+    mScissorTrace.PushCall( "Scissor", out.str(), namedParams );
+  }
+
+  inline void ShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length)
+  {
+  }
+
+  inline void ShaderSource(GLuint shader, GLsizei count, const char** string, const GLint* length)
+  {
+    std::string stringBuilder;
+    for(int i = 0; i < count; ++i)
+    {
+      stringBuilder += string[i];
+    }
+    mShaderSources[shader] = stringBuilder;
+    mLastShaderCompiled = shader;
+  }
+
+  inline void GetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, char* source)
+  {
+    const std::string shaderSource = mShaderSources[shader];
+    const int shaderSourceLength = static_cast<int>(shaderSource.length());
+    if( shaderSourceLength < bufsize )
+    {
+      strncpy( source, shaderSource.c_str(), shaderSourceLength );
+      *length = shaderSourceLength;
+    }
+    else
+    {
+      *length = bufsize -1;
+      strncpy(source, shaderSource.c_str(), *length);
+      source[*length] = 0x0;
+    }
+  }
+
+  inline std::string GetShaderSource(GLuint shader)
+  {
+    return mShaderSources[shader];
+  }
+
+  inline void StencilFunc(GLenum func, GLint ref, GLuint mask)
+  {
+    std::stringstream out;
+    out << func << ", " << ref << ", " << mask;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["func"] = ToString( func );
+    namedParams["ref"] = ToString( ref );
+    namedParams["mask"] = ToString( mask );
+
+    mStencilFunctionTrace.PushCall( "StencilFunc", out.str(), namedParams );
+  }
+
+  inline void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
+  {
+    std::stringstream out;
+    out << face << ", " << func << ", " << ref << ", " << mask;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["face"] = ToString( face );
+    namedParams["func"] = ToString( func );
+    namedParams["ref"] = ToString( ref );
+    namedParams["mask"] = ToString( mask );
+
+    mStencilFunctionTrace.PushCall( "StencilFuncSeparate", out.str(), namedParams );
+  }
+
+  inline void StencilMask(GLuint mask)
+  {
+    std::stringstream out;
+    out << mask;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["mask"] = ToString( mask );
+
+    mStencilFunctionTrace.PushCall( "StencilMask", out.str(), namedParams );
+  }
+
+  inline void StencilMaskSeparate(GLenum face, GLuint mask)
+  {
+    std::stringstream out;
+    out << face << ", " << mask;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["face"] = ToString( face );
+    namedParams["mask"] = ToString( mask );
+
+    mStencilFunctionTrace.PushCall( "StencilMaskSeparate", out.str(), namedParams );
+  }
+
+  inline void StencilOp(GLenum fail, GLenum zfail, GLenum zpass)
+  {
+    std::stringstream out;
+    out << fail << ", " << zfail << ", " << zpass;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["fail"] = ToString( fail );
+    namedParams["zfail"] = ToString( zfail );
+    namedParams["zpass"] = ToString( zpass );
+
+    mStencilFunctionTrace.PushCall( "StencilOp", out.str(), namedParams );
+  }
+
+  inline void StencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
+  {
+    std::stringstream out;
+    out << face << ", " << fail << ", " << zfail << "," << zpass;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["face"] = ToString( face );
+    namedParams["fail"] = ToString( fail );
+    namedParams["zfail"] = ToString( zfail );
+    namedParams["zpass"] = ToString( zpass );
+
+    mStencilFunctionTrace.PushCall( "StencilOpSeparate", out.str(), namedParams );
+  }
+
+  inline void TexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels)
+  {
+    std::stringstream out;
+    out << target<<", "<<level<<", "<<width << ", " << height;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["level"] = ToString(level);
+    namedParams["internalformat"] = ToString(internalformat);
+    namedParams["width"] = ToString(width);
+    namedParams["height"] = ToString(height);
+    namedParams["border"] = ToString(border);
+    namedParams["format"] = ToString(format);
+    namedParams["type"] = ToString(type);
+
+    mTextureTrace.PushCall("TexImage2D", out.str(), namedParams);
+  }
+
+  inline void TexParameterf(GLenum target, GLenum pname, GLfloat param)
+  {
+    std::stringstream out;
+    out << target << ", " << pname << ", " << param;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["pname"] = ToString(pname);
+    namedParams["param"] = ToString(param);
+
+    mTexParamaterTrace.PushCall("TexParameterf", out.str(), namedParams);
+  }
+
+  inline void TexParameterfv(GLenum target, GLenum pname, const GLfloat* params)
+  {
+    std::stringstream out;
+    out << target << ", " << pname << ", " << params[0];
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["pname"] = ToString(pname);
+    namedParams["params[0]"] = ToString(params[0]);
+
+    mTexParamaterTrace.PushCall("TexParameterfv", out.str(), namedParams);
+  }
+
+  inline void TexParameteri(GLenum target, GLenum pname, GLint param)
+  {
+    std::stringstream out;
+    out << target << ", " << pname << ", " << param;
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["pname"] = ToString(pname);
+    namedParams["param"] = ToString(param);
+    mTexParamaterTrace.PushCall("TexParameteri", out.str(), namedParams);
+  }
+
+  inline void TexParameteriv(GLenum target, GLenum pname, const GLint* params)
+  {
+    std::stringstream out;
+    out << target << ", " << pname << ", " << params[0];
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["pname"] = ToString(pname);
+    namedParams["params[0]"] = ToString(params[0]);
+    mTexParamaterTrace.PushCall("TexParameteriv", out.str(), namedParams);
+  }
+
+  inline void TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels)
+  {
+    std::stringstream out;
+    out << target << ", "<<level <<", " << xoffset << ", " << yoffset << ", " << width << ", " << height;
+
+    TraceCallStack::NamedParams namedParams;
+    namedParams["target"] = ToString(target);
+    namedParams["level"] = ToString(level);
+    namedParams["xoffset"] = ToString(xoffset);
+    namedParams["yoffset"] = ToString(yoffset);
+    namedParams["width"] = ToString(width);
+    namedParams["height"] = ToString(height);
+    mTextureTrace.PushCall("TexSubImage2D", out.str(), namedParams);
+  }
+
+  inline void Uniform1f(GLint location, GLfloat value )
+  {
+    std::string params = ToString( value );
+    AddUniformCallToTraceStack( location, params );
+
+    if( ! mProgramUniforms1f.SetUniformValue( mCurrentProgram, location, value ) )
+    {
+      mGetErrorResult = GL_INVALID_OPERATION;
+    }
+  }
+
+  inline void Uniform1fv(GLint location, GLsizei count, const GLfloat* v)
+  {
+    std::string params;
+    for( int i = 0; i < count; ++i )
+    {
+      params = params + ToString( v[i] ) + ",";
+    }
+
+    AddUniformCallToTraceStack( location, params );
+
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniforms1f.SetUniformValue( mCurrentProgram, location, v[i] ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void Uniform1i(GLint location, GLint x)
+  {
+    std::string params = ToString( x );
+
+    AddUniformCallToTraceStack( location,  params );
+
+    if( ! mProgramUniforms1i.SetUniformValue( mCurrentProgram, location, x ) )
+    {
+      mGetErrorResult = GL_INVALID_OPERATION;
+    }
+  }
+
+  inline void Uniform1iv(GLint location, GLsizei count, const GLint* v)
+  {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniforms1i.SetUniformValue( mCurrentProgram,
+                                                 location,
+                                                 v[i] ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void Uniform2f(GLint location, GLfloat x, GLfloat y)
+  {
+    std::string params = ToString( x ) + "," + ToString( y );
+    AddUniformCallToTraceStack( location, params );
+
+    if( ! mProgramUniforms2f.SetUniformValue( mCurrentProgram,
+                                               location,
+                                               Vector2( x, y ) ) )
+    {
+      mGetErrorResult = GL_INVALID_OPERATION;
+    }
+  }
+
+  inline void Uniform2fv(GLint location, GLsizei count, const GLfloat* v)
+  {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniforms2f.SetUniformValue( mCurrentProgram,
+                                                 location,
+                                                 Vector2( v[2*i], v[2*i+1] ) ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void Uniform2i(GLint location, GLint x, GLint y)
+  {
+    std::string params = ToString( x ) + "," + ToString( y );
+    AddUniformCallToTraceStack( location, params );
+  }
+
+  inline void Uniform2iv(GLint location, GLsizei count, const GLint* v)
+  {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+  }
+
+  inline void Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
+  {
+    std::string params = ToString( x ) + "," + ToString( y ) + "," + ToString( z );
+    AddUniformCallToTraceStack( location, params );
+
+    if( ! mProgramUniforms3f.SetUniformValue( mCurrentProgram,
+                                               location,
+                                               Vector3( x, y, z ) ) )
+    {
+      mGetErrorResult = GL_INVALID_OPERATION;
+    }
+  }
+
+  inline void Uniform3fv(GLint location, GLsizei count, const GLfloat* v)
+  {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniforms3f.SetUniformValue(
+          mCurrentProgram,
+          location,
+          Vector3( v[3*i], v[3*i+1], v[3*i+2] ) ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void Uniform3i(GLint location, GLint x, GLint y, GLint z)
+  {
+    std::string params = ToString( x ) + "," + ToString( y ) + "," + ToString( z );
+    AddUniformCallToTraceStack( location, params );
+  }
+
+  inline void Uniform3iv(GLint location, GLsizei count, const GLint* v)
+  {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+  }
+
+  inline void Uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+  {
+    std::string params = ToString( x ) + "," + ToString( y ) + "," + ToString( z ) + "," + ToString( w );
+    AddUniformCallToTraceStack( location, params );
+
+    if( ! mProgramUniforms4f.SetUniformValue( mCurrentProgram,
+                                              location,
+                                              Vector4( x, y, z, w ) ) )
+    {
+      mGetErrorResult = GL_INVALID_OPERATION;
+    }
+  }
+
+  inline void Uniform4fv(GLint location, GLsizei count, const GLfloat* v)
+  {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniforms4f.SetUniformValue(
+          mCurrentProgram,
+          location,
+          Vector4( v[4*i], v[4*i+1], v[4*i+2], v[4*i+3] ) ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
+  {
+    std::string params = ToString( x ) + "," + ToString( y ) + "," + ToString( z ) + "," + ToString( w );
+    AddUniformCallToTraceStack( location, params );
+  }
+
+  inline void Uniform4iv(GLint location, GLsizei count, const GLint* v)
+  {
+    std::string params = ToString( v );
+    AddUniformCallToTraceStack( location, params );
+  }
+
+  inline void UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+    std::string params = ToString( value );
+    AddUniformCallToTraceStack( location, params );
+  }
+
+  inline void UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+    std::string params = ToString( value );
+    AddUniformCallToTraceStack( location, params );
+
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniformsMat3.SetUniformValue(
+            mCurrentProgram,
+            location,
+            Matrix3( value[0], value[1], value[2], value[3], value[4], value[5], value[6], value[7], value[8] ) ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+    std::string params = ToString( value );
+    AddUniformCallToTraceStack( location, params );
+
+    for( int i = 0; i < count; ++i )
+    {
+      if( ! mProgramUniformsMat4.SetUniformValue(
+          mCurrentProgram,
+          location,
+          Matrix( value ) ) )
+      {
+        mGetErrorResult = GL_INVALID_OPERATION;
+        break;
+      }
+    }
+  }
+
+  inline void UseProgram(GLuint program)
+  {
+    mCurrentProgram = program;
+  }
+
+  inline void ValidateProgram(GLuint program)
+  {
+  }
+
+  inline void VertexAttrib1f(GLuint indx, GLfloat x)
+  {
+  }
+
+  inline void VertexAttrib1fv(GLuint indx, const GLfloat* values)
+  {
+  }
+
+  inline void VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
+  {
+  }
+
+  inline void VertexAttrib2fv(GLuint indx, const GLfloat* values)
+  {
+  }
+
+  inline void VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+  {
+  }
+
+  inline void VertexAttrib3fv(GLuint indx, const GLfloat* values)
+  {
+  }
+
+  inline void VertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+  {
+  }
+
+  inline void VertexAttrib4fv(GLuint indx, const GLfloat* values)
+  {
+  }
+
+  inline void VertexAttribPointer(GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr)
+  {
+  }
+
+  inline void Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+    std::string commaString(", ");
+    std::string params( std::to_string(x) + commaString + std::to_string(y) + commaString + std::to_string(width) + commaString + std::to_string(height) );
+
+    mViewportTrace.PushCall("Viewport", params);
+  }
+
+  /* OpenGL ES 3.0 */
+
+  inline void ReadBuffer(GLenum mode)
+  {
+  }
+
+  inline void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices)
+  {
+  }
+
+  inline void TexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
+  {
+  }
+
+  inline void TexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels)
+  {
+  }
+
+  inline void CopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline void CompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data)
+  {
+  }
+
+  inline void CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data)
+  {
+  }
+
+  inline void GenQueries(GLsizei n, GLuint* ids)
+  {
+  }
+
+  inline void DeleteQueries(GLsizei n, const GLuint* ids)
+  {
+  }
+
+  inline GLboolean IsQuery(GLuint id)
+  {
+    return false;
+  }
+
+  inline void BeginQuery(GLenum target, GLuint id)
+  {
+  }
+
+  inline void EndQuery(GLenum target)
+  {
+  }
+
+  inline void GetQueryiv(GLenum target, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetQueryObjectuiv(GLuint id, GLenum pname, GLuint* params)
+  {
+  }
+
+  inline GLboolean UnmapBuffer(GLenum target)
+  {
+    return false;
+  }
+
+  inline void GetBufferPointerv(GLenum target, GLenum pname, GLvoid** params)
+  {
+  }
+
+  inline void DrawBuffers(GLsizei n, const GLenum* bufs)
+  {
+  }
+
+  inline void UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
+  {
+  }
+
+  inline void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
+  {
+  }
+
+  inline void RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)
+  {
+  }
+
+  inline GLvoid* MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
+  {
+    return NULL;
+  }
+
+  inline void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
+  {
+  }
+
+  inline void BindVertexArray(GLuint array)
+  {
+  }
+
+  inline void DeleteVertexArrays(GLsizei n, const GLuint* arrays)
+  {
+  }
+
+  inline void GenVertexArrays(GLsizei n, GLuint* arrays)
+  {
+  }
+
+  inline GLboolean IsVertexArray(GLuint array)
+  {
+    return false;
+  }
+
+  inline void GetIntegeri_v(GLenum target, GLuint index, GLint* data)
+  {
+  }
+
+  inline void BeginTransformFeedback(GLenum primitiveMode)
+  {
+  }
+
+  inline void EndTransformFeedback(void)
+  {
+  }
+
+  inline void BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)
+  {
+  }
+
+  inline void BindBufferBase(GLenum target, GLuint index, GLuint buffer)
+  {
+  }
+
+  inline void TransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode)
+  {
+  }
+
+  inline void GetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name)
+  {
+  }
+
+  inline void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer)
+  {
+  }
+
+  inline void GetVertexAttribIiv(GLuint index, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint* params)
+  {
+  }
+
+  inline void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
+  {
+  }
+
+  inline void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
+  {
+  }
+
+  inline void VertexAttribI4iv(GLuint index, const GLint* v)
+  {
+  }
+
+  inline void VertexAttribI4uiv(GLuint index, const GLuint* v)
+  {
+  }
+
+  inline void GetUniformuiv(GLuint program, GLint location, GLuint* params)
+  {
+  }
+
+  inline GLint GetFragDataLocation(GLuint program, const GLchar *name)
+  {
+    return -1;
+  }
+
+  inline void Uniform1ui(GLint location, GLuint v0)
+  {
+  }
+
+  inline void Uniform2ui(GLint location, GLuint v0, GLuint v1)
+  {
+  }
+
+  inline void Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2)
+  {
+  }
+
+  inline void Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
+  {
+  }
+
+  inline void Uniform1uiv(GLint location, GLsizei count, const GLuint* value)
+  {
+  }
+
+  inline void Uniform2uiv(GLint location, GLsizei count, const GLuint* value)
+  {
+  }
+
+  inline void Uniform3uiv(GLint location, GLsizei count, const GLuint* value)
+  {
+  }
+
+  inline void Uniform4uiv(GLint location, GLsizei count, const GLuint* value)
+  {
+  }
+
+  inline void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint* value)
+  {
+  }
+
+  inline void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint* value)
+  {
+  }
+
+  inline void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat* value)
+  {
+  }
+
+  inline void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
+  {
+  }
+
+  inline const GLubyte* GetStringi(GLenum name, GLuint index)
+  {
+    return NULL;
+  }
+
+  inline void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
+  {
+  }
+
+  inline void GetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices)
+  {
+  }
+
+  inline void GetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params)
+  {
+  }
+
+  inline GLuint GetUniformBlockIndex(GLuint program, const GLchar* uniformBlockName)
+  {
+    return GL_INVALID_INDEX;
+  }
+
+  inline void GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName)
+  {
+  }
+
+  inline void UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
+  {
+  }
+
+  inline void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
+  {
+  }
+
+  inline void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount)
+  {
+  }
+
+  inline GLsync FenceSync(GLenum condition, GLbitfield flags)
+  {
+    return NULL;
+  }
+
+  inline GLboolean IsSync(GLsync sync)
+  {
+    return false;
+  }
+
+  inline void DeleteSync(GLsync sync)
+  {
+  }
+
+  inline GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
+  {
+    return 0;
+  }
+
+  inline void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
+  {
+  }
+
+  inline void GetInteger64v(GLenum pname, GLint64* params)
+  {
+  }
+
+  inline void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values)
+  {
+  }
+
+  inline void GetInteger64i_v(GLenum target, GLuint index, GLint64* data)
+  {
+  }
+
+  inline void GetBufferParameteri64v(GLenum target, GLenum pname, GLint64* params)
+  {
+  }
+
+  inline void GenSamplers(GLsizei count, GLuint* samplers)
+  {
+  }
+
+  inline void DeleteSamplers(GLsizei count, const GLuint* samplers)
+  {
+  }
+
+  inline GLboolean IsSampler(GLuint sampler)
+  {
+    return false;
+  }
+
+  inline void BindSampler(GLuint unit, GLuint sampler)
+  {
+  }
+
+  inline void SamplerParameteri(GLuint sampler, GLenum pname, GLint param)
+  {
+  }
+
+  inline void SamplerParameteriv(GLuint sampler, GLenum pname, const GLint* param)
+  {
+  }
+
+  inline void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
+  {
+  }
+
+  inline void SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat* param)
+  {
+  }
+
+  inline void GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint* params)
+  {
+  }
+
+  inline void GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat* params)
+  {
+  }
+
+  inline void VertexAttribDivisor(GLuint index, GLuint divisor)
+  {
+  }
+
+  inline void BindTransformFeedback(GLenum target, GLuint id)
+  {
+  }
+
+  inline void DeleteTransformFeedbacks(GLsizei n, const GLuint* ids)
+  {
+  }
+
+  inline void GenTransformFeedbacks(GLsizei n, GLuint* ids)
+  {
+  }
+
+  inline GLboolean IsTransformFeedback(GLuint id)
+  {
+    return false;
+  }
+
+  inline void PauseTransformFeedback(void)
+  {
+  }
+
+  inline void ResumeTransformFeedback(void)
+  {
+  }
+
+  inline void GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary)
+  {
+    mGetProgramBinaryCalled = true;
+  }
+
+  inline void ProgramBinary(GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length)
+  {
+  }
+
+  inline void ProgramParameteri(GLuint program, GLenum pname, GLint value)
+  {
+  }
+
+  inline void InvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments)
+  {
+  }
+
+  inline void InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline void TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
+  {
+  }
+
+  inline void TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
+  {
+  }
+
+  inline void GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params)
+  {
+  }
+
+private:
+
+  inline void AddUniformCallToTraceStack( GLint location, std::string& value )
+    {
+    std::string name = "<not found>";
+    bool matched = false;
+
+    UniformIDMap& map = mUniforms[mCurrentProgram];
+    for (UniformIDMap::iterator it=map.begin(); it!=map.end(); ++it)
+    {
+      if( it->second == location )
+      {
+        name = it->first;
+        matched = true;
+        break;
+      }
+    }
+
+    if ( matched )
+    {
+      mSetUniformTrace.PushCall( name, value );
+    }
+  }
+
+
+public: // TEST FUNCTIONS
+  inline void SetCompileStatus( GLuint value ) { mCompileStatus = value; }
+  inline void SetLinkStatus( GLuint value ) { mLinkStatus = value; }
+  inline void SetGetAttribLocationResult(  int result) { mGetAttribLocationResult = result; }
+  inline void SetGetErrorResult(  GLenum result) { mGetErrorResult = result; }
+  inline void SetGetStringResult(  GLubyte* result) { mGetStringResult = result; }
+  inline void SetIsBufferResult(  GLboolean result) { mIsBufferResult = result; }
+  inline void SetIsEnabledResult(  GLboolean result) { mIsEnabledResult = result; }
+  inline void SetIsFramebufferResult(  GLboolean result) { mIsFramebufferResult = result; }
+  inline void SetIsProgramResult(  GLboolean result) { mIsProgramResult = result; }
+  inline void SetIsRenderbufferResult(  GLboolean result) { mIsRenderbufferResult = result; }
+  inline void SetIsShaderResult(  GLboolean result) { mIsShaderResult = result; }
+  inline void SetIsTextureResult(  GLboolean result) { mIsTextureResult = result; }
+  inline void SetCheckFramebufferStatusResult(  GLenum result) { mCheckFramebufferStatusResult = result; }
+  inline void SetNumBinaryFormats( GLint numFormats ) { mNumBinaryFormats = numFormats; }
+  inline void SetBinaryFormats( GLint binaryFormats ) { mBinaryFormats = binaryFormats; }
+  inline void SetProgramBinaryLength( GLint length ) { mProgramBinaryLength = length; }
+
+  inline bool GetVertexAttribArrayState(GLuint index)
+  {
+    if( index >= MAX_ATTRIBUTE_CACHE_SIZE )
+    {
+      // out of range
+      return false;
+    }
+    return mVertexAttribArrayState[ index ];
+  }
+  inline void ClearVertexAttribArrayChanged() {  mVertexAttribArrayChanged = false; }
+  inline bool GetVertexAttribArrayChanged()  { return mVertexAttribArrayChanged; }
+
+  //Methods for CullFace verification
+  inline void EnableCullFaceCallTrace(bool enable) { mCullFaceTrace.Enable(enable); }
+  inline void ResetCullFaceCallStack() { mCullFaceTrace.Reset(); }
+  inline TraceCallStack& GetCullFaceTrace() { return mCullFaceTrace; }
+
+  //Methods for Enable/Disable call verification
+  inline void EnableEnableDisableCallTrace(bool enable) { mEnableDisableTrace.Enable(enable); }
+  inline void ResetEnableDisableCallStack() { mEnableDisableTrace.Reset(); }
+  inline TraceCallStack& GetEnableDisableTrace() { return mEnableDisableTrace; }
+
+  //Methods for Shader verification
+  inline void EnableShaderCallTrace(bool enable) { mShaderTrace.Enable(enable); }
+  inline void ResetShaderCallStack() { mShaderTrace.Reset(); }
+  inline TraceCallStack& GetShaderTrace() { return mShaderTrace; }
+
+  //Methods for Texture verification
+  inline void EnableTextureCallTrace(bool enable) { mTextureTrace.Enable(enable); }
+  inline void ResetTextureCallStack() { mTextureTrace.Reset(); }
+  inline TraceCallStack& GetTextureTrace() { return mTextureTrace; }
+
+  //Methods for Texture verification
+  inline void EnableTexParameterCallTrace(bool enable) { mTexParamaterTrace.Enable(enable); }
+  inline void ResetTexParameterCallStack() { mTexParamaterTrace.Reset(); }
+  inline TraceCallStack& GetTexParameterTrace() { return mTexParamaterTrace; }
+
+  //Methods for Draw verification
+  inline void EnableDrawCallTrace(bool enable) { mDrawTrace.Enable(enable); }
+  inline void ResetDrawCallStack() { mDrawTrace.Reset(); }
+  inline TraceCallStack& GetDrawTrace() { return mDrawTrace; }
+
+  //Methods for Depth function verification
+  inline void EnableDepthFunctionCallTrace(bool enable) { mDepthFunctionTrace.Enable(enable); }
+  inline void ResetDepthFunctionCallStack() { mDepthFunctionTrace.Reset(); }
+  inline TraceCallStack& GetDepthFunctionTrace() { return mDepthFunctionTrace; }
+
+  //Methods for Stencil function verification
+  inline void EnableStencilFunctionCallTrace(bool enable) { mStencilFunctionTrace.Enable(enable); }
+  inline void ResetStencilFunctionCallStack() { mStencilFunctionTrace.Reset(); }
+  inline TraceCallStack& GetStencilFunctionTrace() { return mStencilFunctionTrace; }
+
+  //Methods for Scissor verification
+  inline void EnableScissorCallTrace(bool enable) { mScissorTrace.Enable(enable); }
+  inline void ResetScissorCallStack() { mScissorTrace.Reset(); }
+  inline TraceCallStack& GetScissorTrace() { return mScissorTrace; }
+
+  //Methods for Uniform function verification
+  inline void EnableSetUniformCallTrace(bool enable) { mSetUniformTrace.Enable(enable); }
+  inline void ResetSetUniformCallStack() { mSetUniformTrace.Reset(); }
+  inline TraceCallStack& GetSetUniformTrace() { return mSetUniformTrace; }
+
+  //Methods for Viewport verification
+  inline void EnableViewportCallTrace(bool enable) { mViewportTrace.Enable(enable); }
+  inline void ResetViewportCallStack() { mViewportTrace.Reset(); }
+  inline TraceCallStack& GetViewportTrace() { return mViewportTrace; }
+
+  template <typename T>
+  inline bool GetUniformValue( const char* name, T& value ) const
+  {
+    for( ProgramUniformMap::const_iterator program_it = mUniforms.begin();
+          program_it != mUniforms.end();
+          ++program_it )
+    {
+      const UniformIDMap &uniformIDs = program_it->second;
+
+      UniformIDMap::const_iterator uniform_it = uniformIDs.find( name );
+      if( uniform_it != uniformIDs.end() )
+      {
+        // found one matching uniform name, lets check the value...
+        GLuint programId = program_it->first;
+        GLint uniformId = uniform_it->second;
+
+        const ProgramUniformValue<T> &mProgramUniforms = GetProgramUniformsForType( value );
+        return mProgramUniforms.GetUniformValue( programId, uniformId, value );
+      }
+    }
+    return false;
+  }
+
+
+  template <typename T>
+  inline bool CheckUniformValue( const char* name, const T& value ) const
+  {
+    for( ProgramUniformMap::const_iterator program_it = mUniforms.begin();
+          program_it != mUniforms.end();
+          ++program_it )
+    {
+      const UniformIDMap &uniformIDs = program_it->second;
+
+      UniformIDMap::const_iterator uniform_it = uniformIDs.find( name );
+      if( uniform_it != uniformIDs.end() )
+      {
+        // found one matching uniform name, lets check the value...
+        GLuint programId = program_it->first;
+        GLint uniformId = uniform_it->second;
+
+        const ProgramUniformValue<T> &mProgramUniforms = GetProgramUniformsForType( value );
+        if( mProgramUniforms.CheckUniformValue( programId, uniformId, value ) )
+        {
+          // the value matches
+          return true;
+        }
+      }
+    }
+
+    fprintf(stderr, "Not found, printing possible values:\n" );
+    for( ProgramUniformMap::const_iterator program_it = mUniforms.begin();
+          program_it != mUniforms.end();
+          ++program_it )
+    {
+      const UniformIDMap &uniformIDs = program_it->second;
+
+      UniformIDMap::const_iterator uniform_it = uniformIDs.find( name );
+      if( uniform_it != uniformIDs.end() )
+      {
+        // found one matching uniform name, lets check the value...
+        GLuint programId = program_it->first;
+        GLint uniformId = uniform_it->second;
+
+        const ProgramUniformValue<T> &mProgramUniforms = GetProgramUniformsForType( value );
+        T origValue;
+        if ( mProgramUniforms.GetUniformValue(programId, uniformId, origValue) )
+        {
+          std::stringstream out;
+          out << uniform_it->first << ": " << origValue;
+          fprintf(stderr, "%s\n", out.str().c_str() );
+        }
+      }
+    }
+    return false;
+  }
+
+  template <typename T>
+  inline bool GetUniformValue( GLuint programId, GLuint uniformId, T& outValue) const
+  {
+    const ProgramUniformValue<T> &mProgramUniforms = GetProgramUniformsForType( outValue );
+    return mProgramUniforms.GetUniformValue( programId, uniformId, outValue );
+  }
+
+  inline bool GetUniformIds( const char* name, GLuint& programId, GLuint& uniformId ) const
+  {
+    for( ProgramUniformMap::const_iterator program_it = mUniforms.begin();
+          program_it != mUniforms.end();
+          ++program_it )
+    {
+      const UniformIDMap &uniformIDs = program_it->second;
+
+      UniformIDMap::const_iterator uniform_it = uniformIDs.find( name );
+      if( uniform_it != uniformIDs.end() )
+      {
+        programId = program_it->first;
+        uniformId = uniform_it->second;
+        return true;
+      }
+    }
+    return false;
+  }
+
+  inline GLuint GetLastShaderCompiled() const
+  {
+    return mLastShaderCompiled;
+  }
+
+  inline GLuint GetLastProgramCreated() const
+  {
+    return mLastProgramIdUsed;
+  }
+
+  inline GLbitfield GetLastClearMask() const
+  {
+    return mLastClearBitMask;
+  }
+
+  enum AttribType
+  {
+    ATTRIB_UNKNOWN = -1,
+    ATTRIB_POSITION,
+    ATTRIB_NORMAL,
+    ATTRIB_TEXCOORD,
+    ATTRIB_COLOR,
+    ATTRIB_BONE_WEIGHTS,
+    ATTRIB_BONE_INDICES,
+    ATTRIB_TYPE_LAST
+  };
+
+  struct ScissorParams
+  {
+    GLint x;
+    GLint y;
+    GLsizei width;
+    GLsizei height;
+
+    ScissorParams() : x( 0 ), y( 0 ), width( 0 ), height( 0 ) { }
+  };
+
+  // Methods to check scissor tests
+  inline const ScissorParams& GetScissorParams() const { return mScissorParams; }
+
+  struct ColorMaskParams
+  {
+    GLboolean red;
+    GLboolean green;
+    GLboolean blue;
+    GLboolean alpha;
+
+    ColorMaskParams() : red( true ), green( true ), blue( true ), alpha( true ) { }
+  };
+
+  inline bool GetProgramBinaryCalled() const { return mGetProgramBinaryCalled; }
+
+  inline unsigned int GetClearCountCalled() const { return mClearCount; }
+
+  inline const ColorMaskParams& GetColorMaskParams() const { return mColorMaskParams; }
+
+  typedef std::vector<size_t> BufferDataCalls;
+  inline const BufferDataCalls& GetBufferDataCalls() const { return mBufferDataCalls; }
+  inline void ResetBufferDataCalls() { mBufferDataCalls.clear(); }
+
+  typedef std::vector<size_t> BufferSubDataCalls;
+  inline const BufferSubDataCalls& GetBufferSubDataCalls() const { return mBufferSubDataCalls; }
+  inline void ResetBufferSubDataCalls() { mBufferSubDataCalls.clear(); }
+
+private:
+  GLuint     mCurrentProgram;
+  GLuint     mCompileStatus;
+  BufferDataCalls mBufferDataCalls;
+  BufferSubDataCalls mBufferSubDataCalls;
+  GLuint     mLinkStatus;
+  GLint      mNumberOfActiveUniforms;
+  GLint      mGetAttribLocationResult;
+  GLenum     mGetErrorResult;
+  GLubyte*   mGetStringResult;
+  GLboolean  mIsBufferResult;
+  GLboolean  mIsEnabledResult;
+  GLboolean  mIsFramebufferResult;
+  GLboolean  mIsProgramResult;
+  GLboolean  mIsRenderbufferResult;
+  GLboolean  mIsShaderResult;
+  GLboolean  mIsTextureResult;
+  GLenum     mActiveTextureUnit;
+  GLenum     mCheckFramebufferStatusResult;
+  GLint      mFramebufferStatus;
+  GLenum     mFramebufferDepthAttached;
+  GLenum     mFramebufferStencilAttached;
+  GLuint     mFramebufferColorAttachmentCount;
+  GLuint     mFrameBufferColorStatus;
+  GLint      mNumBinaryFormats;
+  GLint      mBinaryFormats;
+  GLint      mProgramBinaryLength;
+  bool       mVertexAttribArrayState[MAX_ATTRIBUTE_CACHE_SIZE];
+  bool       mVertexAttribArrayChanged;                            // whether the vertex attrib array has been changed
+  bool       mGetProgramBinaryCalled;
+  typedef std::map< GLuint, std::string> ShaderSourceMap;
+  ShaderSourceMap mShaderSources;
+  GLuint     mLastShaderCompiled;
+  GLbitfield mLastClearBitMask;
+  Vector4 mLastClearColor;
+  unsigned int mClearCount;
+
+  Vector4 mLastBlendColor;
+  GLenum  mLastBlendEquationRgb;
+  GLenum  mLastBlendEquationAlpha;
+  GLenum  mLastBlendFuncSrcRgb;
+  GLenum  mLastBlendFuncDstRgb;
+  GLenum  mLastBlendFuncSrcAlpha;
+  GLenum  mLastBlendFuncDstAlpha;
+
+  GLboolean mLastDepthMask;
+
+  // Data for manipulating the IDs returned by GenTextures
+  GLuint mLastAutoTextureIdUsed;
+  GLuint mNumGeneratedTextures;
+  std::vector<GLuint> mNextTextureIds;
+  std::vector<GLuint> mDeletedTextureIds;
+  std::vector<GLuint> mBoundTextures;
+
+  struct ActiveTextureType
+  {
+    std::vector<GLuint> mBoundTextures;
+  };
+
+  ActiveTextureType mActiveTextures[ MIN_TEXTURE_UNIT_LIMIT ];
+
+  TraceCallStack mCullFaceTrace;
+  TraceCallStack mEnableDisableTrace;
+  TraceCallStack mShaderTrace;
+  TraceCallStack mTextureTrace;
+  TraceCallStack mTexParamaterTrace;
+  TraceCallStack mDrawTrace;
+  TraceCallStack mDepthFunctionTrace;
+  TraceCallStack mStencilFunctionTrace;
+  TraceCallStack mScissorTrace;
+  TraceCallStack mSetUniformTrace;
+  TraceCallStack mViewportTrace;
+
+  // Shaders & Uniforms
+  GLuint mLastShaderIdUsed;
+  GLuint mLastProgramIdUsed;
+  GLuint mLastUniformIdUsed;
+  typedef std::map< std::string, GLint > UniformIDMap;
+  typedef std::map< GLuint, UniformIDMap > ProgramUniformMap;
+  ProgramUniformMap mUniforms;
+
+  template <typename T>
+  struct ProgramUniformValue : public std::map< GLuint, std::map< GLint, T > >
+  {
+  public:
+    typedef std::map< GLint, T > UniformValueMap;
+    typedef std::map< GLuint, UniformValueMap > Map;
+
+    bool SetUniformValue( GLuint program, GLuint uniform, const T& value )
+    {
+      if( program == 0 )
+      {
+        return false;
+      }
+
+      typename Map::iterator it = Map::find( program );
+      if( it == Map::end() )
+      {
+        // if its the first uniform for this program add it
+        std::pair< typename Map::iterator, bool > result =
+            Map::insert( typename Map::value_type( program, UniformValueMap() ) );
+        it = result.first;
+      }
+
+      UniformValueMap& uniforms = it->second;
+      uniforms[uniform] = value;
+
+      return true;
+    }
+
+    bool CheckUniformValue( GLuint program, GLuint uniform, const T& value ) const
+    {
+      T uniformValue;
+      if ( GetUniformValue( program, uniform, uniformValue ) )
+      {
+        return CompareType<T>(value, uniformValue, Math::MACHINE_EPSILON_10);
+      }
+
+      return false;
+    }
+
+    bool GetUniformValue( GLuint program, GLuint uniform, T& value ) const
+    {
+      if( program == 0 )
+      {
+        return false;
+      }
+
+      typename Map::const_iterator it = Map::find( program );
+      if( it == Map::end() )
+      {
+        // Uniform values always initialised as 0
+        value = GetZero();
+        return true;
+      }
+
+      const UniformValueMap& uniforms = it->second;
+      typename UniformValueMap::const_iterator it2 = uniforms.find( uniform );
+      if( it2 == uniforms.end() )
+      {
+        // Uniform values always initialised as 0
+        value = GetZero();
+        return true;
+      }
+      value = it2->second;
+
+      return true;
+    }
+
+    T GetZero() const;
+  };
+  ProgramUniformValue<int> mProgramUniforms1i;
+  ProgramUniformValue<float> mProgramUniforms1f;
+  ProgramUniformValue<Vector2> mProgramUniforms2f;
+  ProgramUniformValue<Vector3> mProgramUniforms3f;
+  ProgramUniformValue<Vector4> mProgramUniforms4f;
+  ProgramUniformValue<Matrix> mProgramUniformsMat4;
+  ProgramUniformValue<Matrix3> mProgramUniformsMat3;
+
+  inline const ProgramUniformValue<int>& GetProgramUniformsForType( const int ) const
+  {
+    return mProgramUniforms1i;
+  }
+  inline const ProgramUniformValue<float>& GetProgramUniformsForType( const float ) const
+  {
+    return mProgramUniforms1f;
+  }
+  inline const ProgramUniformValue<Vector2>& GetProgramUniformsForType( const Vector2& ) const
+  {
+    return mProgramUniforms2f;
+  }
+  inline const ProgramUniformValue<Vector3>& GetProgramUniformsForType( const Vector3& ) const
+  {
+    return mProgramUniforms3f;
+  }
+  inline const ProgramUniformValue<Vector4>& GetProgramUniformsForType( const Vector4& ) const
+  {
+    return mProgramUniforms4f;
+  }
+  inline const ProgramUniformValue<Matrix>& GetProgramUniformsForType( const Matrix& ) const
+  {
+    return mProgramUniformsMat4;
+  }
+  inline const ProgramUniformValue<Matrix3>& GetProgramUniformsForType( const Matrix3& ) const
+  {
+    return mProgramUniformsMat3;
+  }
+  inline void SetVertexAttribArray(GLuint index, bool state)
+  {
+    if( index >= MAX_ATTRIBUTE_CACHE_SIZE )
+    {
+      // out of range
+      return;
+    }
+    mVertexAttribArrayState[ index ] = state;
+    mVertexAttribArrayChanged = true;
+  }
+
+  ScissorParams mScissorParams;
+  ColorMaskParams mColorMaskParams;
+};
+
+template <>
+inline int TestGlAbstraction::ProgramUniformValue<int>::GetZero() const
+{
+  return 0;
+}
+
+template <>
+inline float TestGlAbstraction::ProgramUniformValue<float>::GetZero() const
+{
+  return 0.0f;
+}
+
+template <>
+inline Vector2 TestGlAbstraction::ProgramUniformValue<Vector2>::GetZero() const
+{
+  return Vector2::ZERO;
+}
+
+template <>
+inline Vector3 TestGlAbstraction::ProgramUniformValue<Vector3>::GetZero() const
+{
+  return Vector3::ZERO;
+}
+
+template <>
+inline Vector4 TestGlAbstraction::ProgramUniformValue<Vector4>::GetZero() const
+{
+  return Vector4::ZERO;
+}
+
+template <>
+inline Matrix TestGlAbstraction::ProgramUniformValue<Matrix>::GetZero() const
+{
+  return Matrix();
+}
+
+template <>
+inline Matrix3 TestGlAbstraction::ProgramUniformValue<Matrix3>::GetZero() const
+{
+  return Matrix3( Matrix() );
+}
+
+} // namespace Dali
+
+bool BlendEnabled(const Dali::TraceCallStack& callStack);
+bool BlendDisabled(const Dali::TraceCallStack& callStack);
+
+
+#endif // TEST_GL_ABSTRACTION_H
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-context-helper-abstraction.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-context-helper-abstraction.h
new file mode 100644 (file)
index 0000000..ce150d1
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef TEST_GL_CONTEXT_HELPER_ABSTRACTION_H
+#define TEST_GL_CONTEXT_HELPER_ABSTRACTION_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/gl-context-helper-abstraction.h>
+
+namespace Dali
+{
+
+/**
+ * Class to emulate the GL context helper
+ */
+class DALI_CORE_API TestGlContextHelperAbstraction: public Integration::GlContextHelperAbstraction
+{
+public:
+  /**
+   * Constructor
+   */
+  TestGlContextHelperAbstraction() {};
+
+  /**
+   * Destructor
+   */
+  ~TestGlContextHelperAbstraction() {};
+
+  /**
+   * @brief Switch to the surfaceless GL context
+   */
+  virtual void MakeSurfacelessContextCurrent() {};
+
+  /**
+   * @brief Clear the GL context
+   */
+  virtual void MakeContextNull() {};
+
+  /**
+   * @brief Wait until all GL rendering calls for the current GL context are executed
+   */
+  virtual void WaitClient() {};
+private:
+
+  TestGlContextHelperAbstraction( const TestGlContextHelperAbstraction& ); ///< Undefined
+  TestGlContextHelperAbstraction& operator=( const TestGlContextHelperAbstraction& ); ///< Undefined
+};
+
+} // Dali
+
+#endif // TEST_GL_CONTEXT_HELPER_ABSTRACTION_H
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-sync-abstraction.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-sync-abstraction.cpp
new file mode 100644 (file)
index 0000000..858e930
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * 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 "test-gl-sync-abstraction.h"
+
+namespace Dali
+{
+
+TestSyncObject::TestSyncObject(TraceCallStack& trace)
+: synced(false),
+  mTrace(trace)
+{
+}
+
+TestSyncObject::~TestSyncObject()
+{
+}
+
+bool TestSyncObject::IsSynced()
+{
+  mTrace.PushCall("SyncObject::IsSynced", ""); // Trace the method
+  return synced;
+}
+
+
+
+TestGlSyncAbstraction::TestGlSyncAbstraction()
+{
+  Initialize();
+}
+
+/**
+ * Destructor
+ */
+TestGlSyncAbstraction::~TestGlSyncAbstraction()
+{
+  for( SyncIter iter=mSyncObjects.begin(), end=mSyncObjects.end(); iter != end; ++iter )
+  {
+    delete *iter;
+  }
+}
+
+/**
+ * Initialize the sync objects - clear down the map
+ */
+void TestGlSyncAbstraction::Initialize()
+{
+  mSyncObjects.clear();
+}
+
+/**
+ * Create a sync object
+ * @return the sync object
+ */
+Integration::GlSyncAbstraction::SyncObject* TestGlSyncAbstraction::CreateSyncObject( )
+{
+  mTrace.PushCall("CreateSyncObject", ""); // Trace the method
+
+  TestSyncObject* syncObject = new TestSyncObject(mTrace);
+  mSyncObjects.push_back( syncObject );
+  return syncObject;
+}
+
+/**
+ * Destroy a sync object
+ * @param[in] syncObject The object to destroy
+ */
+void TestGlSyncAbstraction::DestroySyncObject( Integration::GlSyncAbstraction::SyncObject* syncObject )
+{
+  std::stringstream out;
+  out << syncObject;
+  mTrace.PushCall("DestroySyncObject", out.str()); // Trace the method
+
+  for( SyncIter iter=mSyncObjects.begin(), end=mSyncObjects.end(); iter != end; ++iter )
+  {
+    if( *iter == syncObject )
+    {
+      delete *iter;
+      mSyncObjects.erase(iter);
+      break;
+    }
+  }
+}
+
+
+Integration::GlSyncAbstraction::SyncObject* TestGlSyncAbstraction::GetLastSyncObject( )
+{
+  if( !mSyncObjects.empty() )
+  {
+    return mSyncObjects.back();
+  }
+  return NULL;
+}
+
+/**
+ * Test method to trigger the object sync behaviour.
+ * @param[in]
+ * @param[in] sync The sync value to set
+ */
+void TestGlSyncAbstraction::SetObjectSynced( Integration::GlSyncAbstraction::SyncObject* syncObject, bool sync )
+{
+  TestSyncObject* testSyncObject = static_cast<TestSyncObject*>(syncObject);
+  testSyncObject->synced = sync;
+}
+
+/**
+ * Turn trace on
+ */
+void TestGlSyncAbstraction::EnableTrace(bool enable) { mTrace.Enable(enable); }
+
+/**
+ * Reset the trace callstack
+ */
+void TestGlSyncAbstraction::ResetTrace() { mTrace.Reset(); }
+
+/**
+ * Get the trace object (allows test case to find methods on it)
+ */
+TraceCallStack& TestGlSyncAbstraction::GetTrace() { return mTrace; }
+
+int32_t TestGlSyncAbstraction::GetNumberOfSyncObjects()
+{
+  return static_cast<int32_t>( mSyncObjects.size() );
+}
+
+
+} // Dali
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-sync-abstraction.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-gl-sync-abstraction.h
new file mode 100644 (file)
index 0000000..775d209
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef TEST_GL_SYNC_ABSTRACTION_H
+#define TEST_GL_SYNC_ABSTRACTION_H
+
+/*
+ * Copyright (c) 2019 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 <string>
+#include <map>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/core.h>
+#include <dali/integration-api/gl-sync-abstraction.h>
+#include "test-trace-call-stack.h"
+
+namespace Dali
+{
+
+class DALI_CORE_API TestSyncObject : public Integration::GlSyncAbstraction::SyncObject
+{
+public:
+  TestSyncObject(TraceCallStack& trace);
+  ~TestSyncObject();
+  bool IsSynced();
+  bool synced;
+  TraceCallStack& mTrace;
+};
+
+/**
+ * Class to emulate the GL sync functions with tracing
+ */
+class DALI_CORE_API TestGlSyncAbstraction: public Integration::GlSyncAbstraction
+{
+public:
+  /**
+   * Constructor
+   */
+  TestGlSyncAbstraction();
+
+  /**
+   * Destructor
+   */
+  ~TestGlSyncAbstraction();
+
+  /**
+   * Initialize the sync objects - clear down the map
+   */
+  void Initialize();
+
+  /**
+   * Create a sync object
+   * @return the sync object
+   */
+  virtual Integration::GlSyncAbstraction::SyncObject* CreateSyncObject( );
+
+  /**
+   * Destroy a sync object
+   * @param[in] syncObject The object to destroy
+   */
+  virtual void DestroySyncObject( Integration::GlSyncAbstraction::SyncObject* syncObject );
+
+
+public: // TEST FUNCTIONS
+  Integration::GlSyncAbstraction::SyncObject* GetLastSyncObject( );
+
+  /**
+   * Test method to trigger the object sync behaviour.
+   * @param[in]
+   * @param[in] sync The sync value to set
+   */
+  void SetObjectSynced( Integration::GlSyncAbstraction::SyncObject* syncObject, bool sync );
+
+  /**
+   * Turn trace on
+   */
+  void EnableTrace(bool enable);
+
+  /**
+   * Reset the trace callstack
+   */
+  void ResetTrace();
+
+  /**
+   * Get the trace object (allows test case to find methods on it)
+   */
+  TraceCallStack& GetTrace();
+
+  /**
+   * Get the number of sync objects
+   *
+   * @return the number of sync objects
+   */
+  int32_t GetNumberOfSyncObjects();
+
+private:
+
+  TestGlSyncAbstraction( const TestGlSyncAbstraction& ); ///< Undefined
+  TestGlSyncAbstraction& operator=( const TestGlSyncAbstraction& ); ///< Undefined
+
+  typedef std::vector<TestSyncObject*>   SyncContainer;
+  typedef SyncContainer::iterator SyncIter;
+  SyncContainer mSyncObjects;  ///< The sync objects
+  TraceCallStack mTrace; ///< the trace call stack for testing
+};
+
+} // Dali
+
+#endif // TEST_GL_SYNC_ABSTRACTION_H
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-harness.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-harness.cpp
new file mode 100644 (file)
index 0000000..b42b9f9
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "test-harness.h"
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <vector>
+#include <map>
+#include <cstring>
+#include <testcase.h>
+#include <fcntl.h>
+
+namespace TestHarness
+{
+
+typedef std::map<int32_t, TestCase> RunningTestCases;
+
+const char* basename(const char* path)
+{
+  const char* ptr=path;
+  const char* slash=NULL;
+  for( ; *ptr != '\0' ; ++ptr )
+  {
+    if(*ptr == '/') slash=ptr;
+  }
+  if(slash != NULL) ++slash;
+  return slash;
+}
+
+void SuppressLogOutput()
+{
+  // Close stdout and stderr to suppress the log output
+  close(STDOUT_FILENO); // File descriptor number for stdout is 1
+  close(STDERR_FILENO); // File descriptor number for stderr is 2
+
+  // The POSIX specification requires that /dev/null must be provided,
+  // The open function always chooses the lowest unused file descriptor
+  // It is sufficient for stdout to be writable.
+  open("/dev/null", O_WRONLY); // Redirect file descriptor number 1 (i.e. stdout) to /dev/null
+  // When stderr is opened it must be both readable and writable.
+  open("/dev/null", O_RDWR); // Redirect file descriptor number 2 (i.e. stderr) to /dev/null
+}
+
+int32_t RunTestCase( struct ::testcase_s& testCase )
+{
+  int32_t result = EXIT_STATUS_TESTCASE_FAILED;
+
+// dont want to catch exception as we want to be able to get
+// gdb stack trace from the first error
+// by default tests should all always pass with no exceptions
+  if( testCase.startup )
+  {
+    testCase.startup();
+  }
+  try
+  {
+    result = testCase.function();
+  }
+  catch( const char* )
+  {
+    // just catch test fail exception, return is already set to EXIT_STATUS_TESTCASE_FAILED
+  }
+  if( testCase.cleanup )
+  {
+    testCase.cleanup();
+  }
+
+  return result;
+}
+
+
+int32_t RunTestCaseInChildProcess( struct ::testcase_s& testCase, bool suppressOutput )
+{
+  int32_t testResult = EXIT_STATUS_TESTCASE_FAILED;
+
+  int32_t pid = fork();
+  if( pid == 0 ) // Child process
+  {
+    if( suppressOutput )
+    {
+      SuppressLogOutput();
+    }
+    else
+    {
+      printf("\n");
+      for(int32_t i=0; i<80; ++i) printf("#");
+      printf("\nTC: %s\n", testCase.name);
+      fflush(stdout);
+    }
+
+    int32_t status = RunTestCase( testCase );
+
+    if( ! suppressOutput )
+    {
+      fflush(stdout);
+      fflush(stderr);
+      fclose(stdout);
+      fclose(stderr);
+    }
+    exit( status );
+  }
+  else if(pid == -1)
+  {
+    perror("fork");
+    exit(EXIT_STATUS_FORK_FAILED);
+  }
+  else // Parent process
+  {
+    int32_t status = 0;
+    int32_t childPid = waitpid(pid, &status, 0);
+    if( childPid == -1 )
+    {
+      perror("waitpid");
+      exit(EXIT_STATUS_WAITPID_FAILED);
+    }
+    if( WIFEXITED(status) )
+    {
+      if( childPid > 0 )
+      {
+        testResult = WEXITSTATUS(status);
+        if( testResult )
+        {
+          printf("Test case %s failed: %d\n", testCase.name, testResult);
+        }
+      }
+    }
+    else if(WIFSIGNALED(status) )
+    {
+      int32_t signal = WTERMSIG(status);
+      testResult = EXIT_STATUS_TESTCASE_ABORTED;
+      if( signal == SIGABRT )
+      {
+        printf("Test case %s failed: test case asserted\n", testCase.name );
+      }
+      else
+      {
+        printf("Test case %s failed: exit with signal %s\n", testCase.name, strsignal(WTERMSIG(status)));
+      }
+    }
+    else if(WIFSTOPPED(status))
+    {
+      printf("Test case %s failed: stopped with signal %s\n", testCase.name, strsignal(WSTOPSIG(status)));
+    }
+  }
+  fflush(stdout);
+  fflush(stderr);
+  return testResult;
+}
+
+void OutputStatistics( const char* processName, int32_t numPasses, int32_t numFailures )
+{
+  FILE* fp=fopen("summary.xml", "a");
+  if( fp != NULL )
+  {
+    fprintf( fp,
+             "  <suite name=\"%s\">\n"
+             "    <total_case>%d</total_case>\n"
+             "    <pass_case>%d</pass_case>\n"
+             "    <pass_rate>%5.2f</pass_rate>\n"
+             "    <fail_case>%d</fail_case>\n"
+             "    <fail_rate>%5.2f</fail_rate>\n"
+             "    <block_case>0</block_case>\n"
+             "    <block_rate>0.00</block_rate>\n"
+             "    <na_case>0</na_case>\n"
+             "    <na_rate>0.00</na_rate>\n"
+             "  </suite>\n",
+             basename(processName),
+             numPasses+numFailures,
+             numPasses,
+             (float)numPasses/(numPasses+numFailures),
+             numFailures,
+             (float)numFailures/(numPasses+numFailures) );
+    fclose(fp);
+  }
+}
+
+int32_t RunAll( const char* processName, ::testcase tc_array[] )
+{
+  int32_t numFailures = 0;
+  int32_t numPasses = 0;
+
+  // Run test cases in child process( to kill output/handle signals ), but run serially.
+  for( uint32_t i=0; tc_array[i].name; i++)
+  {
+    int32_t result = RunTestCaseInChildProcess( tc_array[i], false );
+    if( result == 0 )
+    {
+      numPasses++;
+    }
+    else
+    {
+      numFailures++;
+    }
+  }
+
+  OutputStatistics( processName, numPasses, numFailures);
+
+  return numFailures;
+}
+
+// Constantly runs up to MAX_NUM_CHILDREN processes
+int32_t RunAllInParallel(  const char* processName, ::testcase tc_array[], bool reRunFailed)
+{
+  int32_t numFailures = 0;
+  int32_t numPasses = 0;
+
+  RunningTestCases children;
+  std::vector<int32_t> failedTestCases;
+
+  // Fork up to MAX_NUM_CHILDREN processes, then
+  // wait. As soon as a proc completes, fork the next.
+
+  int32_t nextTestCase = 0;
+  int32_t numRunningChildren = 0;
+
+  while( tc_array[nextTestCase].name || numRunningChildren > 0)
+  {
+    // Create more children (up to the max number or til the end of the array)
+    while( numRunningChildren < MAX_NUM_CHILDREN && tc_array[nextTestCase].name )
+    {
+      int32_t pid = fork();
+      if( pid == 0 ) // Child process
+      {
+        SuppressLogOutput();
+        exit( RunTestCase( tc_array[nextTestCase] ) );
+      }
+      else if(pid == -1)
+      {
+        perror("fork");
+        exit(EXIT_STATUS_FORK_FAILED);
+      }
+      else // Parent process
+      {
+        TestCase tc(nextTestCase, tc_array[nextTestCase].name);
+        children[pid] = tc;
+        nextTestCase++;
+        numRunningChildren++;
+      }
+    }
+
+    // Wait for the next child to finish
+
+    int32_t status=0;
+    int32_t childPid = waitpid(-1, &status, 0);
+    if( childPid == -1 )
+    {
+      perror("waitpid");
+      exit(EXIT_STATUS_WAITPID_FAILED);
+    }
+
+    if( WIFEXITED(status) )
+    {
+      if( childPid > 0 )
+      {
+        int32_t testResult = WEXITSTATUS(status);
+        if( testResult )
+        {
+          printf("Test case %s failed: %d\n", children[childPid].testCaseName, testResult);
+          failedTestCases.push_back(children[childPid].testCase);
+          numFailures++;
+        }
+        else
+        {
+          numPasses++;
+        }
+        numRunningChildren--;
+      }
+    }
+
+    else if( WIFSIGNALED(status) || WIFSTOPPED(status))
+    {
+      status = WIFSIGNALED(status)?WTERMSIG(status):WSTOPSIG(status);
+
+      if( childPid > 0 )
+      {
+        RunningTestCases::iterator iter = children.find(childPid);
+        if( iter != children.end() )
+        {
+          printf("Test case %s exited with signal %s\n", iter->second.testCaseName, strsignal(status));
+          failedTestCases.push_back(iter->second.testCase);
+        }
+        else
+        {
+          printf("Unknown child process: %d signaled %s\n", childPid, strsignal(status));
+        }
+
+        numFailures++;
+        numRunningChildren--;
+      }
+    }
+  }
+
+  OutputStatistics( processName, numPasses, numFailures );
+
+  if( reRunFailed )
+  {
+    for( uint32_t i=0; i<failedTestCases.size(); i++)
+    {
+      char* testCaseStrapline;
+      int32_t numChars = asprintf(&testCaseStrapline, "Test case %s", tc_array[failedTestCases[i]].name );
+      printf("\n%s\n", testCaseStrapline);
+      for(int32_t j=0; j<numChars; j++)
+      {
+        printf("=");
+      }
+      printf("\n");
+      RunTestCaseInChildProcess( tc_array[failedTestCases[i] ], false );
+    }
+  }
+
+  return numFailures;
+}
+
+
+
+int32_t FindAndRunTestCase(::testcase tc_array[], const char* testCaseName)
+{
+  int32_t result = EXIT_STATUS_TESTCASE_NOT_FOUND;
+
+  for( int32_t i = 0; tc_array[i].name; i++ )
+  {
+    if( !strcmp(testCaseName, tc_array[i].name) )
+    {
+      return RunTestCase( tc_array[i] );
+    }
+  }
+
+  printf("Unknown testcase name: \"%s\"\n", testCaseName);
+  return result;
+}
+
+void Usage(const char* program)
+{
+  printf("Usage: \n"
+         "   %s <testcase name>\t\t Execute a test case\n"
+         "   %s \t\t Execute all test cases in parallel\n"
+         "   %s -r\t\t Execute all test cases in parallel, rerunning failed test cases\n"
+         "   %s -s\t\t Execute all test cases serially\n",
+         program, program, program, program);
+}
+
+} // namespace
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-harness.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-harness.h
new file mode 100644 (file)
index 0000000..e40492c
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef TEST_HARNESS_H
+#define TEST_HARNESS_H
+
+/*
+ * Copyright (c) 2018 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 <stdio.h>
+#include <testcase.h>
+#include <cstdint>
+
+namespace TestHarness
+{
+
+enum ExitStatus
+{
+  EXIT_STATUS_TESTCASE_SUCCEEDED,   // 0
+  EXIT_STATUS_TESTCASE_FAILED,      // 1
+  EXIT_STATUS_TESTCASE_ABORTED,     // 2
+  EXIT_STATUS_FORK_FAILED,          // 3
+  EXIT_STATUS_WAITPID_FAILED,       // 4
+  EXIT_STATUS_BAD_ARGUMENT,         // 5
+  EXIT_STATUS_TESTCASE_NOT_FOUND    // 6
+};
+
+const int32_t MAX_NUM_CHILDREN(16);
+
+struct TestCase
+{
+  int32_t testCase;
+  const char* testCaseName;
+
+  TestCase()
+  : testCase(0),
+    testCaseName(NULL)
+  {
+  }
+
+  TestCase(int32_t tc, const char* name)
+  : testCase(tc),
+    testCaseName(name)
+  {
+  }
+  TestCase(const TestCase& rhs)
+  : testCase(rhs.testCase),
+    testCaseName(rhs.testCaseName)
+  {
+  }
+  TestCase& operator=(const TestCase& rhs)
+  {
+    testCase = rhs.testCase;
+    testCaseName = rhs.testCaseName;
+    return *this;
+
+  }
+};
+
+/**
+ * Run a test case
+ * @param[in] testCase The Testkit-lite test case to run
+ */
+int32_t RunTestCase( struct testcase_s& testCase );
+
+/**
+ * Run all test cases in parallel
+ * @param[in] processName The name of this process
+ * @param[in] tc_array The array of auto-generated testkit-lite test cases
+ * @param[in] reRunFailed True if failed test cases should be re-run
+ * @return 0 on success
+ */
+int32_t RunAllInParallel(const char* processName, testcase tc_array[], bool reRunFailed);
+
+/**
+ * Run all test cases in serial
+ * @param[in] processName The name of this process
+ * @param[in] tc_array The array of auto-generated testkit-lite test cases
+ * @return 0 on success
+ */
+int32_t RunAll( const char* processName, testcase tc_array[] );
+
+/**
+ * Find the named test case in the given array, and run it
+ * @param[in] tc_array The array of auto-generated testkit-lite test cases
+ * @param[in] testCaseName the name of the test case to run
+ * @return 0 on success
+ */
+int32_t FindAndRunTestCase(::testcase tc_array[], const char* testCaseName);
+
+/**
+ * Display usage instructions for this program
+ * @param[in] program The name of this program
+ */
+void Usage(const char* program);
+
+} // namespace TestHarness
+
+#endif
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-intrusive-ptr.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-intrusive-ptr.h
new file mode 100644 (file)
index 0000000..5fb17da
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef TEST_INTRUSIVE_PTR_H
+#define TEST_INTRUSIVE_PTR_H
+
+/*
+ * Copyright (c) 2019 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 <iostream>
+#include <stdlib.h>
+#include <dali/public-api/dali-core.h>
+#include <dali-test-suite-utils.h>
+
+namespace Dali
+{
+
+template <typename T>
+struct UtcCoverageIntrusivePtr
+{
+  typedef IntrusivePtr<T> (*Creator)();
+
+  void Check( Creator creator)
+  {
+    IntrusivePtr<T> a = creator();
+    IntrusivePtr<T> b = creator();
+
+    DALI_TEST_CHECK( a.Get() );
+
+    a.Reset();
+
+    T* pB = b.Detach();
+
+    a.Reset(pB);
+
+    DALI_TEST_CHECK(a);
+
+    a.Reset();
+
+  };
+
+};
+
+} // Dali
+
+#endif // TEST_INTRUSIVE_PTR_H
+
+
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-native-image.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-native-image.cpp
new file mode 100644 (file)
index 0000000..ee6c17a
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+#include "test-application.h"
+#include "test-native-image.h"
+
+
+namespace Dali
+{
+
+TestNativeImagePointer TestNativeImage::New(uint32_t width, uint32_t height)
+{
+  return new TestNativeImage(width, height);
+}
+
+TestNativeImage::TestNativeImage(uint32_t width, uint32_t height)
+: mWidth(width), mHeight(height), mExtensionCreateCalls(0), mExtensionDestroyCalls(0), mTargetTextureCalls(0),createResult(true)
+{
+  mExtension = new TestNativeImageExtension();
+}
+
+TestNativeImage::~TestNativeImage()
+{
+}
+
+
+TestNativeImageNoExtPointer TestNativeImageNoExt::New(uint32_t width, uint32_t height)
+{
+  return new TestNativeImageNoExt(width, height);
+}
+
+TestNativeImageNoExt::TestNativeImageNoExt(uint32_t width, uint32_t height)
+: mWidth(width), mHeight(height), mExtensionCreateCalls(0), mExtensionDestroyCalls(0), mTargetTextureCalls(0),createResult(true)
+{
+}
+
+TestNativeImageNoExt::~TestNativeImageNoExt()
+{
+}
+
+} // namespace dali
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-native-image.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-native-image.h
new file mode 100644 (file)
index 0000000..0c215b7
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef TEST_NATIVE_IMAGE_H
+#define TEST_NATIVE_IMAGE_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/images/native-image-interface.h>
+#include <dali/devel-api/images/native-image-interface-extension.h>
+#include <dali/integration-api/gl-defines.h>
+
+namespace Dali
+{
+class TestNativeImage;
+class TestNativeImageNoExt;
+typedef IntrusivePtr<TestNativeImage> TestNativeImagePointer;
+typedef IntrusivePtr<TestNativeImageNoExt> TestNativeImageNoExtPointer;
+
+class DALI_CORE_API TestNativeImageExtension: public Dali::NativeImageInterface::Extension
+{
+public:
+  inline const char* GetCustomFragmentPreFix(){return "#extension GL_OES_EGL_image_external:require\n";}
+  inline const char* GetCustomSamplerTypename(){return "samplerExternalOES";}
+
+  inline int32_t GetEglImageTextureTarget(){return GL_TEXTURE_EXTERNAL_OES;}
+
+};
+
+class DALI_CORE_API TestNativeImage : public Dali::NativeImageInterface
+{
+public:
+  static TestNativeImagePointer New(uint32_t width, uint32_t height);
+
+  inline void SetGlExtensionCreateResult(bool result){ createResult = result;}
+  inline virtual bool GlExtensionCreate() { ++mExtensionCreateCalls; return createResult;};
+  inline virtual void GlExtensionDestroy() { ++mExtensionDestroyCalls; };
+  inline virtual GLenum TargetTexture() { ++mTargetTextureCalls; return 0;};
+  inline virtual void PrepareTexture() {};
+  inline virtual uint32_t GetWidth() const {return mWidth;};
+  inline virtual uint32_t GetHeight() const {return mHeight;};
+  inline virtual bool RequiresBlending() const {return true;};
+  inline virtual Dali::NativeImageInterface::Extension* GetExtension() {return mExtension;}
+
+private:
+  TestNativeImage(uint32_t width, uint32_t height);
+  virtual ~TestNativeImage();
+
+  uint32_t mWidth;
+  uint32_t mHeight;
+public:
+  int32_t mExtensionCreateCalls;
+  int32_t mExtensionDestroyCalls;
+  int32_t mTargetTextureCalls;
+
+  bool createResult;
+  TestNativeImageExtension* mExtension;
+};
+
+
+class DALI_CORE_API TestNativeImageNoExt : public Dali::NativeImageInterface
+{
+public:
+  static TestNativeImageNoExtPointer New(uint32_t width, uint32_t height);
+
+  inline void SetGlExtensionCreateResult(bool result){ createResult = result;}
+  inline virtual bool GlExtensionCreate() { ++mExtensionCreateCalls; return createResult;};
+  inline virtual void GlExtensionDestroy() { ++mExtensionDestroyCalls; };
+  inline virtual GLenum TargetTexture() { ++mTargetTextureCalls; return 1;};
+  inline virtual void PrepareTexture() {};
+  inline virtual uint32_t GetWidth() const {return mWidth;};
+  inline virtual uint32_t GetHeight() const {return mHeight;};
+  inline virtual bool RequiresBlending() const {return true;};
+
+private:
+  TestNativeImageNoExt(uint32_t width, uint32_t height);
+  virtual ~TestNativeImageNoExt();
+
+  uint32_t mWidth;
+  uint32_t mHeight;
+public:
+  int32_t mExtensionCreateCalls;
+  int32_t mExtensionDestroyCalls;
+  int32_t mTargetTextureCalls;
+  bool createResult;
+};
+
+} // Dali
+
+#endif // TEST_NATIVE_IMAGE_H
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-platform-abstraction.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-platform-abstraction.cpp
new file mode 100644 (file)
index 0000000..3962870
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "test-platform-abstraction.h"
+#include "dali-test-suite-utils.h"
+#include <dali/integration-api/bitmap.h>
+
+namespace Dali
+{
+
+TestPlatformAbstraction::TestPlatformAbstraction()
+: mTrace(),
+  mIsLoadingResult( false ),
+  mClosestSize(),
+  mLoadFileResult(),
+  mSaveFileResult( false ),
+  mSynchronouslyLoadedResource(),
+  mTimerId(0),
+  mCallbackFunction(nullptr)
+{
+  Initialize();
+}
+
+TestPlatformAbstraction::~TestPlatformAbstraction()
+{
+}
+
+ImageDimensions TestPlatformAbstraction::GetClosestImageSize( const std::string& filename,
+                                                              ImageDimensions size,
+                                                              FittingMode::Type fittingMode,
+                                                              SamplingMode::Type samplingMode,
+                                                              bool orientationCorrection )
+{
+  ImageDimensions closestSize = ImageDimensions( mClosestSize );
+  mTrace.PushCall("GetClosestImageSize", "");
+  return closestSize;
+}
+
+ImageDimensions TestPlatformAbstraction::GetClosestImageSize( Integration::ResourcePointer resourceBuffer,
+                                                   ImageDimensions size,
+                                                   FittingMode::Type fittingMode,
+                                                   SamplingMode::Type samplingMode,
+                                                   bool orientationCorrection )
+{
+  ImageDimensions closestSize = ImageDimensions( mClosestSize );
+  mTrace.PushCall("GetClosestImageSize", "");
+  return closestSize;
+}
+
+Integration::ResourcePointer TestPlatformAbstraction::LoadImageSynchronously( const Integration::BitmapResourceType& resourceType, const std::string& resourcePath )
+{
+  mTrace.PushCall("LoadResourceSynchronously", "");
+  return mSynchronouslyLoadedResource;
+}
+
+Integration::BitmapPtr TestPlatformAbstraction::DecodeBuffer( const Integration::BitmapResourceType& resourceType, uint8_t * buffer, size_t size )
+{
+  mTrace.PushCall("DecodeBuffer", "");
+  return mDecodedBitmap;
+}
+
+bool TestPlatformAbstraction::LoadShaderBinaryFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const
+{
+  mTrace.PushCall("LoadShaderBinaryFile", "");
+  if( mLoadFileResult.loadResult )
+  {
+    buffer = mLoadFileResult.buffer;
+  }
+
+  return mLoadFileResult.loadResult;
+}
+
+/** Call this every test */
+void TestPlatformAbstraction::Initialize()
+{
+  mTrace.Reset();
+  mTrace.Enable(true);
+  mIsLoadingResult=false;
+  mSynchronouslyLoadedResource.Reset();
+  mDecodedBitmap.Reset();
+}
+
+bool TestPlatformAbstraction::WasCalled(TestFuncEnum func)
+{
+  switch(func)
+  {
+    case LoadResourceSynchronouslyFunc:       return mTrace.FindMethod("LoadResourceSynchronously");
+    case LoadShaderBinaryFileFunc:            return mTrace.FindMethod("LoadShaderBinaryFile");
+    case SaveShaderBinaryFileFunc:            return mTrace.FindMethod("SaveShaderBinaryFile");
+  }
+  return false;
+}
+
+void TestPlatformAbstraction::SetIsLoadingResult(bool result)
+{
+  mIsLoadingResult = result;
+}
+
+void TestPlatformAbstraction::ClearReadyResources()
+{
+  mSynchronouslyLoadedResource.Reset();
+  mDecodedBitmap.Reset();
+}
+
+void TestPlatformAbstraction::SetClosestImageSize( const Vector2& size )
+{
+  mClosestSize = ImageDimensions( static_cast<uint32_t>( size.x ), static_cast<uint32_t>( size.y ) );
+}
+
+void TestPlatformAbstraction::SetLoadFileResult( bool result, Dali::Vector< unsigned char >& buffer )
+{
+  mLoadFileResult.loadResult = result;
+  if( result )
+  {
+    mLoadFileResult.buffer = buffer;
+  }
+}
+
+void TestPlatformAbstraction::SetSaveFileResult( bool result )
+{
+  mSaveFileResult = result;
+}
+
+void TestPlatformAbstraction::SetSynchronouslyLoadedResource( Integration::ResourcePointer resource )
+{
+  mSynchronouslyLoadedResource = resource;
+}
+
+void TestPlatformAbstraction::SetDecodedBitmap( Integration::BitmapPtr bitmap )
+{
+  mDecodedBitmap = bitmap;
+}
+
+uint32_t TestPlatformAbstraction::StartTimer( uint32_t milliseconds, CallbackBase* callback )
+{
+  mCallbackFunction = callback;
+  mTimerId++;
+  return mTimerId;
+}
+
+void TestPlatformAbstraction::TriggerTimer()
+{
+  if (mCallbackFunction != nullptr)
+  {
+    CallbackBase::Execute( *mCallbackFunction );
+  }
+}
+
+void TestPlatformAbstraction::CancelTimer ( uint32_t timerId )
+{
+  mCallbackFunction = nullptr;
+}
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-platform-abstraction.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-platform-abstraction.h
new file mode 100644 (file)
index 0000000..7c1b010
--- /dev/null
@@ -0,0 +1,208 @@
+#ifndef DALI_TEST_PLATFORM_ABSTRACTION_H
+#define DALI_TEST_PLATFORM_ABSTRACTION_H
+
+/*
+ * Copyright (c) 2019 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 <stdint.h>
+#include <cstring>
+#include <string>
+#include <vector>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/platform-abstraction.h>
+#include <dali/public-api/math/vector2.h>
+
+#include "test-trace-call-stack.h"
+
+namespace Dali
+{
+
+/**
+ * Concrete implementation of the platform abstraction class.
+ */
+class DALI_CORE_API TestPlatformAbstraction : public Dali::Integration::PlatformAbstraction
+{
+
+public:
+
+  /**
+   * Constructor
+   */
+  TestPlatformAbstraction();
+
+  /**
+   * Destructor
+   */
+  virtual ~TestPlatformAbstraction();
+
+  /**
+   * @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 LoadImageSynchronously( const Integration::BitmapResourceType& resourceType, const std::string& resourcePath );
+
+  /**
+   * @copydoc PlatformAbstraction::DecodeBuffer()
+   */
+  virtual Integration::BitmapPtr DecodeBuffer( const Dali::Integration::BitmapResourceType& resourceType, uint8_t * buffer, size_t size );
+
+  /**
+   * @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 { return true; }
+
+  /**
+   * @copydoc PlatformAbstraction::StartTimer()
+   */
+  virtual uint32_t StartTimer( uint32_t milliseconds, CallbackBase* callback );
+
+  /*
+   * @copydoc PlatformAbstraction::CancelTimer()
+   */
+  virtual void CancelTimer ( uint32_t timerId );
+
+public: // TEST FUNCTIONS
+
+  // Enumeration of Platform Abstraction methods
+  typedef enum
+  {
+    LoadResourceSynchronouslyFunc,
+    LoadShaderBinaryFileFunc,
+    SaveShaderBinaryFileFunc
+  } TestFuncEnum;
+
+  /** Call this every test */
+  void Initialize();
+
+  inline void EnableTrace(bool enable) { mTrace.Enable(enable); }
+  inline void ResetTrace() { mTrace.Reset(); }
+  inline TraceCallStack& GetTrace() { return mTrace; }
+
+  /**
+   * @brief Checks if a platform function was called
+   * @param[in] func The function to check
+   * @return true if the function was called
+   */
+  bool WasCalled(TestFuncEnum func);
+
+  /**
+   * @brief Sets the result to return when IsLoading is called by Core.
+   * @param[in] result The result to set.
+   */
+  void SetIsLoadingResult(bool result);
+
+  /**
+   * @brief Clears all resource queues
+   */
+  void ClearReadyResources();
+
+  /**
+   * @brief Sets the value returned by GetClosestImageSize.
+   * @param[in] size The size that should be returned.
+   */
+  void SetClosestImageSize( const Vector2& size );
+
+  /**
+   * @brief Sets the result return by LoadFile.
+   * @param[in] result The value that LoadFile should return.
+   * @param[in] buffer The buffer of the loaded file.
+   */
+  void SetLoadFileResult( bool result, Dali::Vector< unsigned char >& buffer );
+
+  /**
+   * @brief Sets the SaveFile result
+   * @param[in] result The value that SaveFile should return
+   */
+  void SetSaveFileResult( bool result );
+
+  /**
+   * @brief Sets the resource loaded by LoadResourceSynchronously
+   * @param[in] resource The loaded resource
+   */
+  void SetSynchronouslyLoadedResource( Integration::ResourcePointer resource );
+
+  /**
+   * @brief Sets the bitmap returned by DecodeBuffer()
+   * @param[in] bitmap The decoded bitmap
+   */
+  void SetDecodedBitmap( Integration::BitmapPtr bitmap );
+
+  /**
+   * @brief Triggers the previously stored callback function
+   */
+  void TriggerTimer();
+
+private:
+
+  TestPlatformAbstraction( const TestPlatformAbstraction& ); ///< Undefined
+  TestPlatformAbstraction& operator=( const TestPlatformAbstraction& ); ///< Undefined
+
+private:
+
+  struct LoadFileResult
+  {
+    inline LoadFileResult()
+    : loadResult(false)
+    {
+
+    }
+
+    bool loadResult;
+    Dali::Vector< unsigned char> buffer;
+  };
+
+  mutable TraceCallStack        mTrace;
+  bool                          mIsLoadingResult;
+  ImageDimensions               mClosestSize;
+
+  LoadFileResult                mLoadFileResult;
+  bool                          mSaveFileResult;
+
+  Integration::ResourcePointer  mSynchronouslyLoadedResource;
+  Integration::BitmapPtr        mDecodedBitmap;
+
+  uint32_t                      mTimerId;
+  CallbackBase*                 mCallbackFunction;
+};
+
+} // Dali
+
+#endif /* DALI_TEST_PLATFORM_ABSTRACTION_H */
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-render-controller.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-render-controller.cpp
new file mode 100644 (file)
index 0000000..6f845d4
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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 "test-render-controller.h"
+
+namespace Dali
+{
+
+TestRenderController::TestRenderController()
+{
+  Initialize();
+}
+
+TestRenderController::~TestRenderController()
+{
+}
+
+void TestRenderController::RequestUpdate( bool forceUpdate )
+{
+  mRequestUpdateCalled = true;
+}
+
+void TestRenderController::RequestProcessEventsOnIdle( bool forceProcess )
+{
+  mRequestProcessEventsOnIdleCalled = true;
+}
+
+bool TestRenderController::WasCalled(TestRenderControllerFuncEnum func)
+{
+  switch(func)
+  {
+    case RequestUpdateFunc: return mRequestUpdateCalled;
+    case RequestProcessEventsOnIdleFunc: return mRequestProcessEventsOnIdleCalled;
+  }
+
+  return false;
+}
+
+void TestRenderController::Initialize()
+{
+  mRequestUpdateCalled = false;
+  mRequestProcessEventsOnIdleCalled = false;
+}
+
+
+} // namespace dali
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-render-controller.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-render-controller.h
new file mode 100644 (file)
index 0000000..d44e7b6
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef TEST_RENDER_CONTROLLER_H
+#define TEST_RENDER_CONTROLLER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/dali-common.h>
+#include <dali/integration-api/render-controller.h>
+
+namespace Dali
+{
+
+class DALI_CORE_API TestRenderController : public Dali::Integration::RenderController
+{
+public:
+  TestRenderController();
+  ~TestRenderController();
+
+  virtual void RequestUpdate( bool forceUpdate );
+  virtual void RequestProcessEventsOnIdle( bool forceProcess );
+
+  typedef enum
+  {
+    RequestUpdateFunc,
+    RequestProcessEventsOnIdleFunc,
+  } TestRenderControllerFuncEnum;
+
+  bool WasCalled(TestRenderControllerFuncEnum func);
+  void Initialize();
+
+
+private:
+  bool mRequestUpdateCalled;
+  bool mRequestProcessEventsOnIdleCalled;
+};
+
+} // Dali
+
+#endif // TEST_RENDER_CONTROLLER_H
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-touch-utils.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-touch-utils.h
new file mode 100644 (file)
index 0000000..3a623cb
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef TEST_TOUCH_UTILS_H
+#define TEST_TOUCH_UTILS_H
+
+/*
+ * Copyright (c) 2019 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/actors/actor.h>
+
+namespace Dali
+{
+
+// Data for touch events
+struct TouchEventData
+{
+  TouchEventData()
+  : functorCalled(false),
+    receivedTouch(),
+    touchActor()
+  {
+  }
+
+  void Reset()
+  {
+    functorCalled = false;
+
+    receivedTouch.points.clear();
+    receivedTouch.time = 0;
+
+    touchActor.Reset();
+  }
+
+  bool functorCalled;
+  TouchEvent receivedTouch;
+  Actor touchActor;
+};
+
+// Functor that sets the data when called
+struct TouchEventDataFunctor
+{
+  TouchEventDataFunctor(TouchEventData& data) : touchEventData(data) { }
+
+  bool operator()(Actor actor, const TouchEvent& touch)
+  {
+    touchEventData.functorCalled = true;
+    touchEventData.touchActor = actor;
+    touchEventData.receivedTouch = touch;
+    return false;
+  }
+
+  // Generate a touch-event
+  Integration::TouchEvent GenerateSingleTouch( PointState::Type state, const Vector2& screenPosition ) const
+  {
+    Integration::TouchEvent touchEvent;
+    Integration::Point point;
+    point.SetState( state );
+    point.SetScreenPosition( screenPosition );
+    touchEvent.points.push_back( point );
+    return touchEvent;
+  }
+
+  TouchEventData& touchEventData;
+};
+
+
+} // namespace Dali
+
+#endif // TEST_TOUCH_UTILS_H
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-trace-call-stack.cpp b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-trace-call-stack.cpp
new file mode 100644 (file)
index 0000000..f894389
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ * 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 "test-trace-call-stack.h"
+#include <sstream>
+
+namespace Dali
+{
+
+std::string ToString(int x)
+{
+  std::stringstream out;
+  out << x;
+  return out.str();
+}
+
+std::string ToString(unsigned int x)
+{
+  std::stringstream out;
+  out << x;
+  return out.str();
+}
+
+std::string ToString(float x)
+{
+  std::stringstream out;
+  out << x;
+  return out.str();
+}
+
+/**
+ * Constructor
+ */
+TraceCallStack::TraceCallStack() : mTraceActive(false) { }
+
+/**
+ * Destructor
+ */
+TraceCallStack::~TraceCallStack() { }
+
+/**
+ * Turn on / off tracing
+ */
+void TraceCallStack::Enable(bool enable) { mTraceActive = enable; }
+
+bool TraceCallStack::IsEnabled() { return mTraceActive; }
+
+/**
+ * Push a call onto the stack if the trace is active
+ * @param[in] method The name of the method
+ * @param[in] params A comma separated list of parameter values
+ */
+void TraceCallStack::PushCall(std::string method, std::string params)
+{
+  if(mTraceActive)
+  {
+    FunctionCall stackFrame(method, params);
+    mCallStack.push_back( stackFrame );
+  }
+}
+
+void TraceCallStack::PushCall(std::string method, std::string params, const TraceCallStack::NamedParams& altParams)
+{
+  if(mTraceActive)
+  {
+    FunctionCall stackFrame(method, params, altParams);
+    mCallStack.push_back( stackFrame );
+  }
+}
+
+/**
+ * Search for a method in the stack
+ * @param[in] method The name of the method
+ * @return true if the method was in the stack
+ */
+bool TraceCallStack::FindMethod(std::string method) const
+{
+  bool found = false;
+  for( size_t i=0; i < mCallStack.size(); i++ )
+  {
+    if( 0 == mCallStack[i].method.compare(method) )
+    {
+      found = true;
+      break;
+    }
+  }
+  return found;
+}
+
+bool TraceCallStack::FindMethodAndGetParameters(std::string method, std::string& params ) const
+{
+  bool found = false;
+  for( size_t i=0; i < mCallStack.size(); i++ )
+  {
+    if( 0 == mCallStack[i].method.compare(method) )
+    {
+      found = true;
+      params = mCallStack[i].paramList;
+      break;
+    }
+  }
+  return found;
+}
+
+int TraceCallStack::CountMethod(std::string method) const
+{
+  int numCalls = 0;
+  for( size_t i=0; i < mCallStack.size(); i++ )
+  {
+    if( 0 == mCallStack[i].method.compare(method) )
+    {
+      numCalls++;
+    }
+  }
+  return numCalls;
+}
+
+/**
+ * Search for a method in the stack with the given parameter list
+ * @param[in] method The name of the method
+ * @param[in] params A comma separated list of parameter values
+ * @return true if the method was in the stack
+ */
+bool TraceCallStack::FindMethodAndParams(std::string method, std::string params) const
+{
+  return FindIndexFromMethodAndParams( method, params ) > -1;
+}
+
+bool TraceCallStack::FindMethodAndParams(std::string method, const NamedParams& params) const
+{
+  return FindIndexFromMethodAndParams( method, params ) > -1;
+}
+
+bool TraceCallStack::FindMethodAndParamsFromStartIndex( std::string method, std::string params, size_t& startIndex ) const
+{
+  for( size_t i = startIndex; i < mCallStack.size(); ++i )
+  {
+    if( ( mCallStack[i].method.compare( method ) == 0 ) && ( mCallStack[i].paramList.compare( params ) == 0 ) )
+    {
+      startIndex = i;
+      return true;
+    }
+  }
+  return false;
+}
+
+/**
+ * Search for a method in the stack with the given parameter list
+ * @param[in] method The name of the method
+ * @param[in] params A comma separated list of parameter values
+ * @return index in the stack where the method was found or -1 otherwise
+ */
+int32_t TraceCallStack::FindIndexFromMethodAndParams(std::string method, std::string params) const
+{
+  int32_t index = -1;
+  for( size_t i=0; i < mCallStack.size(); i++ )
+  {
+    if( 0 == mCallStack[i].method.compare(method) && 0 == mCallStack[i].paramList.compare(params) )
+    {
+      index = static_cast<int32_t>( i );
+      break;
+    }
+  }
+  return index;
+}
+
+int TraceCallStack::FindIndexFromMethodAndParams(std::string method, const TraceCallStack::NamedParams& params) const
+{
+  int32_t index = -1;
+  for( size_t i=0; i < mCallStack.size(); i++ )
+  {
+    if( 0 == mCallStack[i].method.compare(method) )
+    {
+      // Test each of the passed in parameters:
+      bool match = true;
+      for( NamedParams::const_iterator iter = params.begin() ; iter != params.end() ; ++iter )
+      {
+        NamedParams::const_iterator paramIter = mCallStack[i].namedParams.find(iter->first);
+        if( paramIter == params.end() || paramIter->second.compare(iter->second) != 0 )
+        {
+          match = false;
+          break;
+        }
+      }
+      if( match == true )
+      {
+        index = static_cast<int32_t>( i );
+        break;
+      }
+    }
+  }
+  return index;
+}
+
+
+/**
+ * Test if the given method and parameters are at a given index in the stack
+ * @param[in] index Index in the call stack
+ * @param[in] method Name of method to test
+ * @param[in] params A comma separated list of parameter values to test
+ */
+bool TraceCallStack::TestMethodAndParams(int index, std::string method, std::string params) const
+{
+  return ( 0 == mCallStack[index].method.compare(method) && 0 == mCallStack[index].paramList.compare(params) );
+}
+
+/**
+ * Reset the call stack
+ */
+void TraceCallStack::Reset()
+{
+  mCallStack.clear();
+}
+
+
+} // namespace Dali
diff --git a/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-trace-call-stack.h b/automated-tests/src/dali-adaptor/dali-test-suite-utils/test-trace-call-stack.h
new file mode 100644 (file)
index 0000000..d569cba
--- /dev/null
@@ -0,0 +1,201 @@
+#ifndef TEST_TRACE_CALL_STACK_H
+#define TEST_TRACE_CALL_STACK_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.
+ *
+ */
+
+#include <string>
+#include <vector>
+#include <map>
+#include <sstream>
+
+namespace Dali
+{
+
+template<typename T>
+std::string ToString(const T& x)
+{
+  return "undefined";
+}
+
+std::string ToString(int x);
+std::string ToString(unsigned int x);
+std::string ToString(float x);
+
+/**
+ * Helper class to track method calls in the abstraction and search for them in test cases
+ */
+class TraceCallStack
+{
+public:
+
+  /// Typedef for passing and storing named parameters
+  typedef std::map< std::string, std::string > NamedParams;
+
+  /**
+   * Constructor
+   */
+  TraceCallStack();
+
+  /**
+   * Destructor
+   */
+  ~TraceCallStack();
+
+  /**
+   * Turn on / off tracing
+   */
+  void Enable(bool enable);
+
+  bool IsEnabled();
+
+  /**
+   * Push a call onto the stack if the trace is active
+   * @param[in] method The name of the method
+   * @param[in] params A comma separated list of parameter values
+   */
+  void PushCall(std::string method, std::string params);
+
+  /**
+   * Push a call onto the stack if the trace is active
+   * @param[in] method The name of the method
+   * @param[in] params A comma separated list of parameter values
+   * @param[in] altParams A map of named parameter values
+   */
+  void PushCall(std::string method, std::string params, const NamedParams& altParams);
+
+  /**
+   * Search for a method in the stack
+   * @param[in] method The name of the method
+   * @return true if the method was in the stack
+   */
+  bool FindMethod(std::string method) const;
+
+  /**
+   * Search for a method in the stack and return its parameters if found
+   * @param[in] method The name of the method
+   * @param[out] params of the method
+   * @return true if the method was in the stack
+   */
+  bool FindMethodAndGetParameters(std::string method, std::string& params ) const;
+
+  /**
+   * Count how many times a method was called
+   * @param[in] method The name of the method
+   * @return The number of times it was called
+   */
+  int CountMethod(std::string method) const;
+
+  /**
+   * Search for a method in the stack with the given parameter list
+   * @param[in] method The name of the method
+   * @param[in] params A comma separated list of parameter values
+   * @return true if the method was in the stack
+   */
+  bool FindMethodAndParams(std::string method, std::string params) const;
+
+  /**
+   * Search for a method in the stack with the given parameter list
+   * @param[in] method The name of the method
+   * @param[in] params A map of named parameters to test for
+   * @return true if the method was in the stack
+   */
+  bool FindMethodAndParams(std::string method, const NamedParams& params) const;
+
+  /**
+   * Search for a method in the stack with the given parameter list.
+   * The search is done from a given index.
+   * This allows the order of methods and parameters to be checked.
+   * @param[in] method The name of the method
+   * @param[in] params A comma separated list of parameter values
+   * @param[in/out] startIndex The method index to start looking from.
+   *                This is updated if a method is found so subsequent
+   *                calls can search for methods occuring after this one.
+   * @return True if the method was in the stack
+   */
+  bool FindMethodAndParamsFromStartIndex( std::string method, std::string params, size_t& startIndex ) const;
+
+  /**
+   * Search for a method in the stack with the given parameter list
+   * @param[in] method The name of the method
+   * @param[in] params A comma separated list of parameter values
+   * @return index in the stack where the method was found or -1 otherwise
+   */
+  int FindIndexFromMethodAndParams(std::string method, std::string params) const;
+
+  /**
+   * Search for a method in the stack with the given parameter list
+   * @param[in] method The name of the method
+   * @param[in] params A map of named parameter values to match
+   * @return index in the stack where the method was found or -1 otherwise
+   */
+  int FindIndexFromMethodAndParams(std::string method, const NamedParams& params) const;
+
+  /**
+   * Test if the given method and parameters are at a given index in the stack
+   * @param[in] index Index in the call stack
+   * @param[in] method Name of method to test
+   * @param[in] params A comma separated list of parameter values to test
+   */
+  bool TestMethodAndParams(int index, std::string method, std::string params) const;
+
+  /**
+   * Reset the call stack
+   */
+  void Reset();
+
+  /**
+   * Method to display contents of the TraceCallStack.
+   * @return A string containing a list of function calls and parameters (may contain newline characters)
+   */
+  std::string GetTraceString()
+  {
+    std::stringstream traceStream;
+    std::size_t functionCount = mCallStack.size();
+    for( std::size_t i = 0; i < functionCount; ++i )
+    {
+      Dali::TraceCallStack::FunctionCall functionCall = mCallStack[ i ];
+      traceStream << "StackTrace: Index:" << i << ",  Function:" << functionCall.method << ",  ParamList:" << functionCall.paramList << std::endl;
+    }
+
+    return traceStream.str();
+  }
+
+private:
+  bool mTraceActive; ///< True if the trace is active
+
+  struct FunctionCall
+  {
+    std::string method;
+    std::string paramList;
+    NamedParams namedParams;
+    FunctionCall( const std::string& aMethod, const std::string& aParamList )
+    : method( aMethod ), paramList( aParamList )
+    {
+    }
+    FunctionCall( const std::string& aMethod, const std::string& aParamList, const NamedParams& altParams )
+    : method( aMethod ), paramList( aParamList ), namedParams( altParams )
+    {
+    }
+  };
+
+  std::vector< FunctionCall > mCallStack; ///< The call stack
+};
+
+} // namespace dali
+
+#endif // TEST_TRACE_CALL_STACK_H
diff --git a/automated-tests/src/dali-adaptor/tct-dali-adaptor-core.cpp b/automated-tests/src/dali-adaptor/tct-dali-adaptor-core.cpp
new file mode 100644 (file)
index 0000000..86e70c9
--- /dev/null
@@ -0,0 +1,51 @@
+#include <string.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <test-harness.h>
+#include "tct-dali-adaptor-core.h"
+
+int main(int argc, char * const argv[])
+{
+  int result = TestHarness::EXIT_STATUS_BAD_ARGUMENT;
+
+  const char* optString = "sf";
+  bool optRerunFailed(true);
+  bool optRunSerially(false);
+
+  int nextOpt = 0;
+  do
+  {
+    nextOpt = getopt( argc, argv, optString );
+    switch(nextOpt)
+    {
+      case 'f':
+        optRerunFailed = false;
+        break;
+      case 's':
+        optRunSerially = true;
+        break;
+      case '?':
+        TestHarness::Usage(argv[0]);
+        exit(TestHarness::EXIT_STATUS_BAD_ARGUMENT);
+        break;
+    }
+  } while( nextOpt != -1 );
+
+  if( optind == argc ) // no testcase name in argument list
+  {
+    if( optRunSerially )
+    {
+      result = TestHarness::RunAll( argv[0], tc_array );
+    }
+    else
+    {
+      result = TestHarness::RunAllInParallel( argv[0], tc_array, optRerunFailed );
+    }
+  }
+  else
+  {
+    // optind is index of next argument - interpret as testcase name
+    result = TestHarness::FindAndRunTestCase(tc_array, argv[optind]);
+  }
+  return result;
+}
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-Application.cpp b/automated-tests/src/dali-adaptor/utc-Dali-Application.cpp
new file mode 100644 (file)
index 0000000..75175ff
--- /dev/null
@@ -0,0 +1,634 @@
+/*
+ * 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 <dali/dali.h>
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+
+void utc_dali_application_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_application_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+struct MyTestApp : public ConnectionTracker
+{
+  MyTestApp( Application& app)
+  : initCalled( false ),
+    application( app )
+  {
+    application.InitSignal().Connect( this, &MyTestApp::Create );
+  }
+
+  void Create(Application& app)
+  {
+    initCalled = true;
+  }
+
+  void Quit()
+  {
+    application.Quit();
+  }
+
+  // Data
+  bool initCalled;
+  Application& application;
+};
+
+void ApplicationSignalCallback( Application& app )
+{
+}
+
+void ApplicationControlSignalCallback(Application&, void *)
+{
+}
+
+} // unnamed namespace
+
+void LowBatterySignalCallback( Dali::DeviceStatus::Battery::Status status )
+{
+}
+
+void LowMemorySignalCallback( Dali::DeviceStatus::Memory::Status status )
+{
+}
+
+int UtcDaliApplicationNew01(void)
+{
+  Application application = Application::New();
+
+  MyTestApp testApp( application );
+
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationNew02(void)
+{
+  int argc( 1 );
+  const char* argList[1] = { "program" };
+  char** argv = const_cast<char**>(argList);
+
+  Application application = Application::New( &argc, &argv );
+
+  MyTestApp testApp( application );
+
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationNew03(void)
+{
+  int argc( 1 );
+  const char* argList[1] = { "program" };
+  char** argv = const_cast<char**>(argList);
+
+  Application application = Application::New( &argc, &argv, "stylesheet" );
+
+  MyTestApp testApp( application );
+
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationNew04(void)
+{
+  int argc( 1 );
+  const char* argList[1] = { "program" };
+  char** argv = const_cast<char**>(argList);
+
+  Application application = Application::New( &argc, &argv, "stylesheet", Application::TRANSPARENT );
+
+  MyTestApp testApp( application );
+
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationCopyAndAssignment(void)
+{
+  Application application = Application::New();
+  Application copy( application );
+  DALI_TEST_CHECK( copy == application );
+
+  Application assigned;
+  DALI_TEST_CHECK( !assigned );
+  assigned = application;
+  DALI_TEST_CHECK( copy == assigned );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationMainLoop01N(void)
+{
+  Application application;
+
+  try
+  {
+    application.MainLoop();
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationMainLoop02N(void)
+{
+  Application application;
+
+  try
+  {
+    application.MainLoop( Configuration::APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationLowerN(void)
+{
+  Application application;
+
+  try
+  {
+    application.Lower();
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationQuitN(void)
+{
+  Application application;
+
+  try
+  {
+    application.Quit();
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationAddIdleN(void)
+{
+  Application application;
+
+  try
+  {
+    CallbackBase* callback = NULL;
+    application.AddIdle( callback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationGetWindowN(void)
+{
+  Application application;
+
+  try
+  {
+    (void) application.GetWindow();
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationReplaceWindowN(void)
+{
+  Application application;
+
+  try
+  {
+    application.ReplaceWindow( PositionSize(), "window" );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationInitSignalP(void)
+{
+  Application application = Application::New();
+  application.InitSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationInitSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.InitSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationTerminateSignalP(void)
+{
+  Application application = Application::New();
+  application.TerminateSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationTerminateSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.TerminateSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationPauseSignalP(void)
+{
+  Application application = Application::New();
+  application.PauseSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationPauseSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.PauseSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationResumeSignalP(void)
+{
+  Application application = Application::New();
+  application.ResumeSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationResumeSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.ResumeSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationResetSignalP(void)
+{
+  Application application = Application::New();
+  application.ResetSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationResetSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.ResetSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationResizeSignalP(void)
+{
+  Application application = Application::New();
+  application.ResizeSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationResizeSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.ResizeSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationlControlSignalP(void)
+{
+  Application application = Application::New();
+  application.AppControlSignal().Connect( &ApplicationControlSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationlControlSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.AppControlSignal().Connect( &ApplicationControlSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationLanguageChangedSignalP(void)
+{
+  Application application = Application::New();
+  application.LanguageChangedSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationLanguageChangedSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.LanguageChangedSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationRegionChangedSignalP(void)
+{
+  Application application = Application::New();
+  application.RegionChangedSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationRegionChangedSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.RegionChangedSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationBatteryLowSignalP(void)
+{
+  Application application = Application::New();
+  application.BatteryLowSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationBatteryLowSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.BatteryLowSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationMemoryLowSignalP(void)
+{
+  Application application = Application::New();
+  application.MemoryLowSignal().Connect( &ApplicationSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationMemoryLowSignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.MemoryLowSignal().Connect( &ApplicationSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationLowBatterySignalP(void)
+{
+  Application application = Application::New();
+  application.LowBatterySignal().Connect( &LowBatterySignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationLowBatterySignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.LowBatterySignal().Connect( &LowBatterySignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationLowMemorySignalP(void)
+{
+  Application application = Application::New();
+  application.LowMemorySignal().Connect( &LowMemorySignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationLowMemorySignalN(void)
+{
+  Application application;
+
+  try
+  {
+    application.LowMemorySignal().Connect( &LowMemorySignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliApplicationGetResourcePathP(void)
+{
+  Application application = Application::New();
+  std::string result ("**invalid path**"); // Calling GetResourcePath should replace this with a system dependent path or "".
+  result = application.GetResourcePath();
+  DALI_TEST_CHECK( result !="**invalid path**" );
+
+  END_TEST;
+}
+
+int UtcDaliApplicationGetRegionP(void)
+{
+  Application application = Application::New();
+  std::string result;
+  result = application.GetRegion();
+  DALI_TEST_CHECK( result == "NOT_SUPPORTED" ); // Not supported in UBUNTU
+
+  END_TEST;
+}
+
+int UtcDaliApplicationGetLanguageP(void)
+{
+  Application application = Application::New();
+  std::string result;
+  result = application.GetLanguage();
+  DALI_TEST_CHECK( result == "NOT_SUPPORTED" ); // Not supported in UBUNTU
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-FileLoader.cpp b/automated-tests/src/dali-adaptor/utc-Dali-FileLoader.cpp
new file mode 100644 (file)
index 0000000..724cbea
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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 <dali/dali.h>
+#include <dali-test-suite-utils.h>
+#include <dali/devel-api/adaptor-framework/file-loader.h>
+
+
+
+using namespace Dali;
+
+
+void utc_dali_file_loader_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_file_loader_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliReadFileNew1(void)
+{
+  int errorCode;
+  Dali::Vector<char> buffer;
+
+  //negative case
+  errorCode = FileLoader::ReadFile( TEST_RESOURCE_DIR "/not_exist.txt", buffer, FileLoader::TEXT );
+
+  DALI_TEST_CHECK( errorCode == 0 );
+
+  DALI_TEST_CHECK( buffer.Size() == 0 );
+
+  //positive case
+  errorCode = FileLoader::ReadFile( TEST_RESOURCE_DIR "/test.txt", buffer, FileLoader::TEXT );
+
+  DALI_TEST_CHECK( errorCode != 0 );
+
+  DALI_TEST_CHECK( buffer.Size() > 0 );
+
+  END_TEST;
+}
+
+int UtcDaliReadFileNew2(void)
+{
+  int errorCode;
+  Dali::Vector<char> buffer;
+  std::streampos fileSize = 0;
+
+  //negative case
+  errorCode = FileLoader::ReadFile( TEST_RESOURCE_DIR "/not_exist.txt", fileSize, buffer, FileLoader::TEXT );
+
+  DALI_TEST_CHECK( errorCode == 0 );
+
+  DALI_TEST_CHECK( buffer.Size() == 0 );
+
+  DALI_TEST_CHECK( fileSize == 0 );
+
+  //positive case
+  errorCode = FileLoader::ReadFile( TEST_RESOURCE_DIR "/test.txt", fileSize, buffer, FileLoader::TEXT );
+
+  DALI_TEST_CHECK( errorCode != 0 );
+
+  DALI_TEST_CHECK( buffer.Size() > 0 );
+
+  DALI_TEST_CHECK( fileSize != 0 );
+
+  END_TEST;
+}
+
+int UtcDaliReadFileNew3(void)
+{
+  std::streampos fileSize = 0;
+
+  //negative case
+  fileSize = FileLoader::GetFileSize( TEST_RESOURCE_DIR "/not_exist.txt" );
+
+  DALI_TEST_CHECK( fileSize == 0 );
+
+  //positive case
+  fileSize = FileLoader::GetFileSize( TEST_RESOURCE_DIR "/test.txt" );
+
+  DALI_TEST_CHECK( fileSize != 0 );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-GifLoading.cpp b/automated-tests/src/dali-adaptor/utc-Dali-GifLoading.cpp
new file mode 100755 (executable)
index 0000000..6a4fa87
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * 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 <stdlib.h>
+#include <dali/dali.h>
+#include <dali-test-suite-utils.h>
+#include <dali/devel-api/adaptor-framework/gif-loading.h>
+
+using namespace Dali;
+
+namespace
+{
+// test gif image, resolution: 100*100, 5 frames, delay: 1 second, disposal method: none
+static const char* gGif_100_None = TEST_RESOURCE_DIR "/canvas-none.gif";
+// test gif image, resolution: 100*100, 5 frames, delay: 1 second, disposal method: none for first frame and previous for the rest
+static const char* gGif_100_Prev = TEST_RESOURCE_DIR "/canvas-prev.gif";
+// test gif image, resolution: 100*100, 5 frames, delay: 1 second, disposal method: background
+static const char* gGif_100_Bgnd = TEST_RESOURCE_DIR "/canvas-bgnd.gif";
+
+// this image if not exist, for negative test
+static const char* gGifNonExist = "non-exist.gif";
+
+void VerifyLoad( std::vector<Dali::PixelData>& pixelDataList, Dali::Vector<uint32_t>& frameDelayList,
+                 uint32_t frameCount, uint32_t width, uint32_t height, uint32_t delay )
+{
+  DALI_TEST_EQUALS( pixelDataList.size(), frameCount, TEST_LOCATION );
+  DALI_TEST_EQUALS( frameDelayList.Size(), frameCount, TEST_LOCATION );
+
+  for( uint32_t idx = 0; idx<frameCount; idx++ )
+  {
+    // Check the image size and delay of each frame
+    DALI_TEST_EQUALS( pixelDataList[idx].GetWidth(), width, TEST_LOCATION );
+    DALI_TEST_EQUALS( pixelDataList[idx].GetHeight(), height, TEST_LOCATION );
+    DALI_TEST_EQUALS( frameDelayList[idx], delay, TEST_LOCATION );
+  }
+}
+}
+
+void utc_dali_gif_loader_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_gif_loader_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliGifLoadingP(void)
+{
+  std::vector<Dali::PixelData> pixelDataList;
+  Dali::Vector<uint32_t> frameDelayList;
+
+  std::unique_ptr<Dali::GifLoading> gifLoading = GifLoading::New( gGif_100_None, true );
+  bool succeed = gifLoading->LoadAllFrames( pixelDataList, frameDelayList );
+
+  // Check that the loading succeed
+  DALI_TEST_CHECK( succeed );
+  VerifyLoad( pixelDataList, frameDelayList, 5u, 100u, 100u, 1000u );
+
+  pixelDataList.clear();
+  gifLoading = GifLoading::New( gGif_100_Prev, true );
+  succeed = gifLoading->LoadAllFrames( pixelDataList, frameDelayList );
+  // Check that the loading succeed
+  DALI_TEST_CHECK( succeed );
+  VerifyLoad( pixelDataList, frameDelayList, 5u, 100u, 100u, 1000u );
+
+  pixelDataList.clear();
+  gifLoading = GifLoading::New( gGif_100_Bgnd, true );
+  succeed = gifLoading->LoadAllFrames( pixelDataList, frameDelayList );
+
+  // Check that the loading succeed
+  DALI_TEST_CHECK( succeed );
+  VerifyLoad( pixelDataList, frameDelayList, 5u, 100u, 100u, 1000u  );
+
+  END_TEST;
+}
+
+int UtcDaliGifLoadingN(void)
+{
+  std::vector<Dali::PixelData> pixelDataList;
+  Dali::Vector<uint32_t> frameDelayList;
+
+  std::unique_ptr<Dali::GifLoading> gifLoading = GifLoading::New( gGifNonExist, true );
+  bool succeed = gifLoading->LoadAllFrames( pixelDataList, frameDelayList );
+
+  // Check that the loading failed
+  DALI_TEST_CHECK( !succeed );
+
+  // Check that both pixelDataList and frameDelayList are empty
+  DALI_TEST_EQUALS( pixelDataList.size(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( frameDelayList.Size(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliGifLoadingGetImageSizeP(void)
+{
+  std::unique_ptr<Dali::GifLoading> gifLoading = GifLoading::New( gGif_100_None, true );
+  ImageDimensions imageSize = gifLoading->GetImageSize();
+
+  // Check that the image size is [100, 100]
+  DALI_TEST_EQUALS( imageSize.GetWidth(), 100u, TEST_LOCATION );
+  DALI_TEST_EQUALS( imageSize.GetHeight(), 100u, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliGifLoadingGetImageSizeN(void)
+{
+  std::unique_ptr<Dali::GifLoading> gifLoading = GifLoading::New( gGifNonExist, true );
+  ImageDimensions imageSize = gifLoading->GetImageSize();
+
+  // Check that it returns zero size when the gif is not valid
+  DALI_TEST_EQUALS( imageSize.GetWidth(), 0u, TEST_LOCATION );
+  DALI_TEST_EQUALS( imageSize.GetHeight(), 0u, TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-ImageLoading.cpp b/automated-tests/src/dali-adaptor/utc-Dali-ImageLoading.cpp
new file mode 100644 (file)
index 0000000..a9b6010
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * 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 <stdlib.h>
+#include <dali/dali.h>
+#include <dali-test-suite-utils.h>
+#include <dali-test-img-utils.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+
+using namespace Dali;
+
+namespace
+{
+// resolution: 34*34, pixel format: RGBA8888
+const char* IMAGE_34_RGBA = TEST_RESOURCE_DIR "/icon-edit.png";
+// resolution: 128*128, pixel format: RGB888
+const char* IMAGE_128_RGB = TEST_RESOURCE_DIR "/gallery-small-1.jpg";
+
+// resolution: 2000*2560, pixel format: RGB888
+const char* IMAGE_LARGE_EXIF3_RGB = TEST_RESOURCE_DIR "/f-large-exif-3.jpg";
+
+// resolution: 55*64, pixel format: RGB888
+const char* IMAGE_WIDTH_ODD_EXIF1_RGB = TEST_RESOURCE_DIR "/f-odd-exif-1.jpg";
+// resolution: 55*64, pixel format: RGB888
+const char* IMAGE_WIDTH_ODD_EXIF2_RGB = TEST_RESOURCE_DIR "/f-odd-exif-2.jpg";
+// resolution: 55*64, pixel format: RGB888
+const char* IMAGE_WIDTH_ODD_EXIF3_RGB = TEST_RESOURCE_DIR "/f-odd-exif-3.jpg";
+// resolution: 55*64, pixel format: RGB888
+const char* IMAGE_WIDTH_ODD_EXIF4_RGB = TEST_RESOURCE_DIR "/f-odd-exif-4.jpg";
+// resolution: 55*64, pixel format: RGB888
+const char* IMAGE_WIDTH_ODD_EXIF5_RGB = TEST_RESOURCE_DIR "/f-odd-exif-5.jpg";
+// resolution: 55*64, pixel format: RGB888
+const char* IMAGE_WIDTH_ODD_EXIF6_RGB = TEST_RESOURCE_DIR "/f-odd-exif-6.jpg";
+// resolution: 55*64, pixel format: RGB888
+const char* IMAGE_WIDTH_ODD_EXIF7_RGB = TEST_RESOURCE_DIR "/f-odd-exif-7.jpg";
+// resolution: 55*64, pixel format: RGB888
+const char* IMAGE_WIDTH_ODD_EXIF8_RGB = TEST_RESOURCE_DIR "/f-odd-exif-8.jpg";
+
+// resolution: 50*64, pixel format: RGB888
+const char* IMAGE_WIDTH_EVEN_EXIF1_RGB = TEST_RESOURCE_DIR "/f-even-exif-1.jpg";
+// resolution: 50*64, pixel format: RGB888
+const char* IMAGE_WIDTH_EVEN_EXIF2_RGB = TEST_RESOURCE_DIR "/f-even-exif-2.jpg";
+// resolution: 50*64, pixel format: RGB888
+const char* IMAGE_WIDTH_EVEN_EXIF3_RGB = TEST_RESOURCE_DIR "/f-even-exif-3.jpg";
+// resolution: 50*64, pixel format: RGB888
+const char* IMAGE_WIDTH_EVEN_EXIF4_RGB = TEST_RESOURCE_DIR "/f-even-exif-4.jpg";
+// resolution: 50*64, pixel format: RGB888
+const char* IMAGE_WIDTH_EVEN_EXIF5_RGB = TEST_RESOURCE_DIR "/f-even-exif-5.jpg";
+// resolution: 50*64, pixel format: RGB888
+const char* IMAGE_WIDTH_EVEN_EXIF6_RGB = TEST_RESOURCE_DIR "/f-even-exif-6.jpg";
+// resolution: 50*64, pixel format: RGB888
+const char* IMAGE_WIDTH_EVEN_EXIF7_RGB = TEST_RESOURCE_DIR "/f-even-exif-7.jpg";
+// resolution: 50*64, pixel format: RGB888
+const char* IMAGE_WIDTH_EVEN_EXIF8_RGB = TEST_RESOURCE_DIR "/f-even-exif-8.jpg";
+
+
+// this is image is not exist, for negative test
+const char* IMAGENONEXIST = "non-exist.jpg";
+}
+
+void utc_dali_load_image_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_load_image_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliLoadImageP(void)
+{
+  Devel::PixelBuffer pixelBuffer = Dali::LoadImageFromFile( IMAGE_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( IMAGE_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  );
+
+  Devel::PixelBuffer pixelBufferJpeg = Dali::LoadImageFromFile( IMAGE_LARGE_EXIF3_RGB );
+  DALI_TEST_CHECK( pixelBufferJpeg );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetWidth(), 2000u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetHeight(), 2560u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+
+  Devel::PixelBuffer BufferJpeg1 = Dali::LoadImageFromFile( IMAGE_WIDTH_ODD_EXIF1_RGB );
+  DALI_TEST_CHECK( BufferJpeg1 );
+  DALI_TEST_EQUALS( BufferJpeg1.GetWidth(), 55u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( BufferJpeg1.GetHeight(), 64u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( BufferJpeg1.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+
+  pixelBufferJpeg = Dali::LoadImageFromFile( IMAGE_WIDTH_ODD_EXIF2_RGB );
+  DALI_TEST_CHECK( pixelBufferJpeg );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetWidth(), 55u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetHeight(), 64u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+  DALI_IMAGE_TEST_EQUALS( BufferJpeg1, pixelBufferJpeg, 8, TEST_LOCATION);
+
+  pixelBufferJpeg = Dali::LoadImageFromFile( IMAGE_WIDTH_ODD_EXIF3_RGB );
+  DALI_TEST_CHECK( pixelBufferJpeg );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetWidth(), 55u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetHeight(), 64u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+  DALI_IMAGE_TEST_EQUALS( BufferJpeg1, pixelBufferJpeg, 8, TEST_LOCATION);
+
+  pixelBufferJpeg = Dali::LoadImageFromFile( IMAGE_WIDTH_ODD_EXIF4_RGB );
+  DALI_TEST_CHECK( pixelBufferJpeg );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetWidth(), 55u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetHeight(), 64u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+  DALI_IMAGE_TEST_EQUALS( BufferJpeg1, pixelBufferJpeg, 8, TEST_LOCATION);
+
+  pixelBufferJpeg = Dali::LoadImageFromFile( IMAGE_WIDTH_ODD_EXIF5_RGB );
+  DALI_TEST_CHECK( pixelBufferJpeg );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetWidth(), 55u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetHeight(), 64u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+  DALI_IMAGE_TEST_EQUALS( BufferJpeg1, pixelBufferJpeg, 8, TEST_LOCATION);
+
+  pixelBufferJpeg = Dali::LoadImageFromFile( IMAGE_WIDTH_ODD_EXIF6_RGB );
+  DALI_TEST_CHECK( pixelBufferJpeg );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetWidth(), 55u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetHeight(), 64u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+  DALI_IMAGE_TEST_EQUALS( BufferJpeg1, pixelBufferJpeg, 8, TEST_LOCATION);
+
+  pixelBufferJpeg = Dali::LoadImageFromFile( IMAGE_WIDTH_ODD_EXIF7_RGB );
+  DALI_TEST_CHECK( pixelBufferJpeg );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetWidth(), 55u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetHeight(), 64u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+  DALI_IMAGE_TEST_EQUALS( BufferJpeg1, pixelBufferJpeg, 8, TEST_LOCATION);
+
+  pixelBufferJpeg = Dali::LoadImageFromFile( IMAGE_WIDTH_ODD_EXIF8_RGB );
+  DALI_TEST_CHECK( pixelBufferJpeg );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetWidth(), 55u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetHeight(), 64u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+  DALI_IMAGE_TEST_EQUALS( BufferJpeg1, pixelBufferJpeg, 8, TEST_LOCATION);
+
+  BufferJpeg1 = Dali::LoadImageFromFile( IMAGE_WIDTH_EVEN_EXIF1_RGB );
+  DALI_TEST_CHECK( BufferJpeg1 );
+  DALI_TEST_EQUALS( BufferJpeg1.GetWidth(), 50u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( BufferJpeg1.GetHeight(), 64u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( BufferJpeg1.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+
+  pixelBufferJpeg = Dali::LoadImageFromFile( IMAGE_WIDTH_EVEN_EXIF2_RGB );
+  DALI_TEST_CHECK( pixelBufferJpeg );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetWidth(), 50u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetHeight(), 64u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+  DALI_IMAGE_TEST_EQUALS( BufferJpeg1, pixelBufferJpeg, 8, TEST_LOCATION);
+
+  pixelBufferJpeg = Dali::LoadImageFromFile( IMAGE_WIDTH_EVEN_EXIF3_RGB );
+  DALI_TEST_CHECK( pixelBufferJpeg );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetWidth(), 50u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetHeight(), 64u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+  DALI_IMAGE_TEST_EQUALS( BufferJpeg1, pixelBufferJpeg, 8, TEST_LOCATION);
+
+  pixelBufferJpeg = Dali::LoadImageFromFile( IMAGE_WIDTH_EVEN_EXIF4_RGB );
+  DALI_TEST_CHECK( pixelBufferJpeg );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetWidth(), 50u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetHeight(), 64u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+  DALI_IMAGE_TEST_EQUALS( BufferJpeg1, pixelBufferJpeg, 8, TEST_LOCATION);
+
+  pixelBufferJpeg = Dali::LoadImageFromFile( IMAGE_WIDTH_EVEN_EXIF5_RGB );
+  DALI_TEST_CHECK( pixelBufferJpeg );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetWidth(), 50u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetHeight(), 64u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+  DALI_IMAGE_TEST_EQUALS( BufferJpeg1, pixelBufferJpeg, 8, TEST_LOCATION);
+
+  pixelBufferJpeg = Dali::LoadImageFromFile( IMAGE_WIDTH_EVEN_EXIF6_RGB );
+  DALI_TEST_CHECK( pixelBufferJpeg );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetWidth(), 50u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetHeight(), 64u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+  DALI_IMAGE_TEST_EQUALS( BufferJpeg1, pixelBufferJpeg, 8, TEST_LOCATION);
+
+  pixelBufferJpeg = Dali::LoadImageFromFile( IMAGE_WIDTH_EVEN_EXIF7_RGB );
+  DALI_TEST_CHECK( pixelBufferJpeg );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetWidth(), 50u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetHeight(), 64u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+  DALI_IMAGE_TEST_EQUALS( BufferJpeg1, pixelBufferJpeg, 8, TEST_LOCATION);
+
+  pixelBufferJpeg = Dali::LoadImageFromFile( IMAGE_WIDTH_EVEN_EXIF8_RGB );
+  DALI_TEST_CHECK( pixelBufferJpeg );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetWidth(), 50u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetHeight(), 64u, TEST_LOCATION  );
+  DALI_TEST_EQUALS( pixelBufferJpeg.GetPixelFormat(), Pixel::RGB888, TEST_LOCATION  );
+  DALI_IMAGE_TEST_EQUALS( BufferJpeg1, pixelBufferJpeg, 8, TEST_LOCATION);
+
+  END_TEST;
+}
+
+int UtcDaliLoadImageN(void)
+{
+  Devel::PixelBuffer pixelBuffer = Dali::LoadImageFromFile( IMAGENONEXIST );
+  DALI_TEST_CHECK( !pixelBuffer );
+
+  END_TEST;
+}
+
+
+int UtcDaliDownloadImageP(void)
+{
+  std::string url("file://");
+  url.append( IMAGE_34_RGBA );
+
+  std::string url2("file://");
+  url2.append( IMAGE_128_RGB );
+
+  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  );
+
+  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)
+{
+  Devel::PixelBuffer pixelBuffer = Dali::DownloadImageSynchronously( IMAGENONEXIST );
+  DALI_TEST_CHECK( !pixelBuffer );
+
+  END_TEST;
+}
+
+
+int UtcDaliDownloadRemoteChunkedImage(void)
+{
+  std::string url("http://d2k43l0oslhof9.cloudfront.net/platform/image/contents/vc/20/01/58/20170629100630071189_0bf6b911-a847-cba4-e518-be40fe2f579420170629192203240.jpg");
+
+  Devel::PixelBuffer pixelBuffer = Dali::DownloadImageSynchronously( url );
+  DALI_TEST_CHECK( pixelBuffer );
+  DALI_TEST_EQUALS( pixelBuffer.GetWidth(), 279u, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelBuffer.GetHeight(), 156u, TEST_LOCATION );
+  DALI_TEST_EQUALS( pixelBuffer.GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION  );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-Key.cpp b/automated-tests/src/dali-adaptor/utc-Dali-Key.cpp
new file mode 100644 (file)
index 0000000..9a2e7dc
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * 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 <map>
+#include <string.h>
+#include <iostream>
+
+// CLASS HEADER
+#include <stdlib.h>
+#include <iostream>
+#include <dali.h>
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+
+void utc_dali_adaptor_key_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_adaptor_key_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+// Copied from key-impl.h
+struct KeyLookup
+{
+  const char* keyName;          ///< XF86 key name
+  const Dali::KEY daliKeyCode;  ///< Dali key code
+  const bool  deviceButton;     ///< Whether the key is from a button on the device
+};
+
+// Common keys for all platforms
+KeyLookup KeyLookupTable[]=
+{
+  { "Escape",                DALI_KEY_ESCAPE,          false },  // item not defined in utilX
+  { "Menu",                  DALI_KEY_MENU,            false },  // item not defined in utilX
+
+  // Now the key names are used as literal string not defined symbols,
+  // since these definition in utilX.h is deprecated and we're guided not to use them
+  { "XF86Camera",            DALI_KEY_CAMERA,          false },
+  { "XF86Camera_Full",       DALI_KEY_CONFIG,          false },
+  { "XF86PowerOff",          DALI_KEY_POWER,           true  },
+  { "XF86Standby",           DALI_KEY_PAUSE,           false },
+  { "Cancel",                DALI_KEY_CANCEL,          false },
+  { "XF86AudioPlay",         DALI_KEY_PLAY_CD,         false },
+  { "XF86AudioStop",         DALI_KEY_STOP_CD,         false },
+  { "XF86AudioPause",        DALI_KEY_PAUSE_CD,        false },
+  { "XF86AudioNext",         DALI_KEY_NEXT_SONG,       false },
+  { "XF86AudioPrev",         DALI_KEY_PREVIOUS_SONG,   false },
+  { "XF86AudioRewind",       DALI_KEY_REWIND,          false },
+  { "XF86AudioForward",      DALI_KEY_FASTFORWARD,     false },
+  { "XF86AudioMedia",        DALI_KEY_MEDIA,           false },
+  { "XF86AudioPlayPause",    DALI_KEY_PLAY_PAUSE,      false },
+  { "XF86AudioMute",         DALI_KEY_MUTE,            false },
+  { "XF86Menu",              DALI_KEY_MENU,            true  },
+  { "XF86Home",              DALI_KEY_HOME,            true  },
+  { "XF86Back",              DALI_KEY_BACK,            true  },
+  { "XF86Send",              DALI_KEY_MENU,            true  },
+  { "XF86Phone",             DALI_KEY_HOME,            true  },
+  { "XF86Stop",              DALI_KEY_BACK,            true  },
+  { "XF86HomePage",          DALI_KEY_HOMEPAGE,        false },
+  { "XF86WWW",               DALI_KEY_WEBPAGE,         false },
+  { "XF86Mail",              DALI_KEY_MAIL,            false },
+  { "XF86ScreenSaver",       DALI_KEY_SCREENSAVER,     false },
+  { "XF86MonBrightnessUp",   DALI_KEY_BRIGHTNESS_UP,   false },
+  { "XF86MonBrightnessDown", DALI_KEY_BRIGHTNESS_DOWN, false },
+  { "XF86SoftKBD",           DALI_KEY_SOFT_KBD,        false },
+  { "XF86QuickPanel",        DALI_KEY_QUICK_PANEL,     false },
+  { "XF86TaskPane",          DALI_KEY_TASK_SWITCH,     false },
+  { "XF86Apps",              DALI_KEY_APPS,            false },
+  { "XF86Search",            DALI_KEY_SEARCH,          false },
+  { "XF86Voice",             DALI_KEY_VOICE,           false },
+  { "Hangul",                DALI_KEY_LANGUAGE,        false },
+  { "XF86AudioRaiseVolume",  DALI_KEY_VOLUME_UP,       true  },
+  { "XF86AudioLowerVolume",  DALI_KEY_VOLUME_DOWN,     true  },
+};
+const std::size_t KEY_LOOKUP_COUNT = (sizeof( KeyLookupTable))/ (sizeof(KeyLookup));
+
+
+// Generate a KeyPressEvent to send to Core
+Dali::KeyEvent GenerateKeyPress( const std::string& keyName )
+{
+  KeyEvent keyPress;
+  keyPress.keyPressedName = keyName;
+  return keyPress;
+}
+
+int UtcDaliKeyIsKey(void)
+{
+  TestApplication application;
+
+  for ( std::size_t i = 0; i < KEY_LOOKUP_COUNT; ++i )
+  {
+    tet_printf( "Checking %s", KeyLookupTable[i].keyName );
+    DALI_TEST_CHECK( IsKey( GenerateKeyPress( KeyLookupTable[i].keyName ), KeyLookupTable[i].daliKeyCode ) );
+  }
+  END_TEST;
+}
+
+int UtcDaliKeyIsKeyNegative(void)
+{
+  TestApplication application;
+
+  // Random value
+  DALI_TEST_CHECK( IsKey( GenerateKeyPress( "invalid-key-name" ), DALI_KEY_MUTE ) == false );
+
+  // Compare with another key value
+  for ( std::size_t i = 0; i < KEY_LOOKUP_COUNT; ++i )
+  {
+    tet_printf( "Checking %s", KeyLookupTable[i].keyName );
+    DALI_TEST_CHECK( IsKey( GenerateKeyPress( KeyLookupTable[i].keyName ), KeyLookupTable[ ( i + 1 ) % KEY_LOOKUP_COUNT ].daliKeyCode ) == false );
+  }
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-KeyGrab.cpp b/automated-tests/src/dali-adaptor/utc-Dali-KeyGrab.cpp
new file mode 100644 (file)
index 0000000..1a5d8ce
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * 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 <map>
+#include <string.h>
+#include <iostream>
+
+// CLASS HEADER
+#include <stdlib.h>
+#include <iostream>
+#include <dali.h>
+#include <dali-test-suite-utils.h>
+#include <dali/public-api/adaptor-framework/key-grab.h>
+
+extern int gArgc;
+extern char ** gArgv;
+
+using namespace Dali;
+
+void utc_dali_adaptor_keygrab_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_adaptor_keygrab_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+// Copied from key-impl.cpp
+struct KeyLookup
+{
+  const char* keyName;      ///< X string representation
+  const KEY   daliKeyCode;  ///< Dali Enum Representation
+  const bool  deviceButton; ///< Whether the key is from a button on the device
+};
+
+// Taken from key-impl.cpp
+KeyLookup TestKeyLookupTable[]=
+{
+  { "Escape",                DALI_KEY_ESCAPE,          false },  // item not defined in utilX
+  { "Menu",                  DALI_KEY_MENU,            false },  // item not defined in utilX
+
+  // Now the key names are used as literal string not defined symbols,
+  // since these definition in utilX.h is deprecated and we're guided not to use them
+  { "XF86Camera",            DALI_KEY_CAMERA,          false },
+  { "XF86Camera_Full",       DALI_KEY_CONFIG,          false },
+  { "XF86PowerOff",          DALI_KEY_POWER,           true  },
+  { "Cancel",                DALI_KEY_CANCEL,          false },
+  { "XF86AudioPlay",         DALI_KEY_PLAY_CD,         false },
+  { "XF86AudioStop",         DALI_KEY_STOP_CD,         false },
+  { "XF86AudioPause",        DALI_KEY_PAUSE_CD,        false },
+  { "XF86AudioNext",         DALI_KEY_NEXT_SONG,       false },
+  { "XF86AudioPrev",         DALI_KEY_PREVIOUS_SONG,   false },
+  { "XF86AudioRewind",       DALI_KEY_REWIND,          false },
+  { "XF86AudioForward",      DALI_KEY_FASTFORWARD,     false },
+  { "XF86AudioMedia",        DALI_KEY_MEDIA,           false },
+  { "XF86AudioPlayPause",    DALI_KEY_PLAY_PAUSE,      false },
+  { "XF86AudioMute",         DALI_KEY_MUTE,            false },
+  { "XF86Menu",              DALI_KEY_MENU,            true  },
+  { "XF86Send",              DALI_KEY_MENU,            true  },
+  { "XF86HomePage",          DALI_KEY_HOMEPAGE,        false },
+  { "XF86WWW",               DALI_KEY_WEBPAGE,         false },
+  { "XF86Mail",              DALI_KEY_MAIL,            false },
+  { "XF86ScreenSaver",       DALI_KEY_SCREENSAVER,     false },
+  { "XF86MonBrightnessUp",   DALI_KEY_BRIGHTNESS_UP,   false },
+  { "XF86MonBrightnessDown", DALI_KEY_BRIGHTNESS_DOWN, false },
+  { "XF86SoftKBD",           DALI_KEY_SOFT_KBD,        false },
+  { "XF86QuickPanel",        DALI_KEY_QUICK_PANEL,     false },
+  { "XF86TaskPane",          DALI_KEY_TASK_SWITCH,     false },
+  { "XF86Apps",              DALI_KEY_APPS,            false },
+  { "XF86Search",            DALI_KEY_SEARCH,          false },
+  { "XF86Voice",             DALI_KEY_VOICE,           false },
+  { "Hangul",                DALI_KEY_LANGUAGE,        false },
+  { "XF86AudioRaiseVolume",  DALI_KEY_VOLUME_UP,       true  },
+  { "XF86AudioLowerVolume",  DALI_KEY_VOLUME_DOWN,     true  },
+
+  { "BackSpace",             DALI_KEY_BACKSPACE,       false },
+  { "Left",                  DALI_KEY_CURSOR_LEFT,     false },
+  { "Right",                 DALI_KEY_CURSOR_RIGHT,    false }
+};
+
+const std::size_t KEY_LOOKUP_COUNT = (sizeof( TestKeyLookupTable))/ (sizeof(KeyLookup));
+
+enum TEST_TYPE
+{
+  GRAB_KEY_TOPMOST_P,
+  UNGRAB_KEY_TOPMOST_P
+};
+
+struct MyTestApp : public ConnectionTracker
+{
+  MyTestApp( Application& app, int type )
+  : mApplication( app ),
+    mTestType( type )
+  {
+    mApplication.InitSignal().Connect( this, &MyTestApp::OnInit );
+  }
+
+  void OnInit(Application& app)
+  {
+    mTimer = Timer::New( 500 );
+    mTimer.TickSignal().Connect( this, &MyTestApp::Tick );
+    mTimer.Start();
+
+    ExcuteTest();
+  }
+
+  bool Tick()
+  {
+    mTimer.Stop();
+    mApplication.Quit();
+    return true;
+  }
+
+  void ExcuteTest()
+  {
+    switch (mTestType)
+    {
+      case GRAB_KEY_TOPMOST_P:
+        TestGrabKeyTopmostP();
+        break;
+      case UNGRAB_KEY_TOPMOST_P:
+        TestUngrabKeyTopmostP();
+        break;
+    }
+  }
+
+  void TestGrabKeyTopmostP()
+  {
+    for ( std::size_t i = 0; i < KEY_LOOKUP_COUNT; ++i )
+    {
+      DALI_TEST_CHECK( KeyGrab::GrabKeyTopmost( mApplication.GetWindow(), TestKeyLookupTable[i].daliKeyCode ) );
+    }
+  }
+
+  void TestUngrabKeyTopmostP()
+  {
+    for ( std::size_t i = 0; i < KEY_LOOKUP_COUNT; ++i )
+    {
+      DALI_TEST_CHECK( KeyGrab::GrabKeyTopmost( mApplication.GetWindow(), TestKeyLookupTable[i].daliKeyCode ) );
+      DALI_TEST_CHECK( KeyGrab::UngrabKeyTopmost( mApplication.GetWindow(), TestKeyLookupTable[i].daliKeyCode ) );
+    }
+  }
+
+  // Data
+  Application& mApplication;
+  int mTestType;
+  Timer mTimer;
+};
+
+int UtcDaliKeyGrabGrabKeyTopmostP(void)
+{
+  Application application = Application::New( &gArgc, &gArgv );
+  MyTestApp testApp( application, GRAB_KEY_TOPMOST_P );
+  application.MainLoop();
+  END_TEST;
+}
+
+int UtcDaliKeyGrabUngrabKeyTopmostP(void)
+{
+  Application application = Application::New( &gArgc, &gArgv );
+  MyTestApp testApp( application, UNGRAB_KEY_TOPMOST_P );
+  application.MainLoop();
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-NativeImageSource.cpp b/automated-tests/src/dali-adaptor/utc-Dali-NativeImageSource.cpp
new file mode 100644 (file)
index 0000000..4843047
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/dali.h>
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+
+
+void utc_dali_native_image_source_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_native_image_source_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+int UtcDaliNativeImageSourceNewN(void)
+{
+  unsigned int width = 256u;
+  unsigned int heigth = 256u;
+
+  try
+  {
+    NativeImageSourcePtr nativeImageSource = NativeImageSource::New(width, heigth, NativeImageSource::COLOR_DEPTH_DEFAULT );
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_PRINT_ASSERT( e );
+    DALI_TEST_ASSERT(e, "Adaptor::IsAvailable()", TEST_LOCATION);
+  }
+  catch(...)
+  {
+    tet_printf("Assertion test failed - wrong Exception\n" );
+    tet_result(TET_FAIL);
+  }
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-PixelBuffer.cpp b/automated-tests/src/dali-adaptor/utc-Dali-PixelBuffer.cpp
new file mode 100644 (file)
index 0000000..709b2c9
--- /dev/null
@@ -0,0 +1,752 @@
+/*
+ * 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 MaskCenterSquare( 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 y=0; y<height; ++y)
+  {
+    for( int x=0; x<width; ++x)
+    {
+      if(x>=width/4 && x<3*width/4 &&
+         y>=height/4 && y<3*height/4 )
+      {
+        for(int b=0;b<bpp;++b)
+        {
+          maskBuffer[offset+b] = 0xff;
+        }
+      }
+      offset+=bpp;
+    }
+  }
+}
+
+void AlternateQuadrants( Devel::PixelBuffer buffer )
+{
+  int width = buffer.GetWidth();
+  int height = buffer.GetHeight();
+  Pixel::Format pixelFormat = buffer.GetPixelFormat();
+  int bpp = Pixel::GetBytesPerPixel(pixelFormat);
+  int stride=width*bpp;
+
+  unsigned char* pixels = buffer.GetBuffer();
+  memset( pixels, 0, width*height*bpp );
+
+  for( int x=0; x<width; ++x)
+  {
+    for( int y=0; y<height; ++y)
+    {
+      if( ( x < width/2 && y >= height/2 ) ||
+          ( x >= width/2 && y < height/2 ) )
+      {
+        for(int b=0;b<bpp;++b)
+        {
+          pixels[y*stride+x*bpp+b] = 0xff;
+        }
+      }
+    }
+  }
+}
+
+
+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 GetAlphaAt( Devel::PixelBuffer buffer, int x, int y )
+{
+  unsigned char* pixels = buffer.GetBuffer();
+  int bpp = Pixel::GetBytesPerPixel(buffer.GetPixelFormat());
+  int stride = buffer.GetWidth() * bpp;
+  int byteOffset;
+  int bitMask;
+  GetAlphaOffsetAndMask( buffer.GetPixelFormat(), byteOffset, bitMask );
+  return int(pixels[stride * y + x*bpp + byteOffset])  & bitMask;
+}
+
+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, 1.0f, false );
+
+  // 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, 1.0f, false );
+
+  // 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, 1.0f, false );
+
+  // 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 fourth quadrant has full alpha value
+  DALI_TEST_EQUALS( buffer[(6*10+7)*4+3], 0xffu, TEST_LOCATION );
+
+  // Test that an even pixel in the fourth quadrant has full alpha value
+  DALI_TEST_EQUALS( buffer[(6*10+8)*4+3], 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, 1.0f, false );
+
+  // 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::RGBA8888 );
+  Mask1stQuadrant(maskData);
+
+  width = 10u;
+  height = 10u;
+  Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+  FillCheckerboard(imageData);
+
+  imageData.ApplyMask( maskData, 1.0f, false );
+
+  // 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[39], 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;
+}
+
+int UtcDaliPixelBufferMask06(void)
+{
+  TestApplication application;
+  tet_infoline("Test application of alpha mask to same size RGBA8888 image");
+
+  unsigned int width = 10u;
+  unsigned int height = 10u;
+  Devel::PixelBuffer maskData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+  Mask1stQuadrant(maskData);
+
+  width = 10u;
+  height = 10u;
+  Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+  FillCheckerboard(imageData);
+
+  imageData.ApplyMask( maskData, 1.0f, false );
+
+  // 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[39], 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;
+}
+
+
+int UtcDaliPixelBufferMask07(void)
+{
+  TestApplication application;
+  tet_infoline("Test scaling of source image to match alpha mask" );
+
+  unsigned int width = 20u;
+  unsigned int height = 20u;
+  Devel::PixelBuffer maskData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+  MaskCenterSquare(maskData);
+
+  // +----------+
+  // |  XXXXXX  |
+  // |  XXXXXX  |
+  // |  XXXXXX  |
+  // |  XXXXXX  |
+  // *----------+
+
+  width = 10u;
+  height = 10u;
+  Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+  AlternateQuadrants( imageData );
+
+  // +-----XXXXX+
+  // |     XXXXX|
+  // |     XXXXX|
+  // |XXXXX     |
+  // |XXXXX     |
+  // *XXXXX-----+
+
+  imageData.ApplyMask( maskData, 2.0f, true );
+
+  // +----------+
+  // |     XXX  |
+  // |     XXX  |
+  // |  XXX     |
+  // |  XXX     |
+  // *----------+
+
+  tet_infoline("Test that the image has been scaled to match the alpha mask" );
+  DALI_TEST_EQUALS( imageData.GetWidth(), 20, TEST_LOCATION );
+  DALI_TEST_EQUALS( imageData.GetHeight(), 20, TEST_LOCATION );
+
+  tet_infoline( "Test that pixels in the outer eighths have no alpha\n" );
+
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 0, 0), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 9, 4), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 15, 4), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 19, 4), 0x00u, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 0, 19), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 8, 18), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 15,17), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 19,16), 0x00u, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 0, 1), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 1, 7), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 2, 10), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 3, 19), 0x00u, TEST_LOCATION );
+
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 19, 1), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 18, 7), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 17, 10), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 16, 19), 0x00u, TEST_LOCATION );
+
+  tet_infoline( "Test that pixels in the center have full alpha\n" );
+
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 12, 8), 0xffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData,  8, 12), 0xffu, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPixelBufferMask08(void)
+{
+  TestApplication application;
+  tet_infoline("Test scaling of source image to larger than the alpha mask" );
+
+  unsigned int width = 32u;
+  unsigned int height = 20u;
+  Devel::PixelBuffer maskData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+  AlternateQuadrants( maskData );
+
+  // +-----XXXXX+
+  // |     XXXXX|
+  // |     XXXXX|
+  // |XXXXX     |
+  // |XXXXX     |
+  // *XXXXX-----+
+
+  width = 20u;
+  height = 16u;
+  Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+  MaskCenterSquare(imageData);
+
+  // +----------+
+  // |  XXXXXX  |
+  // |  XXXXXX  |
+  // |  XXXXXX  |
+  // |  XXXXXX  |
+  // *----------+
+
+  imageData.ApplyMask( maskData, 4.0f, true );
+
+  // +-----XXXXX+   quadrant
+  // |     XXXXX|    1    2
+  // |     XXXXX|
+  // |XXXXX     |    4    3
+  // |XXXXX     |
+  // *XXXXX-----+
+
+  tet_infoline("Test that the image has been scaled and cropped to match the alpha mask" );
+  DALI_TEST_EQUALS( imageData.GetWidth(), 32, TEST_LOCATION );
+  DALI_TEST_EQUALS( imageData.GetHeight(), 20, TEST_LOCATION );
+
+  tet_infoline( "Test that the image has been resized (the center square should now fill the image)\n");
+  tet_infoline( "Test that the first quadrant has no alpha");
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 0, 0), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 5, 4), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 5, 8), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 14, 8), 0x00u, TEST_LOCATION );
+
+  tet_infoline( "Test that the second quadrant has alpha and data");
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 18, 0), 0xffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 30, 1), 0xffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 30, 8), 0xffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 19, 8), 0xffu, TEST_LOCATION );
+
+  tet_infoline( "Test that the third quadrant has no alpha");
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 18, 12), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 31, 12), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 31, 19), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 18, 19), 0x00u, TEST_LOCATION );
+
+  tet_infoline( "Test that the fourth quadrant has alpha and data");
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 1, 12), 0xffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 7, 12), 0xffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 7, 19), 0xffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 1, 19), 0xffu, TEST_LOCATION );
+
+  END_TEST;
+}
+
+
+int UtcDaliPixelBufferMask09(void)
+{
+  TestApplication application;
+  tet_infoline("Test scaling of large source image to larger than the alpha mask" );
+
+  unsigned int width = 32u;
+  unsigned int height = 20u;
+  Devel::PixelBuffer maskData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+  AlternateQuadrants( maskData );
+
+  // +-----XXXXX+
+  // |     XXXXX|
+  // |     XXXXX|
+  // |XXXXX     |
+  // |XXXXX     |
+  // *XXXXX-----+
+
+  width = 40u;
+  height = 50u;
+  Devel::PixelBuffer imageData = Devel::PixelBuffer::New( width, height, Pixel::RGBA8888 );
+  MaskCenterSquare(imageData);
+
+  // +----------+
+  // |  XXXXXX  |
+  // |  XXXXXX  |
+  // |  XXXXXX  |
+  // |  XXXXXX  |
+  // *----------+
+
+  imageData.ApplyMask( maskData, 1.6f, true );
+
+  // +-----XXXXX+   quadrant
+  // |     XXXXX|    1    2
+  // |     XXXXX|
+  // |XXXXX     |    4    3
+  // |XXXXX     |
+  // *XXXXX-----+
+
+  tet_infoline("Test that the image has been scaled and cropped to match the alpha mask" );
+  DALI_TEST_EQUALS( imageData.GetWidth(), 32, TEST_LOCATION );
+  DALI_TEST_EQUALS( imageData.GetHeight(), 20, TEST_LOCATION );
+
+  tet_infoline( "Test that the image has been resized (the center square should now fill the image)\n");
+  tet_infoline( "Test that the first quadrant has no alpha");
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 0, 0), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 5, 4), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 5, 8), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 14, 8), 0x00u, TEST_LOCATION );
+
+  tet_infoline( "Test that the second quadrant has alpha and data");
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 18, 0), 0xffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 30, 1), 0xffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 30, 8), 0xffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 19, 8), 0xffu, TEST_LOCATION );
+
+  tet_infoline( "Test that the third quadrant has no alpha");
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 18, 12), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 31, 12), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 31, 19), 0x00u, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 18, 19), 0x00u, TEST_LOCATION );
+
+  tet_infoline( "Test that the fourth quadrant has alpha and data");
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 1, 12), 0xffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 7, 12), 0xffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 7, 19), 0xffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( GetAlphaAt(imageData, 1, 19), 0xffu, TEST_LOCATION );
+
+  END_TEST;
+}
+
+int UtcDaliPixelBufferGaussianBlur(void)
+{
+  TestApplication application;
+
+  Devel::PixelBuffer imageData = Devel::PixelBuffer::New( 10, 10, Pixel::RGBA8888 );
+  FillCheckerboard(imageData);
+
+  DALI_TEST_EQUALS( imageData.GetWidth(), 10, TEST_LOCATION ) ;
+  DALI_TEST_EQUALS( imageData.GetHeight(), 10, TEST_LOCATION ) ;
+
+  unsigned char* buffer = imageData.GetBuffer();
+
+  // Test that an even pixel in the odd row has full alpha value
+  DALI_TEST_EQUALS( buffer[43], 0xffu, TEST_LOCATION );
+
+  // Test that an even pixel in the even row has no alpha value
+  DALI_TEST_EQUALS( buffer[55], 0x00u, TEST_LOCATION );
+
+  imageData.ApplyGaussianBlur( 0.0f );
+
+  // Test that the pixels' alpha values are not changed because there is no blur
+  DALI_TEST_EQUALS( buffer[43], 0xffu, TEST_LOCATION );
+  DALI_TEST_EQUALS( buffer[55], 0x00u, TEST_LOCATION );
+
+  imageData.ApplyGaussianBlur( 1.0f );
+
+  // Test that the pixels' alpha values are changed after applying gaussian blur
+  DALI_TEST_EQUALS( buffer[43], 0x7Au, TEST_LOCATION );
+  DALI_TEST_EQUALS( buffer[55], 0x7Eu, TEST_LOCATION );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-Timer.cpp b/automated-tests/src/dali-adaptor/utc-Dali-Timer.cpp
new file mode 100644 (file)
index 0000000..93e7e44
--- /dev/null
@@ -0,0 +1,447 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdint.h>
+#include <dali/dali.h>
+#include <dali/internal/system/linux/dali-ecore.h>
+#include <dali-test-suite-utils.h>
+#include <adaptor-test-application.h>
+
+using namespace Dali;
+
+void utc_dali_timer_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_timer_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+bool ecore_timer_running = false;
+Ecore_Task_Cb timer_callback_func=NULL;
+const void* timer_callback_data=NULL;
+bool main_loop_can_run = false;
+intptr_t timerId = 0; // intptr_t has the same size as a pointer and is platform independent so this can be returned as a pointer in ecore_timer_add below without compilation warnings
+}// anon namespace
+
+extern "C"
+{
+Ecore_Timer* ecore_timer_add(double in,
+                             Ecore_Task_Cb func,
+                             const void   *data)
+{
+  ecore_timer_running = true;
+  timer_callback_func = func;
+  timer_callback_data = data;
+  timerId+=8;
+  return (Ecore_Timer*)timerId;
+}
+
+void* ecore_timer_del(Ecore_Timer *timer)
+{
+  ecore_timer_running = false;
+  timer_callback_func = NULL;
+  return NULL;
+}
+
+}
+
+namespace
+{
+
+void test_ecore_main_loop_begin()
+{
+  if(timer_callback_func != NULL)
+  {
+    main_loop_can_run = true;
+    while( main_loop_can_run )
+    {
+      if( ! timer_callback_func(const_cast<void*>(timer_callback_data)) )
+        break;
+    }
+  }
+}
+
+void test_ecore_main_loop_quit()
+{
+  timer_callback_func = NULL;
+  main_loop_can_run = false;
+}
+
+
+/**
+ * small class to test timer signal
+ */
+class TimerTestClass : public ConnectionTracker
+{
+public:
+
+  TimerTestClass(bool repeat):mTimerCalled(false),mReturnContiune(repeat) {}
+
+  bool Tick()
+  {
+    tet_printf("timer ticked\n");
+    mTimerCalled = true;
+    // quit the main loop otherwise we'll never return to tet
+    test_ecore_main_loop_quit();
+    return mReturnContiune;
+  }
+  bool mTimerCalled;    // whether tick has been called or not
+  bool mReturnContiune; // whether to return true / false to continue
+
+};
+
+} // anon namespace
+
+
+// Positive test case for a method
+int UtcDaliTimerCreation(void)
+{
+  AdaptorTestApplication application;
+
+  tet_printf("timer creation \n");
+  Timer timer = Timer::New(300);
+
+  DALI_TEST_CHECK( timer );
+
+  DALI_TEST_CHECK( timer.GetInterval() == 300);
+
+  END_TEST;
+}
+
+int UtcDaliTimerUnitializedStart(void)
+{
+  AdaptorTestApplication application;
+
+  tet_printf("unintialized timer start \n");
+
+  Timer *timer = new Timer;
+  DALI_TEST_CHECK(timer != NULL);
+
+  try
+  {
+    timer->Start();
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "timer", TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+int UtcDaliTimerUnitializedStop(void)
+{
+  AdaptorTestApplication application;
+
+  tet_printf("unintialized timer stop \n");
+
+  Timer *timer = new Timer;
+  DALI_TEST_CHECK(timer != NULL);
+
+  try
+  {
+    timer->Stop();
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "timer", TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+int UtcDaliTimerUnitializedGetInterval(void)
+{
+  AdaptorTestApplication application;
+
+  tet_printf("unintialized get interval \n");
+
+  Timer *timer = new Timer;
+  DALI_TEST_CHECK(timer != NULL);
+
+  try
+  {
+    timer->GetInterval();
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "timer", TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+int UtcDaliTimerUnitializedSetInterval(void)
+{
+  AdaptorTestApplication application;
+
+  tet_printf("unintialized set interval \n");
+
+  Timer *timer = new Timer;
+  DALI_TEST_CHECK(timer != NULL);
+
+  try
+  {
+    timer->SetInterval(10);
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "timer", TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+int UtcDaliTimerUnitializedIsRunning(void)
+{
+  AdaptorTestApplication application;
+
+  tet_printf("unintialized is running \n");
+
+  Timer *timer = new Timer;
+  DALI_TEST_CHECK(timer != NULL);
+
+  try
+  {
+    timer->IsRunning();
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "timer", TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+
+int UtcDaliTimerUnitializedSignalTick(void)
+{
+  AdaptorTestApplication application;
+
+  tet_printf("unintialized SignalTick \n");
+
+  Timer *timer = new Timer;
+  DALI_TEST_CHECK(timer != NULL);
+
+  try
+  {
+    TimerTestClass testClass(true);// = new TimerTestClass(true);
+
+    timer->TickSignal().Connect(&testClass, &TimerTestClass::Tick);
+  }
+  catch(Dali::DaliException& e)
+  {
+    DALI_TEST_ASSERT(e, "timer", TEST_LOCATION);
+  }
+  END_TEST;
+}
+
+int UtcDaliTimerSetInterval(void)
+{
+  AdaptorTestApplication application;
+
+  tet_printf("timer set interval \n");
+  Timer timer = Timer::New(10);
+
+  DALI_TEST_CHECK( timer.GetInterval() == 10);
+
+  timer.SetInterval(5000);
+
+  DALI_TEST_CHECK( timer.GetInterval() == 5000);
+
+  END_TEST;
+}
+
+int UtcDaliTimerSetInterval02(void)
+{
+  AdaptorTestApplication application;
+
+  tet_printf("timer set interval 02 \n");
+  Timer timer = Timer::New(10);
+  timer.SetInterval(20);
+
+  DALI_TEST_CHECK( timer.GetInterval() == 20 );
+  DALI_TEST_CHECK( timer.IsRunning() == true );
+
+  timer.SetInterval(5000, false);
+
+  DALI_TEST_CHECK( timer.GetInterval() == 5000 );
+  DALI_TEST_CHECK( timer.IsRunning() == false );
+
+  END_TEST;
+}
+
+int UtcDaliTimerSetInterval03(void)
+{
+  AdaptorTestApplication application;
+
+  tet_printf("UtcDaliTimerSetInterval03 SetInterval and ensure timer restarts \n");
+  Timer timer = Timer::New(10);
+  timer.SetInterval(20);
+
+  DALI_TEST_CHECK( timer.GetInterval() == 20 );
+  DALI_TEST_CHECK( timer.IsRunning() == true );
+
+  timer.SetInterval(5000, true);
+
+  DALI_TEST_CHECK( timer.GetInterval() == 5000 );
+  DALI_TEST_CHECK( timer.IsRunning() == true );
+
+  END_TEST;
+}
+
+int UtcDaliTimerCopyConstructor(void)
+{
+  AdaptorTestApplication application;
+
+  tet_printf("timer copy constructor \n");
+  Timer timer = Timer::New(10);
+
+  Timer anotherTimer( timer );
+
+  DALI_TEST_CHECK( anotherTimer.GetInterval() == 10);
+  END_TEST;
+}
+
+int UtcDaliTimerAssignmentOperator(void)
+{
+  AdaptorTestApplication application;
+
+  tet_printf("assignmnet constructor \n");
+
+  Timer timer = Timer::New(10);
+
+  DALI_TEST_CHECK( timer );
+
+  Timer anotherTimer = Timer::New(40);
+
+  DALI_TEST_CHECK(anotherTimer.GetInterval() == 40);
+
+  tet_printf("timer 1 interval %d, \n",anotherTimer.GetInterval());
+  tet_printf("timer 2 interval %d, \n",timer.GetInterval());
+
+  DALI_TEST_CHECK(timer != anotherTimer);
+
+  timer = anotherTimer;
+
+  DALI_TEST_CHECK(timer == anotherTimer);
+
+  tet_printf("timer 1 interval %d, \n",timer.GetInterval());
+  tet_printf("timer 2 interval %d, \n",anotherTimer.GetInterval());
+
+  DALI_TEST_CHECK(timer.GetInterval() == 40);
+
+  END_TEST;
+}
+
+int UtcDaliTimerIsRunning(void)
+{
+  AdaptorTestApplication application;
+
+  tet_printf("timer is running \n");
+
+  Timer timer = Timer::New(100);
+
+  timer.Start();
+
+  DALI_TEST_CHECK( timer.IsRunning() );
+
+  timer.Stop();
+
+  DALI_TEST_CHECK( timer.IsRunning() == false );
+
+  END_TEST;
+}
+
+int UtcDaliTimerSignalTickContinue(void)
+{
+  AdaptorTestApplication application;
+
+  tet_printf("timer call back\n");
+
+  Timer timer = Timer::New(100);
+  TimerTestClass testClass(true);
+
+  timer.TickSignal().Connect(&testClass, &TimerTestClass::Tick);
+
+  timer.Start();
+
+  test_ecore_main_loop_begin();
+
+  DALI_TEST_CHECK( testClass.mTimerCalled );
+
+  END_TEST;
+}
+
+int UtcDaliTimerSignalTickStop(void)
+{
+  AdaptorTestApplication application;
+
+  Timer timer = Timer::New(100);
+  TimerTestClass testClass(false);
+
+  timer.TickSignal().Connect(&testClass, &TimerTestClass::Tick);
+
+  timer.Start();
+
+  test_ecore_main_loop_begin();
+
+  DALI_TEST_CHECK( testClass.mTimerCalled );
+
+  END_TEST;
+}
+
+int UtcDaliTimerReset(void)
+{
+  AdaptorTestApplication application;
+
+  Timer timer = Timer::New(100);
+
+  DALI_TEST_CHECK(timer);
+
+  timer.Reset();
+
+  DALI_TEST_CHECK(!timer);
+
+  END_TEST;
+}
+
+int UtcDaliTimerDownCastP(void)
+{
+  AdaptorTestApplication application;
+
+  Timer timer = Timer::New(100);
+  Timer cast = Timer::DownCast( timer );
+
+  DALI_TEST_CHECK( cast );
+
+  END_TEST;
+}
+
+int UtcDaliTimerDownCastN(void)
+{
+  AdaptorTestApplication application;
+
+  Timer timer;
+  Timer cast = Timer::DownCast( timer );
+
+  DALI_TEST_CHECK( ! cast );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-TtsPlayer.cpp b/automated-tests/src/dali-adaptor/utc-Dali-TtsPlayer.cpp
new file mode 100644 (file)
index 0000000..d286765
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+ * 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 <dali/dali.h>
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+
+void utc_dali_ttsplayer_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_ttsplayer_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+} // unnamed namespace
+
+int UtcDaliTtsPlayerConstructorP(void)
+{
+  Dali::TtsPlayer player;
+  DALI_TEST_CHECK( !player );
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerCopyConstructorP(void)
+{
+  Dali::TtsPlayer player;
+  Dali::TtsPlayer copy( player );
+  DALI_TEST_CHECK( copy == player );
+
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerAssignmentOperatorP(void)
+{
+  Dali::TtsPlayer player;
+  Dali::TtsPlayer copy;
+  DALI_TEST_CHECK( ! copy );
+  copy = player;
+  DALI_TEST_CHECK( copy == player );
+
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerDestructorP(void)
+{
+  Dali::TtsPlayer* player = new Dali::TtsPlayer();
+  delete player;
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerConstructorFromInternalPointerN(void)
+{
+  Internal::Adaptor::TtsPlayer* internalPlayer = NULL;
+  Dali::TtsPlayer player(internalPlayer);
+  DALI_TEST_CHECK( !player ); // Should not reach here!
+
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerGetP(void)
+{
+  Dali::TtsPlayer player = Dali::TtsPlayer::Get();
+  DALI_TEST_CHECK( !player );
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerPlayN(void)
+{
+  Dali::TtsPlayer player = Dali::TtsPlayer::Get();
+
+  try
+  {
+    player.Play("text");
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerStopN(void)
+{
+  Dali::TtsPlayer player = Dali::TtsPlayer::Get();
+
+  try
+  {
+    player.Stop();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerPauseN(void)
+{
+  Dali::TtsPlayer player = Dali::TtsPlayer::Get();
+
+  try
+  {
+    player.Pause();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerResumeN(void)
+{
+  Dali::TtsPlayer player = Dali::TtsPlayer::Get();
+
+  try
+  {
+    player.Resume();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliTtsPlayerGetStateN(void)
+{
+  Dali::TtsPlayer player = Dali::TtsPlayer::Get();
+
+  try
+  {
+    Dali::TtsPlayer::State state = player.GetState();
+    tet_printf( "Error: TtsPlayer state = %d, expected exception\n", (unsigned int)state );
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-Watch-Time.cpp b/automated-tests/src/dali-adaptor/utc-Dali-Watch-Time.cpp
new file mode 100644 (file)
index 0000000..5fd739e
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+ * 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 "public-api/dali-wearable.h"
+#include <appcore-watch/watch_app.h>
+#include <appcore-watch/watch_app_extension.h>
+#include <stdlib.h>
+#define TIMEZONE_BUFFER_MAX 102
+
+using namespace Dali;
+
+void utc_dali_watchtime_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_watchtime_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+struct MyTestApp : public ConnectionTracker
+{
+  MyTestApp( WatchApplication& app)
+  : initCalled( false ),
+    mApplication( app )
+  {
+    mApplication.InitSignal().Connect( this, &MyTestApp::Create );
+  }
+
+  void Create(Application& app)
+  {
+    initCalled = true;
+  }
+
+  void Quit()
+  {
+    mApplication.Quit();
+  }
+
+  // Data
+  bool initCalled;
+  WatchApplication&  mApplication;
+};
+
+} // unnamed namespace
+
+int UtcDaliWatchTimeNew(void)
+{
+  WatchTime watchTime;
+  WatchTime *watchTimeRef = &watchTime;
+
+  DALI_TEST_CHECK( watchTimeRef );
+
+  END_TEST;
+}
+
+int UtcDaliWatchTimeGetHour(void)
+{
+  int ret, hour;
+  WatchTime watchTime;
+  watch_time_h watch_time = {0,};
+
+  ret = watch_time_get_current_time(&watch_time);
+
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  ret = watch_time_get_hour(watch_time, &hour);
+
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  DALI_TEST_CHECK( watchTime.GetHour() == hour );
+
+  END_TEST;
+}
+
+int UtcDaliWatchTimeGetHour24(void)
+{
+  int ret, hour24;
+  WatchTime watchTime;
+  watch_time_h watch_time = {0,};
+
+  ret = watch_time_get_current_time(&watch_time);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  ret = watch_time_get_hour24(watch_time, &hour24);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  DALI_TEST_CHECK( watchTime.GetHour24() == hour24 );
+
+  END_TEST;
+}
+
+int UtcDaliWatchTimeGetMinute(void)
+{
+  int ret, minute;
+  WatchTime watchTime;
+  watch_time_h watch_time = {0,};
+
+  ret = watch_time_get_current_time(&watch_time);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  ret = watch_time_get_minute(watch_time, &minute);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  DALI_TEST_CHECK( watchTime.GetMinute() == minute );
+
+  END_TEST;
+}
+
+int UtcDaliWatchTimeGetSecond(void)
+{
+  int ret, second;
+  WatchTime watchTime;
+  watch_time_h watch_time = {0,};
+
+  ret = watch_time_get_current_time(&watch_time);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  ret = watch_time_get_second(watch_time, &second);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  DALI_TEST_CHECK( watchTime.GetSecond() == second );
+
+  END_TEST;
+}
+
+int UtcDaliWatchTimeGetMillisecond(void)
+{
+  int ret, millisecond;
+  WatchTime watchTime;
+  watch_time_h watch_time = {0,};
+
+  ret = watch_time_get_current_time(&watch_time);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  ret = watch_time_get_millisecond(watch_time, &millisecond);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  DALI_TEST_CHECK( watchTime.GetMillisecond() == millisecond );
+
+  END_TEST;
+}
+
+int UtcDaliWatchTimeGetYear(void)
+{
+  int ret, year;
+  WatchTime watchTime;
+  watch_time_h watch_time = {0,};
+
+  ret = watch_time_get_current_time(&watch_time);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  ret = watch_time_get_year(watch_time, &year);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  DALI_TEST_CHECK( watchTime.GetYear() == year );
+
+  END_TEST;
+}
+
+int UtcDaliWatchTimeGetMonth(void)
+{
+  int ret, month;
+  WatchTime watchTime;
+  watch_time_h watch_time = {0,};
+
+  ret = watch_time_get_current_time(&watch_time);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  ret = watch_time_get_month(watch_time, &month);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  DALI_TEST_CHECK( watchTime.GetMonth() == month );
+
+  END_TEST;
+}
+
+int UtcDaliWatchTimeGetDay(void)
+{
+  int ret, day;
+  WatchTime watchTime;
+  watch_time_h watch_time = {0,};
+
+  ret = watch_time_get_current_time(&watch_time);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  ret = watch_time_get_day(watch_time, &day);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  DALI_TEST_CHECK( watchTime.GetDay() == day );
+
+  END_TEST;
+}
+
+int UtcDaliWatchTimeGetDayOfWeek(void)
+{
+  int ret, dayOfWeek;
+  WatchTime watchTime;
+  watch_time_h watch_time = {0,};
+
+  ret = watch_time_get_current_time(&watch_time);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  ret = watch_time_get_day_of_week(watch_time, &dayOfWeek);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  DALI_TEST_CHECK( watchTime.GetDayOfWeek() == dayOfWeek );
+
+  END_TEST;
+}
+
+int UtcDaliWatchTimeGetUtcTime(void)
+{
+  int ret;
+  struct tm *utcTime = (struct tm *)calloc( 1, sizeof( struct tm ) );
+  WatchTime watchTime;
+  watch_time_h watch_time = {0,};
+
+  ret = watch_time_get_current_time(&watch_time);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  ret = watch_time_get_day(watch_time, utcTime);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  DALI_TEST_CHECK( watchTime.GetUtcTime().tm_sec == (*utcTime).tm_sec );
+
+  END_TEST;
+}
+
+int UtcDaliWatchTimeGetUtcTimeStamp(void)
+{
+  int ret;
+  time_t *timeStamp = (time_t *)calloc( 1, sizeof( time_t ) );
+  WatchTime watchTime;
+  watch_time_h watch_time = {0,};
+
+  ret = watch_time_get_current_time(&watch_time);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  ret = watch_time_get_day(watch_time, timeStamp);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  DALI_TEST_CHECK( watchTime.GetUtcTimeStamp() == *timeStamp );
+
+  END_TEST;
+}
+
+int UtcDaliWatchTimeGetTimeZone(void)
+{
+  int ret;
+  char *timeZone[TIMEZONE_BUFFER_MAX] = {0,};
+  WatchTime watchTime;
+  watch_time_h watch_time = {0,};
+
+  ret = watch_time_get_current_time(&watch_time);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  ret = watch_time_get_day(watch_time, timeZone);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  DALI_TEST_CHECK( watchTime.GetTimeZone() == timeZone );
+
+  END_TEST;
+}
+
+int UtcDaliWatchTimeGetDaylightSavingTimeStatus(void)
+{
+  int ret;
+  bool daylight;
+  WatchTime watchTime;
+  watch_time_h watch_time = {0,};
+
+  ret = watch_time_get_current_time(&watch_time);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  ret = watch_time_get_day(watch_time, &daylight);
+  DALI_TEST_CHECK( ret == APP_ERROR_NONE );
+
+  DALI_TEST_CHECK( watchTime.GetDaylightSavingTimeStatus() == daylight );
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-Watch.cpp b/automated-tests/src/dali-adaptor/utc-Dali-Watch.cpp
new file mode 100644 (file)
index 0000000..c1603c4
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * 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 <dali/dali.h>
+#include <dali-test-suite-utils.h>
+
+using namespace Dali;
+
+void utc_dali_watchapplication_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_watchapplication_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+struct MyTestApp : public ConnectionTracker
+{
+  MyTestApp( WatchApplication& app)
+  : initCalled( false ),
+    mApplication( app )
+  {
+    mApplication.InitSignal().Connect( this, &MyTestApp::Create );
+  }
+
+  void Create(Application& app)
+  {
+    initCalled = true;
+  }
+
+  void Quit()
+  {
+    mApplication.Quit();
+  }
+
+  // Data
+  bool initCalled;
+  WatchApplication&  mApplication;
+};
+
+void WatchTimeSignalCallback( Application& app, const WatchTime& time)
+{
+}
+
+void WatchChangedSignalCallback( Application& app, bool ambient)
+{
+}
+
+} // unnamed namespace
+
+int UtcDaliWatchApplicationNew01(void)
+{
+  WatchApplication application = WatchApplication::New();
+
+  MyTestApp testApp( application );
+
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliWatchApplicationNew02(void)
+{
+  int argc( 1 );
+  const char* argList[1] = { "program" };
+  char** argv = const_cast<char**>(argList);
+
+  WatchApplication application = WatchApplication::New( &argc, &argv );
+
+  MyTestApp testApp( application );
+
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliWatchApplicationNew03(void)
+{
+  int argc( 1 );
+  const char* argList[1] = { "program" };
+  char** argv = const_cast<char**>(argList);
+
+  WatchApplication application = WatchApplication::New( &argc, &argv, "stylesheet" );
+
+  MyTestApp testApp( application );
+
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliWatchApplicationCopyAndAssignment(void)
+{
+  WatchApplication application = WatchApplication::New();
+  WatchApplication copy( application );
+  DALI_TEST_CHECK( copy == application );
+
+  WatchApplication assigned;
+  DALI_TEST_CHECK( !assigned );
+  assigned = application;
+  DALI_TEST_CHECK( copy == assigned );
+
+  END_TEST;
+}
+
+int UtcDaliWatchApplicationTimeTickSignalP(void)
+{
+  WatchApplication application = WatchApplication::New();
+  application.TimeTickSignal().Connect( &WatchTimeSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliWatchApplicationTimeTickSignalN(void)
+{
+  WatchApplication application;
+
+  try
+  {
+    application.TimeTickSignal().Connect( &WatchTimeSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWatchApplicationAmbientTickSignalP(void)
+{
+  WatchApplication application = WatchApplication::New();
+  application.AmbientTickSignal().Connect( &WatchTimeSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliWatchApplicationAmbientTickSignalN(void)
+{
+  WatchApplication application;
+
+  try
+  {
+    application.AmbientTickSignal().Connect( &WatchTimeSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWatchApplicationAmbientChangedSignalP(void)
+{
+  WatchApplication application = WatchApplication::New();
+  application.AmbientChangedSignal().Connect( &WatchChangedSignalCallback );
+  DALI_TEST_CHECK( application );
+
+  END_TEST;
+}
+
+int UtcDaliWatchApplicationAmbientChangedSignalN(void)
+{
+  WatchApplication application;
+
+  try
+  {
+    application.AmbientChangedSignal().Connect( &WatchChangedSignalCallback );
+    DALI_TEST_CHECK( false ); // Should not get here
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
diff --git a/automated-tests/src/dali-adaptor/utc-Dali-Window.cpp b/automated-tests/src/dali-adaptor/utc-Dali-Window.cpp
new file mode 100644 (file)
index 0000000..4b14df2
--- /dev/null
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/dali.h>
+#include <dali/internal/system/linux/dali-ecore-x.h>
+#include <dali-test-suite-utils.h>
+
+namespace Dali
+{
+class DragAndDropDetector : public BaseHandle {}; // For UtcDaliWindowGetDragAndDropDetectorN
+}
+
+using namespace Dali;
+
+void utc_dali_window_startup(void)
+{
+  test_return_value = TET_UNDEF;
+}
+
+void utc_dali_window_cleanup(void)
+{
+  test_return_value = TET_PASS;
+}
+
+namespace
+{
+
+intptr_t screenId = 0; // intptr_t has the same size as a pointer and is platform independent so this can be returned as a pointer in ecore_x_default_screen_get below without compilation warnings
+
+} // unnamed namespace
+
+extern "C"
+{
+
+Ecore_X_Screen* ecore_x_default_screen_get(void)
+{
+  screenId += 8;
+  return (Ecore_X_Screen*)screenId;
+}
+
+void ecore_x_screen_size_get(const Ecore_X_Screen *screen, int *w, int *h)
+{
+ *w = 100;
+ *h = 100;
+}
+
+Ecore_X_Window ecore_x_window_argb_new(Ecore_X_Window parent, int x, int y, int w, int h)
+{
+  return 0;
+}
+
+}
+
+int UtcDaliWindowConstructorP(void)
+{
+  Dali::Window window;
+  DALI_TEST_CHECK( !window );
+  END_TEST;
+}
+
+int UtcDaliWindowCopyConstructorP(void)
+{
+  Dali::Window window;
+  Dali::Window copy( window );
+  DALI_TEST_CHECK( copy == window );
+
+  END_TEST;
+}
+
+int UtcDaliWindowConstructorFromInternalPointerN(void)
+{
+  Internal::Adaptor::Window* internalWindow = NULL;
+  Dali::Window window(internalWindow);
+  DALI_TEST_CHECK( !window ); // Should not reach here!
+
+  END_TEST;
+}
+
+int UtcDaliWindowAssignmentOperatorP(void)
+{
+  const Dali::Window window;
+  Dali::Window copy;
+  DALI_TEST_CHECK( ! copy );
+  copy = window;
+  DALI_TEST_CHECK( copy == window );
+
+  END_TEST;
+}
+
+int UtcDaliWindowDestructorP(void)
+{
+  Dali::Window* window = new Dali::Window();
+  delete window;
+
+  DALI_TEST_CHECK( true );
+  END_TEST;
+}
+
+int UtcDaliWindowNewN(void)
+{
+  // Attempt to create a new window
+  try
+  {
+    PositionSize windowPosition(0, 0, 0, 0);
+    Dali::Window window = Dali::Window::New( windowPosition, "test-window", true );
+
+    tet_result( TET_FAIL );
+  }
+  catch ( DaliException& e )
+  {
+    DALI_TEST_ASSERT( e, "Failed to create X window", TEST_LOCATION );
+  }
+
+  // Attempt to create a new window
+  try
+  {
+    PositionSize windowPosition(0, 0, 0, 0);
+    Dali::Window window = Dali::Window::New( windowPosition, "test-window", "test-window-class", true );
+
+    tet_result( TET_FAIL );
+  }
+  catch ( DaliException& e )
+  {
+    DALI_TEST_ASSERT( e, "Failed to create X window", TEST_LOCATION );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowShowIndicatorN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.ShowIndicator(Dali::Window::VISIBLE);
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowSetIndicatorBgOpacityN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.SetIndicatorBgOpacity(Dali::Window::OPAQUE);
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowRotateIndicatorN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.RotateIndicator(Dali::Window::PORTRAIT);
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowSetClassN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.SetClass("window-name", "window-class");
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowRaiseN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.Raise();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowLowerN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.Lower();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowActivateN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.Activate();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowAddAvailableOrientationN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.AddAvailableOrientation(Dali::Window::PORTRAIT);
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowRemoveAvailableOrientationN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.RemoveAvailableOrientation(Dali::Window::PORTRAIT);
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowSetPreferredOrientationN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.SetPreferredOrientation(Dali::Window::PORTRAIT);
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowGetPreferredOrientationN(void)
+{
+  Dali::Window window;
+  try
+  {
+    Dali::Window::WindowOrientation orientation = window.GetPreferredOrientation();
+    DALI_TEST_CHECK( orientation == Dali::Window::PORTRAIT ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowGetDragAndDropDetectorN(void)
+{
+  Dali::Window window;
+  try
+  {
+    DragAndDropDetector detector = window.GetDragAndDropDetector();
+    DALI_TEST_CHECK( !detector ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowGetNativeHandleN(void)
+{
+  Dali::Window window;
+  try
+  {
+    Dali::Any handle = window.GetNativeHandle();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowSetAcceptFocusN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.SetAcceptFocus( true );
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowIsFocusAcceptableN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.IsFocusAcceptable();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowIndicatorVisibilityChangedSignalN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.IndicatorVisibilityChangedSignal();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
+
+int UtcDaliWindowFocusChangedSignalN(void)
+{
+  Dali::Window window;
+  try
+  {
+    window.FocusChangedSignal();
+    DALI_TEST_CHECK( false ); // Should not reach here!
+  }
+  catch( ... )
+  {
+    DALI_TEST_CHECK( true );
+  }
+
+  END_TEST;
+}
diff --git a/automated-tests/src/dali-platform-abstraction/CMakeLists.txt b/automated-tests/src/dali-platform-abstraction/CMakeLists.txt
new file mode 100644 (file)
index 0000000..07fc820
--- /dev/null
@@ -0,0 +1,64 @@
+SET(PKG_NAME "dali-platform-abstraction")
+
+SET(EXEC_NAME "tct-${PKG_NAME}-core")
+SET(RPM_NAME "core-${PKG_NAME}-tests")
+
+SET(CAPI_LIB "dali-platform-abstraction")
+
+SET(TC_SOURCES
+    utc-image-fitting-modes.cpp
+)
+
+LIST(APPEND TC_SOURCES
+    ../dali-adaptor/dali-test-suite-utils/mesh-builder.cpp
+    ../dali-adaptor/dali-test-suite-utils/dali-test-suite-utils.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-actor-utils.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-harness.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-application.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-gl-abstraction.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-gl-sync-abstraction.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-native-image.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-platform-abstraction.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-render-controller.cpp
+    ../dali-adaptor/dali-test-suite-utils/test-trace-call-stack.cpp
+    ../dali-adaptor/dali-test-suite-utils/adaptor-test-adaptor-impl.cpp
+    tct-dali-platform-abstraction-core.cpp
+    utc-image-loading-common.cpp
+)
+
+PKG_CHECK_MODULES(${CAPI_LIB} REQUIRED
+    dali-core
+    dali-adaptor
+)
+
+ADD_COMPILE_OPTIONS(-O0 -ggdb --coverage -Wall -Werror)
+ADD_COMPILE_OPTIONS( ${${CAPI_LIB}_CFLAGS_OTHER} )
+
+# Shouldn't have to do this!
+# But CMake's new auto-escape quote policy doesn't work right.
+CMAKE_POLICY(SET CMP0005 OLD)
+ADD_DEFINITIONS(-DTEST_IMAGE_DIR=\"\\\"${CMAKE_CURRENT_SOURCE_DIR}/../../images\\\"\" )
+
+FOREACH(directory ${${CAPI_LIB}_LIBRARY_DIRS})
+    SET(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -L${directory}")
+ENDFOREACH(directory ${CAPI_LIB_LIBRARY_DIRS})
+
+INCLUDE_DIRECTORIES(
+    ../../../
+    ../../../adaptors/tizen
+    ../../../platform-abstractions/tizen
+    ../../../third-party/image-resampler
+    ${${CAPI_LIB}_INCLUDE_DIRS}
+    ../dali-adaptor/dali-test-suite-utils
+    /usr/include/freetype2
+)
+
+ADD_EXECUTABLE(${EXEC_NAME} ${EXEC_NAME}.cpp ${TC_SOURCES})
+TARGET_LINK_LIBRARIES(${EXEC_NAME}
+  ${${CAPI_LIB}_LIBRARIES}
+  --coverage
+)
+
+INSTALL(PROGRAMS ${EXEC_NAME}
+    DESTINATION ${BIN_DIR}/${EXEC_NAME}
+)
diff --git a/automated-tests/src/dali-platform-abstraction/tct-dali-platform-abstraction-core.cpp b/automated-tests/src/dali-platform-abstraction/tct-dali-platform-abstraction-core.cpp
new file mode 100644 (file)
index 0000000..d839c4f
--- /dev/null
@@ -0,0 +1,51 @@
+#include <string.h>
+#include <getopt.h>
+#include <stdlib.h>
+#include <test-harness.h>
+#include "tct-dali-platform-abstraction-core.h"
+
+int main(int argc, char * const argv[])
+{
+  int result = TestHarness::EXIT_STATUS_BAD_ARGUMENT;
+
+  const char* optString = "sf";
+  bool optRerunFailed(true);
+  bool optRunSerially(false);
+
+  int nextOpt = 0;
+  do
+  {
+    nextOpt = getopt( argc, argv, optString );
+    switch(nextOpt)
+    {
+      case 'f':
+        optRerunFailed = false;
+        break;
+      case 's':
+        optRunSerially = true;
+        break;
+      case '?':
+        TestHarness::Usage(argv[0]);
+        exit(TestHarness::EXIT_STATUS_BAD_ARGUMENT);
+        break;
+    }
+  } while( nextOpt != -1 );
+
+  if( optind == argc ) // no testcase name in argument list
+  {
+    if( optRunSerially )
+    {
+      result = TestHarness::RunAll( argv[0], tc_array );
+    }
+    else
+    {
+      result = TestHarness::RunAllInParallel( argv[0], tc_array, optRerunFailed );
+    }
+  }
+  else
+  {
+    // optind is index of next argument - interpret as testcase name
+    result = TestHarness::FindAndRunTestCase(tc_array, argv[optind]);
+  }
+  return result;
+}
diff --git a/automated-tests/src/dali-platform-abstraction/utc-image-fitting-modes.cpp b/automated-tests/src/dali-platform-abstraction/utc-image-fitting-modes.cpp
new file mode 100644 (file)
index 0000000..1195318
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * 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 "utc-image-loading-common.h"
+
+#include <dali/internal/imaging/common/image-operations.h>
+
+using Dali::Internal::Platform::ApplyAttributesToBitmap;
+
+#define ANSI_BLACK   "\x1B[0m"
+#define ANSI_RED     "\x1B[31m"
+#define ANSI_GREEN   "\x1B[32m"
+#define ANSI_YELLOW  "\x1B[33m"
+#define ANSI_BLUE    "\x1B[34m"
+#define ANSI_MAGENTA "\x1B[35m"
+#define ANSI_CYAN    "\x1B[36m"
+#define ANSI_WHITE   "\x1B[37m"
+#define ANSI_RESET   "\033[0m"
+
+const unsigned char BORDER_FILL_VALUE = 0xff;
+const char* ASCII_FILL_VALUE = ANSI_YELLOW "#";
+const char* ASCII_PAD_VALUE = ANSI_BLUE "#";
+typedef unsigned char PixelBuffer;
+
+
+void FillBitmap( Dali::Devel::PixelBuffer bitmap )
+{
+  // Fill the given bitmap fully.
+  const Pixel::Format pixelFormat = bitmap.GetPixelFormat();
+  const unsigned int bytesPerPixel = Pixel::GetBytesPerPixel( pixelFormat );
+  PixelBuffer * const targetPixels = bitmap.GetBuffer();
+  const int bytesToFill = bitmap.GetWidth() * bitmap.GetHeight() * bytesPerPixel;
+
+  memset( targetPixels, BORDER_FILL_VALUE, bytesToFill );
+}
+
+typedef Rect< int > ActiveArea;
+
+// This struct defines all information for one test.
+struct ImageFittingTestParameters
+{
+  unsigned int sourceWidth;
+  unsigned int sourceHeight;
+  unsigned int desiredWidth;
+  unsigned int desiredHeight;
+  FittingMode::Type fittingMode;
+
+  unsigned int expectedWidth;
+  unsigned int expectedHeight;
+  ActiveArea expectedActiveImageArea;
+
+  ImageFittingTestParameters( unsigned int newSourceWidth, unsigned int newSourceHeight, unsigned int newDesiredWidth, unsigned int newDesiredHeight, FittingMode::Type newFittingMode,
+      unsigned int newExpectedWidth, unsigned int newExpectedHeight, ActiveArea newExpectedActiveImageArea )
+  : sourceWidth( newSourceWidth ),
+    sourceHeight( newSourceHeight ),
+    desiredWidth( newDesiredWidth ),
+    desiredHeight( newDesiredHeight ),
+    fittingMode( newFittingMode ),
+    expectedWidth( newExpectedWidth ),
+    expectedHeight( newExpectedHeight ),
+    expectedActiveImageArea( newExpectedActiveImageArea )
+  {
+  }
+};
+
+typedef std::vector< ImageFittingTestParameters > TestContainer;
+
+
+void PerformFittingTests( TestContainer& tests )
+{
+  // Iterate through all pre-defined tests.
+  for( unsigned int testNumber = 0; testNumber < tests.size(); ++testNumber )
+  {
+    // Gather info for this test.
+    ImageFittingTestParameters &test = tests[ testNumber ];
+
+    unsigned int sourceWidth = test.sourceWidth;
+    unsigned int sourceHeight = test.sourceHeight;
+    unsigned int desiredWidth = test.desiredWidth;
+    unsigned int desiredHeight = test.desiredHeight;
+    FittingMode::Type fittingMode = test.fittingMode;
+
+    // Create a source bitmap.
+    ImageDimensions desiredDimensions( desiredWidth, desiredHeight );
+    SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR;
+
+
+    auto sourceBitmap = Dali::Devel::PixelBuffer::New( sourceWidth, sourceHeight, Pixel::Format::RGBA8888 );
+    const Pixel::Format pixelFormat = sourceBitmap.GetPixelFormat();
+    // Completely fill the source bitmap (with white).
+    FillBitmap( sourceBitmap );
+
+    // Perform fitting operations (this is the method we are testing).
+    auto newBitmap = ApplyAttributesToBitmap( sourceBitmap, desiredDimensions, fittingMode, samplingMode );
+
+    DALI_TEST_CHECK( newBitmap );
+
+    // As we do not need performance within this test, we branch to exit here (for readability, maintainability).
+    if( !newBitmap )
+    {
+      return;
+    }
+
+    auto bitmap( newBitmap );
+
+    unsigned int resultWidth = bitmap.GetWidth();
+    unsigned int resultHeight = bitmap.GetHeight();
+
+    // Check the dimensions of the modified image match against the expected values defined in the test.
+    DALI_TEST_EQUALS( resultWidth, test.expectedWidth, TEST_LOCATION );
+    DALI_TEST_EQUALS( resultHeight, test.expectedHeight, TEST_LOCATION );
+
+    PixelBuffer* resultBuffer = bitmap.GetBuffer();
+    const unsigned int bytesPerPixel = Pixel::GetBytesPerPixel( pixelFormat );
+
+    // We generate an ASCII representation of the source, desired and result images to log, purely as a debugging aid.
+    // (0 = border, 1 = active image area - from the source image).
+    std::string xSourceImageString( sourceWidth, '#' );
+    std::string xDesiredSizeString( desiredWidth - 2, '-' );
+    std::string xDesiredSizePadString( desiredWidth - 2, ' ' );
+    tet_printf( "%sRunning test: %d%s\n", ANSI_RED, testNumber + 1, ANSI_RESET );
+    tet_printf( "Source image: %s%s%s\n", ANSI_YELLOW, xSourceImageString.c_str(), ANSI_RESET );
+    for( unsigned int i = 0; i < sourceHeight - 1; ++i )
+    {
+      tet_printf( "              %s%s%s\n", ANSI_YELLOW, xSourceImageString.c_str(), ANSI_RESET );
+    }
+    tet_printf( "Desired size: %s+%s+%s\n", ANSI_YELLOW, xDesiredSizeString.c_str(), ANSI_RESET );
+    for( unsigned int i = 0; i < desiredHeight - 2; ++i )
+    {
+      tet_printf( "              %s|%s|%s\n", ANSI_YELLOW, xDesiredSizePadString.c_str(), ANSI_RESET );
+    }
+    tet_printf( "              %s+%s+%s\n", ANSI_YELLOW, xDesiredSizeString.c_str(), ANSI_RESET );
+
+    // We want to calculate the active image area (the area filled with image data as opposed to borders).
+    // This is so we can determine if the fitting modes worked correctly.
+    ActiveArea resultActiveArea( -1, -1, -1, -1 );
+
+    // Iterate over the result image data to find the active area.
+    for( unsigned int y = 0; y < resultHeight; ++y )
+    {
+      int activeStartX = -1;
+      int activeEndX = -1;
+      std::string xResultImageString;
+
+      for( unsigned int x = 0; x < resultWidth; ++x )
+      {
+        bool pixelPopulated = resultBuffer[ x * bytesPerPixel ] != 0x00;
+
+        // If the pixel is filled AND we haven't found a filled pixel yet,
+        // this is the horizontal start of the active pixel area (for this line).
+        if( pixelPopulated && ( activeStartX == -1 ) )
+        {
+          activeStartX = x;
+        }
+        else if( !pixelPopulated && ( activeStartX != -1 ) && ( activeEndX == -1 ) )
+        {
+          // If the pixel is NOT filled AND we HAVE rpeviously found a filled pixel,
+          // then this is the horizontal end of the active pixel area (for this line).
+          activeEndX = x + 1;
+        }
+
+        // Populate a string with the filled state of the result pixels, to facilitate debugging.
+        xResultImageString += pixelPopulated ? ASCII_FILL_VALUE : ASCII_PAD_VALUE;
+      }
+
+      // First calculate the X-end span value, if we ran out of image before reaching the end of active image area.
+      if( ( activeStartX != -1 ) && ( activeEndX == -1 ) )
+      {
+        activeEndX = resultWidth - activeStartX;
+      }
+
+      // If the X-start pixel on this line is earlier than other lines, the overall active area starts earlier.
+      // Note: This is ignored if there was no pixels found.
+      if( ( activeStartX != -1 ) && ( ( activeStartX < resultActiveArea.x ) || ( resultActiveArea.x == -1 ) ) )
+      {
+        resultActiveArea.x = activeStartX;
+      }
+
+      // If the X-end pixel on this line is later than other lines, the overall active area starts later.
+      // Note: This is ignored if there was no pixels found.
+      if( ( activeEndX != -1 ) && ( ( activeEndX > resultActiveArea.width ) || ( resultActiveArea.width == -1 ) ) )
+      {
+        resultActiveArea.width = activeEndX;
+      }
+
+      // If there was an X-start pixel on this line AND we don't yet have a Y-start, this line IS the Y-start.
+      if( ( activeStartX != -1 ) && ( resultActiveArea.y == -1 ) )
+      {
+        resultActiveArea.y = y;
+      }
+
+      // If there was no X-start pixel on this line AND we already have a Y-start value,
+      // then the last Y becomes the new Y-end value.
+      if( ( activeStartX == -1 ) && ( resultActiveArea.y != -1 ) && ( resultActiveArea.height == -1 ) )
+      {
+        resultActiveArea.height = y - 1;
+      }
+
+      if( y == 0 )
+      {
+        tet_printf( "Result image: %s\n", xResultImageString.c_str() );
+      }
+      else
+      {
+        tet_printf( "              %s\n", xResultImageString.c_str() );
+      }
+
+      resultBuffer += resultWidth * bytesPerPixel;
+    }
+
+    // Calculate the Y-end value, if we ran out of image before reaching the end of active image area.
+    if( ( resultActiveArea.y != -1 ) && ( resultActiveArea.height == -1 ) )
+    {
+      resultActiveArea.height = resultHeight - resultActiveArea.y;
+    }
+
+    tet_printf( "%s", ANSI_RESET );
+    tet_printf( "Test: %d  Result image dimensions: %d,%d  ActiveArea: %d,%d,%d,%d\n",
+        testNumber + 1, resultWidth, resultHeight, resultActiveArea.x, resultActiveArea.y, resultActiveArea.width, resultActiveArea.height );
+
+    // Test the result images active area matches the expected active area defined in the test.
+    DALI_TEST_EQUALS( resultActiveArea, test.expectedActiveImageArea, TEST_LOCATION );
+  }
+}
+
+// Test cases:
+
+// Positive test case for fitting mode: FIT_WIDTH.
+int UtcDaliFittingModesFitWidth(void)
+{
+  tet_printf("Running fitting mode test for: FIT_WIDTH\n");
+
+  TestContainer tests;
+
+  // Here we can define the input and expected output of each test on a single line.
+  // Source Width, Source Height, Desired Width, Desired Height, Fitting Mode, Expected Width, Expected Height, ActiveArea: X-start, Y-start, width, height
+
+  // Test Image source size = desired size. Output should be the same.
+  tests.push_back( ImageFittingTestParameters( 4, 4, 4, 4, FittingMode::FIT_WIDTH,     4, 4, ActiveArea( 0, 0, 4, 4 ) ) );
+  // Test Image source size > desired size, but aspect same. Should scale size down.
+  tests.push_back( ImageFittingTestParameters( 4, 4, 2, 2, FittingMode::FIT_WIDTH,     2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
+  // Test Image source size < desired size, but aspect same. Should not scale size up.
+  tests.push_back( ImageFittingTestParameters( 2, 2, 4, 4, FittingMode::FIT_WIDTH,     2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
+  // Test Image source size < desired size, but aspect different. Should crop height, so no borders. No scale up as result has same aspect after crop.
+  tests.push_back( ImageFittingTestParameters( 2, 4, 8, 8, FittingMode::FIT_WIDTH,     2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
+  // Test Image source size > desired size, but aspect different (w < h). Should crop height, so no borders. No scale as result is same size as desired size.
+  tests.push_back( ImageFittingTestParameters( 4, 8, 4, 4, FittingMode::FIT_WIDTH,     4, 4, ActiveArea( 0, 0, 4, 4 ) ) );
+  // Test Image source size > desired size, but aspect different (w > h). Should add borders, AND scale down to desired size.
+  tests.push_back( ImageFittingTestParameters( 8, 4, 4, 4, FittingMode::FIT_WIDTH,     4, 4, ActiveArea( 0, 1, 4, 2 ) ) );
+
+  PerformFittingTests( tests );
+
+  END_TEST;
+}
+
+// Positive test case for fitting mode: FIT_HEIGHT.
+int UtcDaliFittingModesFitHeight(void)
+{
+  tet_printf("Running fitting mode test for: FIT_HEIGHT\n");
+
+  TestContainer tests;
+
+  // Here we can define the input and expected output of each test on a single line.
+  // Source Width, Source Height, Desired Width, Desired Height, Fitting Mode, Expected Width, Expected Height, ActiveArea: X-start, Y-start, width, height
+
+  // Test Image source size = desired size. Output should be the same.
+  tests.push_back( ImageFittingTestParameters( 4, 4, 4, 4, FittingMode::FIT_HEIGHT,    4, 4, ActiveArea( 0, 0, 4, 4 ) ) );
+  // Test Image source size > desired size, but aspect same. Should scale size down.
+  tests.push_back( ImageFittingTestParameters( 4, 4, 2, 2, FittingMode::FIT_HEIGHT,    2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
+  // Test Image source size < desired size, but aspect same. Should not scale size up.
+  tests.push_back( ImageFittingTestParameters( 2, 2, 4, 4, FittingMode::FIT_HEIGHT,    2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
+  // Test Image source size < desired size, but aspect different. Should add borders, but not scale overall size up.
+  tests.push_back( ImageFittingTestParameters( 2, 4, 8, 8, FittingMode::FIT_HEIGHT,    4, 4, ActiveArea( 1, 0, 4, 4 ) ) );
+  // Test Image source size > desired size, but aspect different (w < h). Should add borders, AND scale down to desired size.
+  tests.push_back( ImageFittingTestParameters( 4, 8, 4, 4, FittingMode::FIT_HEIGHT,    4, 4, ActiveArea( 1, 0, 4, 4 ) ) );
+  // Test Image source size > desired size, but aspect different (w > h). Should crop width, so no borders. No scale as result is same size as desired size.
+  tests.push_back( ImageFittingTestParameters( 8, 4, 4, 4, FittingMode::FIT_HEIGHT,    4, 4, ActiveArea( 0, 0, 4, 4 ) ) );
+
+  PerformFittingTests( tests );
+
+  END_TEST;
+}
+
+// Positive test case for fitting mode: SHRINK_TO_FIT.
+int UtcDaliFittingModesShrinkToFit(void)
+{
+  tet_printf("Running fitting mode test for: SHRINK_TO_FIT\n");
+
+  TestContainer tests;
+
+  // Here we can define the input and expected output of each test on a single line.
+  // Source Width, Source Height, Desired Width, Desired Height, Fitting Mode, Expected Width, Expected Height, ActiveArea: X-start, Y-start, width, height
+
+  // Test Image source size = desired size. Output should be the same.
+  tests.push_back( ImageFittingTestParameters( 4, 4, 4, 4, FittingMode::SHRINK_TO_FIT, 4, 4, ActiveArea( 0, 0, 4, 4 ) ) );
+  // Test Image source size > desired size, but aspect same. Should scale size down.
+  tests.push_back( ImageFittingTestParameters( 4, 4, 2, 2, FittingMode::SHRINK_TO_FIT, 2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
+  // Test Image source size < desired size, but aspect same. Should not scale size up.
+  tests.push_back( ImageFittingTestParameters( 2, 2, 4, 4, FittingMode::SHRINK_TO_FIT, 2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
+  // Test Image source size < desired size, but aspect different. Should add borders, but not scale overall size up, as although image is smaller than desired size, aspect is the same.
+  tests.push_back( ImageFittingTestParameters( 2, 4, 8, 8, FittingMode::SHRINK_TO_FIT, 4, 4, ActiveArea( 1, 0, 4, 4 ) ) );
+  // Test Image source size > desired size, but aspect different (w < h). Should add borders, AND scale down to desired size.
+  tests.push_back( ImageFittingTestParameters( 4, 8, 4, 4, FittingMode::SHRINK_TO_FIT, 4, 4, ActiveArea( 1, 0, 4, 4 ) ) );
+  // Test Image source size > desired size, but aspect different (w > h). Should add borders, AND scale down to desired size.
+  tests.push_back( ImageFittingTestParameters( 8, 4, 4, 4, FittingMode::SHRINK_TO_FIT, 4, 4, ActiveArea( 0, 1, 4, 2 ) ) );
+
+  PerformFittingTests( tests );
+
+  END_TEST;
+}
+
+// Positive test case for fitting mode: SCALE_TO_FILL.
+int UtcDaliFittingModesScaleToFill(void)
+{
+  tet_printf("Running fitting mode test for: SCALE_TO_FILL\n");
+
+  TestContainer tests;
+
+  // Here we can define the input and expected output of each test on a single line.
+  // Source Width, Source Height, Desired Width, Desired Height, Fitting Mode, Expected Width, Expected Height, ActiveArea: X-start, Y-start, width, height
+
+  // Test Image source size = desired size. Output should be the same.
+  tests.push_back( ImageFittingTestParameters( 4, 4, 4, 4, FittingMode::SCALE_TO_FILL, 4, 4, ActiveArea( 0, 0, 4, 4 ) ) );
+  // Test Image source size > desired size, but aspect same. Should scale size down.
+  tests.push_back( ImageFittingTestParameters( 4, 4, 2, 2, FittingMode::SCALE_TO_FILL, 2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
+  // Test Image source size < desired size, but aspect same. Should not scale size up.
+  tests.push_back( ImageFittingTestParameters( 2, 2, 4, 4, FittingMode::SCALE_TO_FILL, 2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
+  // Test Image source size < desired size, but aspect different. Should crop height, so no borders. No scale up as result has same aspect after crop.
+  tests.push_back( ImageFittingTestParameters( 2, 4, 8, 8, FittingMode::SCALE_TO_FILL, 2, 2, ActiveArea( 0, 0, 2, 2 ) ) );
+  // Test Image source size > desired size, but aspect different (w < h). Should crop height, so no borders. No scale as result is same size as desired size.
+  tests.push_back( ImageFittingTestParameters( 4, 8, 4, 4, FittingMode::SCALE_TO_FILL, 4, 4, ActiveArea( 0, 0, 4, 4 ) ) );
+  // Test Image source size > desired size, but aspect different (w > h). Should crop width, so no borders. No scale as result is same size as desired size.
+  tests.push_back( ImageFittingTestParameters( 8, 4, 4, 4, FittingMode::SCALE_TO_FILL, 4, 4, ActiveArea( 0, 0, 4, 4 ) ) );
+
+  PerformFittingTests( tests );
+
+  END_TEST;
+}
+
diff --git a/automated-tests/src/dali-platform-abstraction/utc-image-loading-common.cpp b/automated-tests/src/dali-platform-abstraction/utc-image-loading-common.cpp
new file mode 100644 (file)
index 0000000..f201516
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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 "utc-image-loading-common.h"
+
+double GetTimeMilliseconds( Integration::PlatformAbstraction& abstraction )
+{
+  timespec timeSpec;
+  clock_gettime( CLOCK_MONOTONIC, &timeSpec );
+  return ( timeSpec.tv_sec * 1e3 ) + ( timeSpec.tv_nsec / 1e6 );
+}
+
+/** Live platform abstraction recreated for each test case. */
+TizenPlatform::TizenPlatformAbstraction* gAbstraction = 0;
+
+/** A variety of parameters to reach different code paths in image loading code. */
+std::vector<ImageParameters> gCancelAttributes;
+
+void utc_dali_loading_startup(void)
+{
+  test_return_value = TET_UNDEF;
+  gAbstraction = TizenPlatform::CreatePlatformAbstraction();
+
+  // Setup some loading parameters to engage post-processing stages:
+
+  ImageParameters scaleToFillAttributes;
+  scaleToFillAttributes.second.first = FittingMode::SCALE_TO_FILL;
+  scaleToFillAttributes.first = ImageDimensions( 160, 120 );
+  gCancelAttributes.push_back( scaleToFillAttributes );
+
+  // Hit the derived dimensions code:
+  ImageParameters scaleToFillAttributesDeriveWidth = scaleToFillAttributes;
+  scaleToFillAttributesDeriveWidth.first = ImageDimensions( 0, 120 );
+  gCancelAttributes.push_back( scaleToFillAttributesDeriveWidth );
+
+  ImageParameters scaleToFillAttributesDeriveHeight = scaleToFillAttributes;
+  scaleToFillAttributesDeriveHeight.first = ImageDimensions( 160, 0 );
+  gCancelAttributes.push_back( scaleToFillAttributesDeriveHeight );
+
+  // Try to push a tall crop:
+  ImageParameters scaleToFillAttributesTall = scaleToFillAttributes;
+  scaleToFillAttributesTall.first = ImageDimensions( 160, 480 );
+  ImageParameters scaleToFillAttributesTall2 = scaleToFillAttributes;
+  scaleToFillAttributesTall2.first = ImageDimensions( 160, 509 );
+  ImageParameters scaleToFillAttributesTall3 = scaleToFillAttributes;
+  scaleToFillAttributesTall3.first = ImageDimensions( 37, 251 );
+  gCancelAttributes.push_back( scaleToFillAttributesTall );
+  gCancelAttributes.push_back( scaleToFillAttributesTall2 );
+  gCancelAttributes.push_back( scaleToFillAttributesTall3 );
+
+  // Try to push a wide crop:
+  ImageParameters scaleToFillAttributesWide = scaleToFillAttributes;
+  scaleToFillAttributesWide.first = ImageDimensions( 320, 60 );
+  ImageParameters scaleToFillAttributesWide2 = scaleToFillAttributes;
+  scaleToFillAttributesWide2.first = ImageDimensions( 317, 60 );
+  ImageParameters scaleToFillAttributesWide3 = scaleToFillAttributes;
+  scaleToFillAttributesWide3.first = ImageDimensions( 317, 53 );
+  gCancelAttributes.push_back( scaleToFillAttributesWide );
+  gCancelAttributes.push_back( scaleToFillAttributesWide2 );
+  gCancelAttributes.push_back( scaleToFillAttributesWide3 );
+
+  ImageParameters shrinkToFitAttributes = scaleToFillAttributes;
+  shrinkToFitAttributes.second.first = FittingMode::SHRINK_TO_FIT;
+  gCancelAttributes.push_back( shrinkToFitAttributes );
+
+  ImageParameters fitWidthAttributes = scaleToFillAttributes;
+  fitWidthAttributes.second.first = FittingMode::FIT_WIDTH;
+  gCancelAttributes.push_back( fitWidthAttributes );
+
+  ImageParameters fitHeightAttributes = scaleToFillAttributes;
+  fitHeightAttributes.second.first = FittingMode::FIT_HEIGHT;
+  gCancelAttributes.push_back( fitHeightAttributes );
+
+  ///@ToDo: Add attribute variants for all scale modes.
+  ///@ToDo: Add attribute variants for all filter modes.
+
+  // Pad the array to a prime number to mitigate any accidental periodic
+  // patterns in which image file has which attributes applied to its load:
+  srand48( 104729 );
+  const float lastUniques = gCancelAttributes.size() - 0.001f;
+  while( gCancelAttributes.size() < 61u )
+  {
+    gCancelAttributes.push_back( gCancelAttributes[unsigned(drand48() * lastUniques)] );
+  }
+}
+
+void utc_dali_loading_cleanup(void)
+{
+  delete gAbstraction;
+  gAbstraction = 0;
+
+  test_return_value = TET_PASS;
+}
diff --git a/automated-tests/src/dali-platform-abstraction/utc-image-loading-common.h b/automated-tests/src/dali-platform-abstraction/utc-image-loading-common.h
new file mode 100644 (file)
index 0000000..7aa9e46
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#ifndef DALI_TEST_SUITE_IMAGE_LOADING_COMMON_H
+#define DALI_TEST_SUITE_IMAGE_LOADING_COMMON_H
+#include <unistd.h>
+#include <iostream>
+#include <stdlib.h>
+#include <ctime>
+#include <dali/dali.h>
+#include <dali-test-suite-utils.h>
+#include <dali/internal/legacy/common/tizen-platform-abstraction.h>
+
+using namespace Dali;
+using namespace Dali::Integration;
+
+namespace
+{
+/**
+ * The number of loads issued in test cases is a multiple of this. The higher it
+ * is, the more the tests stress the system but the longer they take to run.
+ * A value of 1000 is enough to make load tests take tens of seconds each
+ * on desktop. */
+const unsigned NUM_LOAD_GROUPS_TO_ISSUE = 158;
+
+/**
+ * The number of loads to issue when they will be cancelled.
+ * Cancelled loads are cheap so we do a lot.
+ */
+const unsigned NUM_CANCELLED_LOAD_GROUPS_TO_ISSUE = NUM_LOAD_GROUPS_TO_ISSUE * 10;
+
+/** The number of times to ask for resource load status. */
+const unsigned MAX_NUM_RESOURCE_TRIES = 10;
+
+/** The maximum time to wait for loads to complete when the number of expected loads is known. */
+const unsigned MAX_MILLIS_TO_WAIT_FOR_KNOWN_LOADS = 1000 * 60;
+
+/** Images that should load without issue. */
+const char* const VALID_IMAGES[] = {
+  TEST_IMAGE_DIR "/frac.jpg",
+  TEST_IMAGE_DIR "/frac.24.bmp",
+  TEST_IMAGE_DIR "/frac.png",
+  TEST_IMAGE_DIR "/interlaced.gif",
+  TEST_IMAGE_DIR "/pattern.gif",
+  TEST_IMAGE_DIR "/fractal-compressed-ETC1_RGB8_OES-45x80.ktx",
+  TEST_IMAGE_DIR "/fractal-compressed-RGBA_ASTC_4x4_KHR-32x64.astc",
+  TEST_IMAGE_DIR "/test-image-4x4-32bpp.ico",
+  TEST_IMAGE_DIR "/test-image.wbmp"
+};
+const unsigned NUM_VALID_IMAGES = sizeof(VALID_IMAGES) / sizeof(VALID_IMAGES[0]);
+
+} // anon namespace
+
+/** Live platform abstraction recreated for each test case. */
+extern TizenPlatform::TizenPlatformAbstraction* gAbstraction;
+
+/** A variety of parameters to reach different code paths in the image loading. */
+typedef std::pair<ImageDimensions, std::pair<FittingMode::Type, std::pair<SamplingMode::Type, bool> > > ImageParameters;
+extern std::vector<ImageParameters> gCancelAttributes;
+
+double GetTimeMilliseconds( Integration::PlatformAbstraction& abstraction ); ///< Returns elapsed milliseconds.
+
+void utc_dali_loading_startup(void);
+void utc_dali_loading_cleanup(void);
+
+#endif // DALI_TEST_SUITE_IMAGE_LOADING_COMMON_H
diff --git a/automated-tests/tcbuild b/automated-tests/tcbuild
new file mode 120000 (symlink)
index 0000000..89c2de7
--- /dev/null
@@ -0,0 +1 @@
+scripts/tcbuild.sh
\ No newline at end of file
diff --git a/automated-tests/templates/tct-package/README b/automated-tests/templates/tct-package/README
new file mode 100644 (file)
index 0000000..0af341f
--- /dev/null
@@ -0,0 +1,43 @@
+The scripts contained in the automated-tests/scripts folder are based on
+the Web Application Security & Privacy module test suite from Intel,
+with the following license:
+
+----------------------------------------------
+License
+----------------------------------------------
+Copyright (c) 2012 Intel Corporation.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+* Redistributions of works must retain the original copyright notice, this list
+  of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the original copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+* Neither the name of Intel Corporation nor the names of its contributors
+  may be used to endorse or promote products derived from this work without
+  specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Authors:
+        Yue, Jianhui <jianhuix.a.yue@intel.com>
+
+Modifications to scripts:
+Added mechanism to build and execute tests with finer granularity.
+Added option to generate tests for executing on desktop
+
+Copyright (c) 2014 Samsung Electronics Co., Ltd.
+
+Authors:
+        Steele, David <david.steele@partner.samsung.com>
diff --git a/automated-tests/templates/tct-package/inst.sh b/automated-tests/templates/tct-package/inst.sh
new file mode 100755 (executable)
index 0000000..c2888df
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/bash
+NAME=$(basename $(cd $(dirname $0);pwd))
+PKG_DIR=%{PKG_DIR} # directory supplied by external script
+PKG_NAME=%{PKG_NAME} # name supplied by external script
+PKG_FULLNAME=%{PKG_FULLNAME} # name supplied by external script
+
+#parse params
+USAGE="Usage: ./inst.sh [-i] [-u]
+  -i install wgt and config environment
+  -u uninstall wgt and remove source file
+[-i] option was set as default."
+
+function installpkg(){
+    rpm -e `rpm -qa | grep $PKG_NAME`
+    rpm -ivh --quiet /$PKG_DIR/$PKG_FULLNAME
+    /tmp/add_all_smack_rule.sh
+}
+
+function uninstallpkg(){
+### remove source file ###
+if [ -d /opt/usr/media/tct/opt/$NAME ];then
+    rm -rf /opt/usr/media/tct/opt/$NAME
+    rpm -e $PKG_NAME
+else
+    echo "Remove source file fail, please check if the source file exist: /opt/usr/media/tct/opt/$NAME ..."
+fi
+}
+
+case "$1" in
+    -h|--help) echo "$USAGE"
+               exit ;;
+    ""|-i) installpkg;;
+    -u) uninstallpkg;;
+    *) echo "Unknown option: $1"
+       echo "$USAGE"
+       exit ;;
+esac
diff --git a/build/tizen/CMakeLists.txt b/build/tizen/CMakeLists.txt
new file mode 100644 (file)
index 0000000..7c56a82
--- /dev/null
@@ -0,0 +1,410 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 3.1)
+CMAKE_POLICY(SET CMP0012 NEW) # Prevent dereferencing of OFF/ON as variables
+
+SET(CMAKE_CXX_STANDARD 11)
+SET(CMAKE_C_STANDARD 99)
+PROJECT(${name} CXX)
+SET(PKG_NAME ${name})
+
+SET(name "dali-adaptor")
+
+SET(GCC_COMPILER_VERSION_REQUIRED "6")
+IF(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+  IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS GCC_COMPILER_VERSION_REQUIRED)
+    MESSAGE(FATAL_ERROR "The GCC required compiler version is " ${GCC_COMPILER_VERSION_REQUIRED})
+  ENDIF()
+ENDIF()
+
+OPTION(ENABLE_PKG_CONFIGURE  "Use pkgconfig" ON)
+OPTION(ENABLE_LINK_TEST      "Enable the link test" ON)
+
+# Include additional macros
+INCLUDE( common.cmake )
+
+IF(CMAKE_BUILD_TYPE MATCHES Debug)
+  MESSAGE( STATUS "CMAKE_BUILD_TYPE: " Debug )
+  SET( ENABLE_DEBUG "ON" CACHE STRING "" )
+  SET( ENABLE_EXPORTALL "ON" CACHE STRING "" )
+ELSE()
+  MESSAGE( STATUS "CMAKE_BUILD_TYPE: " Release )
+ENDIF()
+
+# from root/build/tizen, get back to root.
+# set the variable only if it's not set yet. it allows to access build script
+# from top-level directory
+IF( NOT ROOT_SRC_DIR )
+  SET(ROOT_SRC_DIR ${CMAKE_SOURCE_DIR}/../..)
+ENDIF()
+# Make sure the path is absolute
+GET_FILENAME_COMPONENT(ROOT_SRC_DIR ${ROOT_SRC_DIR} ABSOLUTE)
+
+# API VERSION (Not DALi release version)
+SET(${name}_VERSION_MAJOR 0)
+SET(${name}_VERSION_MINOR 0)
+SET(${name}_VERSION_PATCH 0)
+SET(${name}_VERSION ${${name}_VERSION_MAJOR}.${${name}_VERSION_MINOR}.${${name}_VERSION_PATCH})
+
+SET(DALI_ADAPTOR_VERSION ${${name}_VERSION} )
+
+IF( WIN32 ) # WIN32 includes x64 as well according to the cmake doc.
+  FIND_PACKAGE( dali-windows-dependencies REQUIRED)
+  FIND_PACKAGE( dali-core REQUIRED)
+ENDIF()
+
+SET( VCPKG_INCLUDE_DIR "${_VCPKG_INSTALLED_DIR}/${VCPKG_TARGET_TRIPLET}/include")
+
+IF( UNIX )
+  ADD_DEFINITIONS(-DPLATFORM_TIZEN)
+  ADD_DEFINITIONS(-DPIC -DSTDC_HEADERS)
+
+  IF("${ARCH}" STREQUAL "arm")
+    ADD_DEFINITIONS("-DTARGET")
+  ENDIF("${ARCH}" STREQUAL "arm")
+ELSEIF( WIN32 ) # WIN32 includes x64 as well according to the cmake doc.
+  IF(NOT DEFINED STATIC)
+    ADD_DEFINITIONS( "-DBUILDING_DALI_ADAPTOR" )
+  ENDIF()
+
+  ADD_DEFINITIONS( "-DDALI_ADAPTOR_COMPILATION" )
+  ADD_DEFINITIONS( "-D_NSIG=65" )
+ENDIF()
+
+# Deployment folder should come from spec file or command line:
+SET( PREFIX ${CMAKE_INSTALL_PREFIX})
+SET( EXEC_PREFIX ${CMAKE_INSTALL_PREFIX})
+
+# Set up the include dir
+SET( INCLUDE_DIR $ENV{includedir} )
+IF( NOT INCLUDE_DIR )
+  SET( INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR} )
+ENDIF()
+IF( NOT INCLUDE_DIR )
+  SET( INCLUDE_DIR ${PREFIX}/include )
+ENDIF()
+
+# Set up the lib dir
+SET( LIB_DIR $ENV{libdir} )
+IF( NOT LIB_DIR )
+  SET( LIB_DIR ${CMAKE_INSTALL_LIBDIR} )
+ENDIF()
+IF( NOT LIB_DIR )
+  SET( LIB_DIR ${PREFIX}/lib )
+ENDIF()
+
+# Set up the bin dir
+SET( BIN_DIR $ENV{bindir} )
+IF( NOT BIN_DIR )
+  SET( BIN_DIR ${CMAKE_INSTALL_BINDIR} )
+ENDIF()
+IF( NOT BIN_DIR )
+  SET( BIN_DIR ${PREFIX}/bin )
+ENDIF()
+
+IF( UNIX )
+  INCLUDE( deps-check.cmake )
+ENDIF()
+
+# Set up compiler flags and warnings
+IF( UNIX )
+  ADD_COMPILE_OPTIONS( -Wall ${DALI_CFLAGS} )# -Wextra -Wno-unused-parameter )# -Wfloat-equal )
+ELSEIF( WIN32 ) # WIN32 includes x64 as well according to the cmake doc.
+  ADD_COMPILE_OPTIONS( /FIdali-windows-dependencies.h ) #
+  ADD_COMPILE_OPTIONS( /FIextern-definitions.h )        # Adds missing definitions.
+  ADD_COMPILE_OPTIONS( /FIpreprocessor-definitions.h )  #
+  ADD_COMPILE_OPTIONS( /vmg )                           # Avoids a 'reinterpret_cast' compile error while compiling signals and callbacks.
+  ADD_COMPILE_OPTIONS( /wd4251 )                        # Ignores warning C4251: "'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'"
+ENDIF()
+
+ADD_DEFINITIONS( -DNON_POWER_OF_TWO_TEXTURES
+                 ${DEFINITIONS} )
+
+# from root/build/tizen, get back to root
+SET(ROOT_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../)
+
+# Make sure the path is absolute
+GET_FILENAME_COMPONENT(ROOT_SRC_DIR ${ROOT_SRC_DIR} ABSOLUTE)
+
+SET(SOURCE_DIR "${ROOT_SRC_DIR}/dali")
+SET(ADAPTOR_ROOT ${ROOT_SRC_DIR})
+SET(PACKAGE_DOXY_SRC_DIR "${ROOT_SRC_DIR}/doc")
+SET(SOURCES "")
+
+# Include list of modules
+INCLUDE( module-list.cmake )
+
+# Include profile specific setup
+INCLUDE( profiles/${PROFILE_LCASE}-profile.cmake )
+
+IF( ENABLE_PKG_CONFIGURE )
+  # Configure the pkg-config file
+  # Requires the following variables to be setup:
+  # @PREFIX@ @EXEC_PREFIX@ @DALI_ADAPTOR_VERSION@ @LIB_DIR@ @DEV_INCLUDE_PATH@
+  SET( DEV_INCLUDE_PATH ${INCLUDE_DIR} )
+  SET( ADAPTOR_PKG_CFG_FILE ${CMAKE_CURRENT_SOURCE_DIR}/dali-adaptor.pc )
+  SET( ADAPTOR_INTEGRATION_PKG_CFG_FILE ${CMAKE_CURRENT_SOURCE_DIR}/dali-adaptor-integration.pc )
+  CONFIGURE_FILE( ${ADAPTOR_PKG_CFG_FILE}.in ${ADAPTOR_PKG_CFG_FILE} @ONLY )
+  CONFIGURE_FILE( ${ADAPTOR_INTEGRATION_PKG_CFG_FILE}.in ${ADAPTOR_INTEGRATION_PKG_CFG_FILE} @ONLY )
+ENDIF()
+
+CONFIGURE_FILE( ${CMAKE_CURRENT_SOURCE_DIR}/system-cache-path.in ${ADAPTOR_ROOT}/dali/internal/adaptor/common/system-cache-path.cpp @ONLY)
+
+SET( THIRD_PARTY_WINDOWS_PLATFORM "" )
+IF( WIN32 )
+  SET( THIRD_PARTY_WINDOWS_PLATFORM ${ROOT_SRC_DIR}/third-party/windows-platform )
+ENDIF()
+
+INCLUDE_DIRECTORIES(
+  ${ROOT_SRC_DIR}
+  ${PROFILE_INCLUDE_DIRECTORIES}
+  ${THIRD_PARTY_WINDOWS_PLATFORM}
+  ${VCPKG_INCLUDE_DIR}
+  ${INCLUDE_DIR}
+)
+
+SET(LIBTYPE SHARED)
+IF(DEFINED STATIC)
+  SET(LIBTYPE STATIC)
+ENDIF()
+
+ADD_LIBRARY( ${name} ${LIBTYPE} ${SOURCES} )
+
+IF( UNIX )
+  # pthread required due to gcc issue
+  FIND_LIBRARY( PTHREAD pthread )
+  IF( PTHREAD AND NOT ANDROID_PROFILE )
+    SET( OPTIONAL_LIBS ${OPTIONAL_LIBS} -lpthread )
+  ENDIF()
+ENDIF()
+
+TARGET_LINK_LIBRARIES( ${name}
+                       ${DALI_LDFLAGS}
+  ${REQUIRED_LIBS}
+  ${OPTIONAL_LIBS}
+  ${COVERAGE}
+)
+
+SET_TARGET_PROPERTIES( ${name}
+  PROPERTIES
+  VERSION ${DALI_ADAPTOR_VERSION}
+  SOVERSION ${${name}_VERSION_MAJOR}
+  CLEAN_DIRECT_OUPUT 1
+)
+
+IF( INSTALL_CMAKE_MODULES )
+  IF( ENABLE_DEBUG )
+    SET( BIN_DIR "${BIN_DIR}/debug" )
+    SET( LIB_DIR "${LIB_DIR}/debug" )
+  ENDIF()
+
+  # Install the library files.
+  INSTALL( TARGETS ${name}
+    EXPORT ${name}-targets
+    LIBRARY DESTINATION ${LIB_DIR}
+    ARCHIVE DESTINATION ${LIB_DIR}
+    RUNTIME DESTINATION ${BIN_DIR}
+  )
+
+  # Install the cmake modules.
+  INSTALL(
+    EXPORT ${name}-targets
+    NAMESPACE ${name}::
+    FILE ${name}-targets.cmake
+    DESTINATION share/${name}
+  )
+
+  FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${name}-config.cmake "
+    include(CMakeFindDependencyMacro)
+    include(\${CMAKE_CURRENT_LIST_DIR}/${name}-targets.cmake)
+  ")
+  install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}-config.cmake DESTINATION share/${name})
+
+  # Install the pdb file.
+  IF( ENABLE_DEBUG )
+    install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${name}.pdb DESTINATION ${BIN_DIR} )
+  ENDIF()
+ELSE()
+  # Install the library so file and symlinks
+  INSTALL( TARGETS ${name} DESTINATION ${LIB_DIR} )
+ENDIF()
+
+IF( ENABLE_PKG_CONFIGURE )
+  # Install the pkg-config file
+  INSTALL( FILES ${ADAPTOR_PKG_CFG_FILE} DESTINATION ${LIB_DIR}/pkgconfig )
+  INSTALL( FILES ${ADAPTOR_INTEGRATION_PKG_CFG_FILE} DESTINATION ${LIB_DIR}/pkgconfig )
+ENDIF()
+
+# macro for installing headers by replacing prefix. (TODO, investigate
+# if there is a CMAKE way of doing this automatically)
+MACRO(INSTALL_HEADERS_WITH_DIRECTORY HEADER_LIST STRIP_PREFIX REPLACE_PREFIX)
+  GET_FILENAME_COMPONENT( SPREFIX ${STRIP_PREFIX} ABSOLUTE )
+  FOREACH(HEADER ${${HEADER_LIST}})
+    STRING(REGEX MATCH "(.*)[/]" DIR ${HEADER})
+    STRING(REPLACE ${SPREFIX} ${REPLACE_PREFIX} NEWDIR ${DIR})
+    INSTALL(FILES ${HEADER} DESTINATION ${INCLUDE_DIR}/${NEWDIR})
+  ENDFOREACH(HEADER)
+ENDMACRO(INSTALL_HEADERS_WITH_DIRECTORY)
+
+
+########################################################################################
+# INSTALL:
+# Set deployment directories
+# Due to complicated adaptor deployment the install section is pretty much converted from
+# the automake counterpart.
+SET( tizenadaptorpublicapidir ${INCLUDE_DIR}/dali/public-api )
+SET( tizenadaptordevelapidir ${INCLUDE_DIR}/dali/devel-api )
+SET( tizenadaptorintegrationapidir ${INCLUDE_DIR}/dali/integration-api/adaptor-framework )
+SET( tizenadaptorframeworkpublicapidir ${tizenadaptorpublicapidir}/adaptor-framework )
+SET( tizenadaptorframeworkdevelapidir ${tizenadaptordevelapidir}/adaptor-framework )
+SET( tizentextabstractiondevelapidir ${tizenadaptordevelapidir}/text-abstraction )
+SET( tizenadaptordaliheaderdir ${INCLUDE_DIR}/dali )
+SET( tizenwatchpublicapidir ${tizenadaptorpublicapidir}/watch )
+SET( tizencapturepublicapidir ${tizenadaptorpublicapidir}/capture )
+
+# Android framework headers for Android build
+SET( androidadaptorintegrationapidir ${INCLUDE_DIR}/dali/integration-api/adaptor-framework/android )
+
+# Install headers
+INSTALL( FILES ${public_api_header_files} DESTINATION ${tizenadaptorpublicapidir} )
+INSTALL( FILES ${adaptor_integration_api_header_files} DESTINATION ${tizenadaptorintegrationapidir} )
+INSTALL( FILES ${public_api_adaptor_framework_header_files} DESTINATION ${tizenadaptorframeworkpublicapidir} )
+INSTALL( FILES ${devel_api_adaptor_framework_header_files} DESTINATION ${tizenadaptorframeworkdevelapidir} )
+INSTALL( FILES ${text_abstraction_header_files} DESTINATION ${tizentextabstractiondevelapidir} )
+
+# Install Android framework headers for Android build
+INSTALL( FILES ${adaptor_integration_api_android_header_files} DESTINATION ${androidadaptorintegrationapidir} )
+
+# Install DOXY
+SET( packagedoxydir ${INCLUDE_DIR}/dali/doc )
+SET( package_doxy_dir ${ADAPTOR_ROOT}/doc )
+INCLUDE( ${ADAPTOR_ROOT}/doc/file.list )
+INSTALL( FILES ${package_doxy_files} DESTINATION ${packagedoxydir} )
+
+IF( NOT UBUNTU_PROFILE AND NOT ANDROID_PROFILE AND NOT WINDOWS_PROFILE )
+  INSTALL( FILES ${public_api_adaptor_tizen_header_files} DESTINATION ${tizenadaptorframeworkpublicapidir} )
+  IF( NOT WAYLAND )
+    INSTALL( FILES ${devel_api_adaptor_tizen_x11_header_files} DESTINATION ${tizenadaptorframeworkdevelapidir} )
+  ENDIF()
+ENDIF()
+
+INSTALL( FILES ${adaptor_dali_header_file} DESTINATION ${tizenadaptordaliheaderdir} )
+INSTALL( FILES ${adaptor_dali_wearable_header_file} DESTINATION ${tizenadaptorpublicapidir} )
+INSTALL( FILES ${public_dali_watch_header_files} DESTINATION ${tizenwatchpublicapidir} )
+INSTALL( FILES ${public_dali_capture_header_files} DESTINATION ${tizencapturepublicapidir} )
+
+IF( ANDROID_PROFILE )
+  SET( daliShaderbinCacheDir ${CMAKE_INSTALL_PREFIX}/core/shaderbin/)
+  INSTALL( DIRECTORY DESTINATION ${daliShaderbinCacheDir} )
+ELSEIF( UNIX )
+  SET( daliShaderbinCacheDir ${CMAKE_BINARY_DIR}/${dataReadOnlyDir}/core/shaderbin/)
+  INSTALL( DIRECTORY DESTINATION ${dataReadOnlyDir}/core/shaderbin )
+ENDIF()
+
+INSTALL( FILES ${ADAPTOR_ROOT}/adaptors/scripts/dalireslog.sh DESTINATION ${CMAKE_INSTALL_PREFIX}/bin )
+
+########################################################################################
+
+# The DALI_ADAPTOR_PREFIX must be set if this CMakeLists.txt is executed
+# from the top-level CMake script using ADD_SUBDIRECTORY() to avoid
+# target names duplication with other DALi modules.
+IF( ENABLE_COVERAGE )
+  FIND_PROGRAM( LCOV_BIN "lcov" )
+  IF( LCOV_BIN )
+
+    # Define custom rules for coverage
+    SET(COVERAGE_DIR .cov)
+    SET(COVERAGE_OUTPUT_DIR doc/coverage)
+
+    # lcov prior to 1.10 doesn't have -rc option; this and subsequent version don't output
+    # branch coverage. Determine the lcov version, and enable branch coverage accordingly.
+    EXECUTE_PROCESS( COMMAND bash -c "${LCOV_BIN} --version | cut -d' ' -f4" OUTPUT_VARIABLE LCOV_VERSION )
+    STRING( REPLACE "." ";" LCOV_VLIST ${LCOV_VERSION})
+    IF( NOT $<VERSION_LESS:${LCOV_VERSION},"1.10"> )
+      SET(LCOV_OPTS --rc lcov_branch_coverage=1)
+    ENDIF()
+
+    ADD_CUSTOM_TARGET( ${DALI_ADAPTOR_PREFIX}rename_cov_data ./rename-cov-data )
+
+    ADD_CUSTOM_TARGET( ${DALI_ADAPTOR_PREFIX}cov_data ${LCOV_BIN} ${LCOV_OPTS} --base-directory . --directory . -c -o dali.info
+      COMMAND ${LCOV_BIN} ${LCOV_OPTS} --remove dali.info \"*/dali-env/*\" \"/usr/include/*\" -o dali.info )
+
+    ADD_CUSTOM_TARGET( ${DALI_ADAPTOR_PREFIX}coverage genhtml ${LCOV_OPTS} -o ${COVERAGE_OUTPUT_DIR} dali.info
+      DEPENDS cov_data )
+
+    ADD_CUSTOM_TARGET( ${DALI_ADAPTOR_PREFIX}reset_coverage @${LCOV_BIN} -z --directory `pwd` )
+
+    # Define custom rule for distclean
+    ADD_CUSTOM_TARGET( ${DALI_ADAPTOR_PREFIX}distclean @echo cleaning for source distribution )
+    ADD_CUSTOM_COMMAND(
+          DEPENDS clean
+          COMMENT "distribution clean"
+          COMMAND find
+          ARGS    .
+          -not -name config.cmake -and \(
+          -name tester.c -or
+          -name Testing -or
+          -name CMakeFiles -or
+          -name doc -or
+          -name cmake.depends -or
+          -name cmake.check_depends -or
+          -name CMakeCache.txt -or
+          -name cmake.check_cache -or
+          -name *.cmake -or
+          -name Makefile -or
+          -name core -or
+          -name core.* -or
+          -name gmon.out -or
+          -name install_manifest.txt -or
+          -name *.pc -or
+          -name *.gcov -or
+          -name *.gcno -or
+          -name *.gcda -or
+          -name *~ -or
+          -name libdali*.so* \)
+          | grep -v TC | xargs rm -rf
+          TARGET  ${DALI_ADAPTOR_PREFIX}distclean
+          VERBATIM
+          )
+
+  ENDIF( LCOV_BIN )
+ENDIF()
+
+IF( ENABLE_LINK_TEST )
+  # Linker Test
+  SET( DALI_TEST_SUITE_DIR ${ROOT_SRC_DIR}/automated-tests/src/dali/dali-test-suite-utils )
+  SET( LINKER_TEST_NAME ${DALI_ADAPTOR_PREFIX}linker-test )
+  SET( LINKER_TEST_SOURCES
+    linker-test.cpp
+  )
+  ADD_EXECUTABLE( ${LINKER_TEST_NAME} ${LINKER_TEST_SOURCES} )
+  MESSAGE(STATUS "libs: ${DALICORE_LDFLAGS}")
+  TARGET_COMPILE_OPTIONS( ${LINKER_TEST_NAME} PRIVATE -I${ROOT_SRC_DIR} ${DALICORE_CFLAGS} )
+  TARGET_LINK_LIBRARIES(${LINKER_TEST_NAME} ${name} ${DALICORE_LDFLAGS} ${VCONF_LDFLAGS} ${HARFBUZZ_LDFLAGS} )
+  TARGET_INCLUDE_DIRECTORIES( ${LINKER_TEST_NAME} PRIVATE ${DALI_TEST_SUITE_DIR} )
+ENDIF()
+
+# Configuration Messages
+MESSAGE( STATUS "Configuration:\n" )
+MESSAGE( STATUS "Prefix:                           ${PREFIX}")
+MESSAGE( STATUS "Lib Dir:                          ${LIB_DIR}" )
+MESSAGE( STATUS "Include Dir:                      ${INCLUDE_DIR}" )
+MESSAGE( STATUS "Coverage:                         ${ENABLE_COVERAGE}" )
+MESSAGE( STATUS "Debug Build:                      ${ENABLE_DEBUG}")
+MESSAGE( STATUS "Freetype bitmap support (Emoji):  ${freetype_bitmap_support_ENABLED}")
+MESSAGE( STATUS "Profile:                          ${ENABLE_PROFILE}")
+MESSAGE( STATUS "Data Dir (Read/Write):            ${dataReadWriteDir}")
+MESSAGE( STATUS "Data Dir (Read Only):             ${dataReadOnlyDir}")
+MESSAGE( STATUS "EldBus:                           ${eldbus_available_ENABLED}")
+MESSAGE( STATUS "Shader Binary Cache:              ${ENABLE_SHADERBINCACHE}")
+MESSAGE( STATUS "Network logging enabled:          ${ENABLE_NETWORKLOGGING}")
+MESSAGE( STATUS "Font config file:                 ${fontConfigurationFile}")
+MESSAGE( STATUS "Using Tizen APP FW libraries:     ${ENABLE_APPFW}")
+MESSAGE( STATUS "Use pkg configure:                ${ENABLE_PKG_CONFIGURE}" )
+MESSAGE( STATUS "Enable link test:                 ${ENABLE_LINK_TEST}" )
+MESSAGE( STATUS "Tizen Platform Config supported   ${TIZEN_PLATFORM_CONFIG_SUPPORTED_LOGMSG}")
+MESSAGE( STATUS "Compile flags:                    ${CMAKE_CXX_FLAGS}")
+MESSAGE( STATUS "Compile flags:                    ${CMAKE_C_FLAGS}")
+IF( enable_feedback )
+  ADD_SUBDIRECTORY( plugins )
+ENDIF()
+
+CLEAN_ARG_CACHE()
diff --git a/build/tizen/common.cmake b/build/tizen/common.cmake
new file mode 100644 (file)
index 0000000..83a3dd4
--- /dev/null
@@ -0,0 +1,86 @@
+# Find dependencies ( linux, tizen )
+IF( ENABLE_PKG_CONFIGURE )
+  FIND_PACKAGE(PkgConfig REQUIRED)
+ENDIF()
+
+# Special constant for ARG_ENABLE function
+SET( ENABLE_VAL "#ENABLE_VAL" )
+SET( HELP_ENABLES "" )
+SET( CUSTOM_ARGUMENTS "" )
+
+# Macro checks if the module is available and sets user variable
+MACRO( CHECK_MODULE_AND_SET PKG_VAR PKG_LIB_REQUIREMENTS VAR_TO_SET )
+  PKG_CHECK_MODULES(${PKG_VAR} "${PKG_LIB_REQUIREMENTS}")
+  IF( ${PKG_VAR}_FOUND )
+    SET( ${VAR_TO_SET} ON )
+    SET( ${VAR_TO_SET}_ENABLED ON )
+  ELSE()
+    SET( ${VAR_TO_SET}_ENABLED OFF )
+  ENDIF()
+ENDMACRO()
+
+# Simple ternary operator
+FUNCTION( TEST_IF CONDITION OUTPUT_VAR VAL0 VAL1 )
+  IF( ${CONDITION} )
+    SET( ${OUTPUT_VAR} ${VAL0} PARENT_SCOPE )
+  ELSE()
+    SET( ${OUTPUT_VAR} {VAL1} PARENT_SCOPE )
+  ENDIF()
+ENDFUNCTION()
+
+# Conditional macro immitates autoconf AM_CONDITIONAL
+MACRO( CONDITIONAL VARIABLE )
+  IF( ${ARGN} )
+      SET( ${VARIABLE} ON )
+  ENDIF()
+ENDMACRO()
+
+MACRO( OPT_STRING NAME DEFAULT_VALUE )
+  SET( ${NAME} ${DEFAULT_VALUE} CACHE STRING "${ARGN}" )
+ENDMACRO()
+
+FUNCTION( ARG_ENABLE NAME INTERNAL_VAR LIST_OF_VALUES )
+  SET(HELP_ENABLES "${HELP_ENABLES}\n${NAME}\t-\t${ARGN}" PARENT_SCOPE)
+  SET(CUSTOM_ARGUMENTS "${CUSTOM_ARGUMENTS};${NAME}" PARENT_SCOPE)
+  LIST(LENGTH LIST_OF_VALUES SIZE)
+  LIST(GET LIST_OF_VALUES 0 OPT_ON )
+  IF( SIZE EQUAL 2 )
+    LIST(GET LIST_OF_VALUES 1 OPT_OFF )
+  ENDIF()
+  IF( OPT_OFF )
+    SET( ${NAME} "${OPT_OFF}" CACHE STRING "${ARGN}" )
+  ELSE()
+    SET( ${NAME} "OFF" CACHE STRING "${ARGN}" )
+  ENDIF()
+  IF( ${NAME} )
+    IF(OPT_ON MATCHES ENABLE_VAL)
+      SET( ${INTERNAL_VAR} ${${NAME}} PARENT_SCOPE )
+    ELSE()
+      SET( ${INTERNAL_VAR} ${OPT_ON} PARENT_SCOPE )
+    ENDIF()
+  ELSE()
+    IF( OPT_OFF )
+      SET( ${INTERNAL_VAR} ${OPT_OFF} PARENT_SCOPE )
+    ELSE()
+      IF( CMAKE_MAJOR_VERSION GREATER 3 )
+        UNSET( ${INTERNAL_VAR} PARENT_SCOPE )
+      ELSE()
+        UNSET( ${INTERNAL_VAR} )
+      ENDIF()
+    ENDIF()
+  ENDIF()
+  MESSAGE( STATUS "${NAME} = ${${NAME}}")
+ENDFUNCTION()
+
+# This macro unsets all cached argument variables, should be called
+# upon exit
+MACRO( CLEAN_ARG_CACHE )
+  FOREACH( arg IN LISTS CUSTOM_ARGUMENTS )
+    UNSET( ${arg} CACHE )
+  ENDFOREACH()
+ENDMACRO()
+
+MACRO( EXIT )
+  CLEAN_ARG_CACHE()
+  MESSAGE(FATAL_ERROR ${ARGN})
+ENDMACRO()
diff --git a/build/tizen/dali-adaptor-integration.pc.in b/build/tizen/dali-adaptor-integration.pc.in
new file mode 100644 (file)
index 0000000..fbbb3cd
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@PREFIX@
+exec_prefix=@EXEC_PREFIX@
+apiversion=@DALI_ADAPTOR_VERSION@
+libdir=@LIB_DIR@
+includedir=@DEV_INCLUDE_PATH@
+
+Name: dali-adaptor-integration
+Description: Integration APIs for dali-adaptor
+Version: ${apiversion}
+Requires: dali-adaptor
+Libs: -L${libdir}
+Cflags: -I${includedir}/dali/public-api/adaptor-framework/ -I${includedir}/dali/devel-api/adaptor-framework/ -I${includedir}/dali/integration-api/adaptor-framework/
diff --git a/build/tizen/dali-adaptor.pc.in b/build/tizen/dali-adaptor.pc.in
new file mode 100644 (file)
index 0000000..8838a0d
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@PREFIX@
+exec_prefix=@EXEC_PREFIX@
+apiversion=@DALI_ADAPTOR_VERSION@
+libdir=@LIB_DIR@
+includedir=@DEV_INCLUDE_PATH@
+
+Name: dali-adaptor
+Description: DALi adaptor using ecore
+Version: ${apiversion}
+Requires: dali-core
+Libs: -L${libdir} -ldali-adaptor
+Cflags: -I${includedir}/dali
diff --git a/build/tizen/deps-check.cmake b/build/tizen/deps-check.cmake
new file mode 100644 (file)
index 0000000..b496dd9
--- /dev/null
@@ -0,0 +1,465 @@
+INCLUDE( common.cmake )
+
+# Options
+#           OPTION, VARIABLE, LIST_OF_VALUES, DESCRIPTION
+ARG_ENABLE( ENABLE_EXPORTALL enable_exportall 1 "Enables the exporting of all the symbols in the library" )
+ARG_ENABLE( ENABLE_DEBUG enable_debug ${ENABLE_VAL} "Turns on debugging" )
+ARG_ENABLE( ENABLE_SHADERBINCACHE enable_shaderbincache ${ENABLE_VAL} "Enables shader binary cache" )
+ARG_ENABLE( ENABLE_NETWORKLOGGING enable_networklogging ${ENABLE_VAL} "Enables network for debug tool" )
+
+# Currently, dali-adaptor requires appfw on Tizen
+# and does not require it on Ubuntu.
+# So we should be able to enable/disable this option for dali-adaptor.
+ARG_ENABLE( ENABLE_APPFW enable_appfw ${ENABLE_VAL} "Builds with Tizen App framework libraries, off by default" )
+
+# Tizen Profile option
+ARG_ENABLE( ENABLE_PROFILE enable_profile "${ENABLE_VAL};UBUNTU" "Select the variant of tizen" )
+
+# Tizen Major version
+ARG_ENABLE( ENABLE_TIZEN_MAJOR_VERSION enable_tizen_major_version "${ENABLE_VAL};0" "Specify the Tizen Major version for backwards compatibility" )
+
+ARG_ENABLE( ENABLE_FEEDBACK enable_feedback 1 "Enable feedback plugin" )
+
+ARG_ENABLE( ENABLE_WAYLAND enable_wayland "${ENABLE_VAL}" "Build on Wayland" )
+ARG_ENABLE( ENABLE_ECORE_WAYLAND2 enable_ecore_wayland2 "${ENABLE_VAL}" "Build on Ecore Wayland2" )
+ARG_ENABLE( ENABLE_RENAME_SO enable_rename_so "${ENABLE_VAL};1" "Specify whether so file is renamed or not" )
+ARG_ENABLE( ENABLE_COVERAGE enable_coverage "${ENABLE_VAL}" "Enables coverage" )
+
+# help option
+ARG_ENABLE( PRINT_HELP print_help "${ENABLE_VAL}" "Prints help" )
+
+IF( print_help )
+  MESSAGE( STATUS ${HELP_ENABLES} )
+  EXIT()
+ENDIF()
+
+IF( NOT enable_profile )
+  IF( ANDROID )
+    SET( enable_profile ANDROID )
+  ELSE()
+    SET( enable_profile UBUNTU )
+  ENDIF()
+ENDIF()
+
+# Test for profile and exit if something wrong
+SET( VALID_PROFILES COMMON MOBILE WEARABLE TV IVI UBUNTU ANDROID WINDOWS )
+LIST( FIND VALID_PROFILES ${enable_profile} RESULT )
+IF( RESULT EQUAL -1 )
+  MESSAGE( FATAL_ERROR "Invalid profile!" )
+ENDIF()
+
+# Defines profile specific variable
+SET( ${enable_profile}_PROFILE 1 )
+
+# TODO check what version we really need for Android
+IF( ANDROID_PROFILE )
+  SET( FREETYPE_REQUIRED 6.16.0 )
+  SET( FREETYPE_BITMAP_SUPPORT_VERSION 6.16.0 )
+ELSE()
+  SET( FREETYPE_REQUIRED 9.16.3 )
+  SET( FREETYPE_BITMAP_SUPPORT_VERSION 17.1.11 )
+ENDIF()
+
+# checking all possibly used modules (required and optionals)
+CHECK_MODULE_AND_SET( EXIF exif exif_available )
+CHECK_MODULE_AND_SET( FREETYPE freetype2>=${FREETYPE_REQUIRED} freetype_available )
+CHECK_MODULE_AND_SET( FREETYPE_BITMAP_SUPPORT freetype2>=${FREETYPE_BITMAP_SUPPORT_VERSION} freetype_bitmap_support)
+CHECK_MODULE_AND_SET( FONTCONFIG fontconfig fontconfig_available )
+CHECK_MODULE_AND_SET( PNG libpng [] )
+CHECK_MODULE_AND_SET( LIBEXIF libexif [] )
+CHECK_MODULE_AND_SET( LIBDRM libdrm [] )
+CHECK_MODULE_AND_SET( LIBCURL libcurl [] )
+CHECK_MODULE_AND_SET( HARFBUZZ harfbuzz [] )
+CHECK_MODULE_AND_SET( FRIBIDI fribidi [] )
+CHECK_MODULE_AND_SET( CAIRO cairo [] )
+CHECK_MODULE_AND_SET( EVAS evas [] )
+CHECK_MODULE_AND_SET( TTRACE ttrace ENABLE_TTRACE )
+CHECK_MODULE_AND_SET( ECORE ecore [] )
+CHECK_MODULE_AND_SET( ECORE_IPC ecore-ipc [] )
+CHECK_MODULE_AND_SET( ECORE_IMF ecore-imf [] )
+CHECK_MODULE_AND_SET( ELDBUS eldbus eldbus_available )
+CHECK_MODULE_AND_SET( UTILX utilX utilx_available )
+CHECK_MODULE_AND_SET( OPENGLES20 glesv2 [] )
+CHECK_MODULE_AND_SET( EGL egl [] )
+CHECK_MODULE_AND_SET( DLOG dlog [] )
+CHECK_MODULE_AND_SET( TTS tts [] )
+CHECK_MODULE_AND_SET( VCONF vconf [] )
+
+CHECK_MODULE_AND_SET( CAPI_SYSTEM_INFO capi-system-info [] )
+CHECK_MODULE_AND_SET( CAPI_SYSTEM_SENSOR capi-system-sensor capi_system_sensor_support )
+CHECK_MODULE_AND_SET( CAPI_SYSTEM_SYSTEM_SETTINGS capi-system-system-settings [] )
+CHECK_MODULE_AND_SET( CAPI_APPFW_APPLICATION capi-appfw-application [] )
+
+CHECK_MODULE_AND_SET( ELEMENTARY elementary [] )
+CHECK_MODULE_AND_SET( BUNDLE bundle [] )
+CHECK_MODULE_AND_SET( SCREENCONNECTORPROVIDER screen_connector_provider [] )
+CHECK_MODULE_AND_SET( APPFW_WATCH capi-appfw-watch-application watch_available )
+CHECK_MODULE_AND_SET( APPCORE_WATCH appcore-watch [] )
+
+CHECK_MODULE_AND_SET( CAPI_APPFW_APPLICATION appcore-ui [] )
+CHECK_MODULE_AND_SET( CAPI_APPFW_WIDGET_BASE appcore-widget-base [] )
+CHECK_MODULE_AND_SET( CAPI_APPFW_COMMON capi-appfw-app-common [] )
+CHECK_MODULE_AND_SET( CAPI_APPFW_CONTROL capi-appfw-app-control [] )
+
+CHECK_MODULE_AND_SET( DALICORE dali-core [] )
+
+IF( ANDROID_PROFILE )
+  INCLUDE_DIRECTORIES( ${ANDROID_NDK} )
+  INCLUDE_DIRECTORIES( ${ANDROID_NDK}/sources )
+  INCLUDE_DIRECTORIES( ${ANDROID_NDK}/sources/android )
+  INCLUDE_DIRECTORIES( ${ANDROID_NDK}/sources/android/native_app_glue )
+  INCLUDE_DIRECTORIES( ${ANDROID_NDK}/sysroot/usr )
+  INCLUDE_DIRECTORIES( ${ANDROID_NDK}/sysroot/usr/include/android )
+ENDIF()
+
+IF( enable_wayland )
+  IF( enable_ecore_wayland2 )
+    PKG_CHECK_MODULES(WAYLAND ecore-wl2 egl wayland-egl wayland-egl-tizen wayland-client>=1.2.0 xkbcommon libtbm )
+  ELSE()
+    PKG_CHECK_MODULES(WAYLAND ecore-wayland egl wayland-egl wayland-client>=1.2.0 xkbcommon libtbm)
+  ENDIF()
+  SET(WAYLAND 1)
+ELSE()
+  CHECK_MODULE_AND_SET( ECORE_X ecore-x DALI_USE_ECORE_X11 [] )
+  CHECK_MODULE_AND_SET( X11 x11 DALI_USE_X11 [] )
+ENDIF()
+
+CHECK_MODULE_AND_SET( WAYLAND_EXTENSION xdg-shell-client text-client input-method-client [] )
+
+# BUILD CONDITIONS
+IF( watch_available AND WEARABLE_PROFILE )
+  ADD_DEFINITIONS( -DAPPCORE_WATCH_AVAILABLE )
+ENDIF()
+
+IF( eldbus_available )
+  SET(DALI_ELDBUS_AVAILABLE 1)
+  ADD_DEFINITIONS( -DDALI_ELDBUS_AVAILABLE )
+ENDIF()
+
+ADD_DEFINITIONS( -DPLATFORM_TIZEN )
+
+IF( enable_debug )
+  ADD_DEFINITIONS( -DDEBUG_ENABLED )
+  SET( ENABLE_EXPORTALL ON )
+ENDIF()
+
+IF( NOT ${ENABLE_EXPORTALL} )
+  ADD_DEFINITIONS( "-fvisibility=hidden -DHIDE_DALI_INTERNALS" )
+ENDIF()
+
+IF( enable_shaderbincache )
+  ADD_DEFINITIONS( -DSHADERBIN_CACHE_ENABLED )
+ENDIF()
+
+IF( enable_networklogging )
+  ADD_DEFINITIONS( -DNETWORK_LOGGING_ENABLED )
+ENDIF()
+
+IF( watch_available AND WEARABLE_PROFILE )
+  ADD_DEFINITIONS( -DAPPCORE_WATCH_AVAILABLE )
+ENDIF()
+
+IF( capi_system_sensor_support AND (NOT UBUNTU_PROFILE) )
+  ADD_DEFINITIONS( -DCAPI_SYSTEM_SENSOR_SUPPORT )
+ENDIF()
+
+IF( enable_appfw AND (enable_tizen_major_version EQUAL 3) )
+  ADD_DEFINITIONS( -DWIDGET_AVAILABLE )
+ENDIF()
+
+IF( enable_wayland AND (NOT COMMON_PROFILE) )
+  PKG_CHECK_MODULES( WAYLAND_EXTENSION [xdg-shell-client text-client input-method-client] )
+ENDIF()
+
+IF( freetype_bitmap_support )
+  ADD_DEFINITIONS( -DFREETYPE_BITMAP_SUPPORT )
+ENDIF()
+
+IF( ENABLE_COVERAGE OR "$ENV{CXXFLAGS}" MATCHES --coverage )
+  ADD_COMPILE_OPTIONS( --coverage )
+  SET(ENABLE_COVERAGE ON)
+  SET(COVERAGE --coverage)
+ENDIF()
+
+IF( DEFINED ENV{DALI_DATA_RW_DIR} )
+  SET( dataReadWriteDir $ENV{DALI_DATA_RW_DIR} )
+ELSE()
+  SET( dataReadWriteDir ${CMAKE_INSTALL_PREFIX}/share/dali/ )
+ENDIF()
+
+IF( DEFINED ENV{DALI_DATA_RO_DIR} )
+  SET( dataReadOnlyDir $ENV{DALI_DATA_RO_DIR} )
+ELSE()
+  SET( dataReadOnlyDir ${CMAKE_INSTALL_PREFIX}/share/dali/ )
+ENDIF()
+
+IF( DEFINED ENV{TIZEN_PLATFORM_CONFIG_SUPPORTED} )
+  SET( tizenPlatformConfigSupported $ENV{TIZEN_PLATFORM_CONFIG_SUPPORTED} )
+  SET( TIZEN_PLATFORM_CONFIG_SUPPORTED_LOGMSG "YES" )
+ELSE()
+  SET( tizenPlatformConfigSupported 0 )
+  SET( TIZEN_PLATFORM_CONFIG_SUPPORTED_LOGMSG "NO" )
+ENDIF()
+
+IF( DEFINED ENV{FONT_CONFIGURATION_FILE} )
+  SET( fontConfigurationFile $ENV{FONT_CONFIGURATION_FILE} )
+ENDIF()
+
+IF( UBUNTU_PROFILE )
+  SET( cachePath $ENV{HOME} )
+ELSE()
+  SET( cachePath /home/owner )
+ENDIF()
+
+#######################################################
+
+ADD_DEFINITIONS( -DDALI_PROFILE_${enable_profile})
+SET( DALI_PROFILE_CFLAGS -DDALI_PROFILE_${enable_profile} )
+
+# Platforms with highp shader support can use vector based text
+CONDITIONAL( ENABLE_VECTOR_BASED_TEXT_RENDERING UBUNTU_PROFILE )
+CONDITIONAL( WAYLAND enable_wayland )
+
+# set lowercase profile name
+STRING( TOLOWER ${ENABLE_PROFILE} PROFILE_LCASE )
+
+##########################################################3
+# Default CFLAGS of packages
+#
+SET( DALI_CFLAGS
+  ${DALI_ADAPTOR_CFLAGS}
+  ${DALICORE_CFLAGS}
+  ${OPENGLES20_CFLAGS}
+  ${FREETYPE_CFLAGS}
+  ${FONTCONFIG_CFLAGS}
+  ${CAIRO_CFLAGS}
+  ${PNG_CFLAGS}
+  ${DLOG_CFLAGS}
+  ${VCONF_CFLAGS}
+  ${EXIF_CFLAGS}
+  ${MMFSOUND_CFLAGS}
+  ${TTS_CFLAGS}
+  ${CAPI_SYSTEM_SENSOR_CFLAGS}
+  ${LIBDRM_CFLAGS}
+  ${LIBEXIF_CFLAGS}
+  ${LIBCURL_CFLAGS}
+  ${UTILX_CFLAGS}
+  -Wall
+)
+
+# Default set of linked librarires
+SET( DALI_LDFLAGS
+  ${DALICORE_LDFLAGS}
+  ${OPENGLES20_LDFLAGS}
+  ${FREETYPE_LDFLAGS}
+  ${FONTCONFIG_LDFLAGS}
+  ${CAIRO_LDFLAGS}
+  ${PNG_LDFLAGS}
+  ${DLOG_LDFLAGS}
+  ${VCONF_LDFLAGS}
+  ${EXIF_LDFLAGS}
+  ${TTS_LDFLAGS}
+  ${CAPI_SYSTEM_SENSOR_LDFLAGS}
+  ${LIBDRM_LDFLAGS}
+  ${LIBEXIF_LDFLAGS}
+  ${LIBCURL_LDFLAGS}
+  ${LIBCRYPTO_LDFLAGS}
+  ${HARFBUZZ_LDFLAGS}
+  ${UTILX_LDFLAGS}
+  -lgif
+  -lturbojpeg
+  -ljpeg
+)
+
+# Android includes pthread with android lib
+if( NOT ANDROID_PROFILE )
+  SET( DALI_LDFLAGS ${DALI_LDFLAGS}
+    -lpthread
+  )
+ENDIF()
+
+# You need to include manually private and Android libs deps in order to link for Android
+IF( ANDROID_PROFILE )
+  CHECK_MODULE_AND_SET( PIXMAN pixman-1 [] )
+  CHECK_MODULE_AND_SET( EXPAT expat [] )
+
+  SET( DALI_CFLAGS ${DALI_CFLAGS}
+    ${PIXMAN_CFLAGS}
+    ${EXPAT_CFLAGS}
+    ${FRIBIDI_CFLAGS}
+  )
+
+  LIST( APPEND DALI_LDFLAGS
+    ${FRIBIDI_LDFLAGS}
+    ${FREETYPE_LDFLAGS}
+    ${PNG_LDFLAGS}
+    ${PIXMAN_LDFLAGS}
+    ${EXPAT_LDFLAGS}
+    z
+    android
+    log
+    EGL
+    GLESv3
+  )
+ENDIF()
+
+# EVAS used indicator
+SET( DALI_CFLAGS ${DALI_CFLAGS}
+  ${EVAS_CFLAGS}
+  ${ECORE_CFLAGS}
+  ${ECORE_IPC_CFLAGS}
+  ${ELDBUS_CFLAGS}
+)
+
+SET( DALI_LDFLAGS ${DALI_LDFLAGS}
+  ${ECORE_IPC_LDFLAGS}
+  ${ELDBUS_LDFLAGS}
+)
+
+# APPFW
+IF( enable_appfw )
+  SET( DALI_CFLAGS ${DALI_CFLAGS}
+    ${CAPI_APPFW_APPLICATION_CFLAGS}
+    ${CAPI_SYSTEM_SYSTEM_SETTINGS_CFLAGS}
+    ${CAPI_SYSTEM_INFO_CFLAGS}
+    ${TTS_CFLAGS}
+    ${SENSOR_CFLAGS}
+    ${BUNDLE_CFLAGS}
+    ${CAPI_APPFW_COMMON_CFLAGS}
+    ${CAPI_APPFW_CONTROL_CFLAGS}
+    ${CAPI_APPFW_WIDGET_BASE_CFLAGS}
+    ${ECORE_IMF_CFLAGS}
+    ${FRIBIDI_CFLAGS}
+  )
+
+  SET( DALI_LDFLAGS ${DALI_LDFLAGS}
+    ${CAPI_APPFW_APPLICATION_LDFLAGS}
+    ${CAPI_SYSTEM_SYSTEM_SETTINGS_LDFLAGS}
+    ${CAPI_SYSTEM_INFO_LDFLAGS}
+    ${TTS_LDFLAGS}
+    ${SENSOR_LDFLAGS}
+    ${BUNDLE_LDFLAGS}
+    ${CAPI_APPFW_COMMON_LDFLAGS}
+    ${CAPI_APPFW_CONTROL_LDFLAGS}
+    ${CAPI_APPFW_WIDGET_BASE_LDFLAGS}
+    ${ECORE_IMF_LDFLAGS}
+    ${FRIBIDI_LDFLAGS}
+  )
+ELSE()
+  SET( DALI_CFLAGS ${DALI_CFLAGS}
+    ${ELEMENTARY_CFLAGS}
+  )
+
+  SET( DALI_LDFLAGS ${DALI_LDFLAGS}
+    ${ELEMENTARY_LDFLAGS}
+  )
+ENDIF()
+
+# WAYLAND
+IF( WAYLAND )
+  SET( DALI_CFLAGS ${DALI_CFLAGS}
+    -DWL_EGL_PLATFORM
+    ${WAYLAND_CFLAGS}
+  )
+  SET( DALI_LDFLAGS ${DALI_LDFLAGS}
+    ${WAYLAND_LDFLAGS}
+  )
+ELSE()
+  SET( DALI_CFLAGS ${DALI_CFLAGS}
+       ${X11_CFLAGS}
+       )
+  SET( DALI_LDFLAGS ${DALI_LDFLAGS}
+       ${X11_LDFLAGS}
+       ${ECORE_X_LDFLAGS}
+       )
+ENDIF()
+
+# COMMON PROFILE
+IF( COMMON_PROFILE )
+  SET( DALI_CFLAGS ${DALI_CFLAGS} ${HAPTIC_CFLAGS} )
+ENDIF()
+
+# MOBILE PROFILE
+IF( MOBILE_PROFILE )
+  SET( DALI_CFLAGS ${DALI_CFLAGS}
+      ${DEVICED_CFLAGS}
+      ${EFL_ASSIST_CFLAGS}
+      ${NATIVE_BUFFER_CFLAGS}
+      ${NATIVE_BUFFER_POOL_CFLAGS}
+      )
+
+  SET( DALI_LDFLAGS ${DALI_LDFLAGS}
+      ${EFL_ASSIST_LDFLAGS}
+      ${NATIVE_BUFFER_LDFLAGS}
+      ${NATIVE_BUFFER_POOL_LDFLAGS}
+  )
+ENDIF()
+
+# WEARABLE PROFILE
+IF( WEARABLE_PROFILE )
+  SET( DALI_CFLAGS ${DALI_CFLAGS}
+    ${HAPTIC_CFLAGS}
+    ${EFL_ASSIST_CFLAGS}
+    ${SCREENCONNECTORPROVIDER_CFLAGS}
+    ${APPCORE_WATCH_CFLAGS}
+  )
+  SET( DALI_LDFLAGS ${DALI_LDFLAGS}
+    ${SCREENCONNECTORPROVIDER_LDFLAGS}
+    ${APPCORE_WATCH_LDFLAGS}
+  )
+ENDIF()
+
+# TV PROFILE
+IF( TV_PROFILE )
+  SET( DALI_CFLAGS ${DALI_CFLAGS} ${HAPTIC_CFLAGS} )
+ENDIF()
+
+# IVI PROFILE
+IF( IVI_PROFILE )
+  SET( DALI_CFLAGS ${DALI_CFLAGS}
+      ${DEVICED_CFLAGS}
+      ${EFL_ASSIST_CFLAGS}
+      ${NATIVE_BUFFER_CFLAGS}
+      ${NATIVE_BUFFER_POOL_CFLAGS}
+  )
+  SET( DALI_LDFLAGS ${DALI_LDFLAGS}
+      ${EFL_ASSIST_LDFLAGS}
+      ${NATIVE_BUFFER_LDFLAGS}
+      ${NATIVE_BUFFER_POOL_LDFLAGS}
+  )
+ENDIF()
+
+# UBUNTU PROFILE
+IF( UBUNTU_PROFILE )
+  SET( DALI_CFLAGS ${DALI_CFLAGS} -fPIC )
+  SET( DALI_LDFLAGS ${DALI_LDFLAGS} -ljpeg )
+ENDIF()
+
+IF( NOT COMMON_PROFILE )
+  ADD_DEFINITIONS( -DWAYLAND_EXTENSIONS_SUPPORTED )
+ENDIF()
+
+# had to do it here for Android by some reason, even if it is set above already
+IF( ANDROID_PROFILE )
+  SET( daliReadOnlyDir $ENV{DALI_DATA_RO_DIR} )
+  SET( daliReadWriteDir $ENV{DALI_DATA_RW_DIR} )
+ENDIF()
+
+SET( daliDefaultThemeDir ${dataReadWriteDir}/theme/ )
+SET( fontPreloadedPath $ENV{FONT_PRELOADED_PATH} )
+SET( fontDownloadedPath $ENV{FONT_DOWNLOADED_PATH} )
+SET( fontApplicationPath $ENV{FONT_APPLICATION_PATH} )
+
+# Configure paths
+ADD_DEFINITIONS(  -DDALI_DATA_RW_DIR="${daliReadWriteDir}"
+                  -DDALI_DATA_RO_DIR="${daliReadOnlyDir}"
+                  -DDALI_DEFAULT_FONT_CACHE_DIR="${daliDefaultFontCacheDir}"
+                  -DDALI_USER_FONT_CACHE_DIR="${daliUserFontCacheDir}"
+                  -DDALI_SHADERBIN_DIR="${daliShaderbinCacheDir}"
+                  -DDALI_DEFAULT_THEME_DIR="${daliDefaultThemeDir}"
+                  -DFONT_PRELOADED_PATH="${fontPreloadedPath}"
+                  -DFONT_DOWNLOADED_PATH="${fontDownloadedPath}"
+                  -DFONT_APPLICATION_PATH="${fontApplicationPath}"
+                  -DFONT_CONFIGURATION_FILE="${fontConfigurationFile}"
+                  -DTIZEN_PLATFORM_CONFIG_SUPPORTED=${tizenPlatformConfigSupported}
+)
diff --git a/build/tizen/linker-test.cpp b/build/tizen/linker-test.cpp
new file mode 100644 (file)
index 0000000..90f365a
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <iostream>
+#include <dali/public-api/dali-core.h>
+#include <dali/devel-api/adaptor-framework/orientation.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/timer.h>
+#include <dali/public-api/adaptor-framework/application.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+
+using namespace Dali;
+
+/*****************************************************************************
+ * Test to see if the dali-adaptor is linking correctly.
+ */
+
+class LinkerApp : public ConnectionTracker
+{
+public:
+  LinkerApp(Application &app)
+  {
+    app.InitSignal().Connect(this, &LinkerApp::Create);
+  }
+
+public:
+
+  void Create(Application& app)
+  {
+  }
+};
+
+/*****************************************************************************/
+
+int
+main(int argc, char **argv)
+{
+  try
+  {
+    Application app = Application::New(&argc, &argv);
+
+    LinkerApp linkerApp (app);
+    app.MainLoop();
+  }
+  catch(...)
+  {
+    std::cout << "Exception caught";
+  }
+
+  return 0;
+}
diff --git a/build/tizen/module-list.cmake b/build/tizen/module-list.cmake
new file mode 100644 (file)
index 0000000..9e45dea
--- /dev/null
@@ -0,0 +1,149 @@
+SET( adaptor_accessibility_dir ${ADAPTOR_ROOT}/dali/internal/accessibility )
+include( ${ADAPTOR_ROOT}/dali/internal/accessibility/file.list )
+
+SET( adaptor_adaptor_dir ${ADAPTOR_ROOT}/dali/internal/adaptor )
+include( ${ADAPTOR_ROOT}/dali/internal/adaptor/file.list )
+
+SET( adaptor_clipboard_dir ${ADAPTOR_ROOT}/dali/internal/clipboard )
+include( ${ADAPTOR_ROOT}/dali/internal/clipboard/file.list )
+
+SET( adaptor_framework_dir ${ADAPTOR_ROOT}/dali/internal/adaptor-framework )
+include( ${ADAPTOR_ROOT}/dali/internal/adaptor-framework/file.list )
+
+SET( adaptor_graphics_dir ${ADAPTOR_ROOT}/dali/internal/graphics )
+include( ${ADAPTOR_ROOT}/dali/internal/graphics/file.list )
+
+SET( adaptor_haptics_dir ${ADAPTOR_ROOT}/dali/internal/haptics )
+include( ${ADAPTOR_ROOT}/dali/internal/haptics/file.list )
+
+SET( adaptor_imaging_dir ${ADAPTOR_ROOT}/dali/internal/imaging )
+include( ${ADAPTOR_ROOT}/dali/internal/imaging/file.list )
+
+SET( adaptor_input_dir ${ADAPTOR_ROOT}/dali/internal/input )
+include( ${ADAPTOR_ROOT}/dali/internal/input/file.list )
+
+SET( adaptor_legacy_dir ${ADAPTOR_ROOT}/dali/internal/legacy )
+include( ${ADAPTOR_ROOT}/dali/internal/legacy/file.list )
+
+SET( adaptor_network_dir ${ADAPTOR_ROOT}/dali/internal/network )
+include( ${ADAPTOR_ROOT}/dali/internal/network/file.list )
+
+SET( adaptor_sensor_dir ${ADAPTOR_ROOT}/dali/internal/sensor )
+include( ${ADAPTOR_ROOT}/dali/internal/sensor/file.list )
+
+SET( adaptor_styling_dir ${ADAPTOR_ROOT}/dali/internal/styling )
+include( ${ADAPTOR_ROOT}/dali/internal/styling/file.list )
+
+SET( adaptor_system_dir ${ADAPTOR_ROOT}/dali/internal/system )
+include( ${ADAPTOR_ROOT}/dali/internal/system/file.list )
+
+SET( adaptor_text_dir ${ADAPTOR_ROOT}/dali/internal/text )
+include( ${ADAPTOR_ROOT}/dali/internal/text/file.list )
+
+SET( adaptor_video_dir ${ADAPTOR_ROOT}/dali/internal/video )
+include( ${ADAPTOR_ROOT}/dali/internal/video/file.list )
+
+SET( adaptor_web_engine_dir ${ADAPTOR_ROOT}/dali/internal/web-engine )
+include( ${ADAPTOR_ROOT}/dali/internal/web-engine/file.list )
+
+SET( adaptor_window_system_dir ${ADAPTOR_ROOT}/dali/internal/window-system )
+include( ${ADAPTOR_ROOT}/dali/internal/window-system/file.list )
+
+SET( adaptor_trace_dir ${ADAPTOR_ROOT}/dali/internal/trace )
+include( ${ADAPTOR_ROOT}/dali/internal/trace/file.list )
+
+SET( adaptor_thread_dir ${ADAPTOR_ROOT}/dali/internal/thread )
+include( ${ADAPTOR_ROOT}/dali/internal/thread/file.list )
+
+SET( adaptor_vector_animation_dir ${ADAPTOR_ROOT}/dali/internal/vector-animation )
+include( ${ADAPTOR_ROOT}/dali/internal/vector-animation/file.list )
+
+SET( adaptor_public_api_dir ${ADAPTOR_ROOT}/dali/public-api )
+include( ${ADAPTOR_ROOT}/dali/public-api/file.list )
+
+SET( adaptor_dali_header_dir ${ADAPTOR_ROOT}/dali )
+include( ${ADAPTOR_ROOT}/dali/file.list )
+
+SET( adaptor_devel_api_dir ${ADAPTOR_ROOT}/dali/devel-api )
+include( ${ADAPTOR_ROOT}/dali/devel-api/file.list )
+
+SET( adaptor_integration_api_dir ${ADAPTOR_ROOT}/dali/integration-api )
+include( ${ADAPTOR_ROOT}/dali/integration-api/file.list )
+
+SET( adaptor_thirdparty_dir ${ADAPTOR_ROOT}/third-party )
+include( ${ADAPTOR_ROOT}/third-party/file.list )
+SET( adaptor_accessibility_dir ${ADAPTOR_ROOT}/dali/internal/accessibility )
+include( ${ADAPTOR_ROOT}/dali/internal/accessibility/file.list )
+
+SET( adaptor_adaptor_dir ${ADAPTOR_ROOT}/dali/internal/adaptor )
+include( ${ADAPTOR_ROOT}/dali/internal/adaptor/file.list )
+
+SET( adaptor_clipboard_dir ${ADAPTOR_ROOT}/dali/internal/clipboard )
+include( ${ADAPTOR_ROOT}/dali/internal/clipboard/file.list )
+
+SET( adaptor_framework_dir ${ADAPTOR_ROOT}/dali/internal/adaptor-framework )
+include( ${ADAPTOR_ROOT}/dali/internal/adaptor-framework/file.list )
+
+SET( adaptor_graphics_dir ${ADAPTOR_ROOT}/dali/internal/graphics )
+include( ${ADAPTOR_ROOT}/dali/internal/graphics/file.list )
+
+SET( adaptor_haptics_dir ${ADAPTOR_ROOT}/dali/internal/haptics )
+include( ${ADAPTOR_ROOT}/dali/internal/haptics/file.list )
+
+SET( adaptor_imaging_dir ${ADAPTOR_ROOT}/dali/internal/imaging )
+include( ${ADAPTOR_ROOT}/dali/internal/imaging/file.list )
+
+SET( adaptor_input_dir ${ADAPTOR_ROOT}/dali/internal/input )
+include( ${ADAPTOR_ROOT}/dali/internal/input/file.list )
+
+SET( adaptor_legacy_dir ${ADAPTOR_ROOT}/dali/internal/legacy )
+include( ${ADAPTOR_ROOT}/dali/internal/legacy/file.list )
+
+SET( adaptor_network_dir ${ADAPTOR_ROOT}/dali/internal/network )
+include( ${ADAPTOR_ROOT}/dali/internal/network/file.list )
+
+SET( adaptor_sensor_dir ${ADAPTOR_ROOT}/dali/internal/sensor )
+include( ${ADAPTOR_ROOT}/dali/internal/sensor/file.list )
+
+SET( adaptor_styling_dir ${ADAPTOR_ROOT}/dali/internal/styling )
+include( ${ADAPTOR_ROOT}/dali/internal/styling/file.list )
+
+SET( adaptor_system_dir ${ADAPTOR_ROOT}/dali/internal/system )
+include( ${ADAPTOR_ROOT}/dali/internal/system/file.list )
+
+SET( adaptor_text_dir ${ADAPTOR_ROOT}/dali/internal/text )
+include( ${ADAPTOR_ROOT}/dali/internal/text/file.list )
+
+SET( adaptor_video_dir ${ADAPTOR_ROOT}/dali/internal/video )
+include( ${ADAPTOR_ROOT}/dali/internal/video/file.list )
+
+SET( adaptor_web_engine_dir ${ADAPTOR_ROOT}/dali/internal/web-engine )
+include( ${ADAPTOR_ROOT}/dali/internal/web-engine/file.list )
+
+SET( adaptor_window_system_dir ${ADAPTOR_ROOT}/dali/internal/window-system )
+include( ${ADAPTOR_ROOT}/dali/internal/window-system/file.list )
+
+SET( adaptor_trace_dir ${ADAPTOR_ROOT}/dali/internal/trace )
+include( ${ADAPTOR_ROOT}/dali/internal/trace/file.list )
+
+SET( adaptor_thread_dir ${ADAPTOR_ROOT}/dali/internal/thread )
+include( ${ADAPTOR_ROOT}/dali/internal/thread/file.list )
+
+SET( adaptor_vector_animation_dir ${ADAPTOR_ROOT}/dali/internal/vector-animation )
+include( ${ADAPTOR_ROOT}/dali/internal/vector-animation/file.list )
+
+SET( adaptor_public_api_dir ${ADAPTOR_ROOT}/dali/public-api )
+include( ${ADAPTOR_ROOT}/dali/public-api/file.list )
+
+SET( adaptor_dali_header_dir ${ADAPTOR_ROOT}/dali )
+include( ${ADAPTOR_ROOT}/dali/file.list )
+
+SET( adaptor_devel_api_dir ${ADAPTOR_ROOT}/dali/devel-api )
+include( ${ADAPTOR_ROOT}/dali/devel-api/file.list )
+
+SET( adaptor_integration_api_dir ${ADAPTOR_ROOT}/dali/integration-api )
+include( ${ADAPTOR_ROOT}/dali/integration-api/file.list )
+
+SET( adaptor_thirdparty_dir ${ADAPTOR_ROOT}/third-party )
+include( ${ADAPTOR_ROOT}/third-party/file.list )
+
diff --git a/build/tizen/plugins/CMakeLists.txt b/build/tizen/plugins/CMakeLists.txt
new file mode 100644 (file)
index 0000000..5ee1048
--- /dev/null
@@ -0,0 +1,39 @@
+IF( (NOT UBUNTU_PROFILE) )
+  PKG_CHECK_MODULES(FEEDBACK feedback)
+  PKG_CHECK_MODULES(MMFSOUND mm-sound)
+
+  SET(PLUGIN_TARGET dali-feedback-plugin-cxx11 )
+
+  MESSAGE(STATUS ${ROOT_SRC_DIR}/plugins )
+  SET( plugin_src_dir ${ROOT_SRC_DIR}/plugins )
+
+  INCLUDE( ${plugin_src_dir}/file.list )
+
+  SET( PLUGIN_SOURCES ${feedback_plugin_src_files})
+
+  ADD_LIBRARY( ${PLUGIN_TARGET} SHARED ${PLUGIN_SOURCES} )
+
+  TARGET_LINK_LIBRARIES( ${PLUGIN_TARGET} PUBLIC
+    ${DLOG_LDFLAGS}
+    ${MMFSOUND_LDFLAGS})
+
+  TARGET_COMPILE_DEFINITIONS( ${PLUGIN_TARGET} PUBLIC
+    -DDALI_SOUND_DIR=\"${dalisounddir}\")
+
+  TARGET_COMPILE_OPTIONS( ${PLUGIN_TARGET} PUBLIC
+    ${DLOG_CFLAGS}
+    ${DALICORE_CFLAGS}
+    ${MMFSOUND_CFLAGS}
+    ${FEEDBACK_CFLAGS}
+    ${DALI_PROFILE_CFLAGS}
+    ${DALI_ADAPTOR_CFLAGS}
+    -I../../../
+    -Wall
+  )
+  # Install plugin resources
+  #SET( dalisounddir ${dataReadOnlyDir}/plugins/sounds/ )
+  SET( dalisounddir ${CMAKE_INSTALL_PREFIX}/../plugins/sounds/ )
+    #EXIT(${dalisounddir})
+  INSTALL( FILES ${dali_plugin_sound_files} DESTINATION ${dalisounddir} )
+  INSTALL( TARGETS ${PLUGIN_TARGET} DESTINATION ${LIB_DIR} )
+ENDIF()
diff --git a/build/tizen/profiles/android-profile.cmake b/build/tizen/profiles/android-profile.cmake
new file mode 100644 (file)
index 0000000..f0d1cf0
--- /dev/null
@@ -0,0 +1,67 @@
+# PROFILE: ANDROID
+
+include( ${adaptor_integration_api_dir}/adaptor-framework/android/file.list )
+
+# Set the sources
+SET( SOURCES
+        ${adaptor_accessibility_common_src_files}
+        ${adaptor_accessibility_android_src_files}
+        ${adaptor_adaptor_common_src_files}
+        ${adaptor_clipboard_common_src_files}
+        ${adaptor_clipboard_android_src_files}
+        ${adaptor_framework_android_src_files}
+        ${devel_api_src_files}
+        ${adaptor_devel_api_text_abstraction_src_files}
+        ${adaptor_graphics_common_src_files}
+        ${adaptor_graphics_gles_src_files}
+        ${adaptor_graphics_android_src_files}
+        ${adaptor_haptics_common_src_files}
+        ${adaptor_imaging_common_src_files}
+        ${adaptor_imaging_android_src_files}
+        ${adaptor_input_common_src_files}
+        ${adaptor_input_generic_src_files}
+        ${adaptor_integration_api_src_files}
+        ${adaptor_integration_api_android_src_files}
+        ${adaptor_legacy_common_src_files}
+        ${adaptor_network_common_src_files}
+        ${adaptor_public_api_src_files}
+        ${adaptor_sensor_common_src_files}
+        ${adaptor_sensor_android_src_files}
+        ${adaptor_styling_common_src_files}
+        ${adaptor_system_common_src_files}
+        ${adaptor_system_android_src_files}
+        ${adaptor_text_common_src_files}
+        ${adaptor_resampler_src_files}
+        ${adaptor_vector_animation_common_src_files}
+        ${adaptor_video_common_src_files}
+        ${adaptor_web_engine_common_src_files}
+        ${adaptor_window_system_common_src_files}
+        ${adaptor_window_system_android_src_files}
+        ${adaptor_trace_common_src_files}
+        ${adaptor_thread_common_src_files}
+        ${devel_api_text_abstraction_src_files}
+        ${static_libraries_libunibreak_src_files}
+        ${static_libraries_glyphy_src_files}
+)
+
+IF( ENABLE_ANDROIDJNI_FRAMEWORK )
+    SET( SOURCES ${SOURCES}
+      ${adaptor_adaptor_androidjni_src_files}
+    )
+ELSE()
+    SET( SOURCES ${SOURCES}
+      ${adaptor_adaptor_android_src_files}
+    )
+ENDIF()
+
+IF( ENABLE_NETWORK_LOGGING )
+    SET( SOURCES ${SOURCES}
+      ${adaptor_performance_logging_src_files}
+    )
+ENDIF()
+
+IF( ENABLE_TRACE )
+    SET( SOURCES ${SOURCES}
+      ${adaptor_trace_generic_src_files}
+    )
+ENDIF()
diff --git a/build/tizen/profiles/common-profile.cmake b/build/tizen/profiles/common-profile.cmake
new file mode 100644 (file)
index 0000000..2c18ce0
--- /dev/null
@@ -0,0 +1,67 @@
+# PROFILE: IVI
+
+# Set the sources
+SET( SOURCES
+    ${adaptor_accessibility_common_src_files}
+    ${adaptor_accessibility_tizen_wayland_src_files}
+    ${adaptor_accessibility_tizen_common_src_files}
+    ${adaptor_adaptor_common_src_files}
+    ${adaptor_adaptor_tizen_wayland_src_files}
+    ${adaptor_clipboard_common_src_files}
+    ${adaptor_clipboard_tizen_wayland_src_files}
+    ${adaptor_framework_generic_src_files}
+    ${devel_api_src_files}
+    ${adaptor_devel_api_text_abstraction_src_files}
+    ${adaptor_graphics_common_src_files}
+    ${adaptor_graphics_gles_src_files}
+    ${adaptor_graphics_tizen_src_files}
+    ${adaptor_haptics_common_src_files}
+    ${adaptor_imaging_common_src_files}
+    ${adaptor_imaging_tizen_src_files}
+    ${adaptor_input_common_src_files}
+    ${adaptor_input_tizen_wayland_src_files}
+    ${adaptor_integration_api_src_files}
+    ${adaptor_legacy_common_src_files}
+    ${adaptor_network_common_src_files}
+    ${adaptor_public_api_src_files}
+    ${adaptor_sensor_common_src_files}
+    ${adaptor_sensor_tizen_src_files}
+    ${adaptor_styling_common_src_files}
+    ${adaptor_system_common_src_files}
+    ${adaptor_system_linux_src_files}
+    ${adaptor_system_tizen_wayland_src_files}
+    ${adaptor_text_common_src_files}
+    ${adaptor_resampler_src_files}
+    ${adaptor_vector_animation_common_src_files}
+    ${adaptor_video_common_src_files}
+    ${adaptor_web_engine_common_src_files}
+    ${adaptor_window_system_common_src_files}
+    ${adaptor_window_system_tizen_src_files}
+    ${adaptor_window_system_tizen_wayland_src_files}
+    ${adaptor_trace_common_src_files}
+    ${adaptor_thread_common_src_files}
+    ${devel_api_text_abstraction_src_files}
+    ${static_libraries_glyphy_src_files}
+    ${static_libraries_libunibreak_src_files}
+     )
+IF( enable_ecore_wayland2 )
+    SET( SOURCES ${SOURCES}
+         ${adaptor_window_system_ecore_wl2_src_files}
+         )
+ELSE()
+    SET( SOURCES ${SOURCES}
+         ${adaptor_window_system_ecore_wl_src_files}
+         )
+ENDIF()
+
+IF( ENABLE_NETWORK_LOGGING )
+    SET( SOURCES ${SOURCES}
+         ${adaptor_performance_logging_src_files}
+         )
+ENDIF()
+
+IF( ENABLE_TRACE )
+    SET( SOURCES ${SOURCES}
+         ${adaptor_trace_tizen_src_files}
+         )
+ENDIF()
diff --git a/build/tizen/profiles/ivi-profile.cmake b/build/tizen/profiles/ivi-profile.cmake
new file mode 100644 (file)
index 0000000..765a1ea
--- /dev/null
@@ -0,0 +1,68 @@
+# PROFILE: IVI
+
+# Set the sources
+SET( SOURCES
+     ${adaptor_accessibility_common_src_files}
+     ${adaptor_accessibility_tizen_wayland_src_files}
+     ${adaptor_accessibility_tizen_ivi_src_files}
+     ${adaptor_adaptor_common_src_files}
+     ${adaptor_adaptor_tizen_wayland_src_files}
+     ${adaptor_clipboard_common_src_files}
+     ${adaptor_clipboard_tizen_wayland_src_files}
+     ${adaptor_framework_generic_src_files}
+     ${devel_api_src_files}
+     ${adaptor_devel_api_text_abstraction_src_files}
+     ${adaptor_graphics_common_src_files}
+     ${adaptor_graphics_gles_src_files}
+     ${adaptor_graphics_tizen_src_files}
+     ${adaptor_haptics_common_src_files}
+     ${adaptor_haptics_tizen_src_files}
+     ${adaptor_imaging_common_src_files}
+     ${adaptor_imaging_tizen_src_files}
+     ${adaptor_input_common_src_files}
+     ${adaptor_input_tizen_wayland_src_files}
+     ${adaptor_integration_api_src_files}
+     ${adaptor_legacy_common_src_files}
+     ${adaptor_network_common_src_files}
+     ${adaptor_public_api_src_files}
+     ${adaptor_sensor_common_src_files}
+     ${adaptor_sensor_tizen_src_files}
+     ${adaptor_styling_common_src_files}
+     ${adaptor_system_common_src_files}
+     ${adaptor_system_linux_src_files}
+     ${adaptor_system_tizen_wayland_src_files}
+     ${adaptor_text_common_src_files}
+     ${adaptor_resampler_src_files}
+     ${adaptor_vector_animation_common_src_files}
+     ${adaptor_video_common_src_files}
+     ${adaptor_web_engine_common_src_files}
+     ${adaptor_window_system_common_src_files}
+     ${adaptor_window_system_tizen_src_files}
+     ${adaptor_window_system_tizen_wayland_src_files}
+     ${adaptor_trace_common_src_files}
+     ${adaptor_thread_common_src_files}
+     ${devel_api_text_abstraction_src_files}
+     ${static_libraries_glyphy_src_files}
+     ${static_libraries_libunibreak_src_files}
+     )
+IF( enable_ecore_wayland2 )
+    SET( SOURCES ${SOURCES}
+         ${adaptor_window_system_ecore_wl2_src_files}
+         )
+ELSE()
+    SET( SOURCES ${SOURCES}
+         ${adaptor_window_system_ecore_wl_src_files}
+         )
+ENDIF()
+
+IF( ENABLE_NETWORK_LOGGING )
+    SET( SOURCES ${SOURCES}
+         ${adaptor_performance_logging_src_files}
+         )
+ENDIF()
+
+IF( ENABLE_TRACE )
+    SET( SOURCES ${SOURCES}
+         ${adaptor_trace_tizen_src_files}
+         )
+ENDIF()
diff --git a/build/tizen/profiles/mobile-profile.cmake b/build/tizen/profiles/mobile-profile.cmake
new file mode 100644 (file)
index 0000000..38cc849
--- /dev/null
@@ -0,0 +1,68 @@
+# PROFILE: UBUNTU
+
+# Set the sources
+SET( SOURCES
+        ${adaptor_accessibility_common_src_files}
+        ${adaptor_accessibility_tizen_wayland_src_files}
+        ${adaptor_accessibility_tizen_mobile_src_files}
+        ${adaptor_adaptor_common_src_files}
+        ${adaptor_adaptor_tizen_wayland_src_files}
+        ${adaptor_clipboard_common_src_files}
+        ${adaptor_clipboard_tizen_wayland_src_files}
+        ${adaptor_framework_generic_src_files}
+        ${devel_api_src_files}
+        ${adaptor_devel_api_text_abstraction_src_files}
+        ${adaptor_graphics_common_src_files}
+        ${adaptor_graphics_gles_src_files}
+        ${adaptor_graphics_tizen_src_files}
+        ${adaptor_haptics_common_src_files}
+        ${adaptor_imaging_common_src_files}
+        ${adaptor_imaging_tizen_src_files}
+        ${adaptor_input_common_src_files}
+        ${adaptor_input_tizen_wayland_src_files}
+        ${adaptor_integration_api_src_files}
+        ${adaptor_legacy_common_src_files}
+        ${adaptor_network_common_src_files}
+        ${adaptor_public_api_src_files}
+        ${adaptor_sensor_common_src_files}
+        ${adaptor_sensor_tizen_src_files}
+        ${adaptor_styling_common_src_files}
+        ${adaptor_system_common_src_files}
+        ${adaptor_system_linux_src_files}
+        ${adaptor_system_tizen_wayland_src_files}
+        ${adaptor_text_common_src_files}
+        ${adaptor_resampler_src_files}
+        ${adaptor_vector_animation_common_src_files}
+        ${adaptor_video_common_src_files}
+        ${adaptor_web_engine_common_src_files}
+        ${adaptor_window_system_common_src_files}
+        ${adaptor_window_system_tizen_src_files}
+        ${adaptor_window_system_tizen_wayland_src_files}
+        ${adaptor_trace_common_src_files}
+        ${adaptor_thread_common_src_files}
+        ${devel_api_text_abstraction_src_files}
+        ${static_libraries_glyphy_src_files}
+        ${static_libraries_libunibreak_src_files}
+)
+IF( enable_ecore_wayland2 )
+    SET( SOURCES ${SOURCES}
+         ${adaptor_window_system_ecore_wl2_src_files}
+         )
+ELSE()
+    SET( SOURCES ${SOURCES}
+         ${adaptor_window_system_ecore_wl_src_files}
+         )
+ENDIF()
+
+IF( ENABLE_NETWORK_LOGGING )
+    SET( SOURCES ${SOURCES}
+          ${adaptor_performance_logging_src_files}
+    )
+ENDIF()
+
+IF( ENABLE_TRACE )
+    SET( SOURCES ${SOURCES}
+        ${adaptor_trace_tizen_src_files}
+      )
+ENDIF()
+
diff --git a/build/tizen/profiles/tizen-post-install.cmake b/build/tizen/profiles/tizen-post-install.cmake
new file mode 100644 (file)
index 0000000..ba59acb
--- /dev/null
@@ -0,0 +1,2 @@
+# This file runs stuff
+
diff --git a/build/tizen/profiles/tv-profile.cmake b/build/tizen/profiles/tv-profile.cmake
new file mode 100644 (file)
index 0000000..fbaa533
--- /dev/null
@@ -0,0 +1,67 @@
+# PROFILE: IVI
+
+# Set the sources
+SET( SOURCES
+    ${adaptor_accessibility_common_src_files}
+    ${adaptor_accessibility_tizen_wayland_src_files}
+    ${adaptor_accessibility_tizen_tv_src_files}
+    ${adaptor_adaptor_common_src_files}
+    ${adaptor_adaptor_tizen_wayland_src_files}
+    ${adaptor_clipboard_common_src_files}
+    ${adaptor_clipboard_tizen_wayland_src_files}
+    ${adaptor_framework_generic_src_files}
+    ${devel_api_src_files}
+    ${adaptor_devel_api_text_abstraction_src_files}
+    ${adaptor_graphics_common_src_files}
+    ${adaptor_graphics_gles_src_files}
+    ${adaptor_graphics_tizen_src_files}
+    ${adaptor_haptics_common_src_files}
+    ${adaptor_imaging_common_src_files}
+    ${adaptor_imaging_tizen_src_files}
+    ${adaptor_input_common_src_files}
+    ${adaptor_input_tizen_wayland_src_files}
+    ${adaptor_integration_api_src_files}
+    ${adaptor_legacy_common_src_files}
+    ${adaptor_network_common_src_files}
+    ${adaptor_public_api_src_files}
+    ${adaptor_sensor_common_src_files}
+    ${adaptor_sensor_tizen_src_files}
+    ${adaptor_styling_common_src_files}
+    ${adaptor_system_common_src_files}
+    ${adaptor_system_linux_src_files}
+    ${adaptor_system_tizen_wayland_src_files}
+    ${adaptor_text_common_src_files}
+    ${adaptor_resampler_src_files}
+    ${adaptor_vector_animation_common_src_files}
+    ${adaptor_video_common_src_files}
+    ${adaptor_web_engine_common_src_files}
+    ${adaptor_window_system_common_src_files}
+    ${adaptor_window_system_tizen_src_files}
+    ${adaptor_window_system_tizen_wayland_src_files}
+    ${adaptor_trace_common_src_files}
+    ${adaptor_thread_common_src_files}
+    ${devel_api_text_abstraction_src_files}
+    ${static_libraries_glyphy_src_files}
+    ${static_libraries_libunibreak_src_files}
+     )
+IF( enable_ecore_wayland2 )
+    SET( SOURCES ${SOURCES}
+         ${adaptor_window_system_ecore_wl2_src_files}
+         )
+ELSE()
+    SET( SOURCES ${SOURCES}
+         ${adaptor_window_system_ecore_wl_src_files}
+         )
+ENDIF()
+
+IF( ENABLE_NETWORK_LOGGING )
+    SET( SOURCES ${SOURCES}
+         ${adaptor_performance_logging_src_files}
+         )
+ENDIF()
+
+IF( ENABLE_TRACE )
+    SET( SOURCES ${SOURCES}
+         ${adaptor_trace_tizen_src_files}
+         )
+ENDIF()
diff --git a/build/tizen/profiles/ubuntu-profile.cmake b/build/tizen/profiles/ubuntu-profile.cmake
new file mode 100644 (file)
index 0000000..27cc6ad
--- /dev/null
@@ -0,0 +1,143 @@
+# PROFILE: UBUNTU
+
+# Set the sources
+SET( SOURCES
+        ${adaptor_accessibility_common_src_files}
+        ${adaptor_accessibility_ubuntu_src_files}
+        ${adaptor_adaptor_common_src_files}
+        ${adaptor_adaptor_ubuntu_src_files}
+        ${adaptor_clipboard_common_src_files}
+        ${adaptor_clipboard_ubuntu_x11_src_files}
+        ${adaptor_framework_generic_src_files}
+        ${devel_api_src_files}
+        ${adaptor_devel_api_text_abstraction_src_files}
+        ${adaptor_graphics_common_src_files}
+        ${adaptor_graphics_gles_src_files}
+        ${adaptor_graphics_ubuntu_src_files}
+        ${adaptor_haptics_common_src_files}
+        ${adaptor_imaging_common_src_files}
+        ${adaptor_imaging_ubuntu_x11_src_files}
+        ${adaptor_input_common_src_files}
+        ${adaptor_input_ubuntu_x11_src_files}
+        ${adaptor_integration_api_src_files}
+        ${adaptor_legacy_common_src_files}
+        ${adaptor_network_common_src_files}
+        ${adaptor_public_api_src_files}
+        ${adaptor_sensor_common_src_files}
+        ${adaptor_sensor_ubuntu_src_files}
+        ${adaptor_styling_common_src_files}
+        ${adaptor_system_common_src_files}
+        ${adaptor_system_linux_src_files}
+        ${adaptor_system_ubuntu_x11_src_files}
+        ${adaptor_text_common_src_files}
+        ${adaptor_text_ubuntu_src_files}
+        ${adaptor_resampler_src_files}
+        ${adaptor_vector_animation_common_src_files}
+        ${adaptor_video_common_src_files}
+        ${adaptor_web_engine_common_src_files}
+        ${adaptor_window_system_common_src_files}
+        ${adaptor_trace_common_src_files}
+        ${adaptor_thread_common_src_files}
+        ${adaptor_window_system_ubuntu_x11_src_files}
+        ${devel_api_text_abstraction_src_files}
+        ${static_libraries_glyphy_src_files}
+        ${static_libraries_libunibreak_src_files}
+)
+
+IF( ECORE_WAYLAND2 )
+    SET( SOURCES ${SOURCES}
+      ${adaptor_window_system_ecore_wl2_src_files}
+    )
+ENDIF()
+
+IF( ENABLE_NETWORK_LOGGING )
+    SET( SOURCES ${SOURCES}
+          ${adaptor_performance_logging_src_files}
+    )
+ENDIF()
+
+IF( ENABLE_TRACE )
+    SET( SOURCES ${SOURCES}
+        ${adaptor_trace_generic_src_files}
+      )
+ENDIF()
+
+# Set the header directories
+SET( PROFILE_INCLUDE_DIRECTORIES
+        ${ECORE_INCLUDE_DIRS}
+        ${EXIF_INCLUDE_DIRS}
+        ${FREETYPE_INCLUDE_DIRS}
+        ${FREETYPE_BITMAP_SUPPORT}
+        ${FONTCONFIG_INCLUDE_DIRS}
+        ${PNG_INCLUDE_DIRS}
+        ${LIBEXIF_INCLUDE_DIRS}
+        ${LIBDRM_INCLUDE_DIRS}
+        ${LIBCURL_INCLUDE_DIRS}
+        ${LIBCRYPTO_INCLUDE_DIRS}
+        ${HARFBUZZ_INCLUDE_DIRS}
+        ${FRIBIDI_INCLUDE_DIRS}
+        ${CAIRO_INCLUDE_DIRS}
+        ${EVAS_INCLUDE_DIRS}
+        ${ECORE_IPC_INCLUDE_DIRS}
+        ${ECORE_IMF_INCLUDE_DIRS}
+        ${ECORE_IMF_INCLUDE_DIRS}
+        ${CAPI_APPFW_APPLICATION_INCLUDE_DIRS}
+        ${ELEMENTARY_INCLUDE_DIRS}
+        ${ECORE_X_INCLUDE_DIRS}
+        ${X11_INCLUDE_DIRS}
+        ${DALICORE_INCLUDE_DIRS}
+        )
+
+# Set compile options
+ADD_COMPILE_OPTIONS(
+  ${DALI_ADAPTOR_CFLAGS}
+  ${DALICORE_CFLAGS}
+  ${OPENGLES20_CFLAGS}
+  ${FREETYPE_CFLAGS}
+  ${FONTCONFIG_CFLAGS}
+  ${CAIRO_CFLAGS}
+  ${PNG_CFLAGS}
+  ${DLOG_CFLAGS}
+  ${VCONF_CFLAGS}
+  ${EXIF_CFLAGS}
+  ${MMFSOUND_CFLAGS}
+  ${TTS_CFLAGS}
+  ${CAPI_SYSTEM_SENSOR_CFLAGS}
+  ${LIBDRM_CFLAGS}
+  ${LIBEXIF_CFLAGS}
+  ${LIBCURL_CFLAGS}
+  ${LIBCRYPTO_CFLAGS}
+  ${UTILX_CFLAGS}
+)
+
+# Set the linker flags
+SET(REQUIRED_LIBS ${ECORE_LDFLAGS}
+  ${EXIF_LDFLAGS}
+  ${FREETYPE_LDFLAGS}
+  ${FREETYPE_BITMAP_SUPPORT}
+  ${FONTCONFIG_LDFLAGS}
+  ${PNG_LDFLAGS}
+  ${LIBEXIF_LDFLAGS}
+  ${LIBDRM_LDFLAGS}
+  ${LIBCURL_LDFLAGS}
+  ${LIBCRYPTO_LDFLAGS}
+  ${HARFBUZZ_LDFLAGS}
+  ${FRIBIDI_LDFLAGS}
+  ${CAIRO_LDFLAGS}
+  ${EVAS_LDFLAGS}
+  ${ECORE_IPC_LDFLAGS}
+  ${ECORE_IMF_LDFLAGS}
+  ${ECORE_IMF_LDFLAGS}
+  ${CAPI_APPFW_APPLICATION_LDFLAGS}
+  ${ELEMENTARY_LDFLAGS}
+  ${ECORE_X_LDFLAGS}
+  ${X11_LDFLAGS}
+  ${DALICORE_LDFLAGS}
+  ${OPENGLES20_LDFLAGS}
+  ${EGL_LDFLAGS}
+  ${EFL_ASSIST_LIBS}
+  -lgif
+  -lpthread
+  -lturbojpeg
+  -ljpeg
+)
diff --git a/build/tizen/profiles/wearable-profile.cmake b/build/tizen/profiles/wearable-profile.cmake
new file mode 100644 (file)
index 0000000..8488967
--- /dev/null
@@ -0,0 +1,68 @@
+# PROFILE: WEARABLE
+
+# Set the sources
+SET( SOURCES
+    ${adaptor_accessibility_common_src_files}
+    ${adaptor_accessibility_tizen_wayland_src_files}
+    ${adaptor_accessibility_tizen_wearable_src_files}
+    ${adaptor_adaptor_common_src_files}
+    ${adaptor_adaptor_tizen_wayland_src_files}
+    ${adaptor_adaptor_tizen_wearable_src_files}
+    ${adaptor_clipboard_common_src_files}
+    ${adaptor_clipboard_tizen_wayland_src_files}
+    ${adaptor_framework_generic_src_files}
+    ${devel_api_src_files}
+    ${adaptor_devel_api_text_abstraction_src_files}
+    ${adaptor_graphics_common_src_files}
+    ${adaptor_graphics_gles_src_files}
+    ${adaptor_graphics_tizen_src_files}
+    ${adaptor_haptics_common_src_files}
+    ${adaptor_imaging_common_src_files}
+    ${adaptor_imaging_tizen_src_files}
+    ${adaptor_input_common_src_files}
+    ${adaptor_input_tizen_wayland_src_files}
+    ${adaptor_integration_api_src_files}
+    ${adaptor_legacy_common_src_files}
+    ${adaptor_network_common_src_files}
+    ${adaptor_public_api_src_files}
+    ${adaptor_sensor_common_src_files}
+    ${adaptor_sensor_tizen_src_files}
+    ${adaptor_styling_common_src_files}
+    ${adaptor_system_common_src_files}
+    ${adaptor_system_linux_src_files}
+    ${adaptor_system_tizen_wearable_src_files}
+    ${adaptor_text_common_src_files}
+    ${adaptor_resampler_src_files}
+    ${adaptor_vector_animation_common_src_files}
+    ${adaptor_video_common_src_files}
+    ${adaptor_web_engine_common_src_files}
+    ${adaptor_window_system_common_src_files}
+    ${adaptor_window_system_tizen_src_files}
+    ${adaptor_window_system_tizen_wayland_src_files}
+    ${adaptor_trace_common_src_files}
+    ${adaptor_thread_common_src_files}
+    ${devel_api_text_abstraction_src_files}
+    ${static_libraries_glyphy_src_files}
+    ${static_libraries_libunibreak_src_files}
+)
+IF( enable_ecore_wayland2 )
+    SET( SOURCES ${SOURCES}
+         ${adaptor_window_system_ecore_wl2_src_files}
+         )
+ELSE()
+    SET( SOURCES ${SOURCES}
+         ${adaptor_window_system_ecore_wl_src_files}
+         )
+ENDIF()
+
+IF( ENABLE_NETWORK_LOGGING )
+    SET( SOURCES ${SOURCES}
+          ${adaptor_performance_logging_src_files}
+    )
+ENDIF()
+
+IF( ENABLE_TRACE )
+    SET( SOURCES ${SOURCES}
+        ${adaptor_trace_tizen_src_files}
+      )
+ENDIF()
diff --git a/build/tizen/profiles/windows-profile.cmake b/build/tizen/profiles/windows-profile.cmake
new file mode 100644 (file)
index 0000000..b190e23
--- /dev/null
@@ -0,0 +1,84 @@
+# PROFILE: WINDOWS
+
+# Set the sources
+SET( SOURCES
+        ${adaptor_accessibility_common_src_files}
+        ${adaptor_accessibility_windows_src_files}
+        ${adaptor_adaptor_common_src_files}
+        ${adaptor_clipboard_common_src_files}
+        ${adaptor_framework_generic_src_files}
+        ${devel_api_src_files}
+        ${adaptor_devel_api_text_abstraction_src_files}
+        ${adaptor_graphics_common_src_files}
+        ${adaptor_graphics_gles_src_files}
+        ${adaptor_haptics_common_src_files}
+        ${adaptor_imaging_common_src_files}
+        ${adaptor_input_common_src_files}
+        ${adaptor_integration_api_src_files}
+        ${adaptor_legacy_common_src_files}
+        ${adaptor_network_common_src_files}
+        ${adaptor_public_api_src_files}
+        ${adaptor_sensor_common_src_files}
+        ${adaptor_styling_common_src_files}
+        ${adaptor_system_common_src_files}
+        ${adaptor_system_windows_src_files}
+        ${adaptor_text_common_src_files}
+        ${adaptor_resampler_src_files}
+        ${adaptor_vector_animation_common_src_files}
+        ${adaptor_video_common_src_files}
+        ${adaptor_web_engine_common_src_files}
+        ${adaptor_window_system_common_src_files}
+        ${adaptor_trace_common_src_files}
+        ${adaptor_thread_common_src_files}
+        ${devel_api_text_abstraction_src_files}
+        ${static_libraries_glyphy_src_files}
+        ${static_libraries_libunibreak_src_files}
+        ${adaptor_windows_platform_src_files}
+        ${adaptor_adaptor_windows_src_files}
+        ${adaptor_window_system_windows_src_files}
+        ${adaptor_graphics_windows_src_files}
+        ${adaptor_input_windows_src_files}
+        ${adaptor_clipboard_windows_src_files}
+        ${adaptor_imaging_windows_src_files}
+)
+
+# Builds the c files as c++
+SET_SOURCE_FILES_PROPERTIES( ${static_libraries_libunibreak_src_files} PROPERTIES LANGUAGE CXX )
+
+FIND_PACKAGE( pthreads REQUIRED )
+FIND_PACKAGE( curl REQUIRED )
+FIND_LIBRARY( GETOPT_LIBRARY NAMES getopt )
+FIND_LIBRARY( EXIF_LIBRARY NAMES libexif )
+
+FIND_PACKAGE( png REQUIRED )
+FIND_PACKAGE( gif REQUIRED )
+FIND_PACKAGE( jpeg REQUIRED )
+FIND_LIBRARY( TURBO_JPEG_LIBRARY NAMES turbojpeg )
+
+FIND_PACKAGE( unofficial-fontconfig REQUIRED )
+FIND_PACKAGE( freetype REQUIRED )
+FIND_PACKAGE( harfbuzz REQUIRED )
+FIND_LIBRARY( FRIBIDI_LIBRARY NAMES fribidi )
+
+FIND_PACKAGE( unofficial-angle REQUIRED )
+FIND_PACKAGE( unofficial-cairo REQUIRED )
+
+# Set the linker flags
+SET( REQUIRED_LIBS
+        PThreads4W::PThreads4W
+        CURL::libcurl
+        ${GETOPT_LIBRARY}
+        ${EXIF_LIBRARY}
+        ${PNG_LIBRARIES}
+        ${GIF_LIBRARIES}
+        JPEG::JPEG
+        ${TURBO_JPEG_LIBRARY}
+        unofficial::fontconfig::fontconfig
+        Freetype::Freetype
+        harfbuzz::harfbuzz
+        ${FRIBIDI_LIBRARY}
+        unofficial::angle::libEGL
+        unofficial::angle::libGLESv2
+        unofficial::cairo::cairo
+        dali-core::dali-core
+)
diff --git a/build/tizen/rename-cov-data b/build/tizen/rename-cov-data
new file mode 100755 (executable)
index 0000000..a29f21b
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/bash
+COVERAGE_DIR=.cov
+[[ -d ${COVERAGE_DIR} ]] || mkdir ${COVERAGE_DIR}
+rm -f ${COVERAGE_DIR}/*
+
+COVERAGE_EXTENSIONS="
+  gcda
+  gcno
+"
+
+SOURCE_EXTENSIONS="
+ c
+ cpp
+"
+
+for covExt in $COVERAGE_EXTENSIONS
+do
+  # Move into .cov directory
+  for file in `find -name *.${covExt}`
+  do
+    cp $file ${COVERAGE_DIR}
+  done
+
+  # strip source extensions liks .cpp as that's the format expected by patch-coverage.pl
+  for srcExt in $SOURCE_EXTENSIONS
+  do
+    for file in `find ${COVERAGE_DIR} -name *.${srcExt}.${covExt}`
+    do
+      name=`echo $file | sed "s/.${srcExt}.${covExt}//g"`
+      mv $file $name.${covExt}
+    done
+  done
+
+done
diff --git a/build/tizen/system-cache-path.in b/build/tizen/system-cache-path.in
new file mode 100644 (file)
index 0000000..b1bf5d9
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2019 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 <cstdlib>
+
+#if ANDROID
+#include <dali/integration-api/adaptor-framework/android/android-framework.h>
+#endif
+
+std::string GetSystemCachePath()
+{
+#if ANDROID
+  return Dali::Integration::AndroidFramework::Get().GetInternalDataPath() + "/dali_common_caches/";
+#else
+  return std::string( "@cachePath@/.cache/dali_common_caches/" );
+#endif
+}
diff --git a/dali-adaptor.manifest b/dali-adaptor.manifest
new file mode 100644 (file)
index 0000000..97e8c31
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_"/>
+       </request>
+</manifest>
diff --git a/dali/dali.h b/dali/dali.h
new file mode 100644 (file)
index 0000000..dd85954
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef DALI_H
+#define DALI_H
+
+/*
+ * Copyright (c) 2019 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/dali-core.h>
+
+// Application / UI Framework adaption
+#include <dali/public-api/adaptor-framework/application.h>
+#include <dali/public-api/adaptor-framework/device-status.h>
+#include <dali/public-api/adaptor-framework/input-method.h>
+#include <dali/public-api/adaptor-framework/key.h>
+#include <dali/public-api/adaptor-framework/key-grab.h>
+#include <dali/public-api/adaptor-framework/timer.h>
+#include <dali/public-api/adaptor-framework/tts-player.h>
+#include <dali/public-api/adaptor-framework/native-image-source.h>
+#include <dali/public-api/adaptor-framework/widget-application.h>
+#include <dali/public-api/adaptor-framework/widget-impl.h>
+#include <dali/public-api/adaptor-framework/widget.h>
+#include <dali/public-api/dali-adaptor-version.h>
+
+#endif //DALI_H
diff --git a/dali/devel-api/adaptor-framework/accessibility-action-handler.h b/dali/devel-api/adaptor-framework/accessibility-action-handler.h
new file mode 100644 (file)
index 0000000..a23620d
--- /dev/null
@@ -0,0 +1,212 @@
+#ifndef DALI_ACCESSIBILITY_ACTION_HANDLER_H
+#define DALI_ACCESSIBILITY_ACTION_HANDLER_H
+
+/*
+ * Copyright (c) 2019 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-adaptor-common.h>
+#include <dali/public-api/events/touch-event.h>
+
+namespace Dali
+{
+
+/**
+ * AccessibilityActionHandler is an abstract interface, used by Dali to handle accessibility actions
+ * passed by the accessibility manager.
+ */
+class AccessibilityActionHandler
+{
+public:
+
+  /**
+   * Change the accessibility status when Accessibility feature(screen-reader) turned on or off.
+   * @return whether the status is changed or not.
+   */
+  virtual bool ChangeAccessibilityStatus() = 0;
+
+  /**
+   * Clear the accessibility focus from the current focused actor.
+   * @return whether the focus is cleared or not.
+   */
+  virtual bool ClearAccessibilityFocus() = 0;
+
+  /**
+   * Perform the accessibility action associated with a scroll event.
+   * @param touchEvent The touch point (and time) of the event.
+   * @return whether the focus is cleared or not.
+   */
+  virtual bool AccessibilityActionScroll( Dali::TouchEvent& touchEvent ) = 0;
+
+  /**
+   * Perform the accessibility action to move focus to the previous focusable actor (by one finger flick up).
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionPrevious(bool allowEndFeedback) = 0;
+
+  /**
+   * Perform the accessibility action to move focus to the next focusable actor (by one finger flick down).
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionNext(bool allowEndFeedback) = 0;
+
+  /**
+   * Perform the accessibility action to move focus to the previous focusable actor (by one finger flick left).
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionReadPrevious(bool allowEndFeedback) = 0;
+
+  /**
+   * Perform the accessibility action to move focus to the next focusable actor (by one finger flick right).
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionReadNext(bool allowEndFeedback) = 0;
+
+  /**
+   * Perform the accessibility action to focus and read the actor (by one finger tap or move).
+   * @param allowReadAgain true if the action read again the same object (i.e. read action)
+   *                       false if the action just read when the focus object is changed (i.e. over action)
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionRead(bool allowReadAgain) = 0;
+
+  /**
+   * Perform the accessibility action to activate the current focused actor (by one finger double tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionActivate() = 0;
+
+  /**
+   * Perform the accessibility action to change the value when the current focused actor is a slider
+   * (by double finger down and move up and right).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionUp() = 0;
+
+  /**
+   * Perform the accessibility action to change the value when the current focused actor is a slider
+   * (by double finger down and move down and left).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionDown() = 0;
+
+  /**
+   * Perform the accessibility action to navigate back (by two fingers circle draw).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionBack() = 0;
+
+  /**
+   * Perform the accessibility action to scroll up the list and focus on the first item on the list
+   * after the scrolling and read the item (by two finger swipe up).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionScrollUp() = 0;
+
+  /**
+   * Perform the accessibility action to scroll down the list and focus on the first item on the list
+   * after the scrolling and read the item (by two finger swipe down).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionScrollDown() = 0;
+
+  /**
+   * Perform the accessibility action to scroll left to the previous page (by two finger swipe left).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionPageLeft() = 0;
+
+  /**
+   * Perform the accessibility action to scroll right to the next page (by two finger swipe right).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionPageRight() = 0;
+
+  /**
+   * Perform the accessibility action to scroll up to the previous page (by one finger swipe left and right).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionPageUp() = 0;
+
+  /**
+   * Perform the accessibility action to scroll down to the next page (by one finger swipe right and left).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionPageDown() = 0;
+
+  /**
+   * Perform the accessibility action to move the focus to the first item on the screen
+   * (by one finger swipe up and down).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionMoveToFirst() = 0;
+
+  /**
+   * Perform the accessibility action to move the focus to the last item on the screen
+   * (by one finger swipe down and up).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionMoveToLast() = 0;
+
+  /**
+   * Perform the accessibility action to move the focus to the first item on the top
+   * and read from the top item continuously (by three fingers single tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionReadFromTop() = 0;
+
+  /**
+   * Perform the accessibility action to move the focus to and read from the next item
+   * continuously (by three fingers double tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionReadFromNext() = 0;
+
+  /**
+   * Perform the accessibility action to move the focus to do the zooming (by one finger triple tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionZoom() = 0;
+
+  /**
+   * Perform the accessibility action to pause/resume the current read out (by two fingers single tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionReadPauseResume() = 0;
+
+  /**
+   * Perform the accessibility action to start/stop the current action (by two fingers double tap).
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionStartStop() = 0;
+
+  /**
+   * Perform the accessibility action to mouse move (by one finger tap & hold and move).
+   * @param touchEvent touch event structure
+   * @return whether the accessibility action is performed or not.
+   */
+  virtual bool AccessibilityActionTouch(const Dali::TouchEvent& touchEvent) = 0;
+
+}; // class AccessibilityActionHandler
+
+} // namespace Dali
+
+#endif // DALI_ACCESSIBILITY_ACTION_HANDLER_H
diff --git a/dali/devel-api/adaptor-framework/accessibility-adaptor.cpp b/dali/devel-api/adaptor-framework/accessibility-adaptor.cpp
new file mode 100644 (file)
index 0000000..f635aba
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/accessibility-adaptor.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/accessibility/common/accessibility-adaptor-impl.h>
+
+namespace Dali
+{
+
+AccessibilityAdaptor::AccessibilityAdaptor()
+{
+}
+
+AccessibilityAdaptor AccessibilityAdaptor::Get()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::Get();
+}
+
+AccessibilityAdaptor::~AccessibilityAdaptor()
+{
+}
+
+Vector2 AccessibilityAdaptor::GetReadPosition() const
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).GetReadPosition();
+}
+
+bool AccessibilityAdaptor::IsEnabled() const
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).IsEnabled();
+}
+
+void AccessibilityAdaptor::SetActionHandler(AccessibilityActionHandler& handler)
+{
+  Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).SetActionHandler(handler);
+}
+
+void AccessibilityAdaptor::SetGestureHandler(AccessibilityGestureHandler& handler)
+{
+  Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).SetGestureHandler(handler);
+}
+
+bool AccessibilityAdaptor::HandleActionNextEvent(bool allowEndFeedback)
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionNextEvent(allowEndFeedback);
+}
+
+bool AccessibilityAdaptor::HandleActionPreviousEvent(bool allowEndFeedback)
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionPreviousEvent(allowEndFeedback);
+}
+
+bool AccessibilityAdaptor::HandleActionActivateEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionActivateEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionReadEvent(unsigned int x, unsigned int y,  bool allowReadAgain)
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadEvent(x, y, allowReadAgain);
+}
+
+bool AccessibilityAdaptor::HandleActionReadNextEvent(bool allowEndFeedback)
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadNextEvent(allowEndFeedback);
+}
+
+bool AccessibilityAdaptor::HandleActionReadPreviousEvent(bool allowEndFeedback)
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadPreviousEvent(allowEndFeedback);
+}
+
+bool AccessibilityAdaptor::HandleActionUpEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionUpEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionDownEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionDownEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionClearFocusEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionClearFocusEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionScrollEvent(const TouchPoint& point, unsigned long timeStamp)
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionScrollEvent(point, timeStamp);
+}
+
+bool AccessibilityAdaptor::HandleActionTouchEvent(const TouchPoint& point, unsigned long timeStamp)
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionTouchEvent(point, timeStamp);
+}
+
+bool AccessibilityAdaptor::HandleActionBackEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionBackEvent();
+}
+
+void AccessibilityAdaptor::HandleActionEnableEvent()
+{
+  Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionEnableEvent();
+}
+
+void AccessibilityAdaptor::HandleActionDisableEvent()
+{
+  Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionDisableEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionScrollUpEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionScrollUpEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionScrollDownEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionScrollDownEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionPageLeftEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionPageLeftEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionPageRightEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionPageRightEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionPageUpEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionPageUpEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionPageDownEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionPageDownEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionMoveToFirstEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionMoveToFirstEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionMoveToLastEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionMoveToLastEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionReadFromTopEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadFromTopEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionReadFromNextEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadFromNextEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionZoomEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionZoomEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionReadPauseResumeEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionReadPauseResumeEvent();
+}
+
+bool AccessibilityAdaptor::HandleActionStartStopEvent()
+{
+  return Internal::Adaptor::AccessibilityAdaptor::GetImplementation(*this).HandleActionStartStopEvent();
+}
+
+AccessibilityAdaptor::AccessibilityAdaptor( Internal::Adaptor::AccessibilityAdaptor& manager )
+: BaseHandle( &manager )
+{
+}
+
+AccessibilityAdaptor::AccessibilityAdaptor( Internal::Adaptor::AccessibilityAdaptor* manager )
+: BaseHandle( manager )
+{
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/accessibility-adaptor.h b/dali/devel-api/adaptor-framework/accessibility-adaptor.h
new file mode 100755 (executable)
index 0000000..251f591
--- /dev/null
@@ -0,0 +1,341 @@
+#ifndef DALI_ACCESSIBILITY_ADAPTOR_H
+#define DALI_ACCESSIBILITY_ADAPTOR_H
+
+/*
+ * Copyright (c) 2019 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/events/touch-event.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class AccessibilityAdaptor;
+}
+}
+
+class AccessibilityActionHandler;
+class AccessibilityGestureHandler;
+class TouchPoint;
+
+/**
+ * @brief The AccessibilityAdaptor provides communication to the accessibility manager interface (implemented in toolkit).
+ *
+ */
+class DALI_ADAPTOR_API AccessibilityAdaptor : public BaseHandle
+{
+public:
+
+  /**
+   * @brief Create an uninitialized handle.
+   *
+   * This can be initialized by calling getting the adaptor from Dali::Adaptor.
+   */
+  AccessibilityAdaptor();
+
+  /**
+   * @brief Retrieve a handle to the AccessibilityAdaptor.
+   *
+   * @return A handle to the AccessibilityAdaptor.
+   */
+  static AccessibilityAdaptor Get();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~AccessibilityAdaptor();
+
+  /**
+   * @brief Returns the current position of the read action.
+   * @return The current event position.
+   */
+  Vector2 GetReadPosition() const;
+
+  /**
+   * @brief Query whether the accessibility(screen-reader) is enabled.
+   *
+   * The accessibility will be enabled by system setting.
+   * @return True if the accessibility(screen-reader) is enabled.
+   */
+  bool IsEnabled() const;
+
+  /**
+   * @brief Set the handler to handle accessibility actions.
+   *
+   * @param[in] handler The Accessibility action handler.
+   * @note Handlers should remove themselves when they are destroyed.
+   */
+  void SetActionHandler(AccessibilityActionHandler& handler);
+
+  /**
+   * @brief Set the handler to handle accessibility gestures.
+   *
+   * @param[in] handler The Accessibility gesture handler.
+   * @note Handlers should remove themselves when they are destroyed.
+   */
+  void SetGestureHandler(AccessibilityGestureHandler& handler);
+
+  /**
+   * @brief Handle the accessibility action to move focus to the next focusable actor
+   * (by one finger flick down).
+   *
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionNextEvent(bool allowEndFeedback = true);
+
+  /**
+   * @brief Handle the accessibility action to move focus to the previous focusable actor
+   * (by one finger flick up).
+   *
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionPreviousEvent(bool allowEndFeedback = true);
+
+  /**
+   * @brief Handle the accessibility action to activate the current focused actor (by one
+   * finger )
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionActivateEvent();
+
+  /**
+   * @brief Handle the accessibility action to focus and read the actor (by one finger tap or move).
+   *
+   * @param x x position of event
+   * @param y y position of event
+   * @param allowReadAgain true if the action read again the same object (i.e. read action)
+   *                       false if the action just read when the focus object is changed (i.e. over action)
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain);
+
+  /**
+   * @brief Handle the accessibility action to move focus to the next focusable actor
+   * (by one finger flick right).
+   *
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the end
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionReadNextEvent(bool allowEndFeedback = true);
+
+  /**
+   * @brief Handle the accessibility action to move focus to the previous focusable actor
+   * (by one finger flick up).
+   *
+   * @param allowEndFeedback true if end of list feedback should be played when the focus is alread reached to the front
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionReadPreviousEvent(bool allowEndFeedback = true);
+
+  /**
+   * @brief Handle the accessibility action to change the value when the current focused
+   * actor is a slider (by double finger down and move up and right).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionUpEvent();
+
+  /**
+   * @brief Handle the accessibility action to change the value when the current focused
+   * actor is a slider (by double finger down and move down and left).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionDownEvent();
+
+  /**
+   * @brief Handle the accessibility action to clear the focus from the current focused
+   * actor if any, so that no actor is focused in the focus chain.
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionClearFocusEvent();
+
+  /**
+   * @brief Handle the accessibility action to scroll when there is a scroller on the touched position
+   * (by 2 finger touch & move, 2 finger flick).
+   *
+   * @param[in]  point      The touch point information.
+   * @param[in]  timeStamp  The time the touch occurred.
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionScrollEvent(const TouchPoint& point, unsigned long timeStamp);
+
+  /**
+   * @brief Handle the accessibility action to move for the current focused actor
+   * (by 1 finger tap & hold and move).
+   *
+   * @param[in]  point      The touch point information.
+   * @param[in]  timeStamp  The time the touch occurred.
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionTouchEvent(const TouchPoint& point, unsigned long timeStamp);
+
+  /**
+   * @brief Handle the accessibility action to navigate back (by two fingers circle draw).
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionBackEvent();
+
+  /**
+   * @brief Handle the accessibility action to enable the feature.
+   */
+  void HandleActionEnableEvent();
+
+  /**
+   * @brief Handle the accessibility action to disable the feature.
+   */
+  void HandleActionDisableEvent();
+
+  /**
+   * @brief Handle the accessibility action to scroll up the list and focus on
+   * the first item on the list after the scrolling and read the item
+   * (by two finger swipe up).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionScrollUpEvent();
+
+  /**
+   * @brief Handle the accessibility action to scroll down the list and focus on
+   * the first item on the list after the scrolling and read the item
+   * (by two finger swipe down).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionScrollDownEvent();
+
+  /**
+   * @brief Handle the accessibility action to scroll left to the previous page
+   * (by two finger swipe left).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionPageLeftEvent();
+
+  /**
+   * @brief Handle the accessibility action to scroll right to the next page
+   * (by two finger swipe right).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionPageRightEvent();
+
+  /**
+   * @brief Handle the accessibility action to scroll up to the previous page
+   * (by one finger swipe left and right).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionPageUpEvent();
+
+  /**
+   * @brief Handle the accessibility action to scroll down to the next page
+   * (by one finger swipe right and left).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionPageDownEvent();
+
+  /**
+   * @brief Handle the accessibility action to move the focus to the first item on the screen
+   * (by one finger swipe up and down).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionMoveToFirstEvent();
+
+  /**
+   * @brief Handle the accessibility action to move the focus to the last item on the screen
+   * (by one finger swipe down and up).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionMoveToLastEvent();
+
+  /**
+   * @brief Handle the accessibility action to move the focus to the first item on the top
+   * and read from the top item continuously (by three fingers single tap).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionReadFromTopEvent();
+
+  /**
+   * @brief Handle the accessibility action to move focus to and read from the next focusable
+   * actor continuously (by three fingers double tap).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionReadFromNextEvent();
+
+  /**
+   * @brief Handle the accessibility action to do the zooming
+   * (by one finger triple tap).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionZoomEvent();
+
+  /**
+   * @brief Handle the accessibility action to pause/resume the current speech
+   * (by two fingers single tap).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionReadPauseResumeEvent();
+
+  /**
+   * @brief Handle the accessibility action to start/stop the current action
+   * (by two fingers double tap).
+   *
+   * @return Whether the action is performed successfully or not.
+   */
+  bool HandleActionStartStopEvent();
+
+public: // Not intended for application developers
+
+  /**
+   * @brief Creates a handle using the Adaptor::Internal implementation.
+   *
+   * @param[in] adaptor The AccessibilityAdaptor implementation.
+   */
+  DALI_INTERNAL AccessibilityAdaptor( Internal::Adaptor::AccessibilityAdaptor& adaptor );
+
+  /**
+   * @brief This constructor is used by AccessibilityAdaptor::Get().
+   *
+   * @param[in] adaptor A pointer to the accessibility adaptor.
+   */
+  explicit DALI_INTERNAL AccessibilityAdaptor( Internal::Adaptor::AccessibilityAdaptor* adaptor );
+};
+
+} // namespace Dali
+
+#endif // DALI_ACCESSIBILITY_ADAPTOR_H
diff --git a/dali/devel-api/adaptor-framework/accessibility-gesture-event.h b/dali/devel-api/adaptor-framework/accessibility-gesture-event.h
new file mode 100644 (file)
index 0000000..30a54f2
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef DALI_INTEGRAION_ACCESSIBILITY_GESTURE_STRUCTS_H
+#define DALI_INTEGRAION_ACCESSIBILITY_GESTURE_STRUCTS_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/events/gesture.h>
+#include <dali/public-api/math/vector2.h>
+
+namespace Dali
+{
+
+struct AccessibilityGestureEvent
+{
+  // Construction & Destruction
+
+  /**
+   * Virtual destructor
+   */
+  ~AccessibilityGestureEvent()
+  {
+  }
+
+  // Data
+
+  /**
+   * The previous touch position of the primary touch point in screen coordinates.
+   */
+  Vector2 previousPosition;
+
+  /**
+   * This current touch position of the primary touch point in screen coordinates.
+   */
+  Vector2 currentPosition;
+
+  /**
+   * The time difference between the previous and latest touch motion events (in ms).
+   */
+  unsigned long timeDelta;
+
+  /**
+   * The total number of fingers touching the screen in a pan gesture.
+   */
+  unsigned int numberOfTouches;
+
+  enum State
+  {
+    Clear,      ///< There is no state associated with this gesture. @SINCE_1_0.0
+    Started,    ///< The touched points on the screen have moved enough to be considered a gesture. @SINCE_1_0.0
+    Continuing, ///< The gesture is continuing. @SINCE_1_0.0
+    Finished,   ///< The user has lifted a finger or touched an additional point on the screen. @SINCE_1_0.0
+    Cancelled,  ///< The gesture has been cancelled. @SINCE_1_0.0
+    Possible    ///< A gesture is possible. @SINCE_1_0.0
+  };
+
+  State state;
+
+  uint32_t time;
+
+  /**
+   * Default Constructor
+   * @param[in]  state  The state of the gesture
+   */
+  AccessibilityGestureEvent(AccessibilityGestureEvent::State state)
+  : timeDelta( 0 ),
+  numberOfTouches( 0 ),
+  state( state ),
+  time( 0 )
+  {}
+};
+
+} // namespace Dali
+
+#endif // DALI_INTEGRAION_ACCESSIBILITY_GESTURE_STRUCTS_H
diff --git a/dali/devel-api/adaptor-framework/accessibility-gesture-handler.h b/dali/devel-api/adaptor-framework/accessibility-gesture-handler.h
new file mode 100644 (file)
index 0000000..4b8c859
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef DALI_ACCESSIBILITY_GESTURE_HANDLER_H
+#define DALI_ACCESSIBILITY_GESTURE_HANDLER_H
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/accessibility-gesture-event.h>
+
+namespace Dali
+{
+
+/**
+ * AccessibilityGestureHandler is an interface used by Dali to handle accessibility gestures
+ * passed by the accessibility manager.
+ */
+class AccessibilityGestureHandler
+{
+public:
+
+  /**
+   * Handle the accessibility pan gesture.
+   * @param[in]  panEvent  The pan event to be handled.
+   * @return whether the gesture is handled successfully or not.
+   */
+  virtual bool HandlePanGesture( const AccessibilityGestureEvent& panEvent ) = 0;
+
+}; // class AccessibilityGestureHandler
+
+} // namespace Dali
+
+#endif // DALI_ACCESSIBILITY_GESTURE_HANDLER_H
diff --git a/dali/devel-api/adaptor-framework/application-devel.cpp b/dali/devel-api/adaptor-framework/application-devel.cpp
new file mode 100644 (file)
index 0000000..d6403a5
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/adaptor-framework/application-devel.h>
+#include <dali/integration-api/adaptor-framework/scene-holder.h>
+#include <dali/internal/adaptor/common/application-impl.h>
+
+namespace Dali
+{
+
+namespace DevelApplication
+{
+
+
+bool AddIdleWithReturnValue( Application application, CallbackBase* callback )
+{
+  return Internal::Adaptor::GetImplementation( application ).AddIdle( callback, true );
+}
+
+std::string GetDataPath()
+{
+  return Internal::Adaptor::Application::GetDataPath();
+}
+
+Application DownCast( Dali::RefObject* refObject )
+{
+  return Application( dynamic_cast<Dali::Internal::Adaptor::Application*>( refObject ) );
+}
+
+} // namespace DevelApplication
+
+} // namespace Dali
+
+extern "C"
+void ApplicationPreInitialize( int* argc, char** argv[] )
+{
+  Dali::Internal::Adaptor::Application::PreInitialize( argc, argv );
+}
+
diff --git a/dali/devel-api/adaptor-framework/application-devel.h b/dali/devel-api/adaptor-framework/application-devel.h
new file mode 100644 (file)
index 0000000..76d41f5
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef DALI_APPLICATION_DEVEL_H
+#define DALI_APPLICATION_DEVEL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/adaptor-framework/application.h>
+
+namespace Dali
+{
+
+namespace DevelApplication
+{
+
+
+/**
+ * @brief Ensures that the function passed in is called from the main loop when it is idle.
+ * @param[in] application A handle to the Application
+ * @param[in] callback The function to call
+ * @return @c true if added successfully, @c false otherwise
+ *
+ * @note Function must be called from main event thread only
+ *
+ * A callback of the following type should be used:
+ * @code
+ *   bool MyFunction();
+ * @endcode
+ * This callback will be called repeatedly as long as it returns true. A return of 0 deletes this callback.
+ *
+ * @note Ownership of the callback is passed onto this class.
+ */
+DALI_ADAPTOR_API bool AddIdleWithReturnValue( Application application, CallbackBase* callback );
+
+/**
+* @brief Gets the absolute path to the application's data directory which is used to store private data of the application.
+* @return The absolute path to the application's data directory
+*/
+DALI_ADAPTOR_API std::string GetDataPath();
+
+/**
+ * @brief Downcasts a ref object to Application handle
+ *
+ * If handle points to an Application object, the downcast produces valid base handle
+ * If not, the returned base handle is left uninitialized
+ *
+ * @param[in] refObject to an Application
+ * @return handle to an Application object or an uninitialized base handle
+ */
+DALI_ADAPTOR_API Application DownCast( Dali::RefObject* refObject );
+
+} // namespace DevelApplication
+
+} // namespace Dali
+
+/**
+ * @brief This is used to improve application launch performance.
+ * Initializes some functions in advance and makes a window in advance.
+ * @param[in,out]  argc A pointer to the number of arguments
+ * @param[in,out]  argv A pointer to the argument list
+ *
+ * @note Declared in C style for calling from app-launcher.
+ *
+ */
+extern "C"
+DALI_ADAPTOR_API void ApplicationPreInitialize( int* argc, char** argv[] );
+
+#endif // DALI_APPLICATION_DEVEL_H
diff --git a/dali/devel-api/adaptor-framework/atspi-accessibility.h b/dali/devel-api/adaptor-framework/atspi-accessibility.h
new file mode 100755 (executable)
index 0000000..ce65360
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef DALI_DEVEL_ATSPI_ACCESSIBILITY_H
+#define DALI_DEVEL_ATSPI_ACCESSIBILITY_H
+/*
+ * Copyright (c) 2019 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 <functional>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+namespace AtspiAccessibility
+{
+/**
+ * @brief Reads given text by screen reader
+ * @param text The text to read
+ * @param discardable If TRUE, reading can be discarded by subsequent reading requests,
+ * if FALSE the reading must finish before next reading request can be started
+ * @param callback the callback function that is called on reading signals emitted
+ * during processing of this reading request.
+ * Callback can be one of the following signals:
+ * ReadingCancelled, ReadingStopped, ReadingSkipped
+ */
+DALI_ADAPTOR_API void Say( const std::string &text, bool discardable, std::function<void(std::string)> callback );
+
+/**
+ * @brief Force accessibility client to pause.
+ */
+DALI_ADAPTOR_API void Pause();
+
+/**
+ * @brief Force accessibility client to resume.
+ */
+DALI_ADAPTOR_API void Resume();
+
+/**
+ * @brief Set ATSPI to be turned On or Off forcibly.
+ *
+ * @param[in] turnOn true to turn on, false to turn off.
+ * @return The status of ATSPI : 0(ATSPI OFF, ScreenReader OFF), 1(ATSPI ON, ScreenReader OFF),
+ * 2 (ATSPI OFF, ScreenReader ON), 3(ATSPI ON, ScreenReader ON)
+ */
+DALI_ADAPTOR_API int SetForcefully( bool turnOn );
+
+/**
+ * @brief Get ATSPI status.
+ * @return Status of ATSPI : 0(ATSPI OFF, ScreenReader OFF), 1(ATSPI ON, ScreenReader OFF),
+ * 2 (ATSPI OFF, ScreenReader ON), 3(ATSPI ON, ScreenReader ON)
+ */
+DALI_ADAPTOR_API int GetStatus();
+
+} //namespace AtspiAccessibility
+} //namespace Dali
+
+#endif // DALI_DEVEL_ATSPI_ACCESSIBILITY_H
diff --git a/dali/devel-api/adaptor-framework/bitmap-saver.cpp b/dali/devel-api/adaptor-framework/bitmap-saver.cpp
new file mode 100644 (file)
index 0000000..c39bb70
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/bitmap-saver.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/imaging/common/loader-jpeg.h>
+#include <dali/internal/imaging/common/loader-png.h>
+#include <dali/internal/legacy/common/tizen-platform-abstraction.h>
+#include <dali/internal/legacy/tizen/image-encoder.h>
+
+
+namespace Dali
+{
+
+// Pieces needed to save compressed images (temporary location while plumbing):
+namespace
+{
+
+/**
+ * Simple function to tell intended image file format from filename
+ */
+FileFormat GetFormatFromFileName( const std::string& filename )
+{
+  if (filename.length() < 5)
+  {
+    DALI_LOG_WARNING("Invalid (short) filename.\n");
+  }
+  FileFormat format(INVALID_FORMAT);
+
+  const std::size_t filenameSize = filename.length();
+
+  if(filenameSize >= 4){ // Avoid throwing out_of_range or failing silently if exceptions are turned-off on the compare(). (http://www.cplusplus.com/reference/string/string/compare/)
+    if( !filename.compare( filenameSize - 4, 4, ".jpg" )
+        || !filename.compare( filenameSize - 4, 4, ".JPG" ) )
+    {
+      format = JPG_FORMAT;
+    }
+    else if( !filename.compare( filenameSize - 4, 4, ".png" )
+             || !filename.compare( filenameSize - 4, 4, ".PNG" ) )
+    {
+      format = PNG_FORMAT;
+    }
+    else if( !filename.compare( filenameSize - 4, 4, ".bmp" )
+             || !filename.compare( filenameSize - 4, 4, ".BMP" ) )
+    {
+      format = BMP_FORMAT;
+    }
+    else if( !filename.compare( filenameSize - 4, 4, ".gif" )
+             || !filename.compare( filenameSize - 4, 4, ".GIF" ) )
+    {
+      format = GIF_FORMAT;
+    }
+    else if( !filename.compare( filenameSize - 4, 4, ".ico" )
+             || !filename.compare( filenameSize - 4, 4, ".ICO" ) )
+    {
+      format = ICO_FORMAT;
+    }
+    else if(filenameSize >= 5){
+      if( !filename.compare( filenameSize - 5, 5, ".jpeg" )
+          || !filename.compare( filenameSize - 5, 5, ".JPEG" ) )
+      {
+        format = JPG_FORMAT;
+      }
+    }
+  }
+
+  return format;
+}
+
+bool EncodeToFormat( const unsigned char* pixelBuffer,
+                     Vector< unsigned char >& encodedPixels,
+                     FileFormat formatEncoding,
+                     std::size_t width,
+                     std::size_t height,
+                     Pixel::Format pixelFormat )
+{
+  switch( formatEncoding )
+  {
+    case JPG_FORMAT:
+    {
+      return TizenPlatform::EncodeToJpeg( pixelBuffer, encodedPixels, width, height, pixelFormat );
+      break;
+    }
+    case PNG_FORMAT:
+    {
+      return TizenPlatform::EncodeToPng( pixelBuffer, encodedPixels, width, height, pixelFormat );
+      break;
+    }
+    default:
+    {
+      DALI_LOG_ERROR("Format not supported for image encoding (supported formats are PNG and JPEG)\n");
+      break;
+    }
+  }
+  return false;
+}
+} // anonymous namespace
+
+
+bool EncodeToFile(const unsigned char* const pixelBuffer,
+                  const std::string& filename,
+                  const Pixel::Format pixelFormat,
+                  const std::size_t width,
+                  const std::size_t height )
+{
+  DALI_ASSERT_DEBUG(pixelBuffer != 0 && filename.size() > 4 && width > 0 && height > 0);
+  Vector< unsigned char > pixbufEncoded;
+  const FileFormat format = GetFormatFromFileName( filename );
+  const bool encodeResult = EncodeToFormat( pixelBuffer, pixbufEncoded, format, width, height, pixelFormat );
+  if(!encodeResult)
+  {
+    DALI_LOG_ERROR("Encoding pixels failed\n");
+    return false;
+  }
+  return TizenPlatform::SaveFile( filename, pixbufEncoded.Begin(), pixbufEncoded.Count() );
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/bitmap-saver.h b/dali/devel-api/adaptor-framework/bitmap-saver.h
new file mode 100755 (executable)
index 0000000..e1f6ab7
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef DALI_ADAPTOR_BITMAP_SAVER_H
+#define DALI_ADAPTOR_BITMAP_SAVER_H
+
+/*
+ * Copyright (c) 2019 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>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+/**
+ * Store the given pixel data to a file.
+ * The suffix of the filename determines what type of file will be stored,
+ * currently only jpeg and png formats are supported.
+ *
+ * @param[in] pixelBuffer Pointer to the pixel data
+ * @param[in] filename    Filename to save
+ * @param[in] pixelFormat The format of the buffer's pixels
+ * @param[in] width       The width of the image in pixels
+ * @param[in] height      The height of the image in pixels
+ *
+ * @return true if the file was saved
+ */
+DALI_ADAPTOR_API bool EncodeToFile(const unsigned char* const pixelBuffer,
+                                  const std::string& filename,
+                                  const Pixel::Format pixelFormat,
+                                  const std::size_t width,
+                                  const std::size_t height);
+
+} // namespace Dali
+
+
+#endif // DALI_ADAPTOR_BITMAP_SAVER_H
diff --git a/dali/devel-api/adaptor-framework/clipboard-event-notifier.cpp b/dali/devel-api/adaptor-framework/clipboard-event-notifier.cpp
new file mode 100644 (file)
index 0000000..10163b4
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/clipboard-event-notifier.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/clipboard/common/clipboard-event-notifier-impl.h>
+
+namespace Dali
+{
+
+ClipboardEventNotifier::ClipboardEventNotifier()
+{
+}
+
+ClipboardEventNotifier ClipboardEventNotifier::Get()
+{
+  return Internal::Adaptor::ClipboardEventNotifier::Get();
+}
+
+ClipboardEventNotifier::~ClipboardEventNotifier()
+{
+}
+
+const std::string& ClipboardEventNotifier::GetContent() const
+{
+  return Internal::Adaptor::ClipboardEventNotifier::GetImplementation(*this).GetContent();
+}
+
+void ClipboardEventNotifier::SetContent( const std::string& content )
+{
+  Internal::Adaptor::ClipboardEventNotifier::GetImplementation(*this).SetContent(content);
+}
+
+void ClipboardEventNotifier::ClearContent()
+{
+  Internal::Adaptor::ClipboardEventNotifier::GetImplementation(*this).ClearContent();
+}
+
+void ClipboardEventNotifier::EmitContentSelectedSignal()
+{
+  Internal::Adaptor::ClipboardEventNotifier::GetImplementation(*this).EmitContentSelectedSignal();
+}
+
+ClipboardEventNotifier::ClipboardEventSignalType& ClipboardEventNotifier::ContentSelectedSignal()
+{
+  return Internal::Adaptor::ClipboardEventNotifier::GetImplementation(*this).ContentSelectedSignal();
+}
+
+ClipboardEventNotifier::ClipboardEventNotifier( Internal::Adaptor::ClipboardEventNotifier* notifier )
+: BaseHandle( notifier )
+{
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/clipboard-event-notifier.h b/dali/devel-api/adaptor-framework/clipboard-event-notifier.h
new file mode 100755 (executable)
index 0000000..83c4008
--- /dev/null
@@ -0,0 +1,121 @@
+#ifndef DALI_CLIPBOARD_EVENT_NOTIFIER_H
+#define DALI_CLIPBOARD_EVENT_NOTIFIER_H
+
+/*
+ * Copyright (c) 2019 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/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class ClipboardEventNotifier;
+}
+}
+
+/**
+ * @brief The ClipboardEventNotifier provides signals when clipboard events are received from the device.
+ */
+class DALI_ADAPTOR_API ClipboardEventNotifier : public BaseHandle
+{
+public:
+
+  // Typedefs
+
+  /**
+   * @brief Clipboard event
+   */
+  typedef Signal< void ( ClipboardEventNotifier& ) > ClipboardEventSignalType;
+
+  /**
+   * @brief Create an uninitialized handle.
+   *
+   * This can be initialized by getting the notifier from Dali::Adaptor.
+   */
+  ClipboardEventNotifier();
+
+  /**
+   * @brief Retrieve a handle to the ClipboardEventNotifier instance.
+   *
+   * @return A handle to the ClipboardEventNotifier
+   */
+  static ClipboardEventNotifier Get();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~ClipboardEventNotifier();
+
+  /**
+   * @brief Returns the selected content.
+   * @return A reference to the string representing the selected content.
+   */
+  const std::string& GetContent() const;
+
+  /**
+   * @brief Sets the selected content.
+   * @param[in] content  A string that represents the content that has been selected.
+   */
+  void SetContent( const std::string& content );
+
+  /**
+   * @brief Clears the stored content.
+   */
+  void ClearContent();
+
+  /**
+   * @brief Called when content is selected in the clipboard.
+   */
+  void EmitContentSelectedSignal();
+
+public:  // Signals
+
+  /**
+   * @brief This is emitted when content is selected from the clipboard.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallback( ClipboardEventNotifier& notifier );
+   * @endcode
+   * @return The signal to connect to.
+   */
+  ClipboardEventSignalType& ContentSelectedSignal();
+
+public: // Not intended for application developers
+
+  /**
+   * @brief This constructor is used by ClipboardEventNotifier::Get().
+   *
+   * @param[in] notifier A pointer to the drag and drop notifier.
+   */
+  explicit DALI_INTERNAL ClipboardEventNotifier( Internal::Adaptor::ClipboardEventNotifier* notifier );
+};
+
+} // namespace Dali
+
+#endif // DALI_CLIPBOARD_EVENT_NOTIFIER_H
diff --git a/dali/devel-api/adaptor-framework/clipboard.cpp b/dali/devel-api/adaptor-framework/clipboard.cpp
new file mode 100644 (file)
index 0000000..b6eee54
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/clipboard.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/clipboard/common/clipboard-impl.h>
+
+namespace Dali
+{
+
+Clipboard::Clipboard()
+{
+}
+Clipboard::~Clipboard()
+{
+}
+Clipboard::Clipboard(Internal::Adaptor::Clipboard *impl)
+  : BaseHandle(impl)
+{
+}
+
+Clipboard Clipboard::Get()
+{
+  return Internal::Adaptor::Clipboard::Get();
+}
+
+bool Clipboard::SetItem( const std::string &itemData)
+{
+  return GetImplementation(*this).SetItem( itemData );
+}
+
+void Clipboard::RequestItem()
+{
+  GetImplementation(*this).RequestItem();
+}
+
+unsigned int Clipboard::NumberOfItems()
+{
+  return GetImplementation(*this).NumberOfItems();
+}
+
+void Clipboard::ShowClipboard()
+{
+  GetImplementation(*this).ShowClipboard();
+}
+
+void Clipboard::HideClipboard()
+{
+  GetImplementation(*this).HideClipboard(false);
+}
+
+bool Clipboard::IsVisible() const
+{
+  return GetImplementation(*this).IsVisible();
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/clipboard.h b/dali/devel-api/adaptor-framework/clipboard.h
new file mode 100755 (executable)
index 0000000..c462182
--- /dev/null
@@ -0,0 +1,120 @@
+#ifndef  DALI_CLIPBOARD_H
+#define  DALI_CLIPBOARD_H
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/object/base-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+
+namespace Adaptor
+{
+class Clipboard;
+}
+}
+
+/**
+ * @brief Interface to the device's clipboard.
+ *
+ * Clipboard can manage it's item and set show / hide status.
+ */
+
+class DALI_ADAPTOR_API Clipboard : public BaseHandle
+{
+public:
+  /**
+   * @brief Create an uninitialized Clipboard.
+   *
+   * this can be initialized with one of the derived Clipboard' New() methods
+   */
+  Clipboard();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~Clipboard();
+
+  /**
+   * @brief This constructor is used by Adaptor::GetClipboard().
+   *
+   * @param[in] clipboard A pointer to the clipboard.
+   */
+  explicit DALI_INTERNAL Clipboard( Internal::Adaptor::Clipboard* clipboard );
+
+  /**
+   * @brief Retrieve a handle to the ClipboardEventNotifier instance.
+   *
+   * @return A handle to the Clipboard
+   */
+  static Clipboard Get();
+
+  /**
+   * @brief Send the given string to the clipboard.
+   *
+   * @param[in] itemData string to send to clip board
+   * @return bool true if the internal clip board sending was successful.
+   */
+  bool SetItem( const std::string& itemData );
+
+  /**
+   * @brief Request clipboard service to retrieve an item
+   *
+   * Calling this method will trigger a signal from the clipboard event notifier.
+   * @see Dali::ClipboardEventNotifier::ContentSelectedSignal()
+   */
+  void RequestItem();
+
+  /**
+   * @brief Returns the number of item currently in the clipboard.
+   *
+   * @return unsigned int number of clipboard items
+   */
+  unsigned int NumberOfItems();
+
+  /**
+   * @brief Show the clipboard window.
+   */
+  void ShowClipboard();
+
+  /**
+   * @brief Hide the clipboard window.
+   */
+  void HideClipboard();
+
+  /**
+  * @brief Retrieves the clipboard's visibility
+  * @return bool true if the clipboard is visible.
+  */
+  bool IsVisible() const;
+
+};
+} // namespace Dali
+
+#endif // DALI_CLIPBOARD_H
diff --git a/dali/devel-api/adaptor-framework/color-controller-plugin.h b/dali/devel-api/adaptor-framework/color-controller-plugin.h
new file mode 100755 (executable)
index 0000000..2d761dc
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef DALI_COLOR_CONTROLLER_PLUGIN_H
+#define DALI_COLOR_CONTROLLER_PLUGIN_H
+
+/*
+ * Copyright (c) 2019 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 <cstdlib>
+
+namespace Dali
+{
+
+/**
+ * @brief ColorControllerPlugin is an abstract interface, used by dali-adaptor to access Color Controller plugin.
+ * A concrete implementation must be created for each platform and provided as dynamic library.
+ */
+class ColorControllerPlugin
+{
+public:
+
+  /**
+   * @brief Constructor.
+   */
+  ColorControllerPlugin(){}
+
+  /**
+   * @brief Destructor.
+   */
+  virtual ~ColorControllerPlugin(){}
+
+  /**
+   * @brief Retrieve the RGBA value by given the color code.
+   *
+   * @param[in] colorCode The color code string.
+   * @param[out] colorValue The RGBA color
+   * @return true if the color code exists, otherwise false
+   */
+  virtual bool RetrieveColor( const std::string& colorCode, Vector4& colorValue ) const = 0;
+
+  /**
+   * @brief Retrieve the RGBA value by given the color code.
+   *
+   * @param[in] colorCode The color code string.
+   * @param[out] textColor The text color.
+   * @param[out] textOutlineColor The text outline color.
+   * @param[out] textShadowColor The text shadow color.
+   * @return true if the color code exists, otherwise false
+   */
+  virtual bool RetrieveColor( const std::string& colorCode , Vector4& textColor, Vector4& textOutlineColor, Vector4& textShadowColor ) const = 0;
+};
+
+} // namespace Dali;
+
+#endif // DALI_COLOR_CONTROLLER_PLUGIN_H
diff --git a/dali/devel-api/adaptor-framework/color-controller.cpp b/dali/devel-api/adaptor-framework/color-controller.cpp
new file mode 100644 (file)
index 0000000..ee1f7df
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/color-controller.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/color-controller-impl.h>
+
+namespace Dali
+{
+
+ColorController::ColorController()
+{
+}
+
+ColorController::ColorController(const ColorController& controller)
+: BaseHandle(controller)
+{
+}
+
+ColorController& ColorController::operator=(const ColorController& rhs)
+{
+  BaseHandle::operator=(rhs);
+  return *this;
+}
+
+ColorController ColorController::Get()
+{
+  return Internal::Adaptor::ColorController::Get();
+}
+
+ColorController::~ColorController()
+{
+}
+
+bool ColorController::RetrieveColor( const std::string& colorCode, Vector4& colorValue )
+{
+  return GetImplementation(*this).RetrieveColor( colorCode, colorValue );
+}
+
+bool ColorController::RetrieveColor( const std::string& colorCode , Vector4& textColor, Vector4& textOutlineColor, Vector4& textShadowColor)
+{
+  return GetImplementation(*this).RetrieveColor( colorCode, textColor, textOutlineColor, textShadowColor );
+}
+
+ColorController::ColorController(Internal::Adaptor::ColorController* internal)
+: BaseHandle(internal)
+{
+}
+
+}
diff --git a/dali/devel-api/adaptor-framework/color-controller.h b/dali/devel-api/adaptor-framework/color-controller.h
new file mode 100755 (executable)
index 0000000..bc067a9
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef DALI_COLOR_CONTROLLER_H
+#define DALI_COLOR_CONTROLLER_H
+
+/*
+ * Copyright (c) 2019 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/object/base-handle.h>
+#include <dali/public-api/math/vector4.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class ColorController;
+}
+
+}
+
+/**
+ * Color controller currently caches the changeable color table which updates with the theme change
+ *
+ * It provides the functionality of retrieving a RGBA color by passing in the color code string.
+ */
+class DALI_ADAPTOR_API ColorController : public BaseHandle
+{
+public:
+
+  /**
+   * @brief Create an uninitialized ColorController handle.
+   */
+  ColorController();
+
+  /**
+   * @brief Creates a copy of the handle.
+   *
+   * The copy will point to the same implementation as the original.
+   * @param[in]  colorController  The Color Controller to copy from.
+   */
+  ColorController( const ColorController& colorController);
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @param [in] rhs  A reference to the copied handle
+   * @return A reference to this
+   */
+  ColorController& operator=(const ColorController& rhs);
+
+  /**
+   * @brief Retrieve the initialized instance of the ColorController.
+   *
+   * @return Handle to ColorController.
+   */
+  static ColorController Get();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~ColorController();
+
+  /**
+   * @brief Retrieve the RGBA value by given the color code.
+   *
+   * @param[in] colorCode The color code string.
+   * @param[out] colorValue The RGBA color
+   * @return true if the color code exists, otherwise false
+   */
+  bool RetrieveColor( const std::string& colorCode, Vector4& colorValue );
+
+  /**
+    * @brief Retrieve the RGBA values by given the color code.
+    *
+    * @param[in] colorCode The color code string.
+    * @param[out] textColor The text color.
+    * @param[out] textOutlineColor The text outline color.
+    * @param[out] textShadowColor The text shadow color.
+    * @return true if the color code exists, otherwise false
+    */
+  bool RetrieveColor( const std::string& colorCode , Vector4& textColor, Vector4& textOutlineColor, Vector4& textShadowColor);
+
+
+public: // Not intended for application developers
+  /**
+   * @brief This constructor is used internally to create a handle from an object pointer.
+   * @param [in] colorController A pointer the internal color controller.
+   */
+  explicit DALI_INTERNAL ColorController(Internal::Adaptor::ColorController* colorController);
+};
+
+
+} //namespace Dali
+
+#endif // DALI_COLOR_CONTROLLER_H
diff --git a/dali/devel-api/adaptor-framework/environment-variable.cpp b/dali/devel-api/adaptor-framework/environment-variable.cpp
new file mode 100644 (file)
index 0000000..1bcf1b6
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/environment-variable.h>
+
+// EXTERNAL INCLUDE
+#include <cstdlib>
+
+namespace Dali
+{
+
+namespace EnvironmentVariable
+{
+
+const char * GetEnvironmentVariable( const char * variable )
+{
+  return std::getenv( variable );
+}
+
+bool SetEnvironmentVariable( const char * variable, const char * value )
+{
+  return setenv( variable, value, 1 ) == 0;
+}
+
+} // namespace EnvironmentVariable
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/environment-variable.h b/dali/devel-api/adaptor-framework/environment-variable.h
new file mode 100644 (file)
index 0000000..f3c1c79
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef DALI_ENVIRONMENT_VARIABLE_H
+#define DALI_ENVIRONMENT_VARIABLE_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace EnvironmentVariable
+{
+
+/**
+ * @brief Search the environment list for the specified variable name and return a pointer to the C string that is associated with the matched environment list member.
+ *
+ * @param[in] variable Null-terminated character string identifying the name of the environmental variable to look for.
+ * @return A C-string containing the value of the specified environment variable.
+ */
+DALI_ADAPTOR_API const char * GetEnvironmentVariable( const char * variable );
+
+/**
+ * @brief Create or overwrite (when it does not exist) an environment variable.
+ *
+ * @param[in] variable Null-terminated character string identifying the name of the environmental variable.
+ * @param[in] value Null-terminated character string to set as a value.
+ * @return True on success, false on error.
+ */
+DALI_ADAPTOR_API bool SetEnvironmentVariable( const char * variable, const char * value );
+
+} // namespace EnvironmentVariable
+
+} // namespace Dali
+
+#endif /*DALI_ ENVIRONMENT_VARIABLE_H */
diff --git a/dali/devel-api/adaptor-framework/event-feeder.cpp b/dali/devel-api/adaptor-framework/event-feeder.cpp
new file mode 100644 (file)
index 0000000..050d0c1
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/event-feeder.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+
+namespace Dali
+{
+
+namespace EventFeeder
+{
+
+void FeedTouchPoint( TouchPoint& point, int timeStamp )
+{
+  if ( Adaptor::IsAvailable() )
+  {
+    Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).FeedTouchPoint( point, timeStamp );
+  }
+}
+
+void FeedWheelEvent( WheelEvent& wheelEvent )
+{
+  if ( Adaptor::IsAvailable() )
+  {
+    Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).FeedWheelEvent( wheelEvent );
+  }
+}
+
+void FeedKeyEvent( KeyEvent& keyEvent )
+{
+  if ( Adaptor::IsAvailable() )
+  {
+    Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).FeedKeyEvent( keyEvent );
+  }
+}
+
+} // namespace EventFeeder
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/event-feeder.h b/dali/devel-api/adaptor-framework/event-feeder.h
new file mode 100644 (file)
index 0000000..bffbcd4
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef DALI_EVENT_FEEDER_H
+#define DALI_EVENT_FEEDER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+struct KeyEvent;
+struct WheelEvent;
+struct TouchPoint;
+
+namespace EventFeeder
+{
+
+/**
+ * Feed a touch point to the adaptor.
+ *
+ * @param[in] point touch point
+ * @param[in] timeStamp time value of event
+ *
+ * @note For testing/automation purposes only.
+ */
+DALI_ADAPTOR_API void FeedTouchPoint( TouchPoint& point, int timeStamp );
+
+/**
+ * Feed a wheel event to the adaptor.
+ *
+ * @param[in]  wheelEvent wheel event
+ *
+ * @note For testing/automation purposes only.
+ */
+DALI_ADAPTOR_API void FeedWheelEvent( WheelEvent& wheelEvent );
+
+/**
+ * Feed a key event to the adaptor.
+ *
+ * @param[in] keyEvent The key event holding the key information.
+ *
+ * @note For testing/automation purposes only.
+ */
+DALI_ADAPTOR_API void FeedKeyEvent( KeyEvent& keyEvent );
+
+} // namespace EventFeeder
+
+} // namespace Dali
+
+#endif // DALI_EVENT_FEEDER_H
diff --git a/dali/devel-api/adaptor-framework/event-thread-callback.cpp b/dali/devel-api/adaptor-framework/event-thread-callback.cpp
new file mode 100644 (file)
index 0000000..366d03f
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/event-thread-callback.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
+
+namespace Dali
+{
+
+struct EventThreadCallback::Impl
+{
+  TriggerEventInterface* eventTrigger;
+};
+
+EventThreadCallback::EventThreadCallback( CallbackBase* callback )
+: mImpl( new Impl() )
+{
+  mImpl->eventTrigger = TriggerEventFactory::CreateTriggerEvent( callback, TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
+}
+
+EventThreadCallback::~EventThreadCallback()
+{
+  TriggerEventFactory::DestroyTriggerEvent( mImpl->eventTrigger );
+  delete mImpl;
+}
+
+void EventThreadCallback::Trigger()
+{
+  if( mImpl->eventTrigger )
+  {
+    mImpl->eventTrigger->Trigger();
+  }
+}
+
+}
diff --git a/dali/devel-api/adaptor-framework/event-thread-callback.h b/dali/devel-api/adaptor-framework/event-thread-callback.h
new file mode 100644 (file)
index 0000000..5c65b51
--- /dev/null
@@ -0,0 +1,74 @@
+#ifndef DALI_EVENT_THREAD_CALLBACK_H
+#define DALI_EVENT_THREAD_CALLBACK_H
+
+/*
+ * Copyright (c) 2019 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/signals/callback.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+/**
+ * @brief The EventThreadCallback class provides a mechanism for the worker thread to trigger the execution of a given callback in main event thread .
+ *
+ * @note The EventThreadCallback object should only be created in the main thread.
+ */
+class DALI_ADAPTOR_API EventThreadCallback
+{
+public:
+
+  /**
+   * @brief Constructor. Create an object that will call the given callback in main event thread.
+   *
+   * @param[in] callback The callback to call.
+   */
+  EventThreadCallback( CallbackBase* callback );
+
+  /**
+   * @brief Destructor.
+   */
+  ~EventThreadCallback();
+
+  /**
+   * @brief Trigger the calling of callback.
+   *
+   * The method can be used from worker threads to notify the main thread as main thread is running the event loop and thus cannot be blocked
+   */
+  void Trigger();
+
+private:
+
+  // undefined copy constructor.
+  EventThreadCallback( const EventThreadCallback& );
+
+  // undefined assignment operator
+  EventThreadCallback& operator=( const EventThreadCallback& );
+
+private:
+
+  struct Impl;
+  Impl* mImpl;
+
+};
+
+}
+#endif /* DALI_EVENT_THREAD_CALLBACK_H */
diff --git a/dali/devel-api/adaptor-framework/feedback-player.cpp b/dali/devel-api/adaptor-framework/feedback-player.cpp
new file mode 100644 (file)
index 0000000..ace10f6
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/feedback-player.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/haptics/common/feedback-player-impl.h>
+
+namespace Dali
+{
+
+FeedbackPlayer::FeedbackPlayer()
+{
+}
+
+FeedbackPlayer FeedbackPlayer::Get()
+{
+  return Internal::Adaptor::FeedbackPlayer::Get();
+}
+
+FeedbackPlayer::~FeedbackPlayer()
+{
+}
+
+void FeedbackPlayer::PlayMonotone(unsigned int duration)
+{
+  GetImplementation(*this).PlayMonotone(duration);
+}
+
+void FeedbackPlayer::PlayFile(const std::string filePath)
+{
+  GetImplementation(*this).PlayFile(filePath);
+}
+
+void FeedbackPlayer::Stop()
+{
+  GetImplementation(*this).Stop();
+}
+
+int FeedbackPlayer::PlaySound( const std::string& fileName )
+{
+  return GetImplementation(*this).PlaySound(fileName);
+}
+
+void FeedbackPlayer::StopSound( int handle )
+{
+  GetImplementation(*this).StopSound(handle);
+}
+
+void FeedbackPlayer::PlayFeedbackPattern( int type, int pattern )
+{
+  GetImplementation(*this).PlayFeedbackPattern(type, pattern);
+}
+
+bool FeedbackPlayer::LoadFile(const std::string& filename, std::string& data)
+{
+  return GetImplementation(*this).LoadFile(filename, data);
+}
+
+FeedbackPlayer::FeedbackPlayer( Internal::Adaptor::FeedbackPlayer* player )
+: BaseHandle( player )
+{
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/feedback-player.h b/dali/devel-api/adaptor-framework/feedback-player.h
new file mode 100755 (executable)
index 0000000..cc7598d
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef DALI_FEEDBACK_PLAYER_H
+#define DALI_FEEDBACK_PLAYER_H
+
+/*
+ * Copyright (c) 2019 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/object/base-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class FeedbackPlayer;
+}
+}
+
+/**
+ * @brief Plays feedback effects.
+ */
+class DALI_ADAPTOR_API FeedbackPlayer : public BaseHandle
+{
+public:
+
+  /**
+   * @brief Create an uninitialized handle.
+   *
+   * This can be initialized by calling FeedbackPlayer::Get().
+   */
+  FeedbackPlayer();
+
+  /**
+   * @brief Create an initialized handle to the FeedbackPlayer.
+   *
+   * @return A handle to a newly allocated Dali resource.
+   */
+  static FeedbackPlayer Get();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~FeedbackPlayer();
+
+  /**
+   * @brief Plays a monotone vibration.
+   * @param[in]  duration  The duration of the vibration.
+   */
+  void PlayMonotone(unsigned int duration);
+
+  /**
+   * @brief Plays vibration in predefined patterns.
+   * @param[in] filePath Path to the file containing the effect.
+   */
+  void PlayFile(const std::string filePath);
+
+  /**
+   * @brief Stops the currently playing vibration effects.
+   */
+  void Stop();
+
+  /**
+   * Plays a sound file.
+   * @param[in] fileName Path to the sound file to play.
+   * @return A handle which can be used to stop the sound playback.
+   */
+  int PlaySound( const std::string& fileName );
+
+  /**
+   * Stops a currently playing sound.
+   * @param[in] handle A handle to the currently playing sound.
+   */
+  void StopSound( int handle );
+
+  /**
+   * Plays a feedback pattern.
+   * @param[in] type The type of feedback.
+   * @param[in] pattern The ID of the pattern to play.
+   */
+  void PlayFeedbackPattern( int type, int pattern );
+
+  /*
+   * Loads a file into data
+   * @param[in] filename The filename.
+   * @param[in] data The data in the file.
+   * @return True if the file data could be loaded
+   */
+  bool LoadFile(const std::string& filename, std::string& data);
+
+public: // Not intended for application developers
+
+  /**
+   * @brief This constructor is used by FeedbackPlayer::Get().
+   * @param[in] feedbackPlayer A pointer to the feedback player.
+   */
+  explicit DALI_INTERNAL FeedbackPlayer( Internal::Adaptor::FeedbackPlayer* feedbackPlayer );
+};
+
+} // namespace Dali
+
+#endif // DALI_FEEDBACK_PLAYER_H
diff --git a/dali/devel-api/adaptor-framework/feedback-plugin.h b/dali/devel-api/adaptor-framework/feedback-plugin.h
new file mode 100644 (file)
index 0000000..45ad08a
--- /dev/null
@@ -0,0 +1,98 @@
+#ifndef DALI_FEEDBACK_PLUGIN_H
+#define DALI_FEEDBACK_PLUGIN_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+/**
+ * FeedbackPlugin is an abstract interface, used by Dali-adaptor to access haptic and audio feedback.
+ * A concrete implementation must be created for each platform and provided as a dynamic library which
+ * will be loaded at run time by the adaptor.
+ */
+class FeedbackPlugin
+{
+public:
+
+  typedef void (*SoundStopCallBack)( void* ptr );
+
+  /**
+   * Destructor.
+   */
+  virtual ~FeedbackPlugin()
+  {
+  }
+
+  /**
+   * Plays vibration in predefined patterns.
+   * @param[in] filePath Path to the file containing the effect.
+   */
+  virtual void PlayHaptic( const std::string& filePath ) = 0;
+
+  /**
+   * Plays a monotone vibration.
+   * @param[in]  duration  The duration of the vibration.
+   */
+  virtual void PlayHapticMonotone( unsigned int duration ) = 0;
+
+  /**
+   * Stops the currently playing vibration effects.
+   */
+  virtual void StopHaptic() = 0;
+
+  /**
+   * Plays a sound file.
+   * @param[in] fileName Path to the sound file to play.
+   * @return A handle which can be used to stop the sound playback.
+   */
+  virtual int PlaySound( const std::string& fileName ) = 0;
+
+  /**
+   * Stops a currently playing sound.
+   * @param[in] handle A handle to the currently playing sound.
+   */
+  virtual void StopSound( int handle ) = 0;
+
+  /**
+   * Plays a feedback pattern.
+   * @param[in] type The type of feedback.
+   * @param[in] pattern The ID of the pattern to play.
+   */
+  virtual void PlayFeedbackPattern( int type, int pattern ) = 0;
+
+  // Types for plugin factories
+
+  /**
+   * Function pointer called in adaptor to create a feedback plugin instance.
+   * @param [in] pluginName name of the plugin to load.
+   * @return Pointer to the newly created plugin object
+   */
+  typedef FeedbackPlugin* CreateFeedbackPlugin( void );
+
+}; // class FeedbackPlugin
+
+} // namespace Dali
+
+#endif // DALI_FEEDBACK_PLUGIN_H
diff --git a/dali/devel-api/adaptor-framework/file-loader.cpp b/dali/devel-api/adaptor-framework/file-loader.cpp
new file mode 100644 (file)
index 0000000..c567456
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/adaptor-framework/file-loader.h>
+
+// EXTERNAL INCLUDES
+#include <iostream>
+#include <fstream>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor-framework/common/file-loader-impl.h>
+#include <dali/internal/imaging/common/file-download.h>
+
+namespace Dali
+{
+
+namespace
+{
+
+// limit maximum image down load size to 50 MB
+const size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE  = 50 * 1024 * 1024 ;
+
+}
+
+namespace FileLoader
+{
+
+int ReadFile(const std::string& filename, Dali::Vector<char> & memblock, FileLoader::FileType fileType)
+{
+  return Dali::Internal::Adaptor::ReadFile( filename, memblock, fileType );
+}
+
+int ReadFile(const std::string& filename, std::streampos& fileSize, Dali::Vector<char>& memblock, FileLoader::FileType fileType)
+{
+  return Dali::Internal::Adaptor::ReadFile( filename, fileSize, memblock, fileType );;
+}
+
+std::streampos GetFileSize(const std::string& filename)
+{
+  return Dali::Internal::Adaptor::GetFileSize(filename);
+}
+
+bool DownloadFileSynchronously(const std::string& filename, Dali::Vector<uint8_t> &dataBuffer)
+{
+  size_t dataSize;
+  return TizenPlatform::Network::DownloadRemoteFileIntoMemory( filename, dataBuffer, dataSize, MAXIMUM_DOWNLOAD_IMAGE_SIZE );
+}
+
+} //FileLoader
+
+} //Dali
diff --git a/dali/devel-api/adaptor-framework/file-loader.h b/dali/devel-api/adaptor-framework/file-loader.h
new file mode 100644 (file)
index 0000000..a658952
--- /dev/null
@@ -0,0 +1,87 @@
+#ifndef DALI_FILE_LOADER_H
+#define DALI_FILE_LOADER_H
+
+/*
+ * Copyright (c) 2019 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/object/base-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace FileLoader
+{
+/**
+ * @brief File type formats
+ * The default format is binary
+ */
+enum FileType           ///< FileType format
+{
+  BINARY,               ///< File will be loaded as a binary
+  TEXT                  ///< File will be loaded as text
+};
+
+/**
+ * @brief Load the file. It will load it either as a binary or as a text
+ *
+ * @param[in] filename  Filename of the file to load.
+ * @param[in] memblock  Dali::Vector containing the buffer loaded
+ * @param[in] fileType  How we want to load the file. Binary or Text. Binary default
+ * @return error code. 0 - Error, 1 - Ok
+ *
+ *
+ */
+DALI_ADAPTOR_API int ReadFile(const std::string& filename, Dali::Vector<char> & memblock, FileLoader::FileType fileType = BINARY);
+
+/**
+ * @brief Load the file. It will load it either as a binary or as a text
+ *
+ * @param[in] filename  Filename of the file to load.
+ * @param[in] fileSize  Size of the loaded file
+ * @param[in] memblock  Dali::Vector containing the buffer loaded
+ * @param[in] fileType  How we want to load the file. Binary or Text. Binary default
+ * @return error code. 0 - Error, 1 - Ok
+ *
+ */
+DALI_ADAPTOR_API int ReadFile(const std::string& filename, std::streampos& fileSize, Dali::Vector<char> & memblock, FileLoader::FileType fileType = BINARY);
+
+/**
+ * @brief Get the file size of a file
+ *
+ * @param[in] filename  Filename of the file to load.
+ * @return the size of the file or 0 if file not found
+ */
+DALI_ADAPTOR_API std::streampos GetFileSize(const std::string& filename);
+
+
+/**
+ * @brief Download a requested file into a memory buffer.
+ *
+ * @param[in] filename  Filename of the file to download.
+ * @param[out] dataBuffer  A memory buffer object to be written with downloaded file data.
+ * @return error code. false - Error, true - Ok
+ */
+DALI_ADAPTOR_API bool DownloadFileSynchronously(const std::string& filename, Dali::Vector<uint8_t> &dataBuffer);
+
+};
+
+} // Dali
+#endif // DALI_FILE_LOADER_H
diff --git a/dali/devel-api/adaptor-framework/file-stream.cpp b/dali/devel-api/adaptor-framework/file-stream.cpp
new file mode 100644 (file)
index 0000000..83dc907
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/adaptor-framework/file-stream.h>
+
+// EXTERNAL INCLUDES
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor-framework/common/file-stream-impl.h>
+
+namespace Dali
+{
+
+FileStream::FileStream(const std::string& filename, uint8_t mode)
+{
+  mImpl.reset( new Impl( filename, mode ) );
+}
+
+FileStream::FileStream(uint8_t* buffer, size_t dataSize, uint8_t mode)
+{
+  mImpl.reset( new Impl( buffer, dataSize, mode ) );
+}
+
+FileStream::FileStream(Dali::Vector<uint8_t>& buffer, size_t dataSize, uint8_t mode)
+{
+  mImpl.reset( new Impl( buffer, dataSize, mode ) );
+}
+
+FileStream::FileStream(FileStream&&) = default;
+
+FileStream& FileStream::operator=(FileStream&&) = default;
+
+FileStream::~FileStream() = default;
+
+std::iostream& FileStream::GetStream()
+{
+  return mImpl->GetStream();
+}
+
+FILE* FileStream::GetFile()
+{
+  return mImpl->GetFile();
+}
+
+} // Dali
diff --git a/dali/devel-api/adaptor-framework/file-stream.h b/dali/devel-api/adaptor-framework/file-stream.h
new file mode 100644 (file)
index 0000000..90a3a15
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef DALI_FILE_STREAM_H
+#define DALI_FILE_STREAM_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <stdio.h>
+#include <stdint.h>
+
+#include <iostream>
+#include <string>
+#include <memory>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+class DALI_ADAPTOR_API FileStream
+{
+public:
+
+  /**
+   * @brief File type formats
+   * The default format is binary
+   */
+  enum FileMode  ///< FileType format
+  {
+    BINARY = 1 << 0,      ///< File stream will be opened as a binary
+    TEXT   = 1 << 1,      ///< File stream will be opened as text
+    READ   = 1 << 2,      ///< File stream will be opened for reading
+    WRITE  = 1 << 3,      ///< File stream will be opened for writing
+    APPEND = 1 << 4,      ///< File stream will be opened for appending
+  };
+
+  /**
+   * Constructor
+   * @param[in] filename Filename of the file to open the stream for
+   * @param[in] mode How we want to open the stream. Binary or Text, Read or Write. Binary & Read default
+   */
+  FileStream(const std::string& filename, uint8_t mode = BINARY | READ);
+
+  /**
+   * Constructor
+   * @param[in] buffer Buffer to open the stream for.
+   *                   The buffer is not owned by FileStream and must be valid for entire lifetime of FileStream
+   * @param[in] dataSize The maximum size of the data in the buffer.
+   * @param[in] mode How we want to open the stream. Binary or Text, Read or Write. Binary & Read default
+   */
+  FileStream(uint8_t* buffer, size_t dataSize, uint8_t mode = BINARY | READ);
+
+  /**
+   * Constructor
+   * @param[in] buffer Buffer to open the stream for.
+   *                   The buffer is not owned by FileStream and must be valid for entire lifetime of FileStream
+   * @param[in] dataSize The maximum size of the data in the buffer.
+   * @param[in] mode How we want to open the stream. Binary or Text, Read or Write. Binary & Read default
+   */
+  FileStream(Dali::Vector<uint8_t>& buffer, size_t dataSize, uint8_t mode = BINARY | READ);
+
+  /**
+   * Default move constructor
+   */
+  FileStream(FileStream&&);
+
+  /**
+   * Non copyable
+   */
+  FileStream(const FileStream&) = delete;
+
+  /**
+   * Non assignable
+   */
+  FileStream& operator=(const FileStream&) = delete;
+
+  /**
+   * Move assignable
+   */
+  FileStream& operator=(FileStream&&);
+
+  /**
+   * Destructor
+   */
+  ~FileStream();
+
+  /**
+   * @brief Returns the stream
+   * @return std::iostream.
+   */
+  std::iostream& GetStream();
+
+  /**
+   * @brief Returns the file stream
+   * @return FILE.
+   * @note This class is responsible for closing the file so the caller SHOULD NOT call fclose() on the returned pointer.
+   */
+  FILE* GetFile();
+
+private:
+
+  struct Impl;
+  std::unique_ptr<Impl> mImpl;
+};
+
+} // Dali
+
+#endif // DALI_FILE_STREAM_H
diff --git a/dali/devel-api/adaptor-framework/gif-loading.cpp b/dali/devel-api/adaptor-framework/gif-loading.cpp
new file mode 100755 (executable)
index 0000000..e49fbc8
--- /dev/null
@@ -0,0 +1,1313 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ * Copyright notice for the EFL:
+ * Copyright (C) EFL developers (see AUTHORS)
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/adaptor-framework/gif-loading.h>
+
+// EXTERNAL INCLUDES
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <gif_lib.h>
+#include <cstring>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/images/pixel-data.h>
+#include <dali/internal/imaging/common/file-download.h>
+#include <dali/internal/system/common/file-reader.h>
+
+#define IMG_TOO_BIG( w, h )                                                        \
+  ( ( static_cast<unsigned long long>(w) * static_cast<unsigned long long>(h) ) >= \
+    ( (1ULL << (29 * (sizeof(void *) / 4))) - 2048) )
+
+#define LOADERR( x )                              \
+  do {                                            \
+    DALI_LOG_ERROR( x );                          \
+    goto on_error;                                \
+  } while ( 0 )
+
+namespace Dali
+{
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter *gGifLoadingLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_GIF_LOADING" );
+#endif
+
+const int IMG_MAX_SIZE = 65000;
+constexpr size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE  = 50 * 1024 * 1024;
+
+#if GIFLIB_MAJOR < 5
+const int DISPOSE_BACKGROUND = 2;       /* Set area too background color */
+const int DISPOSE_PREVIOUS = 3;         /* Restore to previous content */
+#endif
+
+struct FrameInfo
+{
+  FrameInfo()
+  : x( 0 ),
+    y( 0 ),
+    w( 0 ),
+    h( 0 ),
+    delay( 0 ),
+    transparent( -1 ),
+    dispose( DISPOSE_BACKGROUND ),
+    interlace( 0 )
+  {
+  }
+
+  int x, y, w, h;
+  unsigned short delay; // delay time in 1/100ths of a sec
+  short transparent : 10; // -1 == not, anything else == index
+  short dispose : 6; // 0, 1, 2, 3 (others invalid)
+  short interlace : 1; // interlaced or not
+};
+
+struct ImageFrame
+{
+  ImageFrame()
+  : index( 0 ),
+    data( nullptr ),
+    info(),
+    loaded( false )
+  {
+  }
+
+  ~ImageFrame()
+  {
+  }
+
+  int       index;
+  uint32_t  *data;     /* frame decoding data */
+  FrameInfo  info;     /* special image type info */
+  bool loaded : 1;
+};
+
+struct GifAnimationData
+{
+  GifAnimationData()
+  : frames( ),
+    frameCount( 0 ),
+    loopCount( 0 ),
+    currentFrame( 0 ),
+    animated( false )
+  {
+  }
+
+  std::vector<ImageFrame> frames;
+  int frameCount;
+  int loopCount;
+  int currentFrame;
+  bool animated;
+};
+
+struct LoaderInfo
+{
+  LoaderInfo()
+  : gif( nullptr ) ,
+    imageNumber ( 0 )
+  {
+  }
+
+  struct FileData
+  {
+    FileData()
+    : fileName( nullptr ),
+      globalMap ( nullptr ),
+      length( 0 ),
+      isLocalResource( true )
+    {
+    }
+
+    const char *fileName;  /**< The absolute path of the file. */
+    unsigned char *globalMap ;      /**< A pointer to the entire contents of the file that have been mapped with mmap(2). */
+    long long length;  /**< The length of the file in bytes. */
+    bool isLocalResource; /**< The flag whether the file is a local resource */
+  };
+
+  struct FileInfo
+  {
+    FileInfo()
+    : map( nullptr ),
+      position( 0 ),
+      length( 0 )
+    {
+    }
+
+    unsigned char *map;
+    int position, length; // yes - gif uses ints for file sizes.
+  };
+
+  FileData fileData;
+  GifAnimationData animated;
+  GifFileType *gif;
+  int imageNumber;
+  FileInfo fileInfo;
+};
+
+struct ImageProperties
+{
+  ImageProperties()
+  : w( 0 ),
+    h( 0 ),
+    alpha( 0 )
+  {
+  }
+
+  unsigned int w;
+  unsigned int h;
+  bool alpha;
+};
+
+/**
+ * @brief This combines R, G, B and Alpha values into a single 32-bit (ABGR) value.
+ *
+ * @param[in] animated A structure containing GIF animation data
+ * @param[in] index Frame index to be searched in GIF
+ * @return A pointer to the ImageFrame.
+ */
+inline int CombinePixelABGR( int a, int r, int g, int b )
+{
+  return ( ((a) << 24) + ((b) << 16) + ((g) << 8) + (r) );
+}
+
+inline int PixelLookup( ColorMapObject *colorMap, int index )
+{
+  return CombinePixelABGR( 0xFF, colorMap->Colors[index].Red, colorMap->Colors[index].Green, colorMap->Colors[index].Blue );
+}
+
+/**
+ * @brief Brute force find frame index - gifs are normally small so ok for now.
+ *
+ * @param[in] animated A structure containing GIF animation data
+ * @param[in] index Frame index to be searched in GIF
+ * @return A pointer to the ImageFrame.
+ */
+ImageFrame *FindFrame( const GifAnimationData &animated, int index )
+{
+  for( auto &&elem : animated.frames )
+  {
+    if( elem.index == index )
+    {
+      return const_cast<ImageFrame *>( &elem );
+    }
+  }
+  return nullptr;
+}
+
+/**
+ * @brief Fill in an image with a specific rgba color value.
+ *
+ * @param[in] data A pointer pointing to an image data
+ * @param[in] row A int containing the number of rows in an image
+ * @param[in] val A uint32_t containing rgba color value
+ * @param[in] x X-coordinate used an offset to calculate pixel position
+ * @param[in] y Y-coordinate used an offset to calculate pixel position
+ * @param[in] width Width of the image
+ * @param[in] height Height of the image
+ */
+void FillImage( uint32_t *data, int row, uint32_t val, int x, int y, int width, int height )
+{
+  int xAxis, yAxis;
+  uint32_t *pixelPosition;
+
+  for( yAxis = 0; yAxis < height; yAxis++ )
+  {
+    pixelPosition = data + ((y + yAxis) * row) + x;
+    for( xAxis = 0; xAxis < width; xAxis++ )
+    {
+      *pixelPosition = val;
+      pixelPosition++;
+    }
+  }
+}
+
+/**
+ * @brief Fill a rgba data pixle blob with a frame color (bg or trans)
+ *
+ * @param[in] data A pointer pointing to an image data
+ * @param[in] row A int containing the number of rows in an image
+ * @param[in] gif A pointer pointing to GIF File Type
+ * @param[in] frameInfo A pointer pointing to Frame Information data
+ * @param[in] x X-coordinate used an offset to calculate pixel position
+ * @param[in] y Y-coordinate used an offset to calculate pixel position
+ * @param[in] width Width of the image
+ * @param[in] height Height of the image
+ */
+void FillFrame( uint32_t *data, int row, GifFileType *gif, FrameInfo *frameInfo, int x, int y, int w, int h )
+{
+  // solid color fill for pre frame region
+  if( frameInfo->transparent < 0 )
+  {
+    ColorMapObject *colorMap;
+    int backGroundColor;
+
+    // work out color to use from colorMap
+    if( gif->Image.ColorMap )
+    {
+      colorMap = gif->Image.ColorMap;
+    }
+    else
+    {
+      colorMap = gif->SColorMap;
+    }
+    backGroundColor = gif->SBackGroundColor;
+    // and do the fill
+    FillImage( data, row,
+              CombinePixelABGR( 0xff, colorMap->Colors[backGroundColor].Red,
+                                colorMap->Colors[backGroundColor].Green,
+                                colorMap->Colors[backGroundColor].Blue ),
+              x, y, w, h );
+  }
+  // fill in region with 0 (transparent)
+  else
+  {
+    FillImage( data, row, 0, x, y, w, h );
+  }
+}
+
+/**
+ * @brief Store common fields from gif file info into frame info
+ *
+ * @param[in] gif A pointer pointing to GIF File Type
+ * @param[in] frameInfo A pointer pointing to Frame Information data
+ */
+void StoreFrameInfo( GifFileType *gif, FrameInfo *frameInfo )
+{
+  frameInfo->x = gif->Image.Left;
+  frameInfo->y = gif->Image.Top;
+  frameInfo->w = gif->Image.Width;
+  frameInfo->h = gif->Image.Height;
+  frameInfo->interlace = gif->Image.Interlace;
+}
+
+/**
+ * @brief Check if image fills "screen space" and if so, if it is transparent
+ * at all then the image could be transparent - OR if image doesnt fill,
+ * then it could be trasnparent (full coverage of screen). Some gifs will
+ * be recognized as solid here for faster rendering, but not all.
+ *
+ * @param[out] full A boolean to show whether image is transparent or not
+ * @param[in] frameInfo A pointer pointing to Frame Information data
+ * @param[in] width Width of the image
+ * @param[in] height Height of the image
+ */
+void CheckTransparency( bool &full, FrameInfo *frameInfo, int width, int height )
+{
+  if( ( frameInfo->x == 0 ) && ( frameInfo->y == 0 ) &&
+      ( frameInfo->w == width ) && ( frameInfo->h == height ) )
+  {
+    if( frameInfo->transparent >= 0 )
+    {
+      full = false;
+    }
+  }
+  else
+  {
+    full = false;
+  }
+}
+
+/**
+ * @brief Fix coords and work out an x and y inset in orig data if out of image bounds.
+ */
+void ClipCoordinates( int imageWidth, int imageHeight, int *xin, int *yin, int x0, int y0, int w0, int h0, int *x, int *y, int *w, int *h )
+{
+  if( x0 < 0 )
+  {
+    w0 += x0;
+    *xin = -x0;
+    x0 = 0;
+  }
+  if( (x0 + w0) > imageWidth )
+  {
+    w0 = imageWidth - x0;
+  }
+  if( y0 < 0 )
+  {
+    h0 += y0;
+    *yin = -y0;
+    y0 = 0;
+  }
+  if( (y0 + h0) > imageHeight )
+  {
+    h0 = imageHeight - y0;
+  }
+  *x = x0;
+  *y = y0;
+  *w = w0;
+  *h = h0;
+}
+
+/**
+ * @brief Flush out rgba frame images to save memory but skip current,
+ * previous and lastPreservedFrame frames (needed for dispose mode DISPOSE_PREVIOUS)
+ *
+ * @param[in] animated A structure containing GIF animation data
+ * @param[in] width Width of the image
+ * @param[in] height Height of the image
+ * @param[in] thisframe The current frame
+ * @param[in] prevframe The previous frame
+ * @param[in] lastPreservedFrame The last preserved frame
+ */
+void FlushFrames( GifAnimationData &animated, int width, int height, ImageFrame *thisframe, ImageFrame *prevframe, ImageFrame *lastPreservedFrame )
+{
+  DALI_LOG_INFO( gGifLoadingLogFilter, Debug::Concise, "FlushFrames() START \n" );
+
+  // target is the amount of memory we want to be under for stored frames
+  int total = 0, target = 512 * 1024;
+
+  // total up the amount of memory used by stored frames for this image
+  for( auto &&frame : animated.frames )
+  {
+    if( frame.data )
+    {
+      total++;
+    }
+  }
+  total *= ( width * height * sizeof( uint32_t ) );
+
+  DALI_LOG_INFO( gGifLoadingLogFilter, Debug::Concise, "Total used frame size: %d\n", total );
+
+  // If we use more than target (512k) for frames - flush
+  if( total > target )
+  {
+    // Clean frames (except current and previous) until below target
+    for( auto &&frame : animated.frames )
+    {
+      if( (frame.index != thisframe->index) && (!prevframe || frame.index != prevframe->index) &&
+          (!lastPreservedFrame || frame.index != lastPreservedFrame->index) )
+      {
+        if( frame.data != nullptr )
+        {
+          delete[] frame.data;
+          frame.data = nullptr;
+
+          // subtract memory used and if below target - stop flush
+          total -= ( width * height * sizeof( uint32_t ) );
+          if( total < target )
+          {
+            break;
+          }
+        }
+      }
+    }
+  }
+
+  DALI_LOG_INFO( gGifLoadingLogFilter, Debug::Concise, "FlushFrames() END \n" );
+}
+
+/**
+ * @brief allocate frame and frame info and append to list and store fields.
+ *
+ * @param[in] animated A structure containing GIF animation data
+ * @param[in] transparent Transparent index of the new frame
+ * @param[in] dispose Dispose mode of new frame
+ * @param[in] delay The frame delay of new frame
+ * @param[in] index The index of new frame
+ */
+FrameInfo *NewFrame( GifAnimationData &animated, int transparent, int dispose, int delay, int index )
+{
+  ImageFrame frame;
+
+  // record transparent index to be used or -1 if none
+  // for this SPECIFIC frame
+  frame.info.transparent = transparent;
+  // record dispose mode (3 bits)
+  frame.info.dispose = dispose;
+  // record delay (2 bytes so max 65546 /100 sec)
+  frame.info.delay = delay;
+  // record the index number we are at
+  frame.index = index;
+  // that frame is stored AT image/screen size
+
+  animated.frames.push_back( frame );
+
+  DALI_LOG_INFO( gGifLoadingLogFilter, Debug::Concise, "NewFrame: animated.frames.size() = %d\n", animated.frames.size() );
+
+  return &( animated.frames.back().info );
+}
+
+/**
+ * @brief Copy data from gif file into buffer.
+ *
+ * @param[in] gifFileType A pointer pointing to GIF File Type
+ * @param[out] buffer A pointer to buffer containing GIF raw data
+ * @param[in] len The length in bytes to be copied
+ * @return The data length of the image in bytes
+ */
+int FileRead( GifFileType *gifFileType, GifByteType *buffer, int length )
+{
+  LoaderInfo::FileInfo *fi = reinterpret_cast<LoaderInfo::FileInfo *>( gifFileType->UserData );
+
+  if( fi->position >= fi->length )
+  {
+    return 0; // if at or past end - no
+  }
+  if( (fi->position + length) >= fi->length )
+  {
+    length = fi->length - fi->position;
+  }
+  memcpy( buffer, fi->map + fi->position, length );
+  fi->position += length;
+  return length;
+}
+
+/**
+ * @brief Decode a gif image into rows then expand to 32bit into the destination
+ * data pointer.
+ */
+bool DecodeImage( GifFileType *gif, uint32_t *data, int rowpix, int xin, int yin,
+                  int transparent, int x, int y, int w, int h, bool fill )
+{
+  int intoffset[] = {0, 4, 2, 1};
+  int intjump[] = {8, 8, 4, 2};
+  int i, xx, yy, pix, gifW, gifH;
+  GifRowType *rows = NULL;
+  bool ret = false;
+  ColorMapObject *colorMap;
+  uint32_t *p;
+
+  // what we need is image size.
+  SavedImage *sp;
+  sp = &gif->SavedImages[ gif->ImageCount - 1 ];
+  if( !sp )
+  {
+    goto on_error;
+  }
+
+  gifW = sp->ImageDesc.Width;
+  gifH = sp->ImageDesc.Height;
+
+  if( ( gifW < w ) || ( gifH < h ) )
+  {
+    DALI_ASSERT_DEBUG( false && "Dimensions are bigger than the Gif image size");
+    goto on_error;
+  }
+
+  // build a blob of memory to have pointers to rows of pixels
+  // AND store the decoded gif pixels (1 byte per pixel) as welll
+  rows = static_cast<GifRowType *>(malloc( (gifH * sizeof(GifRowType) ) + ( gifW * gifH * sizeof(GifPixelType) )));
+  if( !rows )
+  {
+    goto on_error;
+  }
+
+  // fill in the pointers at the start
+  for( yy = 0; yy < gifH; yy++ )
+  {
+    rows[yy] = reinterpret_cast<unsigned char *>(rows) + (gifH * sizeof(GifRowType)) + (yy * gifW * sizeof(GifPixelType));
+  }
+
+  // if gif is interlaced, walk interlace pattern and decode into rows
+  if( gif->Image.Interlace )
+  {
+    for( i = 0; i < 4; i++ )
+    {
+      for( yy = intoffset[i]; yy < gifH; yy += intjump[i] )
+      {
+        if( DGifGetLine( gif, rows[yy], gifW ) != GIF_OK )
+        {
+          goto on_error;
+        }
+      }
+    }
+  }
+  // normal top to bottom - decode into rows
+  else
+  {
+    for( yy = 0; yy < gifH; yy++ )
+    {
+      if( DGifGetLine( gif, rows[yy], gifW ) != GIF_OK )
+      {
+        goto on_error;
+      }
+    }
+  }
+
+  // work out what colormap to use
+  if( gif->Image.ColorMap )
+  {
+    colorMap = gif->Image.ColorMap;
+  }
+  else
+  {
+    colorMap = gif->SColorMap;
+  }
+
+  // if we need to deal with transparent pixels at all...
+  if( transparent >= 0 )
+  {
+    // if we are told to FILL (overwrite with transparency kept)
+    if( fill )
+    {
+      for( yy = 0; yy < h; yy++ )
+      {
+        p = data + ((y + yy) * rowpix) + x;
+        for( xx = 0; xx < w; xx++ )
+        {
+          pix = rows[yin + yy][xin + xx];
+          if( pix != transparent )
+          {
+            *p = PixelLookup( colorMap, pix );
+          }
+          else
+          {
+            *p = 0;
+          }
+          p++;
+        }
+      }
+    }
+    // paste on top with transparent pixels untouched
+    else
+    {
+      for( yy = 0; yy < h; yy++ )
+      {
+        p = data + ((y + yy) * rowpix) + x;
+        for( xx = 0; xx < w; xx++ )
+        {
+          pix = rows[yin + yy][xin + xx];
+          if( pix != transparent )
+          {
+            *p = PixelLookup( colorMap, pix );
+          }
+          p++;
+        }
+      }
+    }
+  }
+  else
+  {
+    // walk pixels without worring about transparency at all
+    for( yy = 0; yy < h; yy++ )
+    {
+      p = data + ((y + yy) * rowpix) + x;
+      for( xx = 0; xx < w; xx++ )
+      {
+        pix = rows[yin + yy][xin + xx];
+        *p = PixelLookup( colorMap, pix );
+        p++;
+      }
+    }
+  }
+  ret = true;
+
+on_error:
+  if( rows )
+  {
+    free( rows );
+  }
+  return ret;
+}
+
+/**
+ * @brief Reader header from the gif file and populates structures accordingly.
+ *
+ * @param[in] loaderInfo A LoaderInfo structure containing file descriptor and other data about GIF.
+ * @param[out] prop A ImageProperties structure for storing information about GIF data.
+ * @param[out] error Error code
+ * @return The true or false whether reading was successful or not.
+ */
+bool ReadHeader( LoaderInfo &loaderInfo,
+                 ImageProperties &prop, //output struct
+                 int *error )
+{
+  GifAnimationData &animated = loaderInfo.animated;
+  LoaderInfo::FileData &fileData = loaderInfo.fileData;
+  bool ret = false;
+  LoaderInfo::FileInfo fileInfo;
+  GifRecordType rec;
+  GifFileType *gif = NULL;
+  // it is possible which gif file have error midle of frames,
+  // in that case we should play gif file until meet error frame.
+  int imageNumber = 0;
+  int loopCount = -1;
+  FrameInfo *frameInfo = NULL;
+  bool full = true;
+
+  if( fileData.isLocalResource )
+  {
+    Internal::Platform::FileReader fileReader( fileData.fileName );
+    FILE *fp = fileReader.GetFile();
+    if( fp == NULL )
+    {
+      return false;
+    }
+
+    if( fseek( fp, 0, SEEK_END ) <= -1 )
+    {
+      return false;
+    }
+
+    fileData.length = ftell( fp );
+    if( fileData.length <= -1 )
+    {
+      return false;
+    }
+
+    if( ( ! fseek( fp, 0, SEEK_SET ) ) )
+    {
+      fileData.globalMap = reinterpret_cast<GifByteType*>( malloc(sizeof( GifByteType ) * fileData.length ) );
+      fileData.length = fread( fileData.globalMap, sizeof( GifByteType ), fileData.length, fp);
+      fileInfo.map = fileData.globalMap;
+    }
+    else
+    {
+      return false;
+    }
+  }
+  else
+  {
+    // remote file
+    bool succeeded;
+    Dali::Vector<uint8_t> dataBuffer;
+    size_t dataSize;
+
+    succeeded = TizenPlatform::Network::DownloadRemoteFileIntoMemory( fileData.fileName, dataBuffer, dataSize,
+                                                                      MAXIMUM_DOWNLOAD_IMAGE_SIZE );
+    if( succeeded )
+    {
+      size_t blobSize = dataBuffer.Size();
+      if( blobSize > 0U )
+      {
+        // Open a file handle on the memory buffer:
+        Dali::Internal::Platform::FileReader fileReader( dataBuffer, blobSize );
+        FILE * const fp = fileReader.GetFile();
+        if ( NULL != fp )
+        {
+          if( ( ! fseek( fp, 0, SEEK_SET ) ) )
+          {
+            fileData.globalMap = reinterpret_cast<GifByteType*>( malloc(sizeof( GifByteType ) * blobSize ) );
+            fileData.length = fread( fileData.globalMap, sizeof( GifByteType ), blobSize, fp);
+            fileInfo.map = fileData.globalMap;
+          }
+          else
+          {
+            DALI_LOG_ERROR( "Error seeking within file\n" );
+          }
+        }
+        else
+        {
+          DALI_LOG_ERROR( "Error reading file\n" );
+        }
+      }
+    }
+  }
+
+  if( !fileInfo.map )
+  {
+    LOADERR("LOAD_ERROR_CORRUPT_FILE");
+  }
+  fileInfo.length = fileData.length;
+  fileInfo.position = 0;
+
+// actually ask libgif to open the file
+#if GIFLIB_MAJOR >= 5
+  gif = DGifOpen( &fileInfo, FileRead, NULL );
+#else
+  gif = DGifOpen( &fileInfo, FileRead );
+#endif
+
+  if (!gif)
+  {
+    LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
+  }
+
+  // get the gif "screen size" (the actual image size)
+  prop.w = gif->SWidth;
+  prop.h = gif->SHeight;
+
+  // if size is invalid - abort here
+  if( (prop.w < 1) || (prop.h < 1) || (prop.w > IMG_MAX_SIZE) || (prop.h > IMG_MAX_SIZE) || IMG_TOO_BIG(prop.w, prop.h) )
+  {
+    if( IMG_TOO_BIG(prop.w, prop.h) )
+    {
+      LOADERR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
+    }
+    LOADERR("LOAD_ERROR_GENERIC");
+  }
+  // walk through gif records in file to figure out info
+  do
+  {
+    if( DGifGetRecordType(gif, &rec) == GIF_ERROR )
+    {
+      // if we have a gif that ends part way through a sequence
+      // (or animation) consider it valid and just break - no error
+      if( imageNumber > 1 )
+      {
+        break;
+      }
+      LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
+    }
+
+    // get image description section
+    if( rec == IMAGE_DESC_RECORD_TYPE )
+    {
+      int img_code;
+      GifByteType *img;
+
+      // get image desc
+      if( DGifGetImageDesc(gif) == GIF_ERROR )
+      {
+        LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
+      }
+      // skip decoding and just walk image to next
+      if( DGifGetCode(gif, &img_code, &img) == GIF_ERROR )
+      {
+        LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
+      }
+      // skip till next...
+      while( img )
+      {
+        img = NULL;
+        DGifGetCodeNext( gif, &img );
+      }
+      // store geometry in the last frame info data
+      if( frameInfo )
+      {
+        StoreFrameInfo( gif, frameInfo );
+        CheckTransparency( full, frameInfo, prop.w, prop.h );
+      }
+      // or if we dont have a frameInfo entry - create one even for stills
+      else
+      {
+        // allocate and save frame with field data
+        frameInfo = NewFrame( animated, -1, 0, 0, imageNumber + 1 );
+        if (!frameInfo)
+        {
+          LOADERR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
+        }
+        // store geometry info from gif image
+        StoreFrameInfo( gif, frameInfo );
+        // check for transparency/alpha
+        CheckTransparency( full, frameInfo, prop.w, prop.h );
+      }
+      imageNumber++;
+    }
+    // we have an extension code block - for animated gifs for sure
+    else if( rec == EXTENSION_RECORD_TYPE )
+    {
+      int ext_code;
+      GifByteType *ext;
+
+      ext = NULL;
+      // get the first extension entry
+      DGifGetExtension( gif, &ext_code, &ext );
+      while( ext )
+      {
+        // graphic control extension - for animated gif data
+        // and transparent index + flag
+        if( ext_code == 0xf9 )
+        {
+          // create frame and store it in image
+          int transparencyIndex = (ext[1] & 1) ? ext[4] : -1;
+          int disposeMode = (ext[1] >> 2) & 0x7;
+          int delay = (int(ext[3]) << 8) | int(ext[2]);
+          frameInfo = NewFrame(animated, transparencyIndex, disposeMode, delay, imageNumber + 1);
+          if( !frameInfo )
+          {
+            LOADERR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
+          }
+        }
+        // netscape extension indicating loop count.
+        else if( ext_code == 0xff ) /* application extension */
+        {
+          if( !strncmp(reinterpret_cast<char *>(&ext[1]), "NETSCAPE2.0", 11) ||
+              !strncmp(reinterpret_cast<char *>(&ext[1]), "ANIMEXTS1.0", 11) )
+          {
+            ext = NULL;
+            DGifGetExtensionNext( gif, &ext );
+            if( ext[1] == 0x01 )
+            {
+              loopCount = (int(ext[3]) << 8) | int(ext[2]);
+              if( loopCount > 0 )
+              {
+                loopCount++;
+              }
+            }
+          }
+        }
+        // and continue onto the next extension entry
+        ext = NULL;
+        DGifGetExtensionNext( gif, &ext );
+      }
+    }
+  } while( rec != TERMINATE_RECORD_TYPE );
+
+  // if the gif main says we have more than one image or our image counting
+  // says so, then this image is animated - indicate this
+  if( (gif->ImageCount > 1) || (imageNumber > 1) )
+  {
+    animated.animated = 1;
+    animated.loopCount = loopCount;
+  }
+  animated.frameCount = std::min( gif->ImageCount, imageNumber );
+
+  if( !full )
+  {
+    prop.alpha = 1;
+  }
+
+  animated.currentFrame = 1;
+
+  // no errors in header scan etc. so set err and return value
+  *error = 0;
+  ret = true;
+
+on_error: // jump here on any errors to clean up
+#if (GIFLIB_MAJOR > 5) || ((GIFLIB_MAJOR == 5) && (GIFLIB_MINOR >= 1))
+  if( gif )
+  {
+    DGifCloseFile( gif, NULL );
+  }
+#else
+  if( gif )
+  {
+    DGifCloseFile( gif );
+  }
+#endif
+
+  return ret;
+}
+
+/**
+ * @brief Reader next frame of the gif file and populates structures accordingly.
+ *
+ * @param[in] loaderInfo A LoaderInfo structure containing file descriptor and other data about GIF.
+ * @param[in/out] prop A ImageProperties structure containing information about gif data.
+ * @param[out] pixels A pointer to buffer which will contain all pixel data of the frame on return.
+ * @param[out] error Error code
+ * @return The true or false whether reading was successful or not.
+ */
+bool ReadNextFrame( LoaderInfo &loaderInfo, ImageProperties &prop, //  use for w and h
+                    unsigned char *pixels, int *error )
+{
+  GifAnimationData &animated = loaderInfo.animated;
+  LoaderInfo::FileData &fileData = loaderInfo.fileData;
+  bool ret = false;
+  GifRecordType rec;
+  GifFileType *gif = NULL;
+  int index = 0, imageNumber = 0;
+  FrameInfo *frameInfo;
+  ImageFrame *frame = NULL;
+  ImageFrame *lastPreservedFrame = NULL;
+
+  index = animated.currentFrame;
+
+  // if index is invalid for animated image - error out
+  if ((animated.animated) && ((index <= 0) || (index > animated.frameCount)))
+  {
+    LOADERR("LOAD_ERROR_GENERIC");
+  }
+
+  // find the given frame index
+  frame = FindFrame( animated, index );
+  if( frame )
+  {
+    if( (frame->loaded) && (frame->data) )
+    {
+      // frame is already there and decoded - jump to end
+      goto on_ok;
+    }
+  }
+  else
+  {
+    LOADERR("LOAD_ERROR_CORRUPT_FILE");
+  }
+
+open_file:
+  // actually ask libgif to open the file
+  gif = loaderInfo.gif;
+  if( !gif )
+  {
+    loaderInfo.fileInfo.map = fileData.globalMap ;
+    if( !loaderInfo.fileInfo.map )
+    {
+      LOADERR("LOAD_ERROR_CORRUPT_FILE");
+    }
+    loaderInfo.fileInfo.length = fileData.length;
+    loaderInfo.fileInfo.position = 0;
+
+#if GIFLIB_MAJOR >= 5
+    gif = DGifOpen( &( loaderInfo.fileInfo ), FileRead, NULL );
+#else
+    gif = DGifOpen( &( loaderInfo.fileInfo ), FileRead );
+#endif
+    // if gif open failed... get out of here
+    if( !gif )
+    {
+      LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
+    }
+    loaderInfo.gif = gif;
+    loaderInfo.imageNumber = 1;
+  }
+
+  // if we want to go backwards, we likely need/want to re-decode from the
+  // start as we have nothing to build on
+  if( (index > 0) && (index < loaderInfo.imageNumber) && (animated.animated) )
+  {
+#if (GIFLIB_MAJOR > 5) || ((GIFLIB_MAJOR == 5) && (GIFLIB_MINOR >= 1))
+    if( loaderInfo.gif )
+      DGifCloseFile( loaderInfo.gif, NULL );
+#else
+    if( loaderInfo.gif )
+      DGifCloseFile( loaderInfo.gif );
+#endif
+    loaderInfo.gif = NULL;
+    loaderInfo.imageNumber = 0;
+    goto open_file;
+  }
+
+  // our current position is the previous frame we decoded from the file
+  imageNumber = loaderInfo.imageNumber;
+
+  // walk through gif records in file to figure out info
+  do
+  {
+    if( DGifGetRecordType( gif, &rec ) == GIF_ERROR )
+    {
+      LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
+    }
+
+    if( rec == EXTENSION_RECORD_TYPE )
+    {
+      int ext_code;
+      GifByteType *ext = NULL;
+      DGifGetExtension( gif, &ext_code, &ext );
+
+      while( ext )
+      {
+        ext = NULL;
+        DGifGetExtensionNext( gif, &ext );
+      }
+    }
+    // get image description section
+    else if( rec == IMAGE_DESC_RECORD_TYPE )
+    {
+      int xin = 0, yin = 0, x = 0, y = 0, w = 0, h = 0;
+      int img_code;
+      GifByteType *img;
+      ImageFrame *previousFrame = NULL;
+      ImageFrame *thisFrame = NULL;
+
+      // get image desc
+      if( DGifGetImageDesc(gif) == GIF_ERROR )
+      {
+        LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
+      }
+
+      // get the previous frame entry AND the current one to fill in
+      previousFrame = FindFrame(animated, imageNumber - 1);
+      thisFrame = FindFrame(animated, imageNumber);
+
+      // if we have a frame AND we're animated AND we have no data...
+      if( (thisFrame) && (!thisFrame->data) && (animated.animated) )
+      {
+        bool first = false;
+
+        // allocate it
+        thisFrame->data = new uint32_t[prop.w * prop.h];
+
+        if( !thisFrame->data )
+        {
+          LOADERR("LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
+        }
+
+        // if we have no prior frame OR prior frame data... empty
+        if( (!previousFrame) || (!previousFrame->data) )
+        {
+          first = true;
+          frameInfo = &(thisFrame->info);
+          memset( thisFrame->data, 0, prop.w * prop.h * sizeof(uint32_t) );
+        }
+        // we have a prior frame to copy data from...
+        else
+        {
+          frameInfo = &( previousFrame->info );
+
+          // fix coords of sub image in case it goes out...
+          ClipCoordinates( prop.w, prop.h, &xin, &yin,
+                           frameInfo->x, frameInfo->y, frameInfo->w, frameInfo->h,
+                           &x, &y, &w, &h );
+
+          // if dispose mode is not restore - then copy pre frame
+          if( frameInfo->dispose != DISPOSE_PREVIOUS )
+          {
+            memcpy( thisFrame->data, previousFrame->data, prop.w * prop.h * sizeof(uint32_t) );
+          }
+
+          // if dispose mode is "background" then fill with bg
+          if( frameInfo->dispose == DISPOSE_BACKGROUND )
+          {
+            FillFrame( thisFrame->data, prop.w, gif, frameInfo, x, y, w, h );
+          }
+          else if( frameInfo->dispose == DISPOSE_PREVIOUS ) // GIF_DISPOSE_RESTORE
+          {
+            int prevIndex = 2;
+            do
+            {
+              // Find last preserved frame.
+              lastPreservedFrame = FindFrame( animated, imageNumber - prevIndex );
+              if( ! lastPreservedFrame )
+              {
+                LOADERR( "LOAD_ERROR_LAST_PRESERVED_FRAME_NOT_FOUND" );
+              }
+              prevIndex++;
+            } while( lastPreservedFrame && lastPreservedFrame->info.dispose == DISPOSE_PREVIOUS );
+
+            if ( lastPreservedFrame )
+            {
+              memcpy( thisFrame->data, lastPreservedFrame->data, prop.w * prop.h * sizeof(uint32_t) );
+            }
+          }
+        }
+        // now draw this frame on top
+        frameInfo = &( thisFrame->info );
+        ClipCoordinates( prop.w, prop.h, &xin, &yin,
+                         frameInfo->x, frameInfo->y, frameInfo->w, frameInfo->h,
+                         &x, &y, &w, &h );
+        if( !DecodeImage( gif, thisFrame->data, prop.w,
+                          xin, yin, frameInfo->transparent,
+                          x, y, w, h, first) )
+        {
+          LOADERR("LOAD_ERROR_CORRUPT_FILE");
+        }
+
+        // mark as loaded and done
+        thisFrame->loaded = true;
+
+        FlushFrames( animated, prop.w, prop.h, thisFrame, previousFrame, lastPreservedFrame );
+      }
+      // if we have a frame BUT the image is not animated. different
+      // path
+      else if( (thisFrame) && (!thisFrame->data) && (!animated.animated) )
+      {
+        // if we don't have the data decoded yet - decode it
+        if( (!thisFrame->loaded) || (!thisFrame->data) )
+        {
+          // use frame info but we WONT allocate frame pixels
+          frameInfo = &( thisFrame->info );
+          ClipCoordinates( prop.w, prop.h, &xin, &yin,
+                           frameInfo->x, frameInfo->y, frameInfo->w, frameInfo->h,
+                           &x, &y, &w, &h );
+
+          // clear out all pixels
+          FillFrame( reinterpret_cast<uint32_t *>(pixels), prop.w, gif, frameInfo, 0, 0, prop.w, prop.h );
+
+          // and decode the gif with overwriting
+          if( !DecodeImage( gif, reinterpret_cast<uint32_t *>(pixels), prop.w,
+                            xin, yin, frameInfo->transparent, x, y, w, h, true) )
+          {
+            LOADERR("LOAD_ERROR_CORRUPT_FILE");
+          }
+
+          // mark as loaded and done
+          thisFrame->loaded = true;
+        }
+        // flush mem we don't need (at expense of decode cpu)
+      }
+      else
+      {
+        // skip decoding and just walk image to next
+        if( DGifGetCode( gif, &img_code, &img ) == GIF_ERROR )
+        {
+          LOADERR("LOAD_ERROR_UNKNOWN_FORMAT");
+        }
+
+        while( img )
+        {
+          img = NULL;
+          DGifGetCodeNext( gif, &img );
+        }
+      }
+
+      imageNumber++;
+      // if we found the image we wanted - get out of here
+      if( imageNumber > index )
+      {
+        break;
+      }
+    }
+  } while( rec != TERMINATE_RECORD_TYPE );
+
+  // if we are at the end of the animation or not animated, close file
+  loaderInfo.imageNumber = imageNumber;
+  if( (animated.frameCount <= 1) || (rec == TERMINATE_RECORD_TYPE) )
+  {
+#if (GIFLIB_MAJOR > 5) || ((GIFLIB_MAJOR == 5) && (GIFLIB_MINOR >= 1))
+    if( loaderInfo.gif )
+    {
+      DGifCloseFile( loaderInfo.gif, NULL );
+    }
+#else
+    if( loaderInfo.gif )
+    {
+      DGifCloseFile( loaderInfo.gif );
+    }
+#endif
+
+    loaderInfo.gif = NULL;
+    loaderInfo.imageNumber = 0;
+  }
+
+on_ok:
+  // no errors in header scan etc. so set err and return value
+  *error = 0;
+  ret = true;
+
+  // if it was an animated image we need to copy the data to the
+  // pixels for the image from the frame holding the data
+  if( animated.animated && frame->data )
+  {
+    memcpy( pixels, frame->data, prop.w * prop.h * sizeof( uint32_t ) );
+  }
+
+on_error: // jump here on any errors to clean up
+  return ret;
+}
+
+} // unnamed namespace
+
+struct GifLoading::Impl
+{
+public:
+  Impl( const std::string& url, bool isLocalResource )
+  : mUrl( url )
+  {
+    loaderInfo.gif = nullptr;
+    int error;
+    loaderInfo.fileData.fileName = mUrl.c_str();
+    loaderInfo.fileData.isLocalResource = isLocalResource;
+
+    ReadHeader( loaderInfo, imageProperties, &error );
+  }
+
+  // Moveable but not copyable
+
+  Impl( const Impl& ) = delete;
+  Impl& operator=( const Impl& ) = delete;
+  Impl( Impl&& ) = default;
+  Impl& operator=( Impl&& ) = default;
+
+  ~Impl()
+  {
+    if( loaderInfo.fileData.globalMap  )
+    {
+      free( loaderInfo.fileData.globalMap );
+      loaderInfo.fileData.globalMap  = nullptr;
+    }
+
+    // Delete all image frames
+    for( auto &&frame : loaderInfo.animated.frames )
+    {
+      if( frame.data != nullptr )
+      {
+        // De-allocate memory of the frame data.
+        delete[] frame.data;
+        frame.data = nullptr;
+      }
+    }
+  }
+
+  std::string mUrl;
+  LoaderInfo loaderInfo;
+  ImageProperties imageProperties;
+};
+
+std::unique_ptr<GifLoading> GifLoading::New( const std::string &url, bool isLocalResource )
+{
+  return std::unique_ptr<GifLoading>( new GifLoading( url, isLocalResource ) );
+}
+
+GifLoading::GifLoading( const std::string &url, bool isLocalResource )
+: mImpl( new GifLoading::Impl( url, isLocalResource ) )
+{
+}
+
+
+GifLoading::~GifLoading()
+{
+  delete mImpl;
+}
+
+bool GifLoading::LoadNextNFrames( int frameStartIndex, int count, std::vector<Dali::PixelData> &pixelData )
+{
+  int error;
+  bool ret = false;
+
+  const int bufferSize = mImpl->imageProperties.w * mImpl->imageProperties.h * sizeof( uint32_t );
+
+  DALI_LOG_INFO( gGifLoadingLogFilter, Debug::Concise, "LoadNextNFrames( frameStartIndex:%d, count:%d )\n", frameStartIndex, count );
+
+  for( int i = 0; i < count; ++i )
+  {
+    auto pixelBuffer = new unsigned char[ bufferSize ];
+
+    mImpl->loaderInfo.animated.currentFrame = 1 + ( (frameStartIndex + i) % mImpl->loaderInfo.animated.frameCount );
+
+    if( ReadNextFrame( mImpl->loaderInfo, mImpl->imageProperties, pixelBuffer, &error ) )
+    {
+      if( pixelBuffer )
+      {
+        pixelData.push_back( Dali::PixelData::New( pixelBuffer, bufferSize,
+                                                   mImpl->imageProperties.w, mImpl->imageProperties.h,
+                                                   Dali::Pixel::RGBA8888, Dali::PixelData::DELETE_ARRAY) );
+        ret = true;
+      }
+    }
+  }
+
+  return ret;
+}
+
+bool GifLoading::LoadAllFrames( std::vector<Dali::PixelData> &pixelData, Dali::Vector<uint32_t> &frameDelays )
+{
+  if( LoadFrameDelays( frameDelays ) )
+  {
+    return LoadNextNFrames( 0, mImpl->loaderInfo.animated.frameCount, pixelData );
+  }
+  return false;
+}
+
+ImageDimensions GifLoading::GetImageSize()
+{
+  return ImageDimensions( mImpl->imageProperties.w, mImpl->imageProperties.h );
+}
+
+int GifLoading::GetImageCount()
+{
+  return mImpl->loaderInfo.animated.frameCount;
+}
+
+bool GifLoading::LoadFrameDelays( Dali::Vector<uint32_t> &frameDelays )
+{
+  frameDelays.Clear();
+
+  for( auto &&elem : mImpl->loaderInfo.animated.frames )
+  {
+    // Read frame delay time, multiply 10 to change time unit to milliseconds
+    frameDelays.PushBack( elem.info.delay * 10 );
+  }
+
+  return true;
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/gif-loading.h b/dali/devel-api/adaptor-framework/gif-loading.h
new file mode 100755 (executable)
index 0000000..6143f15
--- /dev/null
@@ -0,0 +1,132 @@
+#ifndef DALI_INTERNAL_GIF_LOADING_H
+#define DALI_INTERNAL_GIF_LOADING_H
+
+/*
+ * Copyright (c) 2019 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 <cstdint>
+#include <memory>
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/math/uint-16-pair.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+class PixelData;
+typedef Dali::Uint16Pair ImageDimensions;
+
+/**
+ * Class to manage loading frames of an animated gif in small chunks. Lazy initializes only when
+ * data is actually needed.
+ * Note, once the GIF has loaded, the undecoded data will reside in memory until this object
+ * is released. (This is to speed up frame loads, which would otherwise have to re-acquire the
+ * data from disk)
+ */
+class DALI_ADAPTOR_API GifLoading
+{
+public:
+
+  /**
+   * Create a GifLoading with the given url and resourceType.
+   * @param[in] url The url of the gif image to load
+   * @param[in] isLocalResource The true or false whether this is a local resource.
+   * @return A newly created GifLoading.
+   */
+  static std::unique_ptr<GifLoading> New( const std::string& url, bool isLocalResource );
+
+  /**
+   * @brief Constructor
+   *
+   * Construct a Loader with the given URL
+   * @param[in] url The url of the gif image to load
+   * @param[in] isLocalResource The true or false whether this is a local resource.
+   */
+  GifLoading( const std::string& url, bool isLocalResource );
+
+  // Moveable but not copyable
+
+  GifLoading( const GifLoading& ) = delete;
+  GifLoading& operator=( const GifLoading& ) = delete;
+  GifLoading( GifLoading&& ) = default;
+  GifLoading& operator=( GifLoading&& ) = default;
+
+  /**
+   * @brief Destructor
+   */
+  ~GifLoading();
+
+  /**
+   * @brief Load the next N Frames of the gif.
+   *
+   * @note This function will load the entire gif into memory if not already loaded.
+   * @param[in] frameStartIndex The frame counter to start from. Will usually be the next frame
+   * after the previous invocation of this method, or 0 to start.
+   * @param[in] count The number of frames to load
+   * @param[out] pixelData The vector in which to return the frame data
+   * @return True if the frame data was successfully loaded
+   */
+  bool LoadNextNFrames( int frameStartIndex, int count, std::vector<Dali::PixelData>& pixelData );
+
+  /**
+   * @brief Load all frames of an animated gif file.
+   *
+   * @note This function will load the entire gif into memory if not already loaded.
+   *
+   * @param[out] pixelData The loaded pixel data for each frame.
+   * @param[out] frameDelays The loaded delay time for each frame.
+   *
+   * @return True if the loading succeeded, false otherwise.
+   */
+  bool LoadAllFrames( std::vector<Dali::PixelData>& pixelData, Dali::Vector<uint32_t>& frameDelays );
+
+  /**
+   * @brief Get the size of a gif image.
+   *
+   * @note This function will load the entire gif into memory if not already loaded.
+   *
+   * @return The width and height in pixels of the gif image.
+   */
+  ImageDimensions GetImageSize();
+
+  /**
+   * @brief Get the number of frames in this gif.
+   *
+   * @note This function will load the entire gif into memory if not already loaded.
+   */
+  int GetImageCount();
+
+  /**
+   * @brief Load the frame delay counts into the provided array.
+   *
+   * @note This function will load the entire gif into memory if not already loaded.
+   * @param[in] frameDelays a vector to write the frame delays into
+   * @return true if the frame delays were successfully loaded
+   */
+  bool LoadFrameDelays( Dali::Vector<uint32_t>& frameDelays );
+
+private:
+  struct Impl;
+  Impl* mImpl;
+};
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_GIF_LOADING_H
diff --git a/dali/devel-api/adaptor-framework/image-loader-input.h b/dali/devel-api/adaptor-framework/image-loader-input.h
new file mode 100755 (executable)
index 0000000..f2e7d24
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef DALI_TIZEN_PLATFORM_IMAGE_LOADER_INPUT_H
+#define DALI_TIZEN_PLATFORM_IMAGE_LOADER_INPUT_H
+
+/*
+ * Copyright (c) 2019 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 <cstdio>
+#include <dali/public-api/images/image-operations.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/integration-api/bitmap.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+namespace ImageLoader
+{
+
+/**
+ * @brief A simple immutable struct to bundle together parameters for scaling an image.
+ */
+class ScalingParameters
+{
+public:
+  ScalingParameters( ImageDimensions dimensions = ImageDimensions(), FittingMode::Type fittingMode = FittingMode::DEFAULT, SamplingMode::Type samplingMode = SamplingMode::DEFAULT ) :
+    dimensions(dimensions), scalingMode(fittingMode), samplingMode(samplingMode) {}
+  const ImageDimensions dimensions;
+  const FittingMode::Type scalingMode;
+  const SamplingMode::Type samplingMode;
+};
+
+  /**
+   * @brief Bundle-up the data pushed into an image loader.
+   */
+struct Input
+{
+  Input( FILE* file, ScalingParameters scalingParameters = ScalingParameters(), bool reorientationRequested = true ) :
+    file(file), scalingParameters(scalingParameters), reorientationRequested(reorientationRequested) {}
+  FILE* file;
+  ScalingParameters scalingParameters;
+  bool reorientationRequested;
+};
+
+
+using LoadBitmapFunction = bool( * )( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& pixelData );
+using LoadBitmapHeaderFunction = bool( * )( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+/**
+ * Stores the magic bytes, and the loader and header functions used for each image loader.
+ */
+struct BitmapLoader
+{
+  unsigned char magicByte1;        ///< The first byte in the file should be this
+  unsigned char magicByte2;        ///< The second byte in the file should be this
+  LoadBitmapFunction loader;       ///< The function which decodes the file
+  LoadBitmapHeaderFunction header; ///< The function which decodes the header of the file
+  Dali::Integration::Bitmap::Profile profile;         ///< The kind of bitmap to be created
+                                   ///  (addressable packed pixels or an opaque compressed blob).
+};
+
+} // ImageLoader
+} // Dali
+
+#endif // DALI_TIZEN_PLATFORM_IMAGE_LOADER_INPUT_H
diff --git a/dali/devel-api/adaptor-framework/image-loader-plugin.h b/dali/devel-api/adaptor-framework/image-loader-plugin.h
new file mode 100755 (executable)
index 0000000..02594f6
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef DALI_IMAGE_LOADING_PLUGIN_H
+#define DALI_IMAGE_LOADING_PLUGIN_H
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/image-loader-input.h>
+
+namespace Dali
+{
+
+/**
+ * @brief
+ */
+class ImageLoaderPlugin
+{
+public:
+
+  /**
+   * @brief Constructor.
+   */
+  ImageLoaderPlugin(){}
+
+  /**
+   * @brief Destructor.
+   */
+  virtual ~ImageLoaderPlugin(){}
+
+  /**
+   * @brief Get the image decorder
+   * @param[in] filename The path to the resource.
+   * @return BitmapLoader
+   */
+  virtual const ImageLoader::BitmapLoader* BitmapLoaderLookup( const std::string& filename ) const = 0;
+
+  /**
+   * @brief Function pointer called in adaptor to create a image loading plugin instance.
+   * @return Pointer to the newly created plugin object
+   */
+  typedef ImageLoaderPlugin* CreateImageLoaderPlugin( void );
+
+  /**
+   * @brief Function pointer called in adaptor to destory a image loading plugin instance.
+   */
+  typedef void DestroyImageLoaderPlugin( ImageLoaderPlugin* plugin );
+
+};
+
+} // namespace Dali;
+
+#endif
diff --git a/dali/devel-api/adaptor-framework/image-loading.cpp b/dali/devel-api/adaptor-framework/image-loading.cpp
new file mode 100644 (file)
index 0000000..aed3189
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/image-loading.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/object/property-map.h>
+#include <dali/internal/imaging/common/image-loader.h>
+#include <dali/internal/imaging/common/file-download.h>
+#include <dali/internal/system/common/file-reader.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+
+namespace Dali
+{
+
+namespace
+{
+
+// limit maximum image down load size to 50 MB
+const size_t MAXIMUM_DOWNLOAD_IMAGE_SIZE  = 50 * 1024 * 1024 ;
+
+}
+
+Devel::PixelBuffer LoadImageFromFile( const std::string& url, ImageDimensions size, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection )
+{
+  Integration::BitmapResourceType resourceType( size, fittingMode, samplingMode, orientationCorrection );
+
+  Internal::Platform::FileReader fileReader( url );
+  FILE * const fp = fileReader.GetFile();
+  if( fp != NULL )
+  {
+    Dali::Devel::PixelBuffer bitmap;
+    bool success = TizenPlatform::ImageLoader::ConvertStreamToBitmap( resourceType, url, fp, bitmap );
+    if( success && bitmap )
+    {
+      return bitmap;
+    }
+  }
+  return Dali::Devel::PixelBuffer();
+}
+
+ImageDimensions GetClosestImageSize( const std::string& filename,
+                                     ImageDimensions size,
+                                     FittingMode::Type fittingMode,
+                                     SamplingMode::Type samplingMode,
+                                     bool 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;
+}
+
+ImageDimensions GetOriginalImageSize( const std::string& filename )
+{
+   return TizenPlatform::ImageLoader::GetClosestImageSize( filename, ImageDimensions(0, 0), FittingMode::DEFAULT, SamplingMode::BOX_THEN_LINEAR, true );
+}
+
+Devel::PixelBuffer DownloadImageSynchronously( const std::string& url, ImageDimensions size, FittingMode::Type fittingMode, SamplingMode::Type samplingMode, bool orientationCorrection )
+{
+  Integration::BitmapResourceType resourceType( size, fittingMode, samplingMode, orientationCorrection );
+
+  bool succeeded;
+  Dali::Vector<uint8_t> dataBuffer;
+  size_t dataSize;
+
+  succeeded = TizenPlatform::Network::DownloadRemoteFileIntoMemory( url, dataBuffer, dataSize,
+                                                                    MAXIMUM_DOWNLOAD_IMAGE_SIZE );
+  if( succeeded )
+  {
+    size_t blobSize = dataBuffer.Size();
+
+    DALI_ASSERT_DEBUG( blobSize > 0U );
+
+    if( blobSize > 0U )
+    {
+      // Open a file handle on the memory buffer:
+      Dali::Internal::Platform::FileReader fileReader( dataBuffer, blobSize );
+      FILE * const fp = fileReader.GetFile();
+      if ( NULL != fp )
+      {
+        Dali::Devel::PixelBuffer bitmap;
+        bool result = TizenPlatform::ImageLoader::ConvertStreamToBitmap(
+          resourceType,
+          url,
+          fp,
+          bitmap );
+
+        if ( result && bitmap )
+        {
+          return bitmap;
+        }
+        else
+        {
+          DALI_LOG_WARNING( "Unable to decode bitmap supplied as in-memory blob.\n" );
+        }
+      }
+    }
+  }
+  return Dali::Devel::PixelBuffer();
+}
+
+unsigned int GetMaxTextureSize()
+{
+  return TizenPlatform::ImageLoader::GetMaxTextureSize();
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/image-loading.h b/dali/devel-api/adaptor-framework/image-loading.h
new file mode 100755 (executable)
index 0000000..7230a19
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef DALI_IMAGE_LOADING_H
+#define DALI_IMAGE_LOADING_H
+
+/*
+ * Copyright (c) 2018 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/image-operations.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+
+namespace Dali
+{
+
+/**
+ * @brief Load an image synchronously from local file.
+ *
+ * @note This method is thread safe, i.e. can be called from any thread.
+ *
+ * @param [in] url The URL of the image file to load.
+ * @param [in] size The width and height to fit the loaded image to, 0.0 means whole image
+ * @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 PixelBuffer object or an empty handle in case loading failed.
+ */
+DALI_ADAPTOR_API Devel::PixelBuffer LoadImageFromFile(
+  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 Determine the size of an image that LoadImageFromFile will provide when
+ * given the same image loading parameters.
+ *
+ * This is a synchronous request.
+ * This function is used to determine the size of an image before it has loaded.
+ * @param[in] filename name of the image.
+ * @param[in] size The requested size for the image.
+ * @param[in] fittingMode The method to use to map the source image to the desired
+ * dimensions.
+ * @param[in] samplingMode The image filter to use if the image needs to be
+ * downsampled to the requested size.
+ * @param[in] orientationCorrection Whether to use image metadata to rotate or
+ * flip the image, e.g., from portrait to landscape.
+ * @return dimensions that image will have if it is loaded with given parameters.
+ */
+DALI_ADAPTOR_API ImageDimensions GetClosestImageSize(
+  const std::string& filename,
+  ImageDimensions size = ImageDimensions(0, 0),
+  FittingMode::Type fittingMode = FittingMode::DEFAULT,
+  SamplingMode::Type samplingMode = SamplingMode::BOX_THEN_LINEAR ,
+  bool orientationCorrection = true );
+
+/**
+ * @brief Get the size of an original image
+ * @param[in] filename name of the image.
+ *
+ * @return dimensions to original image
+ */
+DALI_ADAPTOR_API ImageDimensions GetOriginalImageSize(
+  const std::string& filename);
+
+/**
+ * @brief Load an image synchronously from a remote resource.
+ *
+ * @param [in] url The URL of the image file to load.
+ * @param [in] size The width and height to fit the loaded image to, 0.0 means whole image
+ * @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 PixelBuffer object or an empty handle in case downloading or decoding failed.
+ */
+DALI_ADAPTOR_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 get the maximum texture size.
+ *
+ * @return The maximum texture size
+ */
+DALI_ADAPTOR_API unsigned int GetMaxTextureSize();
+
+} // Dali
+
+#endif // DALI_IMAGE_LOADING_H
diff --git a/dali/devel-api/adaptor-framework/input-method-context.cpp b/dali/devel-api/adaptor-framework/input-method-context.cpp
new file mode 100755 (executable)
index 0000000..ae4d1c6
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/adaptor-framework/input-method-context.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/input/common/input-method-context-impl.h>
+
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+
+namespace Dali
+{
+
+InputMethodContext::InputMethodContext() = default;
+
+InputMethodContext::~InputMethodContext() = default;
+
+InputMethodContext InputMethodContext::New()
+{
+  return InputMethodContext::New( Actor() );
+}
+
+InputMethodContext InputMethodContext::New( Actor actor )
+{
+  Internal::Adaptor::InputMethodContextPtr inputMethodContext = Internal::Adaptor::InputMethodContext::New( actor );
+
+  if( inputMethodContext )
+  {
+    inputMethodContext->Initialize();
+  }
+
+  return InputMethodContext( inputMethodContext.Get() );
+}
+
+InputMethodContext::InputMethodContext( const InputMethodContext& inputMethodContext )
+: BaseHandle( inputMethodContext )
+{
+}
+
+InputMethodContext& InputMethodContext::operator=( const InputMethodContext& inputMethodContext )
+{
+ if( *this != inputMethodContext )
+ {
+   BaseHandle::operator=( inputMethodContext );
+ }
+ return *this;
+}
+
+InputMethodContext InputMethodContext::DownCast( BaseHandle handle )
+{
+  return InputMethodContext( dynamic_cast< Internal::Adaptor::InputMethodContext* >( handle.GetObjectPtr() ) );
+}
+
+void InputMethodContext::Finalize()
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).Finalize();
+}
+
+void InputMethodContext::Activate()
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).Activate();
+}
+
+void InputMethodContext::Deactivate()
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).Deactivate();
+}
+
+bool InputMethodContext::RestoreAfterFocusLost() const
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).RestoreAfterFocusLost();
+}
+
+void InputMethodContext::SetRestoreAfterFocusLost( bool toggle )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).SetRestoreAfterFocusLost( toggle );
+}
+
+void InputMethodContext::Reset()
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).Reset();
+}
+
+void InputMethodContext::NotifyCursorPosition()
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).NotifyCursorPosition();
+}
+
+void InputMethodContext::SetCursorPosition( unsigned int SetCursorPosition )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).SetCursorPosition( SetCursorPosition );
+}
+
+unsigned int InputMethodContext::GetCursorPosition() const
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).GetCursorPosition();
+}
+
+void InputMethodContext::SetSurroundingText( const std::string& text )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).SetSurroundingText( text );
+}
+
+const std::string& InputMethodContext::GetSurroundingText() const
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).GetSurroundingText();
+}
+
+void InputMethodContext::NotifyTextInputMultiLine( bool multiLine )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).NotifyTextInputMultiLine( multiLine );
+}
+
+InputMethodContext::TextDirection InputMethodContext::GetTextDirection()
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).GetTextDirection();
+}
+
+Rect<int> InputMethodContext::GetInputMethodArea()
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).GetInputMethodArea();
+}
+
+void InputMethodContext::ApplyOptions( const InputMethodOptions& options )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).ApplyOptions( options );
+}
+
+void InputMethodContext::SetInputPanelData( const std::string& data )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).SetInputPanelData( data );
+}
+
+void InputMethodContext::GetInputPanelData( std::string& data )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).GetInputPanelData( data );
+}
+
+Dali::InputMethodContext::State InputMethodContext::GetInputPanelState()
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).GetInputPanelState();
+}
+
+void InputMethodContext::SetReturnKeyState( bool visible )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).SetReturnKeyState( visible );
+}
+
+void InputMethodContext::AutoEnableInputPanel( bool enabled )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).AutoEnableInputPanel( enabled );
+}
+
+void InputMethodContext::ShowInputPanel()
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).ShowInputPanel();
+}
+
+void InputMethodContext::HideInputPanel()
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).HideInputPanel();
+}
+
+Dali::InputMethodContext::KeyboardType InputMethodContext::GetKeyboardType()
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).GetKeyboardType();
+}
+
+std::string InputMethodContext::GetInputPanelLocale()
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).GetInputPanelLocale();
+}
+
+void InputMethodContext::SetContentMIMETypes( const std::string& mimeTypes )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).SetContentMIMETypes( mimeTypes );
+}
+
+bool InputMethodContext::FilterEventKey( const Dali::KeyEvent& keyEvent )
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).FilterEventKey( keyEvent );
+}
+
+void InputMethodContext::AllowTextPrediction( bool prediction )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).AllowTextPrediction( prediction );
+}
+
+bool InputMethodContext::IsTextPredictionAllowed() const
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).IsTextPredictionAllowed();
+}
+
+void InputMethodContext::SetInputPanelLanguage( Dali::InputMethodContext::InputPanelLanguage language )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).SetInputPanelLanguage( language );
+}
+
+Dali::InputMethodContext::InputPanelLanguage InputMethodContext::GetInputPanelLanguage() const
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).GetInputPanelLanguage();
+}
+
+void InputMethodContext::SetInputPanelPosition( unsigned int x, unsigned int y )
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).SetInputPanelPosition( x, y );
+}
+
+void InputMethodContext::GetPreeditStyle( PreEditAttributeDataContainer& attrs ) const
+{
+  Internal::Adaptor::InputMethodContext::GetImplementation(*this).GetPreeditStyle( attrs );
+}
+
+// Signals
+InputMethodContext::ActivatedSignalType& InputMethodContext::ActivatedSignal()
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).ActivatedSignal();
+}
+
+InputMethodContext::KeyboardEventSignalType& InputMethodContext::EventReceivedSignal()
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).EventReceivedSignal();
+}
+
+InputMethodContext::StatusSignalType& InputMethodContext::StatusChangedSignal()
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).StatusChangedSignal();
+}
+
+InputMethodContext::KeyboardResizedSignalType& InputMethodContext::ResizedSignal()
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).ResizedSignal();
+}
+
+InputMethodContext::LanguageChangedSignalType& InputMethodContext::LanguageChangedSignal()
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).LanguageChangedSignal();
+}
+
+InputMethodContext::KeyboardTypeSignalType& InputMethodContext::KeyboardTypeChangedSignal()
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).KeyboardTypeChangedSignal();
+}
+
+InputMethodContext::ContentReceivedSignalType& InputMethodContext::ContentReceivedSignal()
+{
+  return Internal::Adaptor::InputMethodContext::GetImplementation(*this).ContentReceivedSignal();
+}
+
+InputMethodContext::InputMethodContext(Internal::Adaptor::InputMethodContext *impl)
+  : BaseHandle(impl)
+{
+}
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/input-method-context.h b/dali/devel-api/adaptor-framework/input-method-context.h
new file mode 100755 (executable)
index 0000000..04a8e72
--- /dev/null
@@ -0,0 +1,607 @@
+#ifndef DALI_INPUT_METHOD_CONTEXT_H
+#define DALI_INPUT_METHOD_CONTEXT_H
+
+/*
+ * Copyright (c) 2019 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/events/key-event.h>
+#include <dali/public-api/common/dali-vector.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+#include <dali/devel-api/adaptor-framework/input-method-options.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class InputMethodContext;
+}
+}
+
+class Actor;
+
+/**
+ * @brief The InputMethodContext class
+ *
+ * Specifically manages the ecore input method framework which enables the virtual or hardware keyboards.
+ */
+class DALI_ADAPTOR_API InputMethodContext : public BaseHandle
+{
+public:
+
+  /**
+   * @brief The direction of text.
+   */
+  enum TextDirection
+  {
+    LeftToRight,
+    RightToLeft,
+  };
+
+  /**
+   * @brief Events that are generated by the InputMethodContext.
+   */
+  enum EventType
+  {
+    VOID,                ///< No event
+    PRE_EDIT,             ///< Pre-Edit changed
+    COMMIT,              ///< Commit recieved
+    DELETE_SURROUNDING,   ///< Event to delete a range of characters from the string
+    GET_SURROUNDING,      ///< Event to query string and cursor position
+    PRIVATE_COMMAND       ///< Private command sent from the input panel
+  };
+
+  /**
+   * @brief Enumeration for state of the input panel.
+   */
+  enum State
+  {
+    DEFAULT = 0,   ///< Unknown state
+    SHOW,          ///< Input panel is shown
+    HIDE,          ///< Input panel is hidden
+    WILL_SHOW      ///< Input panel in process of being shown
+  };
+
+  /**
+   * @brief Enumeration for the type of Keyboard.
+   */
+  enum KeyboardType
+  {
+    SOFTWARE_KEYBOARD,  ///< Software keyboard (Virtual keyboard) is default
+    HARDWARE_KEYBOARD   ///< Hardware keyboard
+  };
+
+  /**
+   * @brief Enumeration for the language mode of the input panel.
+   */
+  enum class InputPanelLanguage
+  {
+    AUTOMATIC,    ///< IME Language automatically set depending on the system display
+    ALPHABET      ///< Latin alphabet at all times
+  };
+
+  /**
+   * @brief Enumeration for the preedit style types.
+   */
+  enum class PreeditStyle
+  {
+    NONE,                    ///< None style
+    UNDERLINE,               ///< Underline substring style
+    REVERSE,                 ///< Reverse substring style
+    HIGHLIGHT,               ///< Highlight substring style
+    CUSTOM_PLATFORM_STYLE_1, ///< Custom style for platform
+    CUSTOM_PLATFORM_STYLE_2, ///< Custom style for platform
+    CUSTOM_PLATFORM_STYLE_3, ///< Custom style for platform
+    CUSTOM_PLATFORM_STYLE_4  ///< Custom style for platform
+  };
+
+  /**
+   * @brief This structure is for the preedit style types and indices.
+   */
+  struct PreeditAttributeData
+  {
+    PreeditAttributeData()
+    : preeditType( PreeditStyle::NONE ),
+      startIndex( 0 ),
+      endIndex( 0 )
+    {
+    }
+
+    PreeditStyle preeditType;  /// The preedit style type
+    unsigned int startIndex;   /// The start index of preedit
+    unsigned int endIndex;     /// The end index of preedit
+  };
+
+  /**
+   * @brief This structure is used to pass on data from the InputMethodContext regarding predictive text.
+   */
+  struct EventData
+  {
+    /**
+     * @brief Default Constructor.
+     */
+    EventData()
+    : predictiveString(),
+      eventName( VOID ),
+      cursorOffset( 0 ),
+      numberOfChars ( 0 )
+    {
+    };
+
+    /**
+     * @brief Constructor
+     *
+     * @param[in] aEventName The name of the event from the InputMethodContext.
+     * @param[in] aPredictiveString The pre-edit or commit string.
+     * @param[in] aCursorOffset Start position from the current cursor position to start deleting characters.
+     * @param[in] aNumberOfChars The number of characters to delete from the cursorOffset.
+     */
+    EventData( EventType aEventName, const std::string& aPredictiveString, int aCursorOffset, int aNumberOfChars )
+    : predictiveString( aPredictiveString ),
+      eventName( aEventName ),
+      cursorOffset( aCursorOffset ),
+      numberOfChars( aNumberOfChars )
+    {
+    }
+
+    // Data
+    std::string predictiveString; ///< The pre-edit or commit string.
+    EventType eventName;           ///< The name of the event from the InputMethodContext.
+    int cursorOffset;             ///< Start position from the current cursor position to start deleting characters.
+    int numberOfChars;            ///< number of characters to delete from the cursorOffset.
+  };
+
+  /**
+   * @brief Data required by InputMethodContext from the callback
+   */
+  struct CallbackData
+  {
+    /**
+     * @brief Constructor
+     */
+    CallbackData()
+    : currentText(),
+      cursorPosition( 0 ),
+      update( false ),
+      preeditResetRequired( false )
+    {
+    }
+
+    /**
+     * @brief Constructor
+     * @param[in] aUpdate True if cursor position needs to be updated
+     * @param[in] aCursorPosition new position of cursor
+     * @param[in] aCurrentText current text string
+     * @param[in] aPreeditResetRequired flag if preedit reset is required.
+     */
+    CallbackData( bool aUpdate, int aCursorPosition, const std::string& aCurrentText, bool aPreeditResetRequired )
+    : currentText( aCurrentText ),
+      cursorPosition( aCursorPosition ),
+      update( aUpdate ),
+      preeditResetRequired( aPreeditResetRequired )
+    {
+    }
+
+    std::string currentText;      ///< current text string
+    int cursorPosition;           ///< new position of cursor
+    bool update               :1; ///< if cursor position needs to be updated
+    bool preeditResetRequired :1; ///< flag if preedit reset is required.
+  };
+
+  typedef Signal< void (InputMethodContext&) > ActivatedSignalType; ///< Keyboard actived signal
+  typedef Signal< CallbackData ( InputMethodContext&, const EventData& ) > KeyboardEventSignalType; ///< keyboard events
+  typedef Signal< void () > VoidSignalType;
+  typedef Signal< void ( bool ) > StatusSignalType;
+  typedef Signal< void ( KeyboardType ) > KeyboardTypeSignalType; ///< keyboard type
+  typedef Signal< void ( int ) > KeyboardResizedSignalType;  ///< Keyboard resized signal
+  typedef Signal< void ( int ) > LanguageChangedSignalType;  ///< Language changed signal
+  typedef Signal< void ( const std::string&, const std::string&, const std::string& ) > ContentReceivedSignalType; ///< Content received signal
+
+  using PreEditAttributeDataContainer = Vector< Dali::InputMethodContext::PreeditAttributeData >;
+
+public:
+
+  /**
+   * @brief Retrieve a handle to the instance of InputMethodContext.
+   * @return A handle to the InputMethodContext.
+   * @brief Constructor.
+   */
+  InputMethodContext();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~InputMethodContext();
+
+  /**
+   * @brief Create a new instance of an InputMethodContext.
+   */
+  static InputMethodContext New();
+
+  /**
+   * @brief Create a new instance of an InputMethodContext.
+   *
+   * @param[in] actor The actor that uses the new InputMethodContext instance.
+   */
+  static InputMethodContext New( Actor actor );
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @param[in] inputMethodContext InputMethodContext to copy. The copied inputMethodContext will point at the same implementation.
+   */
+ InputMethodContext( const InputMethodContext& inputMethodContext );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @param[in] inputMethodContext The InputMethodContext to assign from.
+   * @return The updated InputMethodContext.
+   */
+ InputMethodContext& operator=( const InputMethodContext& inputMethodContext );
+
+  /**
+   * @brief Downcast a handle to InputMethodContext handle.
+   *
+   * If handle points to an InputMethodContext the downcast produces valid
+   * handle. If not the returned handle is left uninitialized.
+   *
+   * @param[in] handle Handle to an object.
+   * @return Handle to an InputMethodContext or an uninitialized handle.
+   */
+  static InputMethodContext DownCast( BaseHandle handle );
+
+public:
+
+  /**
+   * @brief Finalize the InputMethodContext.
+   *
+   * It means that the context will be deleted.
+   */
+  void Finalize();
+
+  /**
+   * @brief Activate the InputMethodContext.
+   *
+   * It means that the text editing is started at somewhere.
+   * If the H/W keyboard isn't connected then it will show the virtual keyboard.
+   */
+  void Activate();
+
+  /**
+   * @brief Deactivate the InputMethodContext.
+   *
+   * It means that the text editing is finished at somewhere.
+   */
+  void Deactivate();
+
+  /**
+   * @brief Get the restoration status, which controls if the keyboard is restored after the focus lost then regained.
+   *
+   * If true then keyboard will be restored (activated) after focus is regained.
+   * @return restoration status.
+   */
+  bool RestoreAfterFocusLost() const;
+
+  /**
+   * @brief Set status whether the InputMethodContext has to restore the keyboard after losing focus.
+   *
+   * @param[in] toggle True means that keyboard should be restored after focus lost and regained.
+   */
+  void SetRestoreAfterFocusLost( bool toggle );
+
+  /**
+   * @brief Send message reset the pred-edit state / InputMethodContext module.
+   *
+   * Used to interupt pre-edit state maybe due to a touch input.
+   */
+  void Reset();
+
+  /**
+   * @brief Notifies InputMethodContext that the cursor position has changed, required for features like auto-capitalisation.
+   */
+  void NotifyCursorPosition();
+
+  /**
+   * @brief Sets cursor position stored in VirtualKeyboard, this is required by the InputMethodContext.
+   *
+   * @param[in] cursorPosition position of cursor
+   */
+  void SetCursorPosition( unsigned int cursorPosition );
+
+  /**
+   * @brief Gets cursor position stored in VirtualKeyboard, this is required by the InputMethodContext.
+   *
+   * @return current position of cursor
+   */
+  unsigned int GetCursorPosition() const;
+
+  /**
+   * @brief Method to store the string required by the InputMethodContext, this is used to provide predictive word suggestions.
+   *
+   * @param[in] text The text string surrounding the current cursor point.
+   */
+  void SetSurroundingText( const std::string& text );
+
+  /**
+   * @brief Gets current text string set within the InputMethodContext manager, this is used to offer predictive suggestions.
+   *
+   * @return current position of cursor
+   */
+  const std::string& GetSurroundingText() const;
+
+  /**
+ * @brief Notifies InputMethodContext that text input is set to multi line or not
+ *
+ * @param[in] multiLine True if multiline text input is used
+ */
+  void NotifyTextInputMultiLine( bool multiLine );
+
+  /**
+   * @brief Returns text direction of the keyboard's current input language.
+   * @return The direction of the text.
+   */
+  TextDirection GetTextDirection();
+
+  /**
+   * @brief Provides size and position of keyboard.
+   *
+   * Position is relative to whether keyboard is visible or not.
+   * If keyboard is not visible then position will be off the screen.
+   * If keyboard is not being shown when this method is called the keyboard is partially setup (IMFContext) to get
+   * the values then taken down.  So ideally GetInputMethodArea() should be called after Show().
+   * @return rect which is keyboard panel x, y, width, height
+   */
+  Dali::Rect<int> GetInputMethodArea();
+
+  /**
+   * @brief Set one or more of the Input Method options
+   * @param[in] options The options to be applied
+   */
+  void ApplyOptions( const InputMethodOptions& options );
+
+  /**
+   * @brief Sets up the input-panel specific data.
+   * @param[in] data The specific data to be set to the input panel
+   */
+  void SetInputPanelData( const std::string& data );
+
+  /**
+   * @brief Gets the specific data of the current active input panel.
+   *
+   * Input Panel Data is not always the data which is set by SetInputPanelData().
+   * Data can be changed internally in the input panel.
+   * It is just used to get a specific data from the input panel to an application.
+   * @param[in] data The specific data to be got from the input panel
+   */
+  void GetInputPanelData( std::string& data );
+
+  /**
+   * @brief Gets the state of the current active input panel.
+   * @return The state of the input panel.
+   */
+  State GetInputPanelState();
+
+  /**
+   * @brief Sets the return key on the input panel to be visible or invisible.
+   *
+   * The default is true.
+   * @param[in] visible True if the return key is visible(enabled), false otherwise.
+   */
+  void SetReturnKeyState( bool visible );
+
+  /**
+   * @brief Enable to show the input panel automatically when focused.
+   * @param[in] enabled If true, the input panel will be shown when focused
+   */
+  void AutoEnableInputPanel( bool enabled );
+
+  /**
+   * @brief Shows the input panel.
+   */
+  void ShowInputPanel();
+
+  /**
+   * @brief Hides the input panel.
+   */
+  void HideInputPanel();
+
+  /**
+   * @brief Gets the keyboard type.
+   *
+   * The default keyboard type is SOFTWARE_KEYBOARD.
+   * @return The keyboard type
+   */
+  KeyboardType GetKeyboardType();
+
+  /**
+   * @brief Gets the current language locale of the input panel.
+   *
+   * ex) en_US, en_GB, en_PH, fr_FR, ...
+   * @return The current language locale of the input panel
+   */
+  std::string GetInputPanelLocale();
+
+  /**
+   * @brief Sets the allowed MIME Types to deliver to the input panel.
+   *
+   * ex) std::string mimeTypes = "text/plain,image/png,image/gif,application/pdf";
+   *
+   * You can receive a media content URI and its MIME type from ContentReceivedSignal(). @see ContentReceivedSignal
+   * @param[in] mimeTypes The allowed MIME types
+   */
+  void SetContentMIMETypes( const std::string& mimeTypes );
+
+  /**
+   * @brief Process event key down or up, whether filter a key to isf.
+   *
+   * @param[in] keyEvent The event key to be handled.
+   * @return Whether the event key is handled.
+   */
+  bool FilterEventKey( const Dali::KeyEvent& keyEvent );
+
+  /**
+   * @brief Sets whether the IM context should allow to use the text prediction.
+   *
+   * @param[in] prediction Whether to allow text prediction or not.
+   */
+  void AllowTextPrediction( bool prediction );
+
+  /**
+   * @brief Gets whether the IM context allow to use the text prediction.
+   *
+   * @return Whether the IM allow text prediction or not.
+   */
+  bool IsTextPredictionAllowed() const;
+
+  /**
+   * @brief Sets the language of the input panel.
+   *
+   * This method can be used when you want to show the English keyboard.
+   * @param[in] language The language to be set to the input panel
+   */
+  void SetInputPanelLanguage( InputPanelLanguage language );
+
+  /**
+   * @brief Gets the language of the input panel.
+   *
+   * @return The language of the input panel
+   */
+  InputPanelLanguage GetInputPanelLanguage() const;
+
+  /**
+   * @brief Sets the x,y coordinates of the input panel.
+   *
+   * @param[in] x The top-left x coordinate of the input panel
+   * @param[in] y The top-left y coordinate of the input panel
+   */
+  void SetInputPanelPosition( unsigned int x, unsigned int y );
+
+  /**
+   * @brief Gets the preedit attributes data.
+   *
+   * @param[out] attrs The preedit attributes data.
+   */
+  void GetPreeditStyle( PreEditAttributeDataContainer& attrs ) const;
+
+public:
+
+  // Signals
+
+  /**
+   * @brief This is emitted when the virtual keyboard is connected to or the hardware keyboard is activated.
+   *
+   * @return The InputMethodContext Activated signal.
+   */
+  ActivatedSignalType& ActivatedSignal();
+
+  /**
+   * @brief This is emitted when the InputMethodContext manager receives an event from the InputMethodContext.
+   *
+   * @return The Event signal containing the event data.
+   */
+  KeyboardEventSignalType& EventReceivedSignal();
+
+  /**
+   * @brief Connect to this signal to be notified when the virtual keyboard is shown or hidden.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(bool keyboardShown);
+   * @endcode
+   * If the parameter keyboardShown is true, then the keyboard has just shown, if it is false, then it
+   * has just been hidden.
+   * @return The signal to connect to.
+   */
+  StatusSignalType& StatusChangedSignal();
+
+  /**
+   * @brief Connect to this signal to be notified when the virtual keyboard is resized.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( int resolvedResize );
+   * @endcode
+   * The parameter sends the resolved resize defined by the InputMethodContext.
+   *
+   * User can get changed size by using GetInputMethodArea() in the callback
+   * @return The signal to connect to.
+   */
+  KeyboardResizedSignalType& ResizedSignal();
+
+  /**
+   * @brief Connect to this signal to be notified when the virtual keyboard's language is changed.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( int resolvedLanguage );
+   * @endcode
+   * The parameter sends the resolved language defined by the InputMethodContext.
+   *
+   * User can get the text direction of the language by calling GetTextDirection() in the callback.
+   * @return The signal to connect to.
+   */
+  LanguageChangedSignalType& LanguageChangedSignal();
+
+  /**
+   * @brief Connect to this signal to be notified when the keyboard type is changed.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( KeyboardType keyboard );
+   * @endcode
+   *
+   * @return The signal to connect to.
+   */
+  KeyboardTypeSignalType& KeyboardTypeChangedSignal();
+
+  /**
+   * @brief Connect to this signal to be notified when the content, such as images, of input method is received.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( const std::string& contentUri, const std::string& description, const std::string& contentMIMEType );
+   * @endcode
+   *
+   * @return The signal to connect to.
+   */
+  ContentReceivedSignalType& ContentReceivedSignal();
+
+public:
+
+  /**
+   * @brief This constructor is used by InputMethodContext::New().
+   *
+   * @param[in] inputMethodContext A pointer to the InputMethodContext.
+   */
+  explicit DALI_INTERNAL InputMethodContext( Internal::Adaptor::InputMethodContext* inputMethodContext );
+
+};
+
+
+
+} // namespace Dali
+
+#endif // DALI_INPUT_METHOD_CONTEXT_H
diff --git a/dali/devel-api/adaptor-framework/input-method-options.cpp b/dali/devel-api/adaptor-framework/input-method-options.cpp
new file mode 100644 (file)
index 0000000..4e0d8fa
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/adaptor-framework/input-method-options.h>
+
+using namespace Dali::InputMethod;
+using namespace Dali::InputMethod::Category;
+
+namespace Dali
+{
+
+#define TOKEN_STRING(x) #x
+
+struct InputMethodOptions::Impl
+{
+  Impl()
+  {
+    mPanelLayout = PanelLayout::NORMAL;
+    mAutoCapital = AutoCapital::SENTENCE;
+    mButtonAction = ButtonAction::DEFAULT;
+    mVariation = NormalLayout::NORMAL;
+  }
+
+  PanelLayout::Type mPanelLayout;
+  AutoCapital::Type mAutoCapital;
+  ButtonAction::Type mButtonAction;
+  int mVariation:4;
+};
+
+InputMethodOptions::InputMethodOptions()
+{
+  mImpl.reset(new Impl());
+}
+
+InputMethodOptions::~InputMethodOptions()
+{
+  // destructor cannot be inlined and must be in a unit
+  // for unique_ptr to work with forward declaration
+}
+
+bool InputMethodOptions::IsPassword() const
+{
+  return (mImpl->mPanelLayout == Dali::InputMethod::PanelLayout::PASSWORD);
+}
+
+void InputMethodOptions::ApplyProperty( const Property::Map& settings )
+{
+  for ( unsigned int i = 0, count = settings.Count(); i < count; ++i )
+  {
+    Property::Key key = settings.GetKeyAt( i );
+    if( key.type == Property::Key::INDEX )
+    {
+      continue;
+    }
+
+    Property::Value item = settings.GetValue(i);
+
+    if( key == TOKEN_STRING( PANEL_LAYOUT ) )
+    {
+      if( item.GetType() == Property::INTEGER )
+      {
+        int value = item.Get< int >();
+        mImpl->mPanelLayout = static_cast<InputMethod::PanelLayout::Type>(value);
+      }
+    }
+    else if ( key == TOKEN_STRING( BUTTON_ACTION ) )
+    {
+      if ( item.GetType() == Property::INTEGER )
+      {
+        int value = item.Get< int >();
+        mImpl->mButtonAction = static_cast<InputMethod::ButtonAction::Type>(value);
+      }
+    }
+    else if ( key == TOKEN_STRING( AUTO_CAPITALIZE ) )
+    {
+      if ( item.GetType() == Property::INTEGER )
+      {
+        int value = item.Get< int >();
+        mImpl->mAutoCapital = static_cast<InputMethod::AutoCapital::Type>(value);
+      }
+    }
+    else if( key == TOKEN_STRING( VARIATION ) )
+    {
+      if( item.GetType() == Property::INTEGER )
+      {
+        int value = item.Get< int >();
+        mImpl->mVariation = value;
+      }
+    }
+    else
+    {
+    }
+  }
+}
+
+void InputMethodOptions::RetrieveProperty( Property::Map& settings )
+{
+  settings[TOKEN_STRING( PANEL_LAYOUT )] = mImpl->mPanelLayout;
+  settings[TOKEN_STRING( BUTTON_ACTION )] = mImpl->mButtonAction;
+  settings[TOKEN_STRING( AUTO_CAPITALIZE )] = mImpl->mAutoCapital;
+  settings[TOKEN_STRING( VARIATION )] = mImpl->mVariation;
+}
+
+bool InputMethodOptions::CompareAndSet( InputMethod::Category::Type type, const InputMethodOptions& options, int& index)
+{
+  bool updated = false;
+
+  switch (type)
+  {
+    case PANEL_LAYOUT:
+    {
+      if ( options.mImpl->mPanelLayout != mImpl->mPanelLayout )
+      {
+        mImpl->mPanelLayout = options.mImpl->mPanelLayout;
+        index = static_cast<int>(mImpl->mPanelLayout);
+        updated = true;
+      }
+      break;
+    }
+    case BUTTON_ACTION:
+    {
+      if ( options.mImpl->mButtonAction != mImpl->mButtonAction )
+      {
+        mImpl->mButtonAction = options.mImpl->mButtonAction;
+        index = static_cast<int>(mImpl->mButtonAction);
+        updated = true;
+      }
+      break;
+    }
+    case AUTO_CAPITALIZE:
+    {
+      if ( options.mImpl->mAutoCapital != mImpl->mAutoCapital )
+      {
+        mImpl->mAutoCapital = options.mImpl->mAutoCapital;
+        index = static_cast<int>(mImpl->mAutoCapital);
+        updated = true;
+      }
+      break;
+    }
+    case VARIATION:
+    {
+      if ( options.mImpl->mVariation != mImpl->mVariation )
+      {
+        mImpl->mVariation = options.mImpl->mVariation;
+        index = static_cast<int>(mImpl->mVariation);
+        updated = true;
+      }
+      break;
+    }
+  }
+  return updated;
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/input-method-options.h b/dali/devel-api/adaptor-framework/input-method-options.h
new file mode 100644 (file)
index 0000000..f8598bd
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef DALI_VIRTUAL_KEYBOARD_OPTIONS_H
+#define DALI_VIRTUAL_KEYBOARD_OPTIONS_H
+
+/*
+ * Copyright (c) 2019 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 <memory>
+
+#include <dali/public-api/object/property-map.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/input-method.h>
+
+namespace Dali
+{
+
+/**
+ * Class to handle the Input Method options
+ */
+class DALI_ADAPTOR_API InputMethodOptions
+{
+public:
+
+  /**
+   * Constructor
+   */
+  InputMethodOptions();   /// Default InputMethodOptions options
+
+  /**
+   * Destructor
+   */
+  ~InputMethodOptions();
+
+  /**
+   * @brief Returns whether panel layout type is password or not
+   * @return true if panel layout type is password, false otherwise.
+   */
+  bool IsPassword() const;
+
+  /**
+   * @brief Apply property map to attribute class, this class will keep the virtualKeyboard settings.
+   * @param[in] settings The property map to be applied
+   */
+  void ApplyProperty( const Property::Map& settings );
+
+  /**
+   * @brief Retrieve property map from current option
+   * @param[out] settings The converted property map
+   */
+  void RetrieveProperty( Property::Map& settings );
+
+public: // Intended for internal use
+  /**
+   * @brief Set option respectively
+   * @param[in] type The type of source option will be updated
+   * @param[in] options The source option to be applied
+   * @param[out] index The updated index after applying source option
+   * @return true if the value of this option is updated by source option
+   */
+  DALI_INTERNAL bool CompareAndSet( InputMethod::Category::Type type, const InputMethodOptions& options, int& index );
+
+private:
+
+  struct Impl;
+  std::unique_ptr<Impl> mImpl;
+};
+
+} // namespace Dali
+
+#endif // DALI_VIRTUAL_KEYBOARD_OPTIONS_H
diff --git a/dali/devel-api/adaptor-framework/key-devel.cpp b/dali/devel-api/adaptor-framework/key-devel.cpp
new file mode 100644 (file)
index 0000000..9690ac2
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2019 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 <dali/internal/input/common/key-impl.h>
+
+namespace Dali
+{
+
+namespace DevelKey
+{
+
+int GetDaliKeyCode( const char* keyName )
+{
+  return Internal::Adaptor::KeyLookup::GetDaliKeyCode( keyName );
+}
+
+} // namespace DevelKey
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/key-devel.h b/dali/devel-api/adaptor-framework/key-devel.h
new file mode 100644 (file)
index 0000000..c78c21a
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef DALI_KEY_DEVEL_H
+#define DALI_KEY_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
+#include <dali/public-api/adaptor-framework/key.h>
+
+namespace Dali
+{
+
+namespace DevelKey
+{
+
+enum Key
+{
+  DALI_KEY_INVALID = Dali::DALI_KEY_INVALID,
+  DALI_KEY_ESCAPE = Dali::DALI_KEY_ESCAPE,
+  DALI_KEY_BACKSPACE = Dali::DALI_KEY_BACKSPACE,
+  DALI_KEY_SHIFT_LEFT = Dali::DALI_KEY_SHIFT_LEFT,
+  DALI_KEY_SHIFT_RIGHT = Dali::DALI_KEY_SHIFT_RIGHT,
+  DALI_KEY_CURSOR_UP = Dali::DALI_KEY_CURSOR_UP,
+  DALI_KEY_CURSOR_LEFT = Dali::DALI_KEY_CURSOR_LEFT,
+  DALI_KEY_CURSOR_RIGHT = Dali::DALI_KEY_CURSOR_RIGHT,
+  DALI_KEY_CURSOR_DOWN = Dali::DALI_KEY_CURSOR_DOWN,
+  DALI_KEY_BACK = Dali::DALI_KEY_BACK,
+  DALI_KEY_CAMERA = Dali::DALI_KEY_CAMERA,
+  DALI_KEY_CONFIG = Dali::DALI_KEY_CONFIG,
+  DALI_KEY_POWER = Dali::DALI_KEY_POWER,
+  DALI_KEY_PAUSE = Dali::DALI_KEY_PAUSE,
+  DALI_KEY_CANCEL = Dali::DALI_KEY_CANCEL,
+  DALI_KEY_PLAY_CD = Dali::DALI_KEY_PLAY_CD,
+  DALI_KEY_STOP_CD = Dali::DALI_KEY_STOP_CD,
+  DALI_KEY_PAUSE_CD = Dali::DALI_KEY_PAUSE_CD,
+  DALI_KEY_NEXT_SONG = Dali::DALI_KEY_NEXT_SONG,
+  DALI_KEY_PREVIOUS_SONG = Dali::DALI_KEY_PREVIOUS_SONG,
+  DALI_KEY_REWIND = Dali::DALI_KEY_REWIND,
+  DALI_KEY_FASTFORWARD = Dali::DALI_KEY_FASTFORWARD,
+  DALI_KEY_MEDIA = Dali::DALI_KEY_MEDIA,
+  DALI_KEY_PLAY_PAUSE = Dali::DALI_KEY_PLAY_PAUSE,
+  DALI_KEY_MUTE = Dali::DALI_KEY_MUTE,
+  DALI_KEY_MENU = Dali::DALI_KEY_MENU,
+  DALI_KEY_HOME = Dali::DALI_KEY_HOME,
+  DALI_KEY_HOMEPAGE = Dali::DALI_KEY_HOMEPAGE,
+  DALI_KEY_WEBPAGE = Dali::DALI_KEY_WEBPAGE,
+  DALI_KEY_MAIL = Dali::DALI_KEY_MAIL,
+  DALI_KEY_SCREENSAVER = Dali::DALI_KEY_SCREENSAVER,
+  DALI_KEY_BRIGHTNESS_UP = Dali::DALI_KEY_BRIGHTNESS_UP,
+  DALI_KEY_BRIGHTNESS_DOWN = Dali::DALI_KEY_BRIGHTNESS_DOWN,
+  DALI_KEY_SOFT_KBD = Dali::DALI_KEY_SOFT_KBD,
+  DALI_KEY_QUICK_PANEL = Dali::DALI_KEY_QUICK_PANEL,
+  DALI_KEY_TASK_SWITCH = Dali::DALI_KEY_TASK_SWITCH,
+  DALI_KEY_APPS = Dali::DALI_KEY_APPS,
+  DALI_KEY_SEARCH = Dali::DALI_KEY_SEARCH,
+  DALI_KEY_VOICE = Dali::DALI_KEY_VOICE,
+  DALI_KEY_LANGUAGE = Dali::DALI_KEY_LANGUAGE,
+  DALI_KEY_VOLUME_UP = Dali::DALI_KEY_VOLUME_UP,
+  DALI_KEY_VOLUME_DOWN = Dali::DALI_KEY_VOLUME_DOWN,
+
+  /**
+   * @brief Delete key.
+   */
+  DALI_KEY_DELETE = 119,
+
+  /**
+   * @brief Control Left key.
+   */
+  DALI_KEY_CONTROL_LEFT = 37,
+
+  /**
+   * @brief Control Right key.
+   */
+  DALI_KEY_CONTROL_RIGHT = 105,
+
+  /**
+   * @brief Control Return key.
+   */
+  DALI_KEY_RETURN = 36
+
+};
+
+/**
+ * @brief Get the key code from a key name.
+ * @param[in] keyName The key name
+ * @return The key code. -1 if the daliKey does not exist in the supported key lookup table.
+ */
+DALI_ADAPTOR_API int GetDaliKeyCode( const char* keyName );
+
+} // namespace DevelKey
+
+} // namespace Dali
+
+#endif // DALI_KEY_DEVEL_H
diff --git a/dali/devel-api/adaptor-framework/key-extension-plugin.h b/dali/devel-api/adaptor-framework/key-extension-plugin.h
new file mode 100644 (file)
index 0000000..c2f5b2b
--- /dev/null
@@ -0,0 +1,74 @@
+#ifndef DALI_KEY_EXTENSION_PLUGIN_H
+#define DALI_KEY_EXTENSION_PLUGIN_H
+
+/*
+ * Copyright (c) 2019 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 <cstdlib>
+
+namespace Dali
+{
+
+/**
+ * @brief KeyExtensionPlugin is an abstract interface, used by dali-adaptor to access key extension plugin.
+ * A concrete implementation must be created for each platform and provided as dynamic library.
+ * @SINCE_1_2.41
+ */
+class KeyExtensionPlugin
+{
+public:
+
+  struct KeyLookup
+  {
+    const char* keyName;          ///< XF86 key name
+    const int   daliKeyCode;      ///< Dali key code
+    const bool  deviceButton;     ///< Whether the key is from a button on the device
+  };
+
+  /**
+   * @brief Constructor.
+   * @SINCE_1_2.41
+   */
+  KeyExtensionPlugin(){}
+
+  /**
+   * @brief Destructor.
+   * @SINCE_1_2.41
+   */
+  virtual ~KeyExtensionPlugin(){}
+
+  /**
+   * @brief Get extension key lookup table.
+   *
+   * @SINCE_1_2.41
+   * @return Pointer of extension Key lookup table.
+   */
+  virtual KeyLookup* GetKeyLookupTable() = 0;
+
+  /**
+   * @brief Get count of extension key lookup table.
+   *
+   * @SINCE_1_2.41
+   * @return count of extension Key lookup table.
+   */
+  virtual std::size_t GetKeyLookupTableCount() = 0;
+};
+
+} // namespace Dali;
+
+#endif
diff --git a/dali/devel-api/adaptor-framework/keyboard.h b/dali/devel-api/adaptor-framework/keyboard.h
new file mode 100755 (executable)
index 0000000..9fc3d82
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef DALI_KEYBOARD_H
+#define DALI_KEYBOARD_H
+
+/*
+ * Copyright (c) 2018 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 <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+/**
+ * @brief Keyboard functions.
+ */
+namespace Keyboard
+{
+
+/**
+ * @brief Sets keyboard repeat information.
+ *
+ * @param[in] rate The key repeat rate value in seconds
+ * @param[in] delay The key repeat delay value in seconds
+ * @return true if setting the keyboard repeat succeeds
+ */
+DALI_ADAPTOR_API bool SetRepeatInfo( float rate, float delay );
+
+
+/**
+ * @brief Gets keyboard repeat information.
+ *
+ * @param[in] rate The key repeat rate value in seconds
+ * @param[in] delay The key repeat delay value in seconds
+ * @return true if getting the keyboard repeat succeeds, false otherwise
+ */
+DALI_ADAPTOR_API bool GetRepeatInfo( float& rate, float& delay );
+
+} // namespace Keyboard
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // DALI_KEYBOARD_H
diff --git a/dali/devel-api/adaptor-framework/lifecycle-controller.cpp b/dali/devel-api/adaptor-framework/lifecycle-controller.cpp
new file mode 100644 (file)
index 0000000..7a752be
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/lifecycle-controller.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/lifecycle-controller-impl.h>
+
+namespace Dali
+{
+
+LifecycleController::LifecycleController()
+{
+}
+
+LifecycleController::LifecycleController(const LifecycleController& controller)
+: BaseHandle(controller)
+{
+}
+
+LifecycleController LifecycleController::Get()
+{
+  return Internal::Adaptor::LifecycleController::Get();
+}
+
+LifecycleController::~LifecycleController()
+{
+}
+
+LifecycleController::LifecycleSignalType& LifecycleController::InitSignal()
+{
+  return GetImplementation(*this).InitSignal();
+}
+
+LifecycleController::LifecycleSignalType& LifecycleController::TerminateSignal()
+{
+  return GetImplementation(*this).TerminateSignal();
+}
+
+LifecycleController::LifecycleSignalType& LifecycleController::PauseSignal()
+{
+  return GetImplementation(*this).PauseSignal();
+}
+
+LifecycleController::LifecycleSignalType& LifecycleController::ResumeSignal()
+{
+  return GetImplementation(*this).ResumeSignal();
+}
+
+LifecycleController::LifecycleSignalType& LifecycleController::ResetSignal()
+{
+  return GetImplementation(*this).ResetSignal();
+}
+
+LifecycleController::LifecycleSignalType& LifecycleController::ResizeSignal()
+{
+  return GetImplementation(*this).ResizeSignal();
+}
+
+LifecycleController::LifecycleSignalType& LifecycleController::LanguageChangedSignal()
+{
+  return GetImplementation(*this).LanguageChangedSignal();
+}
+
+LifecycleController& LifecycleController::operator=(const LifecycleController& monitor)
+{
+  if( *this != monitor )
+  {
+    BaseHandle::operator=(monitor);
+  }
+  return *this;
+}
+
+LifecycleController::LifecycleController(Internal::Adaptor::LifecycleController* internal)
+: BaseHandle(internal)
+{
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/lifecycle-controller.h b/dali/devel-api/adaptor-framework/lifecycle-controller.h
new file mode 100755 (executable)
index 0000000..e075d5c
--- /dev/null
@@ -0,0 +1,157 @@
+#ifndef DALI_LIFECYCLE_CONTROLLER_H
+#define DALI_LIFECYCLE_CONTROLLER_H
+
+/*
+ * Copyright (c) 2019 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/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class LifecycleController;
+}
+}
+
+/**
+ * @brief Provides application lifecycle events.
+ *
+ * Connect to the signals of this class to receive notification of events in the lifecycle
+ * of the application. The following example shows how to connect to the Init signal. This
+ * could be done for example in the constructor of a singleton that is known to be created
+ * at startup.
+ *
+ * @code
+ * void MyClass::MyClass()
+ * {
+ *   LifecycleController::Get().InitSignal().Connect( this, &MyClass::OnApplicationInit );
+ * }
+ *
+ * void MyClass::OnApplicationInit()
+ * {
+ *   // ... Do something on init
+ * }
+ * @endcode
+ */
+class DALI_ADAPTOR_API LifecycleController : public BaseHandle
+{
+public: // Typedefs
+
+  typedef Signal< void (void) > LifecycleSignalType;   ///< Lifecycle Signal type
+
+public: // Creation & Destruction
+
+  /**
+   * @brief Create an uninitialized LifecycleController handle.
+   *
+   * Calling member functions when uninitialized is not allowed.
+   */
+  LifecycleController();
+
+  /**
+   * @brief Creates a copy of the handle.
+   *
+   * The copy will point to the same implementation as the original.
+   * @param[in]  monitor  The LifecycleController to copy from.
+   */
+  LifecycleController(const LifecycleController& monitor);
+
+  /**
+   * @brief Retrieve the initialized instance of the LifecycleController.
+   * @return Handle to LifecycleController.
+   */
+  static LifecycleController Get();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~LifecycleController();
+
+public: // Signals
+
+  /**
+   * The user should connect to this signal to determine when they should initialise
+   * their application.
+   */
+  LifecycleSignalType& InitSignal();
+
+  /**
+   * The user should connect to this signal to determine when they should terminate
+   * their application
+   */
+  LifecycleSignalType& TerminateSignal();
+
+  /**
+   * The user should connect to this signal if they need to perform any special
+   * activities when the application is about to be paused.
+   */
+  LifecycleSignalType& PauseSignal();
+
+  /**
+   * The user should connect to this signal if they need to perform any special
+   * activities when the application has resumed.
+   */
+  LifecycleSignalType& ResumeSignal();
+
+  /**
+   * This signal is sent when the system requires the user to reinitialise itself.
+   */
+  LifecycleSignalType& ResetSignal();
+
+  /**
+   * This signal is emitted when the window the application is rendering on is resized.
+   */
+  LifecycleSignalType& ResizeSignal();
+
+  /**
+   * This signal is emitted when the language is changed on the device.
+   */
+  LifecycleSignalType& LanguageChangedSignal();
+
+public: // Operators
+
+  /**
+   * @brief Assignment operator.
+   *
+   * The handle points to the same implementation as the one being copied from.
+   * @param[in]  controller  The LifecycleController to copy from.
+   * @return reference to this object
+   */
+  LifecycleController& operator=(const LifecycleController& controller);
+
+public: // Not intended for application developers
+  /**
+   * @brief This constructor is used internally to create a handle from an object pointer.
+   * @param [in] lifecycleController A pointer to the internal LifecycleController.
+   */
+  explicit DALI_INTERNAL LifecycleController(Internal::Adaptor::LifecycleController* lifecycleController);
+};
+
+} // namespace Dali
+
+#endif // DALI_LIFECYCLE_CONTROLLER_H
diff --git a/dali/devel-api/adaptor-framework/native-image-source-devel.cpp b/dali/devel-api/adaptor-framework/native-image-source-devel.cpp
new file mode 100755 (executable)
index 0000000..3072690
--- /dev/null
@@ -0,0 +1,43 @@
+/*\r
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// CLASS HEADER\r
+#include <dali/devel-api/adaptor-framework/native-image-source-devel.h>\r
+\r
+//INTERNAL INCLUDES\r
+#include <dali/internal/imaging/common/native-image-source-impl.h>\r
+\r
+\r
+namespace Dali\r
+{\r
+\r
+namespace DevelNativeImageSource\r
+{\r
+\r
+uint8_t* AcquireBuffer( NativeImageSource& image, uint16_t& width, uint16_t& height, uint16_t& stride )\r
+{\r
+  return Dali::Internal::Adaptor::NativeImageSource::GetImplementation( image ).AcquireBuffer( width, height, stride );\r
+}\r
+\r
+bool ReleaseBuffer( NativeImageSource& image )\r
+{\r
+  return Dali::Internal::Adaptor::NativeImageSource::GetImplementation( image ).ReleaseBuffer();\r
+}\r
+\r
+} // namespace DevelNativeImageSource\r
+\r
+} // namespace Dali\r
diff --git a/dali/devel-api/adaptor-framework/native-image-source-devel.h b/dali/devel-api/adaptor-framework/native-image-source-devel.h
new file mode 100755 (executable)
index 0000000..0c470c8
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef DALI_NATIVE_IMAGE_SOURCE_DEVEL_H\r
+#define DALI_NATIVE_IMAGE_SOURCE_DEVEL_H\r
+/*\r
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// EXTERNAL INCLUDES\r
+#include <dali/public-api/adaptor-framework/native-image-source.h>\r
+\r
+namespace Dali\r
+{\r
+\r
+namespace DevelNativeImageSource\r
+{\r
+\r
+/**\r
+ * @brief Acquire buffer and information of an internal native image.\r
+ *\r
+ * AcquireBuffer() and ReleaseBuffer() are a pair.\r
+ * It should be call ReleaseBuffer() after AcquireBuffer().\r
+ * @param[in] image The instance of NativeImageSource.\r
+ * @param[out] width The width of image\r
+ * @param[out] height The height of image\r
+ * @param[out] stride The stride of image\r
+ * @return     The buffer of an internal native image\r
+ */\r
+DALI_ADAPTOR_API uint8_t* AcquireBuffer( NativeImageSource& image, uint16_t& width, uint16_t& height, uint16_t& stride );\r
+\r
+/**\r
+ * @brief Release information of an internal native image.\r
+ *\r
+ * AcquireBuffer() and ReleaseBuffer() are a pair.\r
+ * It should be call ReleaseBuffer() after AcquireBuffer().\r
+ * @param[in] image The instance of NativeImageSource.\r
+ * @return     @c true If the buffer is released successfully, and @c false otherwise\r
+ */\r
+DALI_ADAPTOR_API bool ReleaseBuffer( NativeImageSource& image );\r
+\r
+} // namespace DevelNativeImageSource\r
+\r
+} // namespace Dali\r
+\r
+#endif // DALI_NATIVE_IMAGE_SOURCE_DEVEL_H\r
diff --git a/dali/devel-api/adaptor-framework/native-image-source-queue.cpp b/dali/devel-api/adaptor-framework/native-image-source-queue.cpp
new file mode 100755 (executable)
index 0000000..297fd2a
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/adaptor-framework/native-image-source-queue.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/imaging/common/native-image-source-queue-impl.h>
+#include <dali/internal/imaging/common/native-image-source-factory.h>
+
+namespace Dali
+{
+
+NativeImageSourceQueuePtr NativeImageSourceQueue::New( uint32_t width, uint32_t height, ColorDepth depth )
+{
+  Any empty;
+  NativeImageSourceQueuePtr image = new NativeImageSourceQueue( width, height, depth, empty );
+  if( image->mImpl )
+  {
+    return image;
+  }
+  return nullptr;
+}
+
+NativeImageSourceQueuePtr NativeImageSourceQueue::New( Any nativeImageSourceQueue )
+{
+  NativeImageSourceQueuePtr image = new NativeImageSourceQueue( 0, 0, COLOR_DEPTH_DEFAULT, nativeImageSourceQueue );
+  if( image->mImpl )
+  {
+    return image;
+  }
+  return nullptr;
+}
+
+Any NativeImageSourceQueue::GetNativeImageSourceQueue()
+{
+  return mImpl->GetNativeImageSourceQueue();
+}
+
+void NativeImageSourceQueue::SetSize( uint32_t width, uint32_t height )
+{
+  return mImpl->SetSize( width, height );
+}
+
+bool NativeImageSourceQueue::GlExtensionCreate()
+{
+  return mImpl->GlExtensionCreate();
+}
+
+void NativeImageSourceQueue::GlExtensionDestroy()
+{
+  mImpl->GlExtensionDestroy();
+}
+
+uint32_t NativeImageSourceQueue::TargetTexture()
+{
+  return mImpl->TargetTexture();
+}
+
+void NativeImageSourceQueue::PrepareTexture()
+{
+  mImpl->PrepareTexture();
+}
+
+uint32_t NativeImageSourceQueue::GetWidth() const
+{
+  return mImpl->GetWidth();
+}
+
+uint32_t NativeImageSourceQueue::GetHeight() const
+{
+  return mImpl->GetHeight();
+}
+
+bool NativeImageSourceQueue::RequiresBlending() const
+{
+  return mImpl->RequiresBlending();
+}
+
+NativeImageInterface::Extension* NativeImageSourceQueue::GetExtension()
+{
+  return mImpl->GetNativeImageInterfaceExtension();
+}
+
+NativeImageSourceQueue::NativeImageSourceQueue( uint32_t width, uint32_t height, ColorDepth depth, Any nativeImageSourceQueue )
+{
+  auto factory = Dali::Internal::Adaptor::GetNativeImageSourceFactory();
+  mImpl = factory->CreateNativeImageSourceQueue( width, height, depth, nativeImageSourceQueue );
+}
+
+NativeImageSourceQueue::~NativeImageSourceQueue()
+{
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/native-image-source-queue.h b/dali/devel-api/adaptor-framework/native-image-source-queue.h
new file mode 100755 (executable)
index 0000000..32b08c3
--- /dev/null
@@ -0,0 +1,197 @@
+#ifndef DALI_NATIVE_IMAGE_SOURCE_QUEUE_H
+#define DALI_NATIVE_IMAGE_SOURCE_QUEUE_H
+
+/*
+ * Copyright (c) 2018 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/images/native-image-interface.h>
+#include <dali/public-api/object/any.h>
+#include <memory>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class NativeImageSourceQueue;
+}
+}
+
+class NativeImageSourceQueue;
+
+/**
+ * @brief Pointer to Dali::NativeImageSourceQueue.
+ */
+typedef Dali::IntrusivePtr< Dali::NativeImageSourceQueue > NativeImageSourceQueuePtr;
+
+/**
+ * @brief Used for displaying native images.
+ *
+ * NativeImage is a platform specific way of providing pixel data to the GPU for rendering,for example via an EGL image.
+ * NativeImageSourceQueue can be created internally or externally by native image source.
+ * It has a queue which handles some image buffers.
+ * Someone should fill the buffers and enqueue them, then DALi will show them.
+ */
+class DALI_ADAPTOR_API NativeImageSourceQueue : public NativeImageInterface
+{
+public:
+
+   /**
+    * @brief Enumeration for the instance when creating a native image, the color depth has to be specified.
+    */
+   enum ColorDepth
+   {
+     COLOR_DEPTH_DEFAULT,     ///< Uses the current screen default depth (recommended)
+     COLOR_DEPTH_24,          ///< 24 bits per pixel
+     COLOR_DEPTH_32           ///< 32 bits per pixel
+   };
+
+  /**
+   * @brief Creates a new NativeImageSourceQueue.
+   *        Depending on hardware, the width and height may have to be a power of two.
+   * @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
+   */
+  static NativeImageSourceQueuePtr New( uint32_t width, uint32_t height, ColorDepth depth );
+
+  /**
+   * @brief Creates a new NativeImageSourceQueue from an existing native image source.
+   *
+   * @param[in] nativeImageSourceQueue NativeImageSourceQueue must be a any handle with native image source
+   * @return A smart-pointer to a newly allocated image
+   * @see NativeImageInterface
+   */
+  static NativeImageSourceQueuePtr New( Any nativeImageSourceQueue );
+
+  /**
+   * @brief Retrieves the internal native image.
+   *
+   * @return Any object containing the internal native image source queue
+   */
+  Any GetNativeImageSourceQueue();
+
+  /**
+   * @brief Sets the size of the image.
+   *
+   * @param[in] width The width of the image
+   * @param[in] height The height of the image
+   */
+  void SetSize( uint32_t width, uint32_t height );
+
+private:   // native image
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionCreate()
+   */
+  virtual bool GlExtensionCreate();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionDestroy()
+   */
+  virtual void GlExtensionDestroy();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::TargetTexture()
+   */
+  virtual uint32_t TargetTexture();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::PrepareTexture()
+   */
+  virtual void PrepareTexture();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetWidth()
+   */
+  virtual uint32_t GetWidth() const;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetHeight()
+   */
+  virtual uint32_t GetHeight() const;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::RequiresBlending()
+   */
+  virtual bool RequiresBlending() const;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetExtension()
+   */
+  NativeImageInterface::Extension* GetExtension();
+
+private:
+
+  /// @cond internal
+  /**
+   * @brief Private constructor.
+   * @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] nativeImageSourceQueue contains either: native image source or is empty
+   */
+  DALI_INTERNAL NativeImageSourceQueue( uint32_t width, uint32_t height, ColorDepth depth, Any nativeImageSourceQueue );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   *
+   * The implementation should destroy the NativeImage resources.
+   */
+  DALI_INTERNAL virtual ~NativeImageSourceQueue();
+
+  /**
+   * @brief Undefined copy constructor.
+   *
+   * This avoids accidental calls to a default copy constructor.
+   * @param[in] nativeImageSourceQueue A reference to the object to copy
+   */
+  DALI_INTERNAL NativeImageSourceQueue( const NativeImageSourceQueue& nativeImageSourceQueue );
+
+  /**
+   * @brief Undefined assignment operator.
+   *
+   * This avoids accidental calls to a default assignment operator.
+   * @param[in] rhs A reference to the object to copy
+   */
+  DALI_INTERNAL NativeImageSourceQueue& operator=(const NativeImageSourceQueue& rhs);
+  /// @endcond
+
+private:
+
+  /// @cond internal
+  std::unique_ptr< Internal::Adaptor::NativeImageSourceQueue > mImpl; ///< Implementation pointer
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // DALI_NATIVE_IMAGE_SOURCE_QUEUE_H
diff --git a/dali/devel-api/adaptor-framework/orientation.cpp b/dali/devel-api/adaptor-framework/orientation.cpp
new file mode 100644 (file)
index 0000000..bdc7e4a
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/orientation.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/window-system/common/orientation-impl.h>
+
+namespace Dali
+{
+
+Orientation::Orientation()
+{
+}
+
+Orientation::~Orientation()
+{
+}
+
+Orientation::Orientation(const Orientation& handle)
+: BaseHandle(handle)
+{
+}
+
+Orientation& Orientation::operator=(const Orientation& rhs)
+{
+  BaseHandle::operator=(rhs);
+  return *this;
+}
+
+int Orientation::GetDegrees() const
+{
+  return Internal::Adaptor::GetImplementation(*this).GetDegrees();
+}
+
+float Orientation::GetRadians() const
+{
+  return Internal::Adaptor::GetImplementation(*this).GetRadians();
+}
+
+Orientation::OrientationSignalType& Orientation::ChangedSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).ChangedSignal();
+}
+
+Orientation::Orientation( Internal::Adaptor::Orientation* orientation )
+: BaseHandle(orientation)
+{
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/orientation.h b/dali/devel-api/adaptor-framework/orientation.h
new file mode 100755 (executable)
index 0000000..2f38671
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef DALI_ORIENTATION_H
+#define DALI_ORIENTATION_H
+
+/*
+ * Copyright (c) 2019 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/signals/dali-signal.h>
+#include <dali/public-api/object/base-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class Orientation;
+}
+}
+
+/**
+ * @brief Orientation allows the user to determine the orientation of the device.
+ *
+ * A signal is emitted whenever the orientation changes.
+ * Dali applications have full control over visual layout when the device is rotated
+ * i.e. the application developer decides which UI controls to rotate, if any.
+ */
+class DALI_ADAPTOR_API Orientation : public BaseHandle
+{
+public:
+
+  typedef Signal< void (Orientation) > OrientationSignalType; ///< Orientation changed signal type
+
+  /**
+   * @brief Create an unintialized handle.
+   *
+   * This can be initialized by calling Dali::Application::GetOrientation()
+   */
+  Orientation();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~Orientation();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @param [in] handle A reference to the copied handle
+   */
+  Orientation(const Orientation& 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
+   */
+  Orientation& operator=(const Orientation& rhs);
+
+  /**
+   * @brief Returns the orientation of the device in degrees.
+   *
+   * This is one of four discrete values, in degrees clockwise: 0, 90, 180, & 270
+   * For a device with a portrait form-factor:
+   *   0 indicates that the device is in the "normal" portrait orientation.
+   *   90 indicates that device has been rotated clockwise, into a landscape orientation.
+   * @return The orientation in degrees clockwise.
+   */
+  int GetDegrees() const;
+
+  /**
+   * @brief Returns the orientation of the device in radians.
+   *
+   * This is one of four discrete values, in radians clockwise: 0, PI/2, PI, & 3xPI/2
+   * For a device with a portrait form-factor:
+   *   0 indicates that the device is in the "normal" portrait orientation.
+   *   PI/2 indicates that device has been rotated clockwise, into a landscape orientation.
+   * @return The orientation in radians clockwise.
+   */
+  float GetRadians() const;
+
+  /**
+   * @brief The user should connect to this signal so that they can be notified whenever
+   * the orientation of the device changes.
+   *
+   * @return The orientation change signal.
+   */
+  OrientationSignalType& ChangedSignal();
+
+public: // Not intended for application developers
+  /**
+   * @brief Helper function.
+   *
+   * @param[in] orientation A pointer to the orientation object
+   */
+  explicit DALI_INTERNAL Orientation( Internal::Adaptor::Orientation* orientation );
+};
+
+} // namespace Dali
+
+#endif // DALI_ORIENTATION_H
diff --git a/dali/devel-api/adaptor-framework/performance-logger.cpp b/dali/devel-api/adaptor-framework/performance-logger.cpp
new file mode 100644 (file)
index 0000000..60f7112
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/performance-logger.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/performance-logger-impl.h>
+
+namespace Dali
+{
+
+PerformanceLogger::PerformanceLogger()
+{
+}
+
+PerformanceLogger PerformanceLogger::New( const char* name )
+{
+  Internal::Adaptor::PerformanceLoggerPtr internal = Internal::Adaptor::PerformanceLogger::New( name );
+  return PerformanceLogger(internal.Get());
+}
+
+PerformanceLogger::PerformanceLogger( const PerformanceLogger& performanceLogger )
+: BaseHandle(performanceLogger)
+{
+}
+
+PerformanceLogger& PerformanceLogger::operator=( const PerformanceLogger& performanceLogger )
+{
+  // check self assignment
+  if( *this != performanceLogger )
+  {
+    BaseHandle::operator=(performanceLogger);
+  }
+  return *this;
+}
+
+PerformanceLogger::~PerformanceLogger()
+{
+}
+
+PerformanceLogger PerformanceLogger::DownCast( BaseHandle handle )
+{
+  return PerformanceLogger( dynamic_cast<Internal::Adaptor::PerformanceLogger*>( handle.GetObjectPtr() ) );
+}
+
+void PerformanceLogger::AddMarker( Marker markerType )
+{
+  Internal::Adaptor::GetImplementation(*this).AddMarker( markerType );
+}
+
+void PerformanceLogger::SetLoggingFrequency( unsigned int logFrequency)
+{
+  Internal::Adaptor::GetImplementation(*this).SetLoggingFrequency( logFrequency );
+}
+
+void PerformanceLogger::EnableLogging( bool enable )
+{
+  Internal::Adaptor::GetImplementation(*this).EnableLogging( enable );
+}
+
+PerformanceLogger::PerformanceLogger(Internal::Adaptor::PerformanceLogger* PerformanceLogger)
+: BaseHandle(PerformanceLogger)
+{
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/performance-logger.h b/dali/devel-api/adaptor-framework/performance-logger.h
new file mode 100755 (executable)
index 0000000..00055c5
--- /dev/null
@@ -0,0 +1,136 @@
+#ifndef DALI_PERFORMANCE_LOGGER_H
+#define DALI_PERFORMANCE_LOGGER_H
+
+/*
+ * Copyright (c) 2019 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/object/base-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class PerformanceLogger;
+}
+}
+
+/**
+ * @brief Performance logger class
+ */
+class DALI_ADAPTOR_API PerformanceLogger : public BaseHandle
+{
+public:
+
+  /**
+   * Enum for events that can be logged
+   */
+  enum Marker
+  {
+    START_EVENT,      ///< The start of timing
+    END_EVENT         ///< The end of timing
+  };
+
+  /**
+   * @brief Constructor, creates an uninitialized logger.
+   *
+   * Call New to fully construct a logger.
+   */
+  PerformanceLogger();
+
+  /**
+   * @brief Create a new logger
+   *
+   * @param[in] name The name of the logger. This needs to be a compile-time literal and alive for the whole lifetime of the performance logger.
+   * @return a new logger
+   */
+  static PerformanceLogger New( const char* name );
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @param[in] logger The handle to copy. The copied handle will point at the same implementation
+   */
+  PerformanceLogger( const PerformanceLogger& logger );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @param[in] logger The handle to copy. This handle will point at the same implementation
+   * as the copied handle.
+   * @return Reference to this logger handle
+   */
+  PerformanceLogger& operator=( const PerformanceLogger& logger );
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~PerformanceLogger();
+
+  /**
+   * @brief Downcast an Object handle to PerformanceLogger handle.
+   *
+   * If handle points to a PerformanceLogger object the downcast produces a valid
+   * handle. If not the returned handle is left uninitialized.
+   *
+   * @param[in] handle to An object
+   * @return handle to a PerformanceLogger object or an uninitialized handle
+   */
+  static PerformanceLogger DownCast( BaseHandle handle );
+
+  /**
+   * Add a performance marker
+   *
+   * @param markerType Performance marker type
+   */
+  void AddMarker( Marker markerType );
+
+  /**
+   * Set the logging frequency
+   *
+   * @param logFrequency how often to log out in seconds
+   */
+  void SetLoggingFrequency( unsigned int logFrequency);
+
+  /**
+   * Set logging on or off for this logger
+   *
+   * @param[in] enable Enable logging or not
+   */
+  void EnableLogging( bool enable );
+
+  // Not intended for application developers
+
+  /**
+   * Creates a new handle from the implementation.
+   * @param[in] impl A pointer to the object.
+   */
+  explicit DALI_INTERNAL PerformanceLogger( Internal::Adaptor::PerformanceLogger* impl );
+
+};
+
+} // namespace Dali
+
+#endif // DALI_PERFORMANCE_LOGGER_H
diff --git a/dali/devel-api/adaptor-framework/physical-keyboard.cpp b/dali/devel-api/adaptor-framework/physical-keyboard.cpp
new file mode 100644 (file)
index 0000000..9d808f0
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/physical-keyboard.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/input/common/physical-keyboard-impl.h>
+
+namespace Dali
+{
+
+PhysicalKeyboard::PhysicalKeyboard()
+{
+}
+
+PhysicalKeyboard::~PhysicalKeyboard()
+{
+}
+
+PhysicalKeyboard PhysicalKeyboard::Get()
+{
+  // Get the physical keyboard handle
+  PhysicalKeyboard handle = Internal::Adaptor::PhysicalKeyboard::Get();
+
+  // If it's not been created then create one
+  if ( !handle )
+  {
+    handle = Internal::Adaptor::PhysicalKeyboard::New();
+  }
+
+  return handle;
+}
+
+bool PhysicalKeyboard::IsAttached() const
+{
+  return GetImplementation( *this ).IsAttached();
+}
+
+PhysicalKeyboard::PhysicalKeyboardSignalType& PhysicalKeyboard::StatusChangedSignal()
+{
+  return GetImplementation( *this ).StatusChangedSignal();
+}
+
+PhysicalKeyboard::PhysicalKeyboard( Internal::Adaptor::PhysicalKeyboard *impl )
+: BaseHandle(impl)
+{
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/physical-keyboard.h b/dali/devel-api/adaptor-framework/physical-keyboard.h
new file mode 100755 (executable)
index 0000000..ee2c322
--- /dev/null
@@ -0,0 +1,99 @@
+#ifndef DALI_PHYSICAL_KEYBOARD_H
+#define DALI_PHYSICAL_KEYBOARD_H
+
+/*
+ * Copyright (c) 2019 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/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class PhysicalKeyboard;
+}
+}
+
+/**
+ * This is a handle to a physical keyboard connected to the device.
+ */
+class DALI_ADAPTOR_API PhysicalKeyboard : public BaseHandle
+{
+public:
+
+  typedef Signal< void (PhysicalKeyboard) > PhysicalKeyboardSignalType;
+
+public:
+
+  /**
+   * Create an uninitialized PhysicalKeyboard handle; this can be initialized with GetKeyboard()
+   * Calling member functions with an uninitialized Dali::Object is not allowed.
+   */
+  PhysicalKeyboard();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~PhysicalKeyboard();
+
+  /**
+   * Gets a handle to the physical keyboard.
+   * @return A handle to the physical keyboard.
+   */
+  static PhysicalKeyboard Get();
+
+  /**
+   * Queries whether a physical keyboard is attached or not.
+   * @return true if a physical keyboard is attached, false otherwise.
+   */
+  bool IsAttached() const;
+
+  // Signals
+
+  /**
+   * Emitted when the status of the physical keyboard changes.
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(PhysicalKeyboard keyboard);
+   * @endcode
+   * @pre The PhysicalKeyboard has been initialized.
+   * @return The status changed signal.
+   */
+  PhysicalKeyboardSignalType& StatusChangedSignal();
+
+  // Not intended for application developers
+
+  /**
+   * Creates a new handle from the implementation.
+   * @param[in] impl A pointer to the object.
+   */
+  explicit DALI_INTERNAL PhysicalKeyboard( Internal::Adaptor::PhysicalKeyboard* impl );
+};
+
+} // namespace Dali
+
+#endif // DALI_PHYSICAL_KEYBOARD_H
diff --git a/dali/devel-api/adaptor-framework/pixel-buffer.cpp b/dali/devel-api/adaptor-framework/pixel-buffer.cpp
new file mode 100755 (executable)
index 0000000..94af7f8
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+
+// EXTERNAL INLCUDES
+#include <stdlib.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/imaging/common/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();
+}
+
+const unsigned char* const PixelBuffer::GetBuffer() const
+{
+  return GetImplementation(*this).GetConstBuffer();
+}
+
+void PixelBuffer::ApplyMask( PixelBuffer mask, float contentScale, bool cropToMask )
+{
+  GetImplementation(*this).ApplyMask( GetImplementation( mask ), contentScale, cropToMask );
+}
+
+void PixelBuffer::ApplyGaussianBlur( const float blurRadius )
+{
+  GetImplementation(*this).ApplyGaussianBlur( blurRadius );
+}
+
+void PixelBuffer::Crop( uint16_t x, uint16_t y, uint16_t width, uint16_t height )
+{
+  GetImplementation(*this).Crop( x, y, ImageDimensions( width, height ) );
+}
+
+void PixelBuffer::Resize( uint16_t width, uint16_t height )
+{
+  GetImplementation(*this).Resize( ImageDimensions( width, height ) );
+}
+
+void PixelBuffer::MultiplyColorByAlpha()
+{
+  GetImplementation(*this).MultiplyColorByAlpha();
+}
+
+bool PixelBuffer::GetMetadata( Property::Map& metadata ) const
+{
+  return GetImplementation(*this).GetMetadata(metadata);
+}
+
+bool PixelBuffer::Rotate( Degree angle )
+{
+  return GetImplementation(*this).Rotate( angle );
+}
+
+bool PixelBuffer::IsAlphaPreMultiplied() const
+{
+  return GetImplementation(*this).IsAlphaPreMultiplied();
+}
+
+} // namespace Devel
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/pixel-buffer.h b/dali/devel-api/adaptor-framework/pixel-buffer.h
new file mode 100755 (executable)
index 0000000..2a9add4
--- /dev/null
@@ -0,0 +1,265 @@
+#ifndef DALI_PIXEL_BUFFER_H
+#define DALI_PIXEL_BUFFER_H
+
+/*
+ * Copyright (c) 2018 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 <dali/public-api/images/pixel.h>
+#include <dali/public-api/images/pixel-data.h>
+#include <dali/public-api/object/base-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.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_ADAPTOR_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 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.
+   *
+   * @return The pixel buffer, or NULL.
+   */
+  const unsigned char* const GetBuffer() const;
+
+  /**
+   * @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.
+   *
+   * If cropToMask is set to true, then the contentScale is applied first to
+   * this buffer, and the target buffer is cropped to the size of the mask. If
+   * it's set to false, then the mask is scaled to match this buffer's size
+   * before the mask is applied.
+   *
+   * @param[in] mask The mask to apply.
+   * @param[in] contentScale The scaling factor to apply to the content
+   * @param[in] cropToMask Whether to crop the output to the mask size (true)
+   * or scale the mask to the content size (false)
+   */
+  void ApplyMask( PixelBuffer mask, float contentScale=1.0f, bool cropToMask=false );
+
+  /**
+   * Apply a Gaussian blur to this pixel data with the given radius.
+   *
+   * @note A bigger radius will yield a blurrier image. Only works for pixel data in RGBA format.
+   *
+   * @param[in] blurRadius The radius for Gaussian blur. A value of 0 or negative value indicates no blur.
+   */
+  void ApplyGaussianBlur( const float blurRadius );
+
+  /**
+   * @brief Crops this buffer to the given crop rectangle.
+   *
+   * The crop rectangle will be clamped to the edges of the buffer if it is larger.
+   * @param[in] x The top left corner's X
+   * @param[in] y The top left corner's y
+   * @param[in] width The crop width
+   * @param[in] height The crop height
+   */
+  void Crop( uint16_t x, uint16_t y, uint16_t width, uint16_t height );
+
+  /**
+   * @brief Resizes the buffer to the given dimensions.
+   *
+   * Uses either Lanczos4 for downscaling or Mitchell for upscaling
+   * @param[in] width The new width
+   * @param[in] height The new height
+   */
+  void Resize( uint16_t width, uint16_t height );
+
+  /**
+   * @brief Returns Exif metadata as a property map
+   *
+   * @param[out] metadata Property map object to write into
+   * @return True on success
+   */
+  bool GetMetadata( Property::Map& metadata ) const;
+
+  /**
+   * @brief Multiplies the image's color values by the alpha value. This provides better
+   * blending capability.
+   */
+  void MultiplyColorByAlpha();
+
+  /**
+   * @brief Rotates the pixel buffer by the given angle.
+   *
+   * @note Operation valid for pixel formats: A8, L8, LA88, RGB888, RGB8888, BGR8888, RGBA8888 and BGRA8888. Fails otherwise.
+   * @note The operation does nothing for angles equivalent to 0 degrees: -360, 360, 720, etc.
+   * @note If the pixel buffer does rotate, all the pointers to the internal pixel buffer retrieved by the method GetPixelBuffer() become invalid.
+   *
+   * @param[in] angle The angle in degrees.
+   *
+   * @return @e false if the rotation fails (invalid pixel format or memory issues).
+   */
+  bool Rotate( Degree angle );
+
+  /**
+   * @brief Returns pixel-buffer is premultiplied or not.
+   * @return true if alpha is pre-multiplied.
+   */
+  bool IsAlphaPreMultiplied() const;
+
+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
diff --git a/dali/devel-api/adaptor-framework/sound-player.cpp b/dali/devel-api/adaptor-framework/sound-player.cpp
new file mode 100644 (file)
index 0000000..b441ecd
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/sound-player.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/sound-player-impl.h>
+
+namespace Dali
+{
+
+SoundPlayer::SoundPlayer()
+{
+}
+
+SoundPlayer SoundPlayer::Get()
+{
+  return Internal::Adaptor::SoundPlayer::Get();
+}
+
+SoundPlayer::~SoundPlayer()
+{
+}
+
+int SoundPlayer::PlaySound(const std::string fileName)
+{
+  return GetImplementation(*this).PlaySound(fileName);
+}
+
+void SoundPlayer::Stop(int handle)
+{
+  GetImplementation(*this).Stop(handle);
+}
+
+SoundPlayer::SoundPlayFinishedSignalType& SoundPlayer::SoundPlayFinishedSignal()
+{
+  return GetImplementation(*this).SoundPlayFinishedSignal();
+}
+
+SoundPlayer::SoundPlayer( Internal::Adaptor::SoundPlayer* player )
+: BaseHandle( player )
+{
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/sound-player.h b/dali/devel-api/adaptor-framework/sound-player.h
new file mode 100755 (executable)
index 0000000..817c964
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef DALI_SOUND_PLAYER_H
+#define DALI_SOUND_PLAYER_H
+
+/*
+ * Copyright (c) 2019 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/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class SoundPlayer;
+}
+}
+
+/**
+ * @brief Plays sound effects.
+ */
+class DALI_ADAPTOR_API SoundPlayer : public BaseHandle
+{
+public:
+
+  typedef Signal< void (SoundPlayer&) > SoundPlayFinishedSignalType; ///< Sound play finished signal
+
+  /**
+   * @brief Create an uninitialized handle.
+   *
+   * This can be initialized by calling SoundPlayer::Get().
+   */
+  SoundPlayer();
+
+  /**
+   * @brief Create an initialized handle to the SoundPlayer.
+   *
+   * @return A handle to a newly allocated Dali resource.
+   */
+  static SoundPlayer Get();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~SoundPlayer();
+
+  /**
+   * @brief Plays a sound file.
+   *
+   * @pre The SoundPlayer needs to be initialized.
+   * @param[in]  fileName Path to the sound file to play.
+   * @return a handle to the currently playing sound file which can be used to stop.
+   */
+  int PlaySound(const std::string fileName);
+
+  /**
+   * @brief Stops the currently playing sound.
+   *
+   * @pre The SoundPlayer needs to be initialized.
+   * @param[in] handle
+   */
+  void Stop(int handle);
+
+  /**
+   * @brief This signal will be emitted after a given sound file is completely played.
+   *
+   * @pre The SoundPlayer needs to be initialized.
+   * @return The signal to connect to.
+   *
+   * @note The signal name is "soundPlayFinished" if using BaseHandle::ConnectSignal()
+   */
+  SoundPlayFinishedSignalType& SoundPlayFinishedSignal();
+
+public: // Not intended for application developers
+
+  /**
+   * @brief This constructor is used by SoundPlayer::Get().
+   *
+   * @param[in] soundPlayer A pointer to the sound player.
+   */
+  explicit DALI_INTERNAL SoundPlayer( Internal::Adaptor::SoundPlayer* soundPlayer );
+};
+
+} // namespace Dali
+
+#endif // DALI_SOUND_PLAYER_H
diff --git a/dali/devel-api/adaptor-framework/style-monitor.cpp b/dali/devel-api/adaptor-framework/style-monitor.cpp
new file mode 100644 (file)
index 0000000..59775b2
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/style-monitor.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/styling/common/style-monitor-impl.h>
+
+namespace Dali
+{
+
+StyleMonitor::StyleMonitor()
+{
+}
+
+StyleMonitor::StyleMonitor(const StyleMonitor& monitor)
+: BaseHandle(monitor)
+{
+}
+
+StyleMonitor StyleMonitor::StyleMonitor::Get()
+{
+  return Internal::Adaptor::StyleMonitor::Get();
+}
+
+StyleMonitor::~StyleMonitor()
+{
+}
+
+StyleMonitor StyleMonitor::DownCast( BaseHandle handle )
+{
+  return StyleMonitor( dynamic_cast<Internal::Adaptor::StyleMonitor*>( handle.GetObjectPtr() ) );
+}
+
+std::string StyleMonitor::GetDefaultFontFamily() const
+{
+  return GetImplementation(*this).GetDefaultFontFamily();
+}
+
+std::string StyleMonitor::GetDefaultFontStyle() const
+{
+  return GetImplementation(*this).GetDefaultFontStyle();
+}
+
+int StyleMonitor::GetDefaultFontSize() const
+{
+  return GetImplementation(*this).GetDefaultFontSize();
+}
+
+const std::string& StyleMonitor::GetTheme() const
+{
+  return GetImplementation(*this).GetTheme();
+}
+
+void StyleMonitor::SetTheme(const std::string& themFilePath)
+{
+  return GetImplementation(*this).SetTheme(themFilePath);
+}
+
+bool StyleMonitor::LoadThemeFile( const std::string& filename, std::string& output )
+{
+  return GetImplementation(*this).LoadThemeFile( filename, output );
+}
+
+StyleMonitor::StyleChangeSignalType& StyleMonitor::StyleChangeSignal()
+{
+  return GetImplementation(*this).StyleChangeSignal();
+}
+
+StyleMonitor& StyleMonitor::operator=(const StyleMonitor& monitor)
+{
+  if( *this != monitor )
+  {
+    BaseHandle::operator=(monitor);
+  }
+  return *this;
+}
+
+StyleMonitor::StyleMonitor(Internal::Adaptor::StyleMonitor* internal)
+: BaseHandle(internal)
+{
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/style-monitor.h b/dali/devel-api/adaptor-framework/style-monitor.h
new file mode 100644 (file)
index 0000000..464884c
--- /dev/null
@@ -0,0 +1,174 @@
+#ifndef DALI_STYLE_MONITOR_H
+#define DALI_STYLE_MONITOR_H
+
+/*
+ * Copyright (c) 2019 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/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/style-change.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class StyleMonitor;
+}
+}
+
+/**
+ * @brief Monitors the platform for style changes.
+ *
+ * This is a handle to the adaptor's style monitor which holds the platform's style information.
+ * It provides a signal when any aspect of the default style changes on the device.
+ * @see Adaptor::GetStyleMonitor
+ */
+class DALI_ADAPTOR_API StyleMonitor : public BaseHandle
+{
+public: // Typedefs
+
+  typedef Signal< void ( StyleMonitor, StyleChange::Type ) > StyleChangeSignalType;   ///< StyleChange Signal type
+
+public: // Creation & Destruction
+
+  /**
+   * @brief Create an uninitialized StyleMonitor handle.
+   *
+   * Tthis can be set by retrieving the style monitor from the Adaptor
+   * or the Application classes.  Calling member functions when
+   * uninitialized is not allowed.
+   */
+  StyleMonitor();
+
+  /**
+   * @brief Creates a copy of the handle.
+   *
+   * The copy will point to the same implementation as the original.
+   * @param[in]  monitor  The Style Monitor to copy from.
+   */
+  StyleMonitor(const StyleMonitor& monitor);
+
+  /**
+   * @brief Retrieve the initialized instance of the StyleMonitor.
+   * @return Handle to StyleMonitor.
+   */
+  static StyleMonitor Get();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~StyleMonitor();
+
+  /**
+   * @brief Downcast an Object handle to StyleMonitor handle.
+   *
+   * If handle points to a StyleMonitor object the downcast produces a
+   * valid handle. If not the returned handle is left uninitialized.
+   *
+   * @param[in] handle to An object @return handle to a Timer object
+   * or an uninitialized handle
+   */
+  static StyleMonitor DownCast( BaseHandle handle );
+
+public: // Style Information
+
+  /**
+   * @brief Retrieves the default font family.
+   * @return The default font family.
+   */
+  std::string GetDefaultFontFamily() const;
+
+  /**
+   * @brief Retrieves the default font style.
+   * @return The default font style.
+   */
+  std::string GetDefaultFontStyle() const;
+
+  /**
+   * @brief Retrieves the default font size.
+   *
+   * This is an logical size, which is mapped to a UI Control specific point-size in stylesheets.
+   * For example if zero the smallest size, this could potentially map to TextLabel point-size 8.
+   * @return The default font size, or a negative value if not set.
+   */
+  int GetDefaultFontSize() const;
+
+  /**
+   * @brief Retrieves the user defined Theme.
+   * @return The user defined Theme.
+   */
+  const std::string& GetTheme() const;
+
+  /**
+   * @brief Sets an user defined Theme.
+   * @param[in] themeFilePath Path of the user defined theme
+   */
+  void SetTheme(const std::string& themeFilePath);
+
+  /**
+   * @brief Utility to load a theme file
+   * @param filename of the theme
+   * @param output to write the contents to
+   * @return true if the load is successful
+   */
+  bool LoadThemeFile( const std::string& filename, std::string& output );
+
+public: // Signals
+
+  /**
+   * @brief This signal is emitted whenever the style changes on the device.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(StyleMonitor styleMonitor, StyleChange change);
+   * @endcode
+   * @return The signal to connect to.
+   */
+  StyleChangeSignalType& StyleChangeSignal();
+
+public: // Operators
+
+  /**
+   * @brief Assignment operator.
+   *
+   * The handle points to the same implementation as the one being copied from.
+   * @param[in]  monitor  The Style Monitor to copy from.
+   * @return reference to this object
+   */
+  StyleMonitor& operator=(const StyleMonitor& monitor);
+
+public: // Not intended for application developers
+  /**
+   * @brief This constructor is used internally to create a handle from an object pointer.
+   * @param [in] styleMonitor A pointer the internal style monitor.
+   */
+  explicit DALI_INTERNAL StyleMonitor(Internal::Adaptor::StyleMonitor* styleMonitor);
+};
+
+} // namespace Dali
+
+#endif // DALI_STYLE_MONITOR_H
diff --git a/dali/devel-api/adaptor-framework/thread-settings.cpp b/dali/devel-api/adaptor-framework/thread-settings.cpp
new file mode 100644 (file)
index 0000000..84fc940
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/thread-settings.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/thread/common/thread-settings-impl.h>
+
+namespace Dali
+{
+void SetThreadName(const std::string& threadName)
+{
+  Internal::Adaptor::ThreadSettings::SetThreadName( threadName );
+}
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/thread-settings.h b/dali/devel-api/adaptor-framework/thread-settings.h
new file mode 100755 (executable)
index 0000000..78c63a0
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef DALI_THREAD_SETTINGS_H
+#define DALI_THREAD_SETTINGS_H
+
+/*
+ * Copyright (c) 2018 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 <dali/public-api/dali-adaptor-common.h>
+
+// EXTERNAL INCLUDES
+#include <string>
+
+namespace Dali
+{
+/**
+ * @brief Set the thread name.
+ *
+ * @param [in] threadName The name of thread. The name can be up to 16 bytes long, and should be null-terminated if it contains fewer bytes.
+ */
+DALI_ADAPTOR_API void SetThreadName(const std::string& threadName);
+
+} // Dali
+
+#endif // DALI_THREAD_SETTINGS_H
\ No newline at end of file
diff --git a/dali/devel-api/adaptor-framework/tilt-sensor.cpp b/dali/devel-api/adaptor-framework/tilt-sensor.cpp
new file mode 100644 (file)
index 0000000..3c4938b
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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 <dali/devel-api/adaptor-framework/tilt-sensor.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/sensor/common/tilt-sensor-factory.h>
+#include <dali/internal/sensor/common/tilt-sensor-impl.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+
+namespace Dali
+{
+
+const float TiltSensor::DEFAULT_UPDATE_FREQUENCY = 60.0f;
+
+TiltSensor::TiltSensor()
+{
+}
+
+TiltSensor TiltSensor::Get()
+{
+  return Internal::Adaptor::TiltSensorFactory::Get();
+}
+
+TiltSensor::~TiltSensor()
+{
+}
+
+bool TiltSensor::Start()
+{
+  return GetImplementation(*this).Start();
+}
+
+void TiltSensor::Stop()
+{
+  GetImplementation(*this).Stop();
+}
+
+bool TiltSensor::IsStarted() const
+{
+  return GetImplementation(*this).IsStarted();
+}
+
+float TiltSensor::GetRoll() const
+{
+  return GetImplementation(*this).GetRoll();
+}
+
+float TiltSensor::GetPitch() const
+{
+  return GetImplementation(*this).GetPitch();
+}
+
+Quaternion TiltSensor::GetRotation() const
+{
+  return GetImplementation(*this).GetRotation();
+}
+
+TiltSensor::TiltedSignalType& TiltSensor::TiltedSignal()
+{
+  return GetImplementation(*this).TiltedSignal();
+}
+
+void TiltSensor::SetUpdateFrequency( float frequencyHertz )
+{
+  GetImplementation(*this).SetUpdateFrequency( frequencyHertz );
+}
+
+float TiltSensor::GetUpdateFrequency() const
+{
+  return GetImplementation(*this).GetUpdateFrequency();
+}
+
+void TiltSensor::SetRotationThreshold(Radian rotationThreshold)
+{
+  GetImplementation(*this).SetRotationThreshold( rotationThreshold );
+}
+
+Radian TiltSensor::GetRotationThreshold() const
+{
+  return GetImplementation(*this).GetRotationThreshold();
+}
+
+TiltSensor::TiltSensor( Internal::Adaptor::TiltSensor* sensor )
+: BaseHandle( sensor )
+{
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/tilt-sensor.h b/dali/devel-api/adaptor-framework/tilt-sensor.h
new file mode 100755 (executable)
index 0000000..631f9e6
--- /dev/null
@@ -0,0 +1,203 @@
+#ifndef DALI_TILT_SENSOR_H
+#define DALI_TILT_SENSOR_H
+
+/*
+ * Copyright (c) 2019 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/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class TiltSensor;
+}
+}
+
+/**
+ * TiltSensor provides pitch & roll values when the device is tilted.
+ * The basic usage is shown below:
+ *
+ * @code
+ *
+ *  void Example()
+ *  {
+ *    TiltSensor sensor = TiltSensor::Get();
+ *
+ *    // Try to start the tilt sensor
+ *    if ( sensor.Start() )
+ *    {
+ *      // Query the current values
+ *      std::cout << "Roll = " << sensor.GetRoll() << ", Pitch = " << sensor.GetPitch() << std::endl;
+ *
+ *      // Get notifications when the device is tilted
+ *      sensor.TiltedSignal().Connect( &OnTilted );
+ *    }
+ *  }
+ *
+ *  void OnTilted( const TiltSensor& sensor )
+ *  {
+ *    // Query the new values
+ *    std::cout << "Roll = " << sensor.GetRoll() << ", Pitch = " << sensor.GetPitch() << std::endl;
+ *  }
+ *
+ * @endcode
+ *
+ * While the tilt sensor is started, it will periodically poll for the latest pitch & roll values.
+ * For performance & power-saving, applications should disable this polling when no longer needed:
+ *
+ * @code
+ *
+ *  void EndExample()
+ *  {
+ *    // Stop the sensor when no longer needed
+ *    TiltSensor::Get().Stop();
+ *  }
+ *
+ * @endcode
+ */
+class DALI_ADAPTOR_API TiltSensor : public BaseHandle
+{
+public:
+
+  typedef Signal< void (const TiltSensor&) > TiltedSignalType;
+
+  static const float DEFAULT_UPDATE_FREQUENCY; // 60 hertz
+
+  /**
+   * Create an uninitialized handle.
+   * This can be initialized by calling TiltSensor::Get().
+   */
+  TiltSensor();
+
+  /**
+   * Create an initialized handle to the TiltSensor.
+   * @return A handle to a newly allocated Dali resource.
+   */
+  static TiltSensor Get();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~TiltSensor();
+
+  /**
+   * Attempt to start the tilt-sensor. This will fail if the underlying sensor hardware is powered-down,
+   * typically this occurs when the device is set to "sleep" mode.
+   * @return True if the tilt-sensor is started.
+   */
+  bool Start();
+
+  /**
+   * Stop the tilt-sensor.
+   */
+  void Stop();
+
+  /**
+   * Query whether the tilt-sensor is started.
+   * The sensor may be disabled automatically; typically this occurs when the device is set to "sleep" mode.
+   * @return True if the tilt-sensor is started.
+   */
+  bool IsStarted() const;
+
+  /**
+   * Query the roll value. This is in the range -1 to 1.
+   * When the device is lying face-up on a flat surface, this method will return a value close to zero.
+   * A value close to 1 indicates that the right-side of the device is pointing upwards.
+   * A value close to -1 indicates that the right-side of the device is pointing downwards.
+   * @pre The tilt-sensor is started.
+   * @return The roll value.
+   */
+  float GetRoll() const;
+
+  /**
+   * Query the pitch value. This is in the range -1 to 1.
+   * When the device is lying face-up on a flat surface, this method will return a value close to zero.
+   * A value close to 1 indicates that the top of the device is pointing upwards.
+   * A value close to -1 indicates that the top of the device is pointing downwards.
+   * @pre The tilt-sensor is started.
+   * @return The pitch value.
+   */
+  float GetPitch() const;
+
+  /**
+   * Retrieve the rotation of the device.
+   * When the device is lying face-up on a flat surface, the rotation angle will be approximately zero.
+   * The roll & pitch of the device is considered to be a rotation around the Y and X axes respectively.
+   * @pre The tilt-sensor is started.
+   * @return The rotation in quaternion format.
+   */
+  Quaternion GetRotation() const;
+
+  /**
+   * This signal will be emitted when the device is tilted, if the tilt-sensor is started.
+   * The frequency of the signals can be controlled using SetUpdateFrequency().
+   * @return The signal to connect to.
+   *
+   * @note The signal name is "tilted" if using BaseHandle::ConnectSignal()
+   */
+  TiltedSignalType& TiltedSignal();
+
+  /**
+   * Set the sensor update frequency.
+   * The default is TiltSensor::DEFAULT_UPDATE_FREQUENCY.
+   * @param[in] frequencyHertz The frequency in hertz.
+   */
+  void SetUpdateFrequency( float frequencyHertz );
+
+  /**
+   * Query the sensor update frequency.
+   * @return The frequency in hertz.
+   */
+  float GetUpdateFrequency() const;
+
+  /**
+   * Set the threshold value for rotation in Radians, above which TiltedSignal should be emitted.
+   * The default is 0.0f in Radians (i.e) it will be emitted always at the frequency set.
+   * Example tiltSensor.SetRotationThreshold( Radian(Degree(10) ) // A rotation threshold of 10 degrees
+   * @param[in] rotationThreshold The threshold value for rotation.
+   */
+  void SetRotationThreshold( Radian rotationThreshold );
+
+  /**
+   * Query the rotation threshold above which TiltedSignal will be emitted.
+   * @return The rotation degree threshold in Radians.
+   */
+  Radian GetRotationThreshold() const;
+
+public: // Not intended for application developers
+
+  /**
+   * This constructor is used by TiltSensor::Get().
+   * @param[in] sensor A pointer to the tilt sensor.
+   */
+  explicit DALI_INTERNAL TiltSensor( Internal::Adaptor::TiltSensor* sensor );
+};
+
+} // namespace Dali
+
+#endif // DALI_TILT_SENSOR_H
diff --git a/dali/devel-api/adaptor-framework/vector-animation-renderer-plugin.h b/dali/devel-api/adaptor-framework/vector-animation-renderer-plugin.h
new file mode 100644 (file)
index 0000000..c7b0011
--- /dev/null
@@ -0,0 +1,146 @@
+#ifndef DALI_VECTOR_ANIMATION_RENDERER_PLUGIN_H
+#define DALI_VECTOR_ANIMATION_RENDERER_PLUGIN_H
+
+/*
+ * Copyright (c) 2019 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/rendering/renderer.h>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/vector-animation-renderer.h>
+
+namespace Dali
+{
+
+/**
+ * VectorAnimationRendererPlugin is an abstract interface, used by dali-adaptor to render a vector animation.
+ * A concrete implementation must be created for each platform and provided as a dynamic library which
+ * will be loaded at run time by the adaptor.
+ */
+class VectorAnimationRendererPlugin
+{
+public:
+
+  using UploadCompletedSignalType = Dali::VectorAnimationRenderer::UploadCompletedSignalType;
+
+  /**
+   * @brief Constructor
+   */
+  VectorAnimationRendererPlugin() {}
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~VectorAnimationRendererPlugin() {}
+
+  /**
+   * @brief Second-phase constructor.
+   *
+   * @param[in] url The url of the animation file
+   */
+  virtual bool Initialize( const std::string& url ) = 0;
+
+  /**
+   * @brief Finalizes the renderer. It will be called in the main thread.
+   */
+  virtual void Finalize() = 0;
+
+  /**
+   * @brief Sets the renderer used to display the result image.
+   *
+   * @param[in] renderer The renderer used to display the result image
+   */
+  virtual void SetRenderer( Renderer renderer ) = 0;
+
+  /**
+   * @brief Sets the target image size.
+   *
+   * @param[in] width The target image width
+   * @param[in] height The target image height
+   */
+  virtual void SetSize( uint32_t width, uint32_t height ) = 0;
+
+  /**
+   * @brief Renders the content to the target buffer synchronously.
+   *
+   * @param[in] frameNumber The frame number to be rendered
+   * @return True if the rendering success, false otherwise.
+   */
+  virtual bool Render( uint32_t frameNumber ) = 0;
+
+  /**
+   * @brief Gets the total number of frames of the file.
+   *
+   * @return The total number of frames
+   */
+  virtual uint32_t GetTotalFrameNumber() const = 0;
+
+  /**
+   * @brief Gets the frame rate of the file.
+   *
+   * @return The frame rate of the file
+   */
+  virtual float GetFrameRate() const = 0;
+
+  /**
+   * @brief Gets the default size of the file.
+   *
+   * @param[out] width The default width of the file
+   * @param[out] height The default height of the file
+   */
+  virtual void GetDefaultSize( uint32_t& width, uint32_t& height ) const = 0;
+
+  /**
+   * @brief Gets the layer information of all the child layers.
+   *
+   * @param[out] map The layer information
+   */
+  virtual void GetLayerInfo( Property::Map& map ) const = 0;
+
+  /**
+   * @brief Gets the start frame and the end frame number of the composition marker.
+   *
+   * @param[in] marker The composition marker of the file
+   * @param[out] startFrame The start frame number of the specified marker
+   * @param[out] endFrame The end frame number of the specified marker
+   * @return True if the marker is found in the file, false otherwise.
+   *
+   * @note https://helpx.adobe.com/after-effects/using/layer-markers-composition-markers.html
+   * Markers exported from AfterEffect are used to describe a segment of an animation {comment/tag , startFrame, endFrame}
+   * Marker can be use to devide a resource in to separate animations by tagging the segment with comment string,
+   * start frame and duration of that segment.
+   */
+  virtual bool GetMarkerInfo( const std::string& marker, uint32_t& startFrame, uint32_t& endFrame ) const = 0;
+
+  /**
+   * @brief Connect to this signal to be notified when the texture upload is completed.
+   *
+   * @return The signal to connect to.
+   */
+  virtual UploadCompletedSignalType& UploadCompletedSignal() = 0;
+
+  /**
+   * @brief Function pointer called in adaptor to create a plugin instance.
+   */
+  using CreateVectorAnimationRendererFunction = VectorAnimationRendererPlugin* (*)();
+};
+
+} // namespace Dali
+
+#endif // DALI_VECTOR_ANIMATION_RENDERER_PLUGIN_H
diff --git a/dali/devel-api/adaptor-framework/vector-animation-renderer.cpp b/dali/devel-api/adaptor-framework/vector-animation-renderer.cpp
new file mode 100755 (executable)
index 0000000..9cd05ad
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/adaptor-framework/vector-animation-renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/vector-animation/common/vector-animation-renderer-impl.h>
+
+namespace Dali
+{
+
+VectorAnimationRenderer VectorAnimationRenderer::New( const std::string& url )
+{
+  Internal::Adaptor::VectorAnimationRendererPtr animationRenderer = Internal::Adaptor::VectorAnimationRenderer::New();
+  if( animationRenderer )
+  {
+    animationRenderer->Initialize( url );
+  }
+
+  return VectorAnimationRenderer( animationRenderer.Get() );
+}
+
+VectorAnimationRenderer::VectorAnimationRenderer()
+{
+}
+
+VectorAnimationRenderer::~VectorAnimationRenderer()
+{
+}
+
+VectorAnimationRenderer::VectorAnimationRenderer( Internal::Adaptor::VectorAnimationRenderer* internal )
+: BaseHandle( internal )
+{
+}
+
+VectorAnimationRenderer::VectorAnimationRenderer( const VectorAnimationRenderer& handle )
+: BaseHandle( handle )
+{
+}
+
+VectorAnimationRenderer& VectorAnimationRenderer::operator=( const VectorAnimationRenderer& rhs )
+{
+  BaseHandle::operator=( rhs );
+  return *this;
+}
+
+void VectorAnimationRenderer::Finalize()
+{
+  GetImplementation( *this ).Finalize();
+}
+
+void VectorAnimationRenderer::SetRenderer( Renderer renderer )
+{
+  GetImplementation( *this ).SetRenderer( renderer );
+}
+
+void VectorAnimationRenderer::SetSize( uint32_t width, uint32_t height )
+{
+  GetImplementation( *this ).SetSize( width, height );
+}
+
+bool VectorAnimationRenderer::Render( uint32_t frameNumber )
+{
+  return GetImplementation( *this ).Render( frameNumber );
+}
+
+uint32_t VectorAnimationRenderer::GetTotalFrameNumber() const
+{
+  return GetImplementation( *this ).GetTotalFrameNumber();
+}
+
+float VectorAnimationRenderer::GetFrameRate() const
+{
+  return GetImplementation( *this ).GetFrameRate();
+}
+
+void VectorAnimationRenderer::GetDefaultSize( uint32_t& width, uint32_t& height ) const
+{
+  GetImplementation( *this ).GetDefaultSize( width, height );
+}
+
+void VectorAnimationRenderer::GetLayerInfo( Property::Map& map ) const
+{
+  GetImplementation( *this ).GetLayerInfo( map );
+}
+
+bool VectorAnimationRenderer::GetMarkerInfo( const std::string& marker, uint32_t& startFrame, uint32_t& endFrame ) const
+{
+  return GetImplementation( *this ).GetMarkerInfo( marker, startFrame, endFrame );
+}
+
+VectorAnimationRenderer::UploadCompletedSignalType& VectorAnimationRenderer::UploadCompletedSignal()
+{
+  return GetImplementation( *this ).UploadCompletedSignal();
+}
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/vector-animation-renderer.h b/dali/devel-api/adaptor-framework/vector-animation-renderer.h
new file mode 100755 (executable)
index 0000000..0e2f14a
--- /dev/null
@@ -0,0 +1,187 @@
+#ifndef DALI_VECTOR_ANIMATION_RENDERER_H
+#define DALI_VECTOR_ANIMATION_RENDERER_H
+
+/*
+ * Copyright (c) 2019 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/object/base-handle.h>
+#include <dali/public-api/rendering/renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class VectorAnimationRenderer;
+}
+}
+
+/**
+ * @brief Used for rendering a vector animation file
+ */
+class DALI_ADAPTOR_API VectorAnimationRenderer : public BaseHandle
+{
+public:
+
+  /// @brief UploadCompleted signal type.
+  using UploadCompletedSignalType = Signal< void () >;
+
+  /**
+   * @brief Creates an initialized handle to a new VectorAnimationRenderer.
+   *
+   * @param[in] url The url of the vector animation file
+   * @return A handle to a newly allocated VectorAnimationRenderer
+   */
+  static VectorAnimationRenderer New( const std::string& url );
+
+  /**
+   * @brief Creates an empty handle.
+   * Use VectorAnimationRenderer::New() to create an initialized object.
+   */
+  VectorAnimationRenderer();
+
+  /**
+   * @brief Destructor.
+   */
+  ~VectorAnimationRenderer();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @param[in] handle A reference to the copied handle
+   */
+  VectorAnimationRenderer( const VectorAnimationRenderer& 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
+   */
+  VectorAnimationRenderer& operator=( const VectorAnimationRenderer& rhs );
+
+  /**
+   * @brief Finalizes the renderer.
+   */
+  void Finalize();
+
+  /**
+   * @brief Sets the renderer used to display the result image.
+   *
+   * @param[in] renderer The renderer used to display the result image
+   */
+  void SetRenderer( Renderer renderer );
+
+  /**
+   * @brief Sets the target image size.
+   *
+   * @param[in] width The target image width
+   * @param[in] height The target image height
+   */
+  void SetSize( uint32_t width, uint32_t height );
+
+  /**
+   * @brief Renders the content to the target buffer synchronously.
+   *
+   * @param[in] frameNumber The frame number to be rendered
+   * @return True if the rendering success, false otherwise.
+   */
+  bool Render( uint32_t frameNumber );
+
+  /**
+   * @brief Gets the total number of frames of the file
+   *
+   * @return The total number of frames
+   */
+  uint32_t GetTotalFrameNumber() const;
+
+  /**
+   * @brief Gets the frame rate of the file.
+   *
+   * @return The frame rate of the file
+   */
+  float GetFrameRate() const;
+
+  /**
+   * @brief Gets the default size of the file.
+   *
+   * @param[out] width The default width of the file
+   * @param[out] height The default height of the file
+   */
+  void GetDefaultSize( uint32_t& width, uint32_t& height ) const;
+
+  /**
+   * @brief Gets the layer information of all the child layers.
+   *
+   * @param[out] map The layer information
+   */
+  void GetLayerInfo( Property::Map& map ) const;
+
+  /**
+   * @brief Gets the start frame and the end frame number of the composition marker.
+   *
+   * @param[in] marker The composition marker of the file
+   * @param[out] startFrame The start frame number of the specified marker
+   * @param[out] endFrame The end frame number of the specified marker
+   * @return True if the marker is found in the file, false otherwise.
+   *
+   * @note https://helpx.adobe.com/after-effects/using/layer-markers-composition-markers.html
+   * Markers exported from AfterEffect are used to describe a segment of an animation {comment/tag , startFrame, endFrame}
+   * Marker can be use to devide a resource in to separate animations by tagging the segment with comment string,
+   * start frame and duration of that segment.
+   */
+  bool GetMarkerInfo( const std::string& marker, uint32_t& startFrame, uint32_t& endFrame ) const;
+
+public: // Signals
+
+  /**
+   * @brief Connect to this signal to be notified when the texture upload is completed.
+   *
+   * @return The signal to connect to.
+   */
+  UploadCompletedSignalType& UploadCompletedSignal();
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief The constructor.
+   * @note  Not intended for application developers.
+   *
+   * @param[in] pointer A pointer to a newly allocated VectorAnimationRenderer
+   */
+  explicit DALI_INTERNAL VectorAnimationRenderer( Internal::Adaptor::VectorAnimationRenderer* internal );
+  /// @endcond
+
+};
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // DALI_VECTOR_ANIMATION_RENDERER_H
diff --git a/dali/devel-api/adaptor-framework/video-player-plugin.h b/dali/devel-api/adaptor-framework/video-player-plugin.h
new file mode 100755 (executable)
index 0000000..73d175e
--- /dev/null
@@ -0,0 +1,280 @@
+#ifndef DALI_VIDEO_PLAYER_PLUGIN_H
+#define DALI_VIDEO_PLAYER_PLUGIN_H
+
+/*
+ * Copyright (c) 2019 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/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.
+ * A concrete implementation must be created for each platform and provided as dynamic library.
+ * @SINCE_1_1.38
+ */
+class VideoPlayerPlugin
+{
+public:
+
+  typedef Signal< void () > VideoPlayerSignalType;
+
+  /**
+   * @brief Video display rotation option
+   * @SINCE_1_1.38
+   * @remarks The option is needed only for window surface rendering target
+   */
+  enum DisplayRotation
+  {
+    ROTATION_NONE,   ///< Display isn't rotated. @SINCE_1_1.38
+    ROTATION_90,     ///< Display is rotated 90 degree. @SINCE_1_1.38
+    ROTATION_180,    ///< Display is rotated 180 degree. @SINCE_1_1.38
+    ROTATION_270     ///< Display is rotated 270 degree. @SINCE_1_1.38
+  };
+
+  /**
+   * @brief Enumeration for video codec type
+   */
+  enum class CodecType
+  {
+    DEFAULT,      ///< Codec which has higher priority as default. Platform selects it. Usually the H/W codec has higher priority than S/W codec if it exist.
+    HW,           ///< H/W codec
+    SW            ///< S/W codec
+  };
+
+  /**
+   * @brief The values of this enum determine how the video should be display mode to the view
+   */
+  struct DisplayMode
+  {
+    enum Type
+    {
+      LETTER_BOX = 0,     /**< Letter box */
+      ORIGIN_SIZE,        /**< Origin size */
+      FULL_SCREEN,        /**< Full-screen */
+      CROPPED_FULL,       /**< Cropped full-screen */
+      ORIGIN_OR_LETTER,   /**< Origin size (if surface size is larger than video size(width/height)) or Letter box (if video size(width/height) is larger than surface size) */
+      DST_ROI             /**< Region of Interest */
+    };
+  };
+
+  /**
+   * @brief Constructor.
+   * @SINCE_1_1.38
+   */
+  VideoPlayerPlugin(){}
+
+  /**
+   * @brief Destructor.
+   * @SINCE_1_1.38
+   */
+  virtual ~VideoPlayerPlugin(){}
+
+  /**
+   * @brief Sets a URL of the video file to play.
+   *
+   * @SINCE_1_1.38
+   * @param [in] url The url of video file
+   */
+  virtual void SetUrl( const std::string& url ) = 0;
+
+  /**
+   * @brief Returns the URL of the video file.
+   * @SINCE_1_1.38
+   * @return Url of string type
+   */
+  virtual std::string GetUrl() = 0;
+
+  /**
+   * @brief Sets the player looping status.
+   * @SINCE_1_1.38
+   *
+   * @param [in] looping The new looping status: true or false
+   */
+  virtual void SetLooping(bool looping) = 0;
+
+  /**
+   * @brief Returns the player looping status.
+   * @SINCE_1_1.38
+   *
+   * @return True if player is looping, false otherwise.
+   */
+  virtual bool IsLooping() = 0;
+
+  /**
+   * @brief Starts the video playback.
+   * @SINCE_1_1.38
+   */
+  virtual void Play() = 0;
+
+  /**
+   * @brief Pauses the video playback.
+   * @SINCE_1_1.38
+   */
+  virtual void Pause() = 0;
+
+  /**
+   * @brief Stops the video playback.
+   * @SINCE_1_1.38
+   */
+  virtual void Stop() = 0;
+
+  /**
+   * @brief Sets the player mute status.
+   * @SINCE_1_1.38
+   * @param[in] mute The new mute status, true is mute.
+   */
+  virtual void SetMute( bool mute ) = 0;
+
+  /**
+   * @brief Returns the player mute status.
+   * @SINCE_1_1.38
+   * @return True if player is mute.
+   */
+  virtual bool IsMuted() = 0;
+
+  /**
+   * @brief Sets the player volume.
+   * @SINCE_1_1.38
+   * @param[in] left The left volume scalar
+   * @param[in] right The right volume scalar
+   */
+  virtual void SetVolume( float left, float right ) = 0;
+
+  /**
+   * @brief Gets current volume factor.
+   * @SINCE_1_1.38
+   * @param[out] left The current left volume scalar
+   * @param[out] right The current right volume scalar
+   */
+  virtual void GetVolume( float& left, float& right ) = 0;
+
+  /**
+   * @brief Sets video rendering target.
+   * @SINCE_1_1.38
+   * @param[in] target The target for video rendering, window surface or native image source
+   */
+  virtual void SetRenderingTarget( Any target ) = 0;
+
+  /**
+   * @brief Sets the position for playback.
+   * @SINCE_1_1.38
+   *
+   * @param[in] millisecond The position for playback
+   */
+  virtual void SetPlayPosition( int millisecond ) = 0;
+
+  /**
+   * @brief Returns the current position in milliseconds.
+   * @SINCE_1_1.38
+   *
+   * @return The current position of playback
+   */
+  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 void SetDisplayRotation( Dali::VideoPlayerPlugin::DisplayRotation rotation ) = 0;
+
+  /**
+   * @brief Returns rotation of current video display
+   * @SINCE_1_1.38
+   * @return The rotation of current display
+   */
+  virtual Dali::VideoPlayerPlugin::DisplayRotation GetDisplayRotation() = 0;
+
+  /**
+   * @brief Connect to this signal to be notified when a video playback have finished.
+   *
+   * @SINCE_1_1.38
+   * @return A signal object to connect with.
+   */
+  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;
+
+  /**
+   * @brief Checks whether the video texture is supported
+   * @return True if supported, otherwise false.
+   */
+  virtual bool IsVideoTextureSupported() = 0;
+
+  /**
+   * @brief Sets codec type
+   * @param[in] type The CodecType
+   */
+  virtual void SetCodecType( VideoPlayerPlugin::CodecType type ) = 0;
+
+  /**
+   * @brief Gets codec type
+   * @return CodecType
+   */
+  virtual VideoPlayerPlugin::CodecType GetCodecType() const = 0;
+
+  /**
+   * @brief Sets the display mode for playback.
+   * @param[in] mode of playback
+   */
+  virtual void SetDisplayMode( VideoPlayerPlugin::DisplayMode::Type mode ) = 0;
+
+  /**
+   * @brief Returns the current display mode.
+   * @return The current display mode of playback
+   */
+  virtual VideoPlayerPlugin::DisplayMode::Type GetDisplayMode() const = 0;
+
+  /**
+   * @brief Returns the current internal media player.
+   * @return The current internal media player of video player
+   */
+  virtual Any GetMediaPlayer() = 0;
+
+};
+
+} // namespace Dali;
+
+#endif // DALI_VIDEO_PLAYER_PLUGIN_H
diff --git a/dali/devel-api/adaptor-framework/video-player.cpp b/dali/devel-api/adaptor-framework/video-player.cpp
new file mode 100755 (executable)
index 0000000..870571b
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/adaptor-framework/video-player.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/any.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/video/common/video-player-impl.h>
+
+namespace Dali
+{
+
+VideoPlayer::VideoPlayer()
+{
+}
+
+VideoPlayer::VideoPlayer( Internal::Adaptor::VideoPlayer* internal )
+: BaseHandle( internal )
+{
+}
+
+VideoPlayer::~VideoPlayer()
+{
+}
+
+VideoPlayer VideoPlayer::New()
+{
+  Internal::Adaptor::VideoPlayerPtr player = Internal::Adaptor::VideoPlayer::New();
+
+  if( player )
+  {
+    player->Initialize();
+  }
+
+  return VideoPlayer( player.Get() );
+}
+
+VideoPlayer::VideoPlayer( const VideoPlayer& player )
+: BaseHandle( player )
+{
+}
+
+VideoPlayer& VideoPlayer::operator=( const VideoPlayer& player )
+{
+  if( *this != player )
+  {
+    BaseHandle::operator=( player );
+  }
+  return *this;
+}
+
+VideoPlayer VideoPlayer::DownCast( BaseHandle handle )
+{
+  return VideoPlayer( dynamic_cast< Internal::Adaptor::VideoPlayer* >( handle.GetObjectPtr() ) );
+}
+
+void VideoPlayer::SetUrl( const std::string& url )
+{
+  GetImplementation( *this ).SetUrl( url );
+}
+
+std::string VideoPlayer::GetUrl()
+{
+  return GetImplementation( *this ).GetUrl();
+}
+
+void VideoPlayer::SetLooping(bool looping)
+{
+  GetImplementation( *this ).SetLooping( looping );
+}
+
+bool VideoPlayer::IsLooping()
+{
+  return GetImplementation( *this ).IsLooping();
+}
+
+void VideoPlayer::Play()
+{
+  GetImplementation( *this ).Play();
+}
+
+void VideoPlayer::Pause()
+{
+  GetImplementation( *this ).Pause();
+}
+
+void VideoPlayer::Stop()
+{
+  GetImplementation( *this ).Stop();
+}
+
+void VideoPlayer::SetMute( bool mute )
+{
+  GetImplementation( *this ).SetMute( mute );
+}
+
+bool VideoPlayer::IsMuted()
+{
+  return GetImplementation( *this ).IsMuted();
+}
+
+void VideoPlayer::SetVolume( float left, float right )
+{
+  GetImplementation( *this ).SetVolume( left, right );
+}
+
+void VideoPlayer::GetVolume( float& left, float& right )
+{
+  GetImplementation( *this ).GetVolume( left, right );
+}
+
+void VideoPlayer::SetRenderingTarget( Any target )
+{
+  GetImplementation( *this ).SetRenderingTarget( target );
+}
+
+void VideoPlayer::SetPlayPosition( int millisecond )
+{
+  GetImplementation( *this ).SetPlayPosition( millisecond );
+}
+
+int VideoPlayer::GetPlayPosition()
+{
+  return GetImplementation( *this ).GetPlayPosition();
+}
+
+void VideoPlayer::SetDisplayArea( DisplayArea area )
+{
+  GetImplementation( *this ).SetDisplayArea( area );
+}
+
+void VideoPlayer::SetDisplayRotation( Dali::VideoPlayerPlugin::DisplayRotation rotation )
+{
+  GetImplementation( *this ).SetDisplayRotation( rotation );
+}
+
+Dali::VideoPlayerPlugin::DisplayRotation VideoPlayer::GetDisplayRotation()
+{
+  return GetImplementation( *this ).GetDisplayRotation();
+}
+
+Dali::VideoPlayerPlugin::VideoPlayerSignalType& VideoPlayer::FinishedSignal()
+{
+  return GetImplementation( *this ).FinishedSignal();
+}
+
+void VideoPlayer::Forward( int millisecond )
+{
+  GetImplementation( *this ).Forward( millisecond );
+}
+
+void VideoPlayer::Backward( int millisecond )
+{
+  GetImplementation( *this ).Backward( millisecond );
+}
+
+bool VideoPlayer::IsVideoTextureSupported()
+{
+  return GetImplementation( *this ).IsVideoTextureSupported();
+}
+
+void VideoPlayer::SetCodecType( Dali::VideoPlayerPlugin::CodecType type )
+{
+  GetImplementation( *this ).SetCodecType( type );
+}
+
+Dali::VideoPlayerPlugin::CodecType VideoPlayer::GetCodecType() const
+{
+  return GetImplementation( *this ).GetCodecType();
+}
+
+void VideoPlayer::SetDisplayMode( Dali::VideoPlayerPlugin::DisplayMode::Type mode )
+{
+  GetImplementation( *this ).SetDisplayMode( mode );
+}
+
+Dali::VideoPlayerPlugin::DisplayMode::Type VideoPlayer::GetDisplayMode() const
+{
+  return GetImplementation( *this ).GetDisplayMode();
+}
+
+Any VideoPlayer::GetMediaPlayer()
+{
+  return GetImplementation( *this ).GetMediaPlayer();
+}
+
+} // namespace Dali;
+
diff --git a/dali/devel-api/adaptor-framework/video-player.h b/dali/devel-api/adaptor-framework/video-player.h
new file mode 100755 (executable)
index 0000000..6db7304
--- /dev/null
@@ -0,0 +1,292 @@
+#ifndef DALI_VIDEO_PLAYER_H
+#define DALI_VIDEO_PLAYER_H
+
+/*
+ * Copyright (c) 2019 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/object/base-handle.h>
+
+//INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/video-player-plugin.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+class Any;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+  class VideoPlayer;
+} // namespace Adaptor
+
+} // namespace Internal
+
+/**
+ * @brief VideoPlayer class is used for video playback.
+ * @SINCE_1_1.38
+ */
+class DALI_ADAPTOR_API VideoPlayer: public BaseHandle
+{
+public:
+
+  /**
+   * @brief Constructor.
+   * @SINCE_1_1.38
+   */
+  VideoPlayer();
+
+  /**
+   * @brief Destructor.
+   * @SINCE_1_1.38
+   */
+  ~VideoPlayer();
+
+  /**
+   * @brief Creates a new instance of a VideoPlayer.
+   * @SINCE_1_1.38
+   */
+  static VideoPlayer New();
+
+ /**
+   * @brief Copy constructor.
+   *
+   * @SINCE_1_1.38
+   * @param[in] player VideoPlayer to copy. The copied player will point at the same implementation
+   */
+  VideoPlayer( const VideoPlayer& player );
+
+ /**
+   * @brief Assignment operator.
+   *
+   * @SINCE_1_1.38
+   * @param[in] player The VideoPlayer to assign from.
+   * @return The updated VideoPlayer.
+   */
+  VideoPlayer& operator=( const VideoPlayer& player );
+
+  /**
+   * @brief Downcast a handle to VideoPlayer handle.
+   *
+   * If handle points to a VideoPlayer the downcast produces valid
+   * handle. If not the returned handle is left uninitialized.
+   *
+   * @SINCE_1_1.38
+   * @param[in] handle Handle to an object
+   * @return Handle to a VideoPlayer or an uninitialized handle
+   */
+  static VideoPlayer DownCast( BaseHandle handle );
+
+  /**
+   * @brief Sets a URL of the video file to play.
+   *
+   * @SINCE_1_1.38
+   * @param [in] url The url of video file
+   */
+  void SetUrl( const std::string& url );
+
+  /**
+   * @brief Returns the URL of the video file.
+   * @SINCE_1_1.38
+   * @return Url of string type
+   */
+  std::string GetUrl();
+
+  /**
+   * @brief Sets the player looping status.
+   * @SINCE_1_1.38
+   *
+   * @param [in] looping The new looping status: true or false
+   */
+  void SetLooping(bool looping);
+
+  /**
+   * @brief Returns the player looping status.
+   * @SINCE_1_1.38
+   *
+   * @return True if player is looping, false otherwise.
+   */
+  bool IsLooping();
+
+  /**
+   * @brief Starts the video playback.
+   * @SINCE_1_1.38
+   */
+  void Play();
+
+  /**
+   * @brief Pauses the video playback.
+   * @SINCE_1_1.38
+   */
+  void Pause();
+
+  /**
+   * @brief Stops the video playback.
+   * @SINCE_1_1.38
+   */
+  void Stop();
+
+  /**
+   * @brief Sets the player mute status.
+   * @SINCE_1_1.38
+   * @param[in] mute The new mute status, true is mute.
+   */
+  void SetMute( bool mute );
+
+  /**
+   * @brief Returns the player mute status.
+   * @SINCE_1_1.38
+   * @return True if player is mute.
+   */
+  bool IsMuted();
+
+  /**
+   * @brief Sets the player volume.
+   * @SINCE_1_1.38
+   * @param[in] left The left volume scalar
+   * @param[in] right The right volume scalar
+   */
+  void SetVolume( float left, float right );
+
+  /**
+   * @brief Returns current volume factor.
+   * @SINCE_1_1.38
+   * @param[out] left The current left volume scalar
+   * @param[out] right The current right volume scalar
+   */
+  void GetVolume( float& left, float& right );
+
+  /**
+   * @brief Sets video rendering target.
+   * @SINCE_1_1.38
+   * @param[in] target The target for video rendering, window surface or native image source
+   */
+  void SetRenderingTarget( Any target );
+
+  /**
+   * @brief Sets the position for playback.
+   * @SINCE_1_1.38
+   *
+   * @param[in] millisecond The position for playback
+   */
+  void SetPlayPosition( int millisecond );
+
+  /**
+   * @brief Gets the current position in milliseconds.
+   * @SINCE_1_1.38
+   *
+   * @return The current position of playback
+   */
+  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
+   */
+  void SetDisplayRotation( Dali::VideoPlayerPlugin::DisplayRotation rotation );
+
+  /**
+   * @brief Returns rotation of current video display
+   * @SINCE_1_1.38
+   * @return The rotation of current display
+   */
+  Dali::VideoPlayerPlugin::DisplayRotation GetDisplayRotation();
+
+  /**
+   * @brief Connect to this signal to be notified when a video playback have finished.
+   *
+   * @SINCE_1_1.38
+   * @return A signal object to connect with.
+   */
+  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 );
+
+  /**
+   * @brief Checks whether the video texture is supported
+   * @return True if supported, otherwise false.
+   */
+  bool IsVideoTextureSupported();
+
+  /**
+   * @brief Sets codec type
+   * @param[in] type The VideoCodec::Type
+   */
+  void SetCodecType( Dali::VideoPlayerPlugin::CodecType type );
+
+  /**
+   * @brief Gets codec type
+   * @return VideoCodec::Type
+   */
+  Dali::VideoPlayerPlugin::CodecType GetCodecType() const;
+
+  /**
+   * @brief Sets the display mode for playback.
+   * @param[in] mode of playback
+   */
+  void SetDisplayMode( Dali::VideoPlayerPlugin::DisplayMode::Type mode );
+
+  /**
+   * @brief Gets display mode
+   * @return DisplayMode
+   */
+  Dali::VideoPlayerPlugin::DisplayMode::Type GetDisplayMode() const;
+
+  /**
+   * @brief Gets the media player of video player
+   * @return player The media player
+   */
+  Any GetMediaPlayer();
+
+private: // Not intended for application developers
+
+  /**
+   * @brief Internal constructor
+   * @SINCE_1_1.38
+   */
+  explicit DALI_INTERNAL VideoPlayer( Internal::Adaptor::VideoPlayer* internal );
+};
+
+} // namespace Dali;
+
+#endif // DALI_VIDEO_PLAYER_H
diff --git a/dali/devel-api/adaptor-framework/virtual-keyboard.cpp b/dali/devel-api/adaptor-framework/virtual-keyboard.cpp
new file mode 100755 (executable)
index 0000000..f790364
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/adaptor-framework/virtual-keyboard.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/input/common/virtual-keyboard-impl.h>
+
+namespace Dali
+{
+
+namespace VirtualKeyboard
+{
+
+void Show()
+{
+  Internal::Adaptor::VirtualKeyboard::Show();
+}
+
+void Hide()
+{
+  Internal::Adaptor::VirtualKeyboard::Hide();
+}
+
+bool IsVisible()
+{
+  return Internal::Adaptor::VirtualKeyboard::IsVisible();
+}
+
+void ApplySettings( const Property::Map& settingsMap )
+{
+  Internal::Adaptor::VirtualKeyboard::ApplySettings( settingsMap );
+}
+
+void SetReturnKeyType( const InputMethod::ButtonAction::Type type )
+{
+  Internal::Adaptor::VirtualKeyboard::SetReturnKeyType( type );
+}
+
+InputMethod::ButtonAction::Type GetReturnKeyType()
+{
+  return Internal::Adaptor::VirtualKeyboard::GetReturnKeyType();
+}
+
+void EnablePrediction(const bool enable)
+{
+  Internal::Adaptor::VirtualKeyboard::EnablePrediction(enable);
+}
+
+bool IsPredictionEnabled()
+{
+  return Internal::Adaptor::VirtualKeyboard::IsPredictionEnabled();
+}
+
+Rect<int> GetSizeAndPosition()
+{
+  return Internal::Adaptor::VirtualKeyboard::GetSizeAndPosition();
+}
+
+void RotateTo(int angle)
+{
+  Internal::Adaptor::VirtualKeyboard::RotateTo(angle);
+}
+
+TextDirection GetTextDirection()
+{
+  return Internal::Adaptor::VirtualKeyboard::GetTextDirection();
+}
+
+} // namespace VirtualKeyboard
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/virtual-keyboard.h b/dali/devel-api/adaptor-framework/virtual-keyboard.h
new file mode 100755 (executable)
index 0000000..84c2d4e
--- /dev/null
@@ -0,0 +1,154 @@
+#ifndef DALI_VIRTUAL_KEYBOARD_H
+#define DALI_VIRTUAL_KEYBOARD_H
+
+/*
+ * Copyright (c) 2019 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/signals/dali-signal.h>
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/math/rect.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/input-method.h>
+
+namespace Dali
+{
+
+/**
+ * @brief This namespace is provided for application developers to be able to show and hide the on-screen keyboard.
+ *
+ * Key events are sent to the actor in focus. Focus is set through the actor Public API.
+ */
+namespace VirtualKeyboard
+{
+
+// Types
+
+typedef Signal< void () > VoidSignalType;
+typedef Signal< void ( bool ) > StatusSignalType;
+typedef Signal< void ( int ) > KeyboardResizedSignalType;
+typedef Signal< void ( int ) > LanguageChangedSignalType;
+
+// Enumerations
+
+/**
+ * @brief The direction of text.
+ */
+enum TextDirection
+{
+  LeftToRight,
+  RightToLeft,
+};
+
+/**
+ * @brief The meaning of the return key.
+ */
+enum ReturnKeyType
+{
+  DEFAULT,
+  DONE,
+  GO,
+  JOIN,
+  LOGIN,
+  NEXT,
+  SEARCH,
+  SEND,
+  SIGNIN
+};
+
+// Functions
+/**
+ * @brief Show the virtual keyboard.
+ */
+DALI_ADAPTOR_API void Show();
+
+/**
+ * @brief Hide the virtual keyboard.
+ */
+DALI_ADAPTOR_API void Hide();
+
+/**
+ * @brief Returns whether the virtual keyboard is visible or not.
+ * @return true if visible, false otherwise.
+ */
+DALI_ADAPTOR_API bool IsVisible();
+
+/**
+ * @brief Set one or more of the Input Method Settings
+ * @param[in] settingsMap Map of Settings to be applied.
+ */
+DALI_ADAPTOR_API void ApplySettings( const Property::Map& settingsMap );
+
+/**
+ * @brief Set the specific return key into the virtual keyboard.
+ * @param[in] type the kind of return key types.
+ */
+DALI_ADAPTOR_API void SetReturnKeyType( const InputMethod::ButtonAction::Type type );
+
+/**
+ * @brief Retrieve the current return key type.
+ * @return the type of retun key.
+ */
+DALI_ADAPTOR_API InputMethod::ButtonAction::Type GetReturnKeyType();
+
+/**
+ * @brief Enable/disable prediction (predictive text).
+ *
+ * By default prediction text is enabled.
+ * @param[in] enable true or false to enable or disable
+ * Prediction can not be changed while the keyboard is visible. It must be set in advance of showing keyboard.
+ */
+DALI_ADAPTOR_API void EnablePrediction(const bool enable);
+
+/**
+ * @brief Returns whether prediction is enabled in the virtual keyboard
+ * @return true if predictive text enabled, false otherwise.
+ */
+DALI_ADAPTOR_API bool IsPredictionEnabled();
+
+/**
+ * @brief Provides size and position of keyboard.
+ *
+ * Position is relative to whether keyboard is visible or not.
+ * If keyboard is not visible then position will be off the screen.
+ * If keyboard is not being shown when this method is called the keyboard is partially setup (IMFContext) to get
+ * the values then taken down.  So ideally GetSizeAndPosition() should be called after Show().
+ * @return rect which is keyboard panel x, y, width, height
+ */
+DALI_ADAPTOR_API Dali::Rect<int> GetSizeAndPosition();
+
+/**
+ * @brief Rotates the keyboard orientation to the given angle.
+ *
+ * A value of 0 indicates the portrait orientation.
+ * Other valid values are 90, 180, 270.
+ * @param angle the angle is in degrees.
+ */
+DALI_ADAPTOR_API void RotateTo(int angle);
+
+/**
+ * @brief Returns text direction of the keyboard's current input language.
+ * @return The direction of the text.
+ */
+DALI_ADAPTOR_API TextDirection GetTextDirection();
+
+} // namespace VirtualKeyboard
+
+} // namespace Dali
+
+#endif // DALI_VIRTUAL_KEYBOARD_H
diff --git a/dali/devel-api/adaptor-framework/web-engine-plugin.h b/dali/devel-api/adaptor-framework/web-engine-plugin.h
new file mode 100644 (file)
index 0000000..b8d6379
--- /dev/null
@@ -0,0 +1,360 @@
+#ifndef DALI_WEB_ENGINE_PLUGIN_H
+#define DALI_WEB_ENGINE_PLUGIN_H
+
+/*
+ * Copyright (c) 2018 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/images/native-image-interface.h>
+#include <dali/public-api/signals/dali-signal.h>
+#include <functional>
+
+namespace Dali
+{
+
+class KeyEvent;
+class TouchData;
+
+/**
+ * @brief WebEnginePlugin is an abstract interface, used by dali-adaptor to access WebEngine plugin.
+ * A concrete implementation must be created for each platform and provided as dynamic library.
+ */
+class WebEnginePlugin
+{
+public:
+
+  /**
+   * @brief WebEngine signal type related with page loading.
+   */
+  typedef Signal< void( const std::string& ) > WebEnginePageLoadSignalType;
+
+  /**
+   * @brief WebView signal type related with page loading error.
+   */
+  typedef Signal< void( const std::string&, int ) > WebEnginePageLoadErrorSignalType;
+
+  /**
+   * @brief Enumeration for cache model options.
+   */
+  enum class CacheModel
+  {
+    /**
+     * @brief Use the smallest cache capacity.
+     */
+    DOCUMENT_VIEWER,
+
+    /**
+     * @brief Use the bigger cache capacity than DocumentBrowser.
+     */
+    DOCUMENT_BROWSER,
+
+    /**
+     * @brief Use the biggest cache capacity.
+     */
+    PRIMARY_WEB_BROWSER
+  };
+
+  /**
+   * @brief Enumeration for the cookies accept policies.
+   */
+  enum class CookieAcceptPolicy
+  {
+    /**
+     * @brief Accepts every cookie sent from any page.
+     */
+    ALWAYS,
+
+    /**
+     * @brief Rejects all the cookies.
+     */
+    NEVER,
+
+    /**
+     * @brief Accepts only cookies set by the main document that is loaded.
+     */
+    NO_THIRD_PARTY
+  };
+
+  /**
+   * @brief Constructor.
+   */
+  WebEnginePlugin()
+  {
+  }
+
+  /**
+   * @brief Destructor.
+   */
+  virtual ~WebEnginePlugin()
+  {
+  }
+
+  /**
+   * @brief Creates WebEngine instance.
+   *
+   * @param [in] width The width of Web
+   * @param [in] height The height of Web
+   * @param [in] locale The locale of Web
+   * @param [in] timezoneId The timezoneID of Web
+   */
+  virtual void Create( int width, int height, const std::string& locale, const std::string& timezoneId ) = 0;
+
+  /**
+   * @brief Destroys WebEngine instance.
+   */
+  virtual void Destroy() = 0;
+
+  /**
+   * @brief Loads a web page based on a given URL.
+   *
+   * @param [in] url The URL of the resource to load
+   */
+  virtual void LoadUrl( const std::string& url ) = 0;
+
+  /**
+   * @brief Gets image to render.
+   */
+  virtual NativeImageInterfacePtr GetNativeImageSource() = 0;
+
+  /**
+   * @brief Returns the URL of the Web.
+   *
+   * @return Url of string type
+   */
+  virtual const std::string& GetUrl() = 0;
+
+  /**
+   * @brief Loads a given string as web contents.
+   *
+   * @param [in] htmlString The string to use as the contents of the web page
+   */
+  virtual void LoadHTMLString( const std::string& htmlString ) = 0;
+
+  /**
+   * @brief Reloads the Web.
+   */
+  virtual void Reload() = 0;
+
+  /**
+   * @brief Stops loading web contents on the current page.
+   */
+  virtual void StopLoading() = 0;
+
+  /**
+   * @brief Suspends the operation associated with the view.
+   */
+  virtual void Suspend() = 0;
+
+  /**
+   * @brief Resumes the operation associated with the view object after calling Suspend().
+   */
+  virtual void Resume() = 0;
+
+  /**
+   * @brief Returns whether forward is possible.
+   *
+   * @return True if forward is possible, false otherwise
+   */
+  virtual bool CanGoForward() = 0;
+
+  /**
+   * @brief Goes to forward.
+   */
+  virtual void GoForward() = 0;
+
+  /**
+   * @brief Returns whether backward is possible.
+   *
+   * @return True if backward is possible, false otherwise
+   */
+  virtual bool CanGoBack() = 0;
+
+  /**
+   * @brief Goes to back.
+   */
+  virtual void GoBack() = 0;
+
+  /**
+   * @brief Evaluates JavaScript code represented as a string.
+   *
+   * @param[in] script The JavaScript code
+   * @param[in] resultHandler The callback function to be called by the JavaScript runtime. This carries evaluation result.
+   */
+  virtual void EvaluateJavaScript( const std::string& script, std::function< void( const std::string& ) > resultHandler ) = 0;
+
+  /**
+   * @brief Add a message handler into JavaScript.
+   *
+   * @param[in] exposedObjectName The name of exposed object
+   * @param[in] handler The callback function
+   */
+  virtual void AddJavaScriptMessageHandler( const std::string& exposedObjectName, std::function< void( const std::string& ) > handler ) = 0;
+
+  /**
+   * @brief Clears the history of Web.
+   */
+  virtual void ClearHistory() = 0;
+
+  /**
+   * @brief Clears the cache of Web.
+   */
+  virtual void ClearCache() = 0;
+
+  /**
+   * @brief Clears all the cookies of Web.
+   */
+  virtual void ClearCookies() = 0;
+
+  /**
+   * @brief Get cache model option. The default is DOCUMENT_VIEWER.
+   *
+   * @return The cache model option
+   */
+  virtual CacheModel GetCacheModel() const = 0;
+
+  /**
+   * @brief Set cache model option. The default is DOCUMENT_VIEWER.
+   *
+   * @param[in] cacheModel The cache model option
+   */
+  virtual void SetCacheModel( CacheModel cacheModel ) = 0;
+
+  /**
+   * @brief Gets the cookie acceptance policy. The default is NO_THIRD_PARTY.
+   *
+   * @return The cookie acceptance policy
+   */
+  virtual CookieAcceptPolicy GetCookieAcceptPolicy() const = 0;
+
+  /**
+   * @brief Sets the cookie acceptance policy. The default is NO_THIRD_PARTY.
+   *
+   * @param[in] policy The cookie acceptance policy
+   */
+  virtual void SetCookieAcceptPolicy( CookieAcceptPolicy policy ) = 0;
+
+  /**
+   * @brief Get user agent string.
+   *
+   * @return The string value of user agent
+   */
+  virtual const std::string& GetUserAgent() const = 0;
+
+  /**
+   * @brief Set user agent string.
+   *
+   * @param[in] userAgent The string value of user agent
+   */
+  virtual void SetUserAgent( const std::string& userAgent ) = 0;
+
+  /**
+   * @brief Returns whether JavaScript can be executable. The default is true.
+   *
+   * @return true if JavaScript executing is enabled, false otherwise
+   */
+  virtual bool IsJavaScriptEnabled() const = 0;
+
+  /**
+   * @brief Enables/disables JavaScript executing. The default is enabled.
+   *
+   * @param[in] enabled True if JavaScript executing is enabled, false otherwise
+   */
+  virtual void EnableJavaScript( bool enabled ) = 0;
+
+  /**
+   * @brief Returns whether images can be loaded automatically. The default is true.
+   *
+   * @return true if images are loaded automatically, false otherwise
+   */
+  virtual bool AreImagesAutomaticallyLoaded() const = 0;
+
+  /**
+   * @brief Enables/disables auto loading of images. The default is enabled.
+   *
+   * @param[in] automatic True if images are loaded automatically, false otherwise
+   */
+  virtual void LoadImagesAutomatically( bool automatic ) = 0;
+
+  /**
+   * @brief Gets the default text encoding name (e.g. UTF-8).
+   *
+   * @return The default text encoding name
+   */
+  virtual const std::string& GetDefaultTextEncodingName() const = 0;
+
+  /**
+   * @brief Sets the default text encoding name (e.g. UTF-8).
+   *
+   * @param[in] defaultTextEncodingName The default text encoding name
+   */
+  virtual void SetDefaultTextEncodingName( const std::string& defaultTextEncodingName ) = 0;
+
+  /**
+   * @brief Returns the default font size in pixel. The default value is 16.
+   *
+   * @return The default font size
+   */
+  virtual int GetDefaultFontSize() const = 0;
+
+  /**
+   * @brief Sets the default font size in pixel. The default value is 16.
+   *
+   * @param[in] defaultFontSize A new default font size to set
+   */
+  virtual void SetDefaultFontSize( int defaultFontSize ) = 0;
+
+  /**
+   * @brief Sets size of Web Page.
+   */
+  virtual void SetSize( int width, int height ) = 0;
+
+  /**
+   * @brief Sends Touch Events.
+   */
+  virtual bool SendTouchEvent( const TouchData& touch ) = 0;
+
+  /**
+   * @brief Sends Key Events.
+   */
+  virtual bool SendKeyEvent( const KeyEvent& event ) = 0;
+
+  /**
+   * @brief Connects to this signal to be notified when page loading is started.
+   *
+   * @return A signal object to connect with.
+   */
+  virtual WebEnginePageLoadSignalType& PageLoadStartedSignal() = 0;
+
+  /**
+   * @brief Connects to this signal to be notified when page loading is finished.
+   *
+   * @return A signal object to connect with.
+   */
+  virtual WebEnginePageLoadSignalType& PageLoadFinishedSignal() = 0;
+
+  /**
+   * @brief Connects to this signal to be notified when an error occurs in page loading.
+   *
+   * @return A signal object to connect with.
+   */
+  virtual WebEnginePageLoadErrorSignalType& PageLoadErrorSignal() = 0;
+
+};
+
+} // namespace Dali;
+
+#endif
diff --git a/dali/devel-api/adaptor-framework/web-engine.cpp b/dali/devel-api/adaptor-framework/web-engine.cpp
new file mode 100644 (file)
index 0000000..04a7368
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/adaptor-framework/web-engine.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/web-engine/common/web-engine-impl.h>
+
+namespace Dali
+{
+
+WebEngine::WebEngine()
+{
+}
+
+WebEngine::WebEngine( Internal::Adaptor::WebEngine* internal )
+: BaseHandle( internal )
+{
+}
+
+WebEngine::~WebEngine()
+{
+}
+
+WebEngine WebEngine::New()
+{
+  Internal::Adaptor::WebEnginePtr engine = Internal::Adaptor::WebEngine::New();
+
+  return WebEngine( engine.Get() );
+}
+
+WebEngine::WebEngine( const WebEngine& webEngine )
+: BaseHandle( webEngine )
+{
+}
+
+WebEngine& WebEngine::operator=( const WebEngine& webEngine )
+{
+  if( *this != webEngine )
+  {
+    BaseHandle::operator=( webEngine );
+  }
+  return *this;
+}
+
+WebEngine WebEngine::DownCast( BaseHandle handle )
+{
+  return WebEngine( dynamic_cast< Internal::Adaptor::WebEngine* >( handle.GetObjectPtr() ) );
+}
+
+void WebEngine::Create( int width, int height, const std::string& locale, const std::string& timezoneId )
+{
+  GetImplementation( *this ).Create( width, height, locale, timezoneId );
+}
+
+void WebEngine::Destroy()
+{
+  GetImplementation( *this ).Destroy();
+}
+
+NativeImageInterfacePtr WebEngine::GetNativeImageSource()
+{
+  return GetImplementation( *this ).GetNativeImageSource();
+}
+
+void WebEngine::LoadUrl( const std::string& url )
+{
+  return GetImplementation( *this ).LoadUrl( url );
+}
+
+const std::string& WebEngine::GetUrl()
+{
+  return GetImplementation( *this ).GetUrl();
+}
+
+void WebEngine::LoadHTMLString( const std::string& htmlString )
+{
+  GetImplementation( *this ).LoadHTMLString( htmlString );
+}
+
+void WebEngine::Reload()
+{
+  GetImplementation( *this ).Reload();
+}
+
+void WebEngine::StopLoading()
+{
+  GetImplementation( *this ).StopLoading();
+}
+
+void WebEngine::Suspend()
+{
+  GetImplementation( *this ).Suspend();
+}
+
+void WebEngine::Resume()
+{
+  GetImplementation( *this ).Resume();
+}
+
+bool WebEngine::CanGoForward()
+{
+  return GetImplementation( *this ).CanGoForward();
+}
+
+void WebEngine::GoForward()
+{
+  GetImplementation( *this ).GoForward();
+}
+
+bool WebEngine::CanGoBack()
+{
+  return GetImplementation( *this ).CanGoBack();
+}
+
+void WebEngine::GoBack()
+{
+  GetImplementation( *this ).GoBack();
+}
+
+void WebEngine::EvaluateJavaScript( const std::string& script, std::function< void( const std::string& ) > resultHandler )
+{
+  GetImplementation( *this ).EvaluateJavaScript( script, resultHandler );
+}
+
+void WebEngine::AddJavaScriptMessageHandler( const std::string& exposedObjectName, std::function< void( const std::string& ) > handler )
+{
+  GetImplementation( *this ).AddJavaScriptMessageHandler( exposedObjectName, handler );
+}
+
+void WebEngine::ClearHistory()
+{
+  return GetImplementation( *this ).ClearHistory();
+}
+
+void WebEngine::ClearCache()
+{
+  return GetImplementation( *this ).ClearCache();
+}
+
+void WebEngine::ClearCookies()
+{
+  return GetImplementation( *this ).ClearCookies();
+}
+
+Dali::WebEnginePlugin::CacheModel WebEngine::GetCacheModel() const
+{
+  return GetImplementation( *this ).GetCacheModel();
+}
+
+void WebEngine::SetCacheModel( Dali::WebEnginePlugin::CacheModel cacheModel )
+{
+  GetImplementation( *this ).SetCacheModel( cacheModel );
+}
+
+Dali::WebEnginePlugin::CookieAcceptPolicy WebEngine::GetCookieAcceptPolicy() const
+{
+  return GetImplementation( *this ).GetCookieAcceptPolicy();
+}
+
+void WebEngine::SetCookieAcceptPolicy( Dali::WebEnginePlugin::CookieAcceptPolicy policy )
+{
+  GetImplementation( *this ).SetCookieAcceptPolicy( policy );
+}
+
+const std::string& WebEngine::GetUserAgent() const
+{
+  return GetImplementation( *this ).GetUserAgent();
+}
+
+void WebEngine::SetUserAgent( const std::string& userAgent )
+{
+  GetImplementation( *this ).SetUserAgent( userAgent );
+}
+
+bool WebEngine::IsJavaScriptEnabled() const
+{
+  return GetImplementation( *this ).IsJavaScriptEnabled();
+}
+
+void WebEngine::EnableJavaScript( bool enabled )
+{
+  GetImplementation( *this ).EnableJavaScript( enabled );
+}
+
+bool WebEngine::AreImagesAutomaticallyLoaded() const
+{
+  return GetImplementation( *this ).AreImagesAutomaticallyLoaded();
+}
+
+void WebEngine::LoadImagesAutomatically( bool automatic )
+{
+  GetImplementation( *this ).LoadImagesAutomatically( automatic );
+}
+
+const std::string& WebEngine::GetDefaultTextEncodingName() const
+{
+  return GetImplementation( *this ).GetDefaultTextEncodingName();
+}
+
+void WebEngine::SetDefaultTextEncodingName( const std::string& defaultTextEncodingName )
+{
+  GetImplementation( *this ).SetDefaultTextEncodingName( defaultTextEncodingName );
+}
+
+int WebEngine::GetDefaultFontSize() const
+{
+  return GetImplementation( *this ).GetDefaultFontSize();
+}
+
+void WebEngine::SetDefaultFontSize( int defaultFontSize )
+{
+  GetImplementation( *this ).SetDefaultFontSize( defaultFontSize );
+}
+
+void WebEngine::SetSize( int width, int height )
+{
+  return GetImplementation( *this ).SetSize( width, height );
+}
+
+bool WebEngine::SendTouchEvent( const TouchData& touch )
+{
+  return GetImplementation( *this ).SendTouchEvent( touch );
+}
+
+bool WebEngine::SendKeyEvent( const KeyEvent& event )
+{
+  return GetImplementation( *this ).SendKeyEvent( event );
+}
+
+Dali::WebEnginePlugin::WebEnginePageLoadSignalType& WebEngine::PageLoadStartedSignal()
+{
+  return GetImplementation( *this ).PageLoadStartedSignal();
+}
+
+Dali::WebEnginePlugin::WebEnginePageLoadSignalType& WebEngine::PageLoadFinishedSignal()
+{
+  return GetImplementation( *this ).PageLoadFinishedSignal();
+}
+
+Dali::WebEnginePlugin::WebEnginePageLoadErrorSignalType& WebEngine::PageLoadErrorSignal()
+{
+  return GetImplementation( *this ).PageLoadErrorSignal();
+}
+
+} // namespace Dali;
+
diff --git a/dali/devel-api/adaptor-framework/web-engine.h b/dali/devel-api/adaptor-framework/web-engine.h
new file mode 100644 (file)
index 0000000..e9b604e
--- /dev/null
@@ -0,0 +1,350 @@
+#ifndef DALI_WEB_ENGINE_H
+#define DALI_WEB_ENGINE_H
+
+/*
+ * Copyright (c) 2018 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/object/base-handle.h>
+
+//INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/web-engine-plugin.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+  class WebEngine;
+} // namespace Adaptor
+
+} // namespace Internal
+
+/**
+ * @brief Proxy class to dynamically load, use and unload web engine plugin.
+ *
+ * The purpose of this class is to dynamically load the web engine plugin if and when its needed.
+ * So we don't slow down every application startup if they never need web engine.
+ */
+class DALI_ADAPTOR_API WebEngine : public BaseHandle
+{
+public:
+
+  /**
+   * @brief Constructor.
+   */
+  WebEngine();
+
+  /**
+   * @brief Destructor.
+   */
+  ~WebEngine();
+
+  /**
+   * @brief Creates a new instance of a WebEngine.
+   */
+  static WebEngine New();
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @param[in] WebEngine WebEngine to copy. The copied WebEngine will point at the same implementation
+   */
+  WebEngine( const WebEngine& WebEngine );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @param[in] WebEngine The WebEngine to assign from.
+   * @return The updated WebEngine.
+   */
+  WebEngine& operator=( const WebEngine& WebEngine );
+
+  /**
+   * @brief Downcast a handle to WebEngine handle.
+   *
+   * If handle points to a WebEngine the downcast produces valid
+   * handle. If not the returned handle is left uninitialized.
+   *
+   * @param[in] handle Handle to an object
+   * @return Handle to a WebEngine or an uninitialized handle
+   */
+  static WebEngine DownCast( BaseHandle handle );
+
+  /**
+   * @brief Creates WebEngine instance.
+   *
+   * @param [in] width The width of Web
+   * @param [in] height The height of Web
+   * @param [in] locale The locale of Web
+   * @param [in] timezoneId The timezoneID of Web
+   */
+  void Create( int width, int height, const std::string& locale, const std::string& timezoneId );
+
+  /**
+   * @brief Destroys WebEngine instance.
+   */
+  void Destroy();
+
+  /**
+   * @brief Gets native image source to render.
+   */
+  NativeImageInterfacePtr GetNativeImageSource();
+
+  /**
+   * @brief Loads a web page based on a given URL.
+   *
+   * @param [in] url The URL of the resource to load
+   */
+  void LoadUrl( const std::string& url );
+
+  /**
+   * @brief Gets the url.
+   */
+  const std::string& GetUrl();
+
+  /**
+   * @brief Loads a given string as web contents.
+   *
+   * @param [in] htmlString The string to use as the contents of the web page
+   */
+  void LoadHTMLString( const std::string& htmlString );
+
+  /**
+   * @brief Reloads the Web.
+   */
+  void Reload();
+
+  /**
+   * @brief Stops loading web contents on the current page.
+   */
+  void StopLoading();
+
+  /**
+   * @brief Suspends the operation associated with the view.
+   */
+  void Suspend();
+
+  /**
+   * @brief Resumes the operation associated with the view object after calling Suspend().
+   */
+  void Resume();
+
+  /**
+   * @brief Returns whether forward is possible.
+   *
+   * @return True if forward is possible, false otherwise
+   */
+  bool CanGoForward();
+
+  /**
+   * @brief Goes to forward.
+   */
+  void GoForward();
+
+  /**
+   * @brief Returns whether backward is possible.
+   *
+   * @return True if backward is possible, false otherwise
+   */
+  bool CanGoBack();
+
+  /**
+   * @brief Goes to back.
+   */
+  void GoBack();
+
+  /**
+   * @brief Evaluates JavaScript code represented as a string.
+   *
+   * @param[in] script The JavaScript code
+   * @param[in] resultHandler The callback function to be called by the JavaScript runtime. This carries evaluation result.
+   */
+  void EvaluateJavaScript( const std::string& script, std::function< void( const std::string& ) > resultHandler );
+
+  /**
+   * @brief Add a message handler into JavaScript.
+   *
+   * @param[in] exposedObjectName The name of exposed object
+   * @param[in] handler The callback function
+   */
+  void AddJavaScriptMessageHandler( const std::string& exposedObjectName, std::function< void( const std::string& ) > handler );
+
+  /**
+   * @brief Clears the history of Web.
+   */
+  void ClearHistory();
+
+  /**
+   * @brief Clears the cache of Web.
+   */
+  void ClearCache();
+
+  /**
+   * @brief Clears all the cookies of Web.
+   */
+  void ClearCookies();
+
+  /**
+   * @brief Get cache model option. The default is DOCUMENT_VIEWER.
+   *
+   * @return The cache model option
+   */
+  Dali::WebEnginePlugin::CacheModel GetCacheModel() const;
+
+  /**
+   * @brief Set cache model option. The default is DOCUMENT_VIEWER.
+   *
+   * @param[in] cacheModel The cache model option
+   */
+  void SetCacheModel( Dali::WebEnginePlugin::CacheModel cacheModel );
+
+  /**
+   * @brief Gets the cookie acceptance policy. The default is NO_THIRD_PARTY.
+   *
+   * @return The cookie acceptance policy
+   */
+  Dali::WebEnginePlugin::CookieAcceptPolicy GetCookieAcceptPolicy() const;
+
+  /**
+   * @brief Sets the cookie acceptance policy. The default is NO_THIRD_PARTY.
+   *
+   * @param[in] policy The cookie acceptance policy
+   */
+  void SetCookieAcceptPolicy( Dali::WebEnginePlugin::CookieAcceptPolicy policy );
+
+  /**
+   * @brief Get user agent string.
+   *
+   * @return The string value of user agent
+   */
+  const std::string& GetUserAgent() const;
+
+  /**
+   * @brief Set user agent string.
+   *
+   * @param[in] userAgent The string value of user agent
+   */
+  void SetUserAgent( const std::string& userAgent );
+
+  /**
+   * @brief Returns whether JavaScript can be executable. The default is true.
+   *
+   * @return true if JavaScript executing is enabled, false otherwise
+   */
+  bool IsJavaScriptEnabled() const;
+
+  /**
+   * @brief Enables/disables JavaScript executing. The default is enabled.
+   *
+   * @param[in] enabled True if JavaScript executing is enabled, false otherwise
+   */
+  void EnableJavaScript( bool enabled );
+
+  /**
+   * @brief Returns whether JavaScript can be executable. The default is true.
+   *
+   * @return true if images are loaded automatically, false otherwise
+   */
+  bool AreImagesAutomaticallyLoaded() const;
+
+  /**
+   * @brief Enables/disables auto loading of images. The default is enabled.
+   *
+   * @param[in] automatic True if images are loaded automatically, false otherwise
+   */
+  void LoadImagesAutomatically( bool automatic );
+
+  /**
+   * @brief Gets the default text encoding name.
+   *
+   * @return The default text encoding name
+   */
+  const std::string& GetDefaultTextEncodingName() const;
+
+  /**
+   * @brief Sets the default text encoding name.
+   *
+   * @param[in] defaultTextEncodingName The default text encoding name
+   */
+  void SetDefaultTextEncodingName( const std::string& defaultTextEncodingName );
+
+  /**
+   * @brief Returns the default font size in pixel. The default value is 16.
+   *
+   * @return The default font size
+   */
+  int GetDefaultFontSize() const;
+
+  /**
+   * @brief Sets the default font size in pixel. The default value is 16.
+   *
+   * @param[in] defaultFontSize A new default font size to set
+   */
+  void SetDefaultFontSize( int defaultFontSize );
+
+  /**
+   * @brief Sets the size of Web Pages.
+   */
+  void SetSize( int width, int height );
+
+  /**
+   * @brief Sends Touch Events.
+   */
+  bool SendTouchEvent( const TouchData& touch );
+
+  /**
+   * @brief Sends key Events.
+   */
+  bool SendKeyEvent( const KeyEvent& event );
+
+  /**
+   * @brief Connects to this signal to be notified when page loading is started.
+   *
+   * @return A signal object to connect with.
+   */
+  Dali::WebEnginePlugin::WebEnginePageLoadSignalType& PageLoadStartedSignal();
+
+  /**
+   * @brief Connects to this signal to be notified when page loading is finished.
+   *
+   * @return A signal object to connect with.
+   */
+  Dali::WebEnginePlugin::WebEnginePageLoadSignalType& PageLoadFinishedSignal();
+
+  /**
+   * @brief Connects to this signal to be notified when an error occurs in page loading.
+   *
+   * @return A signal object to connect with.
+   */
+  Dali::WebEnginePlugin::WebEnginePageLoadErrorSignalType& PageLoadErrorSignal();
+
+private: // Not intended for application developers
+
+  /**
+   * @brief Internal constructor
+   */
+  explicit DALI_INTERNAL WebEngine( Internal::Adaptor::WebEngine* internal );
+};
+
+} // namespace Dali;
+
+#endif // DALI_WEB_ENGINE_H
diff --git a/dali/devel-api/adaptor-framework/window-devel.cpp b/dali/devel-api/adaptor-framework/window-devel.cpp
new file mode 100644 (file)
index 0000000..e2f503e
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2019 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/events/key-event.h>
+#include <dali/public-api/events/touch-event.h>
+#include <dali/public-api/events/wheel-event.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/window-devel.h>
+#include <dali/internal/window-system/common/window-impl.h>
+
+namespace Dali
+{
+
+namespace DevelWindow
+{
+
+Window New(Any surface, PositionSize windowPosition, const std::string& name, bool isTransparent)
+{
+  return DevelWindow::New(surface, windowPosition, name, "", isTransparent);
+}
+
+Window New(Any surface, PositionSize windowPosition, const std::string& name, const std::string& className, bool isTransparent)
+{
+  Window newWindow;
+
+  const bool isAdaptorAvailable = Dali::Adaptor::IsAvailable();
+  bool isNewWindowAllowed = true;
+
+  if (isAdaptorAvailable)
+  {
+    Dali::Adaptor& adaptor = Internal::Adaptor::Adaptor::Get();
+    isNewWindowAllowed = Internal::Adaptor::Adaptor::GetImplementation(adaptor).IsMultipleWindowSupported();
+  }
+
+  if (isNewWindowAllowed)
+  {
+    Internal::Adaptor::Window* window = Internal::Adaptor::Window::New(surface, windowPosition, name, className, isTransparent);
+
+    Integration::SceneHolder sceneHolder = Integration::SceneHolder(window);
+    if (isAdaptorAvailable)
+    {
+      Dali::Adaptor& adaptor = Internal::Adaptor::Adaptor::Get();
+      Internal::Adaptor::Adaptor::GetImplementation(adaptor).AddWindow(sceneHolder, name, className, isTransparent);
+    }
+    newWindow = Window(window);
+  }
+  else
+  {
+    DALI_LOG_ERROR("This device can't support multiple windows.\n");
+  }
+
+  return newWindow;
+}
+
+void SetPositionSize( Window window, PositionSize positionSize )
+{
+  GetImplementation( window ).SetPositionSize( positionSize );
+}
+
+Dali::RenderTaskList GetRenderTaskList( Window window )
+{
+  return GetImplementation( window ).GetRenderTaskList();
+}
+
+Window Get( Actor actor )
+{
+  return Internal::Adaptor::Window::Get( actor );
+}
+
+EventProcessingFinishedSignalType& EventProcessingFinishedSignal( Window window )
+{
+  return GetImplementation( window ).EventProcessingFinishedSignal();
+}
+
+KeyEventSignalType& KeyEventSignal( Window window )
+{
+  return GetImplementation( window ).KeyEventSignal();
+}
+
+TouchSignalType& TouchSignal( Window window )
+{
+  return GetImplementation( window ).TouchSignal();
+}
+
+WheelEventSignalType& WheelEventSignal( Window window )
+{
+  return GetImplementation( window ).WheelEventSignal();
+}
+
+VisibilityChangedSignalType& VisibilityChangedSignal( Window window )
+{
+  return GetImplementation( window ).VisibilityChangedSignal();
+}
+
+TransitionEffectEventSignalType& TransitionEffectEventSignal( Window window )
+{
+  return GetImplementation( window ).TransitionEffectEventSignal();
+}
+
+void SetParent( Window window, Window parent )
+{
+  GetImplementation( window ).SetParent( parent );
+}
+
+void Unparent( Window window )
+{
+  GetImplementation( window ).Unparent();
+}
+
+Window GetParent( Window window )
+{
+  return GetImplementation( window ).GetParent();
+}
+
+Window DownCast( BaseHandle handle )
+{
+  return Window( dynamic_cast<Dali::Internal::Adaptor::Window*>( handle.GetObjectPtr()) );
+}
+
+Dali::Window::WindowOrientation GetCurrentOrientation( Window window )
+{
+  return GetImplementation( window ).GetCurrentOrientation();
+}
+
+void SetAvailableOrientations( Window window, const Dali::Vector<Dali::Window::WindowOrientation>& orientations )
+{
+  GetImplementation( window ).SetAvailableOrientations( orientations );
+}
+
+} // namespace DevelWindow
+
+} // namespace Dali
diff --git a/dali/devel-api/adaptor-framework/window-devel.h b/dali/devel-api/adaptor-framework/window-devel.h
new file mode 100644 (file)
index 0000000..4687503
--- /dev/null
@@ -0,0 +1,250 @@
+#ifndef DALI_WINDOW_DEVEL_H
+#define DALI_WINDOW_DEVEL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/adaptor-framework/window.h>
+
+namespace Dali
+{
+class KeyEvent;
+class TouchData;
+class WheelEvent;
+class RenderTaskList;
+
+namespace DevelWindow
+{
+/**
+ * @brief Enumeration for transition effect's state.
+ */
+enum class EffectState
+{
+  NONE = 0,    ///< None state
+  START,       ///< Transition effect is started.
+  END          ///< Transition effect is ended.
+};
+
+/**
+ * @brief Enumeration for transition effect's type.
+ */
+enum class  EffectType
+{
+  NONE = 0,    ///< None type
+  SHOW,        ///< Window show effect.
+  HIDE,        ///< Window hide effect.
+};
+
+typedef Signal< void () > EventProcessingFinishedSignalType;       ///< Event Processing finished signal type
+
+typedef Signal< void (const KeyEvent&) > KeyEventSignalType;       ///< Key event signal type
+
+typedef Signal< void (const TouchData&) > TouchSignalType;         ///< Touch signal type
+
+typedef Signal< void (const WheelEvent&) > WheelEventSignalType;   ///< Touched signal type
+
+typedef Signal< void ( Window, bool ) > VisibilityChangedSignalType; ///< Visibility changed signal type
+
+typedef Signal< void (Window, EffectState, EffectType) > TransitionEffectEventSignalType; ///< Effect signal type and state
+
+/**
+ * @brief Creates an initialized handle to a new Window.
+ *
+ * @param[in] surface Can be a window or pixmap.
+ * @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
+ * @note This creates an extra window in addition to the default main window
+*/
+DALI_ADAPTOR_API Window New(Any surface, PositionSize windowPosition, const std::string& name, bool isTransparent = false);
+
+/**
+ * @brief Creates an initialized handle to a new Window.
+ *
+ * @param[in] surface Can be a window or pixmap.
+ * @param[in] windowPosition 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
+ * @note This creates an extra window in addition to the default main window
+ * @return A new Window
+ */
+DALI_ADAPTOR_API Window New(Any surface, PositionSize windowPosition, const std::string& name, const std::string& className, bool isTransparent = false);
+
+/**
+ * @brief Sets position and size of the window. This API guarantees that both moving and resizing of window will appear on the screen at once.
+ *
+ * @param[in] window The window instance
+ * @param[in] positionSize The new window position and size
+ */
+DALI_ADAPTOR_API void SetPositionSize( Window window, PositionSize positionSize );
+
+/**
+ * @brief Retrieves the list of render-tasks in the window.
+ *
+ * @param[in] window The window instance
+ * @return A valid handle to a RenderTaskList
+ */
+DALI_ADAPTOR_API Dali::RenderTaskList GetRenderTaskList( Window window );
+
+/**
+ * @brief Retrieve the window that the given actor is added to.
+ *
+ * @param[in] actor The actor
+ * @return The window the actor is added to or an empty handle if the actor is not added to any window.
+ */
+DALI_ADAPTOR_API Window Get( Actor actor );
+
+/**
+ * @brief This signal is emitted just after the event processing is finished.
+ *
+ * @param[in] window The window instance
+ * @return The signal to connect to
+ */
+DALI_ADAPTOR_API EventProcessingFinishedSignalType& EventProcessingFinishedSignal( Window window );
+
+/**
+ * @brief This signal is emitted when key event is received.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ *   void YourCallbackName(const KeyEvent& event);
+ * @endcode
+ * @param[in] window The window instance
+ * @return The signal to connect to
+ */
+DALI_ADAPTOR_API KeyEventSignalType& KeyEventSignal( Window window );
+
+/**
+ * @brief This signal is emitted when the screen is touched and when the touch ends
+ * (i.e. the down & up touch events only).
+ *
+ * If there are multiple touch points, then this will be emitted when the first touch occurs and
+ * then when the last finger is lifted.
+ * An interrupted event will also be emitted (if it occurs).
+ * A callback of the following type may be connected:
+ * @code
+ *   void YourCallbackName( TouchData event );
+ * @endcode
+ *
+ * @param[in] window The window instance
+ * @return The touch signal to connect to
+ * @note Motion events are not emitted.
+ */
+DALI_ADAPTOR_API TouchSignalType& TouchSignal( Window window );
+
+/**
+ * @brief This signal is emitted when wheel event is received.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ *   void YourCallbackName(const WheelEvent& event);
+ * @endcode
+ * @param[in] window The window instance
+ * @return The signal to connect to
+ */
+DALI_ADAPTOR_API WheelEventSignalType& WheelEventSignal( Window window );
+
+/**
+ * @brief This signal is emitted when the window is shown or hidden.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ *   void YourCallbackName( Window window, bool visible );
+ * @endcode
+ * @param[in] window The window instance
+ * @return The signal to connect to
+ */
+DALI_ADAPTOR_API VisibilityChangedSignalType& VisibilityChangedSignal( Window window );
+
+/**
+ * @brief This signal is emitted for transition effect.
+ *
+ * The transition animation is appeared when the window is shown/hidden.
+ * When the animation is started, START signal is emitted.
+ * Then the animation is ended, END signal is emitted, too.
+ * A callback of the following type may be connected:
+ * @code
+ *   void YourCallbackName( Window window, EffectState state, EffectType type );
+ * @endcode
+ * @param[in] window The window instance
+ * @return The signal to connect to
+ */
+DALI_ADAPTOR_API TransitionEffectEventSignalType& TransitionEffectEventSignal( Window window );
+
+/**
+ * @brief Sets parent window of the window.
+ *
+ * After setting that, these windows do together when raise-up, lower and iconified/deiconified.
+ * Initially, the window is located on top of the parent. The window can go below parent by calling Lower().
+ * If parent's window stack is changed by calling Raise() or Lower(), child windows are located on top of the parent again.
+ *
+ * @param[in] window The window instance
+ * @param[in] parent The parent window instance
+ */
+DALI_ADAPTOR_API void SetParent( Window window, Window parent );
+
+/**
+ * @brief Unsets parent window of the window.
+ *
+ * After unsetting, the window is disconnected his parent window.
+ *
+ * @param[in] window The window instance
+ */
+DALI_ADAPTOR_API void Unparent( Window window );
+
+/**
+ * @brief Gets parent window of the window.
+ *
+ * @param[in] window The window instance
+ * @return The parent window of the window
+ */
+DALI_ADAPTOR_API Window GetParent( Window window );
+
+/**
+ * @brief Downcast sceneHolder to window
+ *
+ * @param[in] handle The handle need to downcast
+ * @return The window cast from SceneHolder
+ */
+DALI_ADAPTOR_API Window DownCast(  BaseHandle handle );
+
+/**
+ * @brief Gets current orientation of the window.
+ *
+ * @param[in] window The window instance
+ * @return The current window orientation if previously set, or none
+ */
+DALI_ADAPTOR_API Dali::Window::WindowOrientation GetCurrentOrientation( Window window );
+
+/**
+ * @brief Sets available orientations of the window.
+ *
+ * This API is for setting several orientations one time.
+ *
+ * @param[in] window The window instance
+ * @param[in] orientations The available orientation list to add
+ */
+DALI_ADAPTOR_API void SetAvailableOrientations( Window window, const Dali::Vector<Dali::Window::WindowOrientation>& orientations );
+
+} // namespace DevelWindow
+
+} // namespace Dali
+
+#endif // DALI_WINDOW_DEVEL_H
diff --git a/dali/devel-api/file.list b/dali/devel-api/file.list
new file mode 100755 (executable)
index 0000000..33c3ab3
--- /dev/null
@@ -0,0 +1,120 @@
+
+
+SET( 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/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/color-controller.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/environment-variable.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/event-feeder.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/event-thread-callback.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/feedback-player.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/file-loader.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/file-stream.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/image-loading.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/gif-loading.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/input-method-context.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/input-method-options.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/native-image-source-devel.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/native-image-source-queue.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/key-devel.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/pixel-buffer.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/tilt-sensor.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/lifecycle-controller.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/vector-animation-renderer.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/video-player.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/virtual-keyboard.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/thread-settings.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/web-engine.cpp
+  ${adaptor_devel_api_dir}/adaptor-framework/window-devel.cpp
+)
+
+
+SET( devel_api_adaptor_framework_header_files
+  ${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/accessibility-gesture-event.h
+  ${adaptor_devel_api_dir}/adaptor-framework/application-devel.h
+  ${adaptor_devel_api_dir}/adaptor-framework/atspi-accessibility.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/color-controller-plugin.h
+  ${adaptor_devel_api_dir}/adaptor-framework/color-controller.h
+  ${adaptor_devel_api_dir}/adaptor-framework/environment-variable.h
+  ${adaptor_devel_api_dir}/adaptor-framework/event-feeder.h
+  ${adaptor_devel_api_dir}/adaptor-framework/event-thread-callback.h
+  ${adaptor_devel_api_dir}/adaptor-framework/feedback-plugin.h
+  ${adaptor_devel_api_dir}/adaptor-framework/feedback-player.h
+  ${adaptor_devel_api_dir}/adaptor-framework/file-loader.h
+  ${adaptor_devel_api_dir}/adaptor-framework/file-stream.h
+  ${adaptor_devel_api_dir}/adaptor-framework/image-loader-input.h
+  ${adaptor_devel_api_dir}/adaptor-framework/image-loader-plugin.h
+  ${adaptor_devel_api_dir}/adaptor-framework/image-loading.h
+  ${adaptor_devel_api_dir}/adaptor-framework/gif-loading.h
+  ${adaptor_devel_api_dir}/adaptor-framework/input-method-context.h
+  ${adaptor_devel_api_dir}/adaptor-framework/input-method-options.h
+  ${adaptor_devel_api_dir}/adaptor-framework/keyboard.h
+  ${adaptor_devel_api_dir}/adaptor-framework/lifecycle-controller.h
+  ${adaptor_devel_api_dir}/adaptor-framework/native-image-source-devel.h
+  ${adaptor_devel_api_dir}/adaptor-framework/native-image-source-queue.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/sound-player.h
+  ${adaptor_devel_api_dir}/adaptor-framework/style-monitor.h
+  ${adaptor_devel_api_dir}/adaptor-framework/tilt-sensor.h
+  ${adaptor_devel_api_dir}/adaptor-framework/vector-animation-renderer.h
+  ${adaptor_devel_api_dir}/adaptor-framework/vector-animation-renderer-plugin.h
+  ${adaptor_devel_api_dir}/adaptor-framework/video-player.h
+  ${adaptor_devel_api_dir}/adaptor-framework/video-player-plugin.h
+  ${adaptor_devel_api_dir}/adaptor-framework/web-engine.h
+  ${adaptor_devel_api_dir}/adaptor-framework/web-engine-plugin.h
+  ${adaptor_devel_api_dir}/adaptor-framework/key-extension-plugin.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/key-devel.h
+  ${adaptor_devel_api_dir}/adaptor-framework/thread-settings.h
+  ${adaptor_devel_api_dir}/adaptor-framework/window-devel.h
+)
+
+
+SET( devel_api_text_abstraction_src_files
+   ${adaptor_devel_api_dir}/text-abstraction/bidirectional-support.cpp
+   ${adaptor_devel_api_dir}/text-abstraction/bitmap-font.cpp
+   ${adaptor_devel_api_dir}/text-abstraction/font-client.cpp
+   ${adaptor_devel_api_dir}/text-abstraction/font-list.cpp
+   ${adaptor_devel_api_dir}/text-abstraction/font-metrics.cpp
+   ${adaptor_devel_api_dir}/text-abstraction/glyph-info.cpp
+   ${adaptor_devel_api_dir}/text-abstraction/script.cpp
+   ${adaptor_devel_api_dir}/text-abstraction/segmentation.cpp
+   ${adaptor_devel_api_dir}/text-abstraction/shaping.cpp
+   ${adaptor_devel_api_dir}/text-abstraction/text-renderer.cpp
+   ${adaptor_devel_api_dir}/text-abstraction/text-renderer-layout-helper.cpp
+)
+
+
+SET( text_abstraction_header_files
+   ${adaptor_devel_api_dir}/text-abstraction/bidirectional-support.h
+   ${adaptor_devel_api_dir}/text-abstraction/bitmap-font.h
+   ${adaptor_devel_api_dir}/text-abstraction/font-client.h
+   ${adaptor_devel_api_dir}/text-abstraction/font-list.h
+   ${adaptor_devel_api_dir}/text-abstraction/font-metrics.h
+   ${adaptor_devel_api_dir}/text-abstraction/glyph-info.h
+   ${adaptor_devel_api_dir}/text-abstraction/script.h
+   ${adaptor_devel_api_dir}/text-abstraction/segmentation.h
+   ${adaptor_devel_api_dir}/text-abstraction/shaping.h
+   ${adaptor_devel_api_dir}/text-abstraction/text-abstraction.h
+   ${adaptor_devel_api_dir}/text-abstraction/text-abstraction-definitions.h
+   ${adaptor_devel_api_dir}/text-abstraction/text-renderer.h
+   ${adaptor_devel_api_dir}/text-abstraction/text-renderer-layout-helper.h
+)
+
diff --git a/dali/devel-api/text-abstraction/bidirectional-support.cpp b/dali/devel-api/text-abstraction/bidirectional-support.cpp
new file mode 100755 (executable)
index 0000000..79389ae
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * 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 <dali/devel-api/text-abstraction/bidirectional-support.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/text/text-abstraction/bidirectional-support-impl.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+BidirectionalSupport::BidirectionalSupport()
+{
+}
+
+BidirectionalSupport::~BidirectionalSupport()
+{
+}
+
+BidirectionalSupport::BidirectionalSupport( Internal::BidirectionalSupport* implementation )
+: BaseHandle( implementation )
+{
+}
+
+BidirectionalSupport BidirectionalSupport::Get()
+{
+  return Internal::BidirectionalSupport::Get();
+}
+
+BidiInfoIndex BidirectionalSupport::CreateInfo( const Character* const paragraph,
+                                                Length numberOfCharacters,
+                                                bool matchSystemLanguageDirection,
+                                                LayoutDirection::Type layoutDirection )
+{
+  return GetImplementation( *this ).CreateInfo( paragraph,
+                                                numberOfCharacters,
+                                                matchSystemLanguageDirection,
+                                                layoutDirection );
+}
+
+void BidirectionalSupport::DestroyInfo( BidiInfoIndex bidiInfoIndex )
+{
+  GetImplementation( *this ).DestroyInfo( bidiInfoIndex );
+}
+
+void BidirectionalSupport::Reorder( BidiInfoIndex bidiInfoIndex,
+                                    CharacterIndex firstCharacterIndex,
+                                    Length numberOfCharacters,
+                                    CharacterIndex* visualToLogicalMap )
+{
+  GetImplementation( *this ).Reorder( bidiInfoIndex,
+                                      firstCharacterIndex,
+                                      numberOfCharacters,
+                                      visualToLogicalMap );
+}
+
+bool BidirectionalSupport::GetMirroredText( Character* text,
+                                            CharacterDirection* directions,
+                                            Length numberOfCharacters )
+{
+  return GetImplementation( *this ).GetMirroredText( text,
+                                                     directions,
+                                                     numberOfCharacters );
+}
+
+bool BidirectionalSupport::GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const
+{
+  return GetImplementation( *this ).GetParagraphDirection( bidiInfoIndex );
+}
+
+void BidirectionalSupport::GetCharactersDirection( BidiInfoIndex bidiInfoIndex,
+                                                   CharacterDirection* directions,
+                                                   Length numberOfCharacters )
+{
+  GetImplementation( *this ).GetCharactersDirection( bidiInfoIndex,
+                                                     directions,
+                                                     numberOfCharacters );
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/devel-api/text-abstraction/bidirectional-support.h b/dali/devel-api/text-abstraction/bidirectional-support.h
new file mode 100755 (executable)
index 0000000..6bd5b75
--- /dev/null
@@ -0,0 +1,154 @@
+#ifndef DALI_PLATFORM_TEXT_ABSTRACTION_BIDIRECTIONAL_SUPPORT_H
+#define DALI_PLATFORM_TEXT_ABSTRACTION_BIDIRECTIONAL_SUPPORT_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/actors/actor-enumerations.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal DALI_INTERNAL
+{
+
+class BidirectionalSupport;
+
+} // Internal
+
+/**
+ * BidirectionalSupport API
+ *
+ */
+class DALI_ADAPTOR_API BidirectionalSupport : public BaseHandle
+{
+
+public:
+
+  /**
+   * @brief Create an uninitialized TextAbstraction handle.
+   *
+   */
+  BidirectionalSupport();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~BidirectionalSupport();
+
+  /**
+   * @brief This constructor is used by BidirectionalSupport::Get().
+   *
+   * @param[in] implementation a pointer to the internal bidirectional support object.
+   */
+  explicit DALI_INTERNAL BidirectionalSupport( Internal::BidirectionalSupport* implementation );
+
+  /**
+   * @brief Retrieve a handle to the BidirectionalSupport instance.
+   *
+   * @return A handle to the BidirectionalSupport
+   */
+  static BidirectionalSupport Get();
+
+  /**
+   * @brief Creates bidirectional data for the whole paragraph.
+   *
+   * @param[in] paragraph Pointer to the first character of the paragraph coded in UTF32.
+   * @param[in] numberOfCharacters The number of characters of the paragraph.
+   * @param[in] matchSystemLanguageDirection Whether match for system language direction or not.
+   * @param[in] layoutDirection The direction of the system language.
+   * @return An index of an object inside a table storing the bidirectional data.
+   */
+  BidiInfoIndex CreateInfo( const Character* const paragraph,
+                            Length numberOfCharacters,
+                            bool matchSystemLanguageDirection,
+                            LayoutDirection::Type layoutDirection );
+
+  /**
+   * @brief Destroys the bidirectional data.
+   *
+   * @param[in] bidiInfoIndex The index to the of the object inside the table storing the bidirectional data for the current paragraph.
+   */
+  void DestroyInfo( BidiInfoIndex bidiInfoIndex );
+
+  /**
+   * @brief Reorders a line of a paragraph.
+   *
+   * @pre visualToLogicalMap must have enough space allocated for @p numberOfCharacters.
+   *
+   * @param[in] bidiInfoIndex The index to the of the object inside the table storing the bidirectional data for the current paragraph.
+   * @param[in] firstCharacterIndex The first character of the line within the whole paragraph.
+   * @param[in] numberOfCharacters The number of characters of the line.
+   * @param[out] visualToLogicalMap The visual to logical conversion map.
+   */
+  void Reorder( BidiInfoIndex bidiInfoIndex,
+                CharacterIndex firstCharacterIndex,
+                Length numberOfCharacters,
+                CharacterIndex* visualToLogicalMap );
+
+  /**
+   * @brief Replaces any character which could be mirrored.
+   *
+   * @param[in,out] text The text.
+   * @param[in] directions The direction of each paragraph.
+   * @param[in] numberOfCharacters The number of characters.
+   *
+   * @return @e true if a character has been replaced.
+   */
+  bool GetMirroredText( Character* text,
+                        CharacterDirection* directions,
+                        Length numberOfCharacters );
+
+  /**
+   * @brief Retrieves the paragrpah's direction.
+   *
+   * @param[in] bidiInfoIndex The index to the of the object inside the table storing the bidirectional data for the current paragraph.
+   *
+   * @return @e true if the paragraph is right to left, otherwise @e false.
+   */
+  bool GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const;
+
+  /**
+   * @brief Retrieves the character's directions.
+   *
+   * @param[in] bidiInfoIndex The index to the of the object inside the table storing the bidirectional data for the current paragraph.
+   * @param[out] directions The direction, @e false is left to right and @e true is right to left, of each character of the paragraph.
+   * @param[in] numberOfCharacters The number of characters.
+   */
+  void GetCharactersDirection( BidiInfoIndex bidiInfoIndex,
+                               CharacterDirection* directions,
+                               Length numberOfCharacters );
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_PLATFORM_TEXT_ABSTRACTION_BIDIRECTIONAL_SUPPORT_H
diff --git a/dali/devel-api/text-abstraction/bitmap-font.cpp b/dali/devel-api/text-abstraction/bitmap-font.cpp
new file mode 100755 (executable)
index 0000000..7b9b5d0
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali/devel-api/text-abstraction/bitmap-font.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+BitmapGlyph::BitmapGlyph()
+: url{},
+  utf32{ 0u },
+  ascender{ 0.f },
+  descender{ 0.f }
+{}
+
+BitmapGlyph::BitmapGlyph( const std::string& url, GlyphIndex utf32, float ascender, float descender )
+: url{ url },
+  utf32{ utf32 },
+  ascender{ ascender },
+  descender{ descender }
+{}
+
+BitmapGlyph::~BitmapGlyph()
+{}
+
+BitmapFont::BitmapFont()
+: glyphs{},
+  name{},
+  ascender{ 0.f },
+  descender{ 0.f },
+  underlinePosition{ 0.f },
+  underlineThickness{ 1.f },
+  isColorFont{ false }
+{}
+
+BitmapFont::~BitmapFont()
+{}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
diff --git a/dali/devel-api/text-abstraction/bitmap-font.h b/dali/devel-api/text-abstraction/bitmap-font.h
new file mode 100755 (executable)
index 0000000..a3c3272
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef DALI_TEXT_ABSTRACTION_BITMAP_FONT_H
+#define DALI_TEXT_ABSTRACTION_BITMAP_FONT_H
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/dali-adaptor-common.h>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+/**
+ * @brief Struct that stores the needed info to create a bitmap glyph.
+ *
+ * BitmapGlyph objects need to be added to a BitmapFont.
+ */
+struct DALI_ADAPTOR_API BitmapGlyph
+{
+  /**
+   * @brief Default constructor.
+   *
+   * Initialize the members to its defaults.
+   */
+  BitmapGlyph();
+
+  /**
+   * @brief Constructor.
+   *
+   * Initialize the members with the given values.
+   *
+   * @param[in] url The url of the bitmap for that glyph.
+   * @param[in] utf32 The utf32 codification of the glyph.
+   * @param[in] ascender The ascender of the glyph.
+   * @param[in] descender The descender of the glyph.
+   */
+  BitmapGlyph( const std::string& url, GlyphIndex utf32, float ascender, float descender );
+
+  /**
+   * @brief Default destructor.
+   */
+  ~BitmapGlyph();
+
+  std::string url;  ///< The url of the glyph's bitmap.
+  GlyphIndex utf32; ///< The id of the glyph encoded in utf32.
+  float ascender;   ///< The ascender in pixels. The distance from the base line to the top of the glyph.
+  float descender;  ///< The descender in pixels. The distance from the base line to the bottom of the glyph.
+};
+
+/**
+ * @brief Struct that stores the needed info to create a bitmap font.
+ *
+ * A bitmap font can be created by calling FontClient::GetFontId( const BitmapFont& ).
+ */
+struct DALI_ADAPTOR_API BitmapFont
+{
+  /**
+   * @brief Default constructor.
+   *
+   * Initialize the members to its defaults but the @e underlineThickness which is initilized to 1 pixel.
+   */
+  BitmapFont();
+
+  /**
+   * @brief Default destructor.
+   */
+  ~BitmapFont();
+
+  std::vector<BitmapGlyph> glyphs; ///< The glyphs of the font.
+  std::string name;                ///< The name of the font.
+  float ascender;                  ///< The ascender in pixels. Maximum ascender of all the glyphs.
+  float descender;                 ///< The descender in pixels. Minimum descender of all the glyphs.
+  float underlinePosition;         ///< The position in pixels of the underline from the base line.
+  float underlineThickness;        ///< The thickness in pixels of the underline.
+  bool isColorFont:1;              ///< Whether the glyphs of this font have their own colors.
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_TEXT_ABSTRACTION_BITMAP_FONT_H
diff --git a/dali/devel-api/text-abstraction/font-client.cpp b/dali/devel-api/text-abstraction/font-client.cpp
new file mode 100755 (executable)
index 0000000..7fed0ab
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/text/text-abstraction/font-client-impl.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+const PointSize26Dot6 FontClient::DEFAULT_POINT_SIZE = 768u; // 12*64
+const float FontClient::DEFAULT_ITALIC_ANGLE = 12.f * Dali::Math::PI_OVER_180; // FreeType documentation states the software italic is done by doing a horizontal shear of 12 degrees (file ftsynth.h).
+
+FontClient::GlyphBufferData::GlyphBufferData()
+: buffer{ nullptr },
+  width{ 0u },
+  height{ 0u },
+  outlineOffsetX{ 0 },
+  outlineOffsetY{ 0 },
+  format{ Pixel::A8 },
+  isColorEmoji{ false },
+  isColorBitmap{ false }
+{
+}
+
+FontClient::GlyphBufferData::~GlyphBufferData()
+{
+}
+
+FontClient FontClient::Get()
+{
+  return Internal::FontClient::Get();
+}
+
+FontClient::FontClient()
+{
+}
+
+FontClient::~FontClient()
+{
+}
+
+FontClient::FontClient( const FontClient& handle )
+: BaseHandle( handle )
+{
+}
+
+FontClient& FontClient::operator=( const FontClient& handle )
+{
+  BaseHandle::operator=( handle );
+  return *this;
+}
+
+void FontClient::ClearCache()
+{
+  GetImplementation(*this).ClearCache();
+}
+
+void FontClient::SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi  )
+{
+  GetImplementation(*this).SetDpi( horizontalDpi, verticalDpi );
+}
+
+void FontClient::GetDpi( unsigned int& horizontalDpi, unsigned int& verticalDpi )
+{
+  GetImplementation(*this).GetDpi( horizontalDpi, verticalDpi );
+}
+
+int FontClient::GetDefaultFontSize()
+{
+  return GetImplementation(*this).GetDefaultFontSize();
+}
+
+void FontClient::ResetSystemDefaults()
+{
+  GetImplementation(*this).ResetSystemDefaults();
+}
+
+void FontClient::GetDefaultFonts( FontList& defaultFonts )
+{
+  GetImplementation(*this).GetDefaultFonts( defaultFonts );
+}
+
+void FontClient::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
+{
+  GetImplementation(*this).GetDefaultPlatformFontDescription( fontDescription );
+}
+
+void FontClient::GetSystemFonts( FontList& systemFonts )
+{
+  GetImplementation(*this).GetSystemFonts( systemFonts );
+}
+
+void FontClient::GetDescription( FontId id, FontDescription& fontDescription )
+{
+  GetImplementation(*this).GetDescription( id, fontDescription );
+}
+
+PointSize26Dot6 FontClient::GetPointSize( FontId id )
+{
+  return GetImplementation(*this).GetPointSize( id );
+}
+
+bool FontClient::IsCharacterSupportedByFont( FontId fontId, Character character )
+{
+  return GetImplementation(*this).IsCharacterSupportedByFont( fontId, character );
+}
+
+FontId FontClient::FindDefaultFont( Character charcode,
+                                    PointSize26Dot6 requestedPointSize,
+                                    bool preferColor )
+{
+  return GetImplementation(*this).FindDefaultFont( charcode,
+                                                   requestedPointSize,
+                                                   preferColor );
+}
+
+FontId FontClient::FindFallbackFont( Character charcode,
+                                     const FontDescription& preferredFontDescription,
+                                     PointSize26Dot6 requestedPointSize,
+                                     bool preferColor )
+{
+  return GetImplementation(*this).FindFallbackFont( charcode, preferredFontDescription, requestedPointSize, preferColor );
+}
+
+FontId FontClient::GetFontId( const FontPath& path, PointSize26Dot6 requestedPointSize, FaceIndex faceIndex )
+{
+  return GetImplementation(*this).GetFontId( path, requestedPointSize, faceIndex );
+}
+
+FontId FontClient::GetFontId( const FontDescription& fontDescription,
+                              PointSize26Dot6 requestedPointSize,
+                              FaceIndex faceIndex )
+{
+  return GetImplementation(*this).GetFontId( fontDescription,
+                                             requestedPointSize,
+                                             faceIndex );
+}
+
+FontId FontClient::GetFontId( const BitmapFont& bitmapFont )
+{
+  return GetImplementation(*this).GetFontId( bitmapFont );
+}
+
+bool FontClient::IsScalable( const FontPath& path )
+{
+  return GetImplementation(*this).IsScalable( path );
+}
+
+bool FontClient::IsScalable( const FontDescription& fontDescription )
+{
+  return GetImplementation(*this).IsScalable( fontDescription );
+}
+
+void FontClient::GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes )
+{
+  GetImplementation(*this).GetFixedSizes( path, sizes );
+}
+
+void FontClient::GetFixedSizes( const FontDescription& fontDescription,
+                                Dali::Vector< PointSize26Dot6 >& sizes )
+{
+  GetImplementation(*this).GetFixedSizes( fontDescription, sizes );
+}
+
+bool FontClient::HasItalicStyle( FontId fontId ) const
+{
+  return GetImplementation(*this).HasItalicStyle( fontId );
+}
+
+void FontClient::GetFontMetrics( FontId fontId, FontMetrics& metrics )
+{
+  GetImplementation(*this).GetFontMetrics( fontId, metrics );
+}
+
+GlyphIndex FontClient::GetGlyphIndex( FontId fontId, Character charcode )
+{
+  return GetImplementation(*this).GetGlyphIndex( fontId, charcode );
+}
+
+bool FontClient::GetGlyphMetrics( GlyphInfo* array, uint32_t size, GlyphType type, bool horizontal )
+{
+  return GetImplementation(*this).GetGlyphMetrics( array, size, type, horizontal );
+}
+
+void FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, GlyphBufferData& data, int outlineWidth )
+{
+  GetImplementation(*this).CreateBitmap( fontId, glyphIndex, isItalicRequired, isBoldRequired, data, outlineWidth );
+}
+
+PixelData FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
+{
+  return GetImplementation(*this).CreateBitmap( fontId, glyphIndex, outlineWidth );
+}
+
+void FontClient::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
+{
+  GetImplementation(*this).CreateVectorBlob( fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
+}
+
+const GlyphInfo& FontClient::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
+{
+  return GetImplementation(*this).GetEllipsisGlyph( requestedPointSize );
+}
+
+bool FontClient::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
+{
+  return GetImplementation(*this).IsColorGlyph( fontId, glyphIndex );
+}
+
+bool FontClient::AddCustomFontDirectory( const FontPath& path )
+{
+  return GetImplementation(*this).AddCustomFontDirectory( path );
+}
+
+GlyphIndex FontClient::CreateEmbeddedItem(const EmbeddedItemDescription& description, Pixel::Format& pixelFormat)
+{
+  return GetImplementation(*this).CreateEmbeddedItem( description, pixelFormat);
+}
+
+FontClient::FontClient( Internal::FontClient* internal )
+: BaseHandle( internal )
+{
+}
+
+FontClient FontClientPreInitialize()
+{
+  return Internal::FontClient::PreInitialize();
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/devel-api/text-abstraction/font-client.h b/dali/devel-api/text-abstraction/font-client.h
new file mode 100755 (executable)
index 0000000..0c3c646
--- /dev/null
@@ -0,0 +1,496 @@
+#ifndef DALI_PLATFORM_TEXT_ABSTRACTION_FONT_CLIENT_H
+#define DALI_PLATFORM_TEXT_ABSTRACTION_FONT_CLIENT_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/images/buffer-image.h>
+#include <dali/public-api/images/pixel-data.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/devel-api/text-abstraction/font-list.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+struct FontMetrics;
+struct GlyphInfo;
+struct BitmapFont;
+
+namespace Internal DALI_INTERNAL
+{
+class FontClient;
+}
+
+/**
+ * @brief FontClient provides access to font information and resources.
+ *
+ * <h3>Querying the System Fonts</h3>
+ *
+ * A "system font" is described by a "path" to a font file on the native filesystem, along with a "family" and "style".
+ * For example on the Ubuntu system a "Regular" style font from the "Ubuntu Mono" family can be accessed from "/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-R.ttf".
+ *
+ * <h3>Accessing Fonts</h3>
+ *
+ * A "font" is created from the system for a specific point size in 26.6 fractional points. A "FontId" is used to identify each font.
+ * For example two different fonts with point sizes 10 & 12 can be created from the "Ubuntu Mono" family:
+ * @code
+ * FontClient fontClient   = FontClient::Get();
+ * FontId ubuntuMonoTen    = fontClient.GetFontId( "/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-R.ttf", 10*64 );
+ * FontId ubuntuMonoTwelve = fontClient.GetFontId( "/usr/share/fonts/truetype/ubuntu-font-family/UbuntuMono-R.ttf", 12*64 );
+ * @endcode
+ * Glyph metrics and bitmap resources can then be retrieved using the FontId.
+ */
+class DALI_ADAPTOR_API FontClient : public BaseHandle
+{
+public:
+  static const PointSize26Dot6 DEFAULT_POINT_SIZE; ///< The default point size.
+  static const float DEFAULT_ITALIC_ANGLE;         ///< The default software italic angle in radians.
+
+  /**
+   * @brief Struct used to retrieve the glyph's bitmap.
+   */
+  struct DALI_ADAPTOR_API GlyphBufferData
+  {
+    /**
+     * @brief Constructor.
+     *
+     * Initializes struct members to their defaults.
+     */
+    GlyphBufferData();
+
+    /**
+     * @brief Destructor.
+     */
+    ~GlyphBufferData();
+
+    unsigned char* buffer;          ///< The glyph's bitmap buffer data.
+    unsigned int   width;           ///< The width of the bitmap.
+    unsigned int   height;          ///< The height of the bitmap.
+    int            outlineOffsetX;  ///< The additional horizontal offset to be added for the glyph's position for outline.
+    int            outlineOffsetY;  ///< The additional vertical offset to be added for the glyph's position for outline.
+    Pixel::Format  format;          ///< The pixel's format of the bitmap.
+    bool           isColorEmoji:1;  ///< Whether the glyph is an emoji.
+    bool           isColorBitmap:1; ///< Whether the glyph is a color bitmap.
+  };
+
+  /**
+   * @brief Used to load an embedded item into the font client.
+   */
+  struct EmbeddedItemDescription
+  {
+    std::string       url;               ///< The url path of the image.
+    unsigned int      width;             ///< The width of the item.
+    unsigned int      height;            ///< The height of the item.
+    ColorBlendingMode colorblendingMode; ///< Whether the color of the image is multiplied by the color of the text.
+  };
+
+public:
+
+  /**
+   * @brief Retrieve a handle to the FontClient instance.
+   *
+   * @return A handle to the FontClient
+   */
+  static FontClient Get();
+
+  /**
+   * @brief Create an uninitialized TextAbstraction handle.
+   */
+  FontClient();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~FontClient();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @param[in] handle A reference to the copied handle.
+   */
+  FontClient( const FontClient& handle );
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @param [in] handle  A reference to the copied handle.
+   * @return A reference to this.
+   */
+  FontClient& operator=( const FontClient& handle );
+
+  ////////////////////////////////////////
+  // Font management and validation.
+  ////////////////////////////////////////
+
+  /**
+   * @brief Clear all caches in FontClient
+   *
+   */
+  void ClearCache();
+
+  /**
+   * @brief Set the DPI of the target window.
+   *
+   * @note Multiple windows are not currently supported.
+   * @param[in] horizontalDpi The horizontal resolution in DPI.
+   * @param[in] verticalDpi The vertical resolution in DPI.
+   */
+  void SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi );
+
+  /**
+   * @brief Retrieves the DPI previously set to the target window.
+   *
+   * @note Multiple windows are not currently supported.
+   * @param[out] horizontalDpi The horizontal resolution in DPI.
+   * @param[out] verticalDpi The vertical resolution in DPI.
+   */
+  void GetDpi( unsigned int& horizontalDpi, unsigned int& verticalDpi );
+
+  /**
+   * @brief Called by Dali to retrieve the default font size for the platform.
+   *
+   * This is an accessibility size, which is mapped to a UI Control specific point-size in stylesheets.
+   * For example if zero the smallest size, this could potentially map to TextLabel point-size 8.
+   * @return The default font size.
+   */
+  int GetDefaultFontSize();
+
+  /**
+   * @brief Called when the user changes the system defaults.
+   *
+   * @post Previously cached system defaults are removed.
+   */
+  void ResetSystemDefaults();
+
+  /**
+   * @brief Retrieve the list of default fonts supported by the system.
+   *
+   * @param[out] defaultFonts A list of default font paths, family, width, weight and slant.
+   */
+  void GetDefaultFonts( FontList& defaultFonts );
+
+  /**
+   * @brief Retrieve the active default font from the system.
+   *
+   * @param[out] fontDescription font structure describing the default font.
+   */
+  void GetDefaultPlatformFontDescription( FontDescription& fontDescription );
+
+  /**
+   * @brief Retrieve the list of fonts supported by the system.
+   *
+   * @param[out] systemFonts A list of font paths, family, width, weight and slant.
+   */
+  void GetSystemFonts( FontList& systemFonts );
+
+  /**
+   * @brief Retrieves the font description of a given font @p id.
+   *
+   * @param[in] id The font identifier.
+   * @param[out] fontDescription The path, family & style (width, weight and slant) describing the font.
+   */
+  void GetDescription( FontId id, FontDescription& fontDescription );
+
+  /**
+   * @brief Retrieves the font point size of a given font @p id.
+   *
+   * @param[in] id The font identifier.
+   *
+   * @return The point size in 26.6 fractional points.
+   */
+  PointSize26Dot6 GetPointSize( FontId id );
+
+  /**
+   * @brief Whether the given @p character is supported by the font.
+   *
+   * @param[in] fontId The id of the font.
+   * @param[in] character The character.
+   *
+   * @return @e true if the character is supported by the font.
+   */
+  bool IsCharacterSupportedByFont( FontId fontId, Character character );
+
+  /**
+   * @brief Find the default font for displaying a UTF-32 character.
+   *
+   * This is useful when localised strings are provided for multiple languages
+   * i.e. when a single default font does not work for all languages.
+   *
+   * @param[in] charcode The character for which a font is needed.
+   * @param[in] requestedPointSize The point size in 26.6 fractional points; the default point size is 12*64.
+   * @param[in] preferColor @e true if a color font is preferred.
+   *
+   * @return A valid font identifier, or zero if the font does not exist.
+   */
+  FontId FindDefaultFont( Character charcode,
+                          PointSize26Dot6 requestedPointSize = DEFAULT_POINT_SIZE,
+                          bool preferColor = false );
+
+  /**
+   * @brief Find a fallback-font for displaying a UTF-32 character.
+   *
+   * This is useful when localised strings are provided for multiple languages
+   * i.e. when a single default font does not work for all languages.
+   *
+   * @param[in] charcode The character for which a font is needed.
+   * @param[in] preferredFontDescription Description of the preferred font which may not provide a glyph for @p charcode.
+   *                                     The fallback-font will be the closest match to @p preferredFontDescription, which does support the required glyph.
+   * @param[in] requestedPointSize The point size in 26.6 fractional points; the default point size is 12*64.
+   * @param[in] preferColor @e true if a color font is preferred.
+   *
+   * @return A valid font identifier, or zero if the font does not exist.
+   */
+  FontId FindFallbackFont( Character charcode,
+                           const FontDescription& preferredFontDescription,
+                           PointSize26Dot6 requestedPointSize = DEFAULT_POINT_SIZE,
+                           bool preferColor = false );
+
+  /**
+   * @brief Retrieve the unique identifier for a font.
+   *
+   * @param[in] path The path to a font file.
+   * @param[in] requestedPointSize The point size in 26.6 fractional points; the default point size is 12*64.
+   * @param[in] faceIndex The index of the font face (optional).
+   *
+   * @return A valid font identifier, or zero if the font does not exist.
+   */
+  FontId GetFontId( const FontPath& path,
+                    PointSize26Dot6 requestedPointSize = DEFAULT_POINT_SIZE,
+                    FaceIndex faceIndex = 0 );
+
+  /**
+   * @brief Retrieves a unique font identifier for a given description.
+   *
+   * @param[in] preferredFontDescription Description of the preferred font.
+   *                                     The font will be the closest match to @p preferredFontDescription.
+   * @param[in] requestedPointSize The point size in 26.6 fractional points; the default point size is 12*64.
+   * @param[in] faceIndex The index of the font face (optional).
+   *
+   * @return A valid font identifier, or zero if no font is found.
+   */
+  FontId GetFontId( const FontDescription& preferredFontDescription,
+                    PointSize26Dot6 requestedPointSize = DEFAULT_POINT_SIZE,
+                    FaceIndex faceIndex = 0 );
+
+  /**
+   * @brief Retrieves a unique font identifier for a given bitmap font.
+   *
+   * @param[in] bitmapFont A bitmap font.
+   *
+   * @return A valid font identifier, or zero if no bitmap font is created.
+   */
+  FontId GetFontId( const BitmapFont& bitmapFont );
+
+  /**
+   * @brief Check to see if a font is scalable.
+   *
+   * @param[in] path The path to a font file.
+   * @return true if scalable.
+   */
+  bool IsScalable( const FontPath& path );
+
+  /**
+   * @brief Check to see if a font is scalable.
+   *
+   * @note It the font style is not empty, it will be used instead the font weight and font slant slant.
+   *
+   * @param[in] fontDescription A font description.
+   *
+   * @return true if scalable
+   */
+  bool IsScalable( const FontDescription& fontDescription );
+
+  /**
+   * @brief Get a list of sizes available for a fixed size font.
+   *
+   * @param[in] path The path to a font file.
+   * @param[out] sizes A list of the available sizes, if no sizes available will return empty.
+   */
+  void GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes );
+
+  /**
+   * @brief Get a list of sizes available for a fixed size font.
+   *
+   * @note It the font style is not empty, it will be used instead the font weight and font slant slant.
+   *
+   * @param[in] fontDescription A font description.
+   * @param[out] sizes A list of the available sizes, if no sizes available will return empty.
+   */
+  void GetFixedSizes( const FontDescription& fontDescription,
+                      Dali::Vector< PointSize26Dot6 >& sizes );
+
+  /**
+   * @brief Whether the font has Italic style.
+   *
+   * @param[in] fontId The font identifier.
+   *
+   * @return true if the font has italic style.
+   */
+  bool HasItalicStyle( FontId fontId ) const;
+
+  ////////////////////////////////////////
+  // Font metrics, glyphs and bitmaps.
+  ////////////////////////////////////////
+
+  /**
+   * @brief Query the metrics for a font.
+   *
+   * @param[in] fontId The identifier of the font for the required glyph.
+   * @param[out] metrics The font metrics.
+   */
+  void GetFontMetrics( FontId fontId, FontMetrics& metrics );
+
+  /**
+   * @brief Retrieve the glyph index for a UTF-32 character code.
+   *
+   * @param[in] fontId The identifier of the font for the required glyph.
+   * @param[in] charcode The UTF-32 character code.
+   *
+   * @return The glyph index, or zero if the character code is undefined.
+   */
+  GlyphIndex GetGlyphIndex( FontId fontId, Character charcode );
+
+  /**
+   * @brief Retrieve the metrics for a series of glyphs.
+   *
+   * @param[in,out] array An array of glyph-info structures with initialized FontId & GlyphIndex values.
+   *                      It may contain the advance and an offset set into the bearing from the shaping tool.
+   *                      On return, the glyph's size value will be initialized. The bearing value will be updated by adding the font's glyph bearing to the one set by the shaping tool.
+   * @param[in] size The size of the array.
+   * @param[in] type The type of glyphs used for rendering; either bitmaps or vectors.
+   * @param[in] horizontal True for horizontal layouts (set to false for vertical layouting).
+   *
+   * @return @e true if all of the requested metrics were found.
+   */
+  bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, GlyphType type, bool horizontal = true );
+
+  /**
+   * @brief Create a bitmap representation of a glyph.
+   *
+   * @note The caller is responsible for deallocating the bitmap data @p data.buffer using delete[].
+   *
+   * @param[in]  fontId           The identifier of the font.
+   * @param[in]  glyphIndex       The index of a glyph within the specified font.
+   * @param[in]  isItalicRequired Whether the glyph requires italic style.
+   * @param[in]  isBoldRequired   Whether the glyph requires bold style.
+   * @param[out] data             The bitmap data.
+   * @param[in]  outlineWidth     The width of the glyph outline in pixels.
+   */
+  void CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, GlyphBufferData& data, int outlineWidth );
+
+  /**
+   * @brief Create a bitmap representation of a glyph.
+   *
+   * @param[in] fontId The identifier of the font.
+   * @param[in] glyphIndex The index of a glyph within the specified font.
+   * @param[in] outlineWidth The width of the glyph outline in pixels.
+   *
+   * @return A valid BufferImage, or an empty handle if the glyph could not be rendered.
+   */
+  PixelData CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth );
+
+  /**
+   * @brief Create a vector representation of a glyph.
+   *
+   * @note This feature requires highp shader support and is not available on all platforms
+   * @param[in] fontId The identifier of the font.
+   * @param[in] glyphIndex The index of a glyph within the specified font.
+   * @param[out] blob A blob of data; this is owned by FontClient and should be copied by the caller of CreateVectorData().
+   * @param[out] blobLength The length of the blob data, or zero if the blob creation failed.
+   * @param[out] nominalWidth The width of the blob.
+   * @param[out] nominalHeight The height of the blob.
+   */
+  void CreateVectorBlob( FontId fontId,
+                         GlyphIndex glyphIndex,
+                         VectorBlob*& blob,
+                         unsigned int& blobLength,
+                         unsigned int& nominalWidth,
+                         unsigned int& nominalHeight );
+
+  /**
+   * @brief Retrieves the ellipsis glyph for a requested point size.
+   *
+   * @param[in] requestedPointSize The requested point size.
+   *
+   * @return The ellipsis glyph.
+   */
+  const GlyphInfo& GetEllipsisGlyph( PointSize26Dot6 requestedPointSize );
+
+  /**
+   * @brief Whether the given glyph @p glyphIndex is a color glyph.
+   *
+   * @param[in] fontId The font id.
+   * @param[in] glyphIndex The glyph index.
+   *
+   * @return @e true if the glyph is a color one.
+   */
+  bool IsColorGlyph( FontId fontId, GlyphIndex glyphIndex );
+
+  /**
+   * @brief  Add custom fonts directory
+   *
+   * @param[in] path to the fonts directory
+   *
+   * @return true if the fonts can be added.
+   */
+  bool AddCustomFontDirectory( const FontPath& path );
+
+  /**
+   * @brief Creates and stores an embedded item and it's metrics.
+   *
+   * If in the @p description there is a non empty url, it calls Dali::LoadImageFromFile() internally.
+   * If in the @p description there is a url and @e width or @e height are zero it stores the default size. Otherwise the image is resized.
+   * If the url in the @p description is empty it stores the size.
+   *
+   * @param[in] description The description of the embedded item.
+   * @param[out] pixelFormat The pixel format of the image.
+   *
+   * return The index within the vector of embedded items.
+   */
+  GlyphIndex CreateEmbeddedItem( const EmbeddedItemDescription& description, Pixel::Format& pixelFormat);
+
+
+public: // Not intended for application developers
+  /**
+   * @brief This constructor is used by FontClient::Get().
+   *
+   * @param[in] fontClient  A pointer to the internal fontClient object.
+   */
+  explicit DALI_INTERNAL FontClient( Internal::FontClient* fontClient );
+};
+
+/**
+ * @brief This is used to improve application launch performance
+ *
+ * @return A pre-initialized FontClient
+ */
+DALI_ADAPTOR_API FontClient FontClientPreInitialize();
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_PLATFORM_TEXT_ABSTRACTION_FONT_CLIENT_H
diff --git a/dali/devel-api/text-abstraction/font-list.cpp b/dali/devel-api/text-abstraction/font-list.cpp
new file mode 100644 (file)
index 0000000..7053174
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/text-abstraction/font-list.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+DALI_ADAPTOR_API std::ostream& operator<<( std::ostream& o, const FontList& fontList )
+{
+  for( unsigned int i=0; i<fontList.size(); ++i )
+  {
+    const FontDescription& description = fontList[i];
+    o << "Font " << i << ") path: " << description.path << " family: " << " width : " << description.width << " weight : " << description.weight << " slant : " << description.slant << std::endl;
+  }
+
+  return o;
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/devel-api/text-abstraction/font-list.h b/dali/devel-api/text-abstraction/font-list.h
new file mode 100755 (executable)
index 0000000..65c8a5a
--- /dev/null
@@ -0,0 +1,177 @@
+#ifndef DALI_TEXT_ABSTRACTION_FONT_LIST_H
+#define DALI_TEXT_ABSTRACTION_FONT_LIST_H
+
+/*
+ * Copyright (c) 2019 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 <iostream>
+#include <dali/public-api/common/vector-wrapper.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+typedef std::string FontPath;
+typedef std::string FontFamily;
+typedef std::string FontStyle;
+
+namespace FontWidth
+{
+  /**
+   * @brief Enumeration type for the font's width
+   */
+  enum Type
+  {
+    NONE,            ///< Means not defined. Will use what is set as default, currently NORMAL.
+    ULTRA_CONDENSED,
+    EXTRA_CONDENSED,
+    CONDENSED,
+    SEMI_CONDENSED,
+    NORMAL,
+    SEMI_EXPANDED,
+    EXPANDED,
+    EXTRA_EXPANDED,
+    ULTRA_EXPANDED
+  };
+
+  const char* const Name[] =
+  {
+    "NONE",
+    "ULTRA_CONDENSED",
+    "EXTRA_CONDENSED",
+    "CONDENSED",
+    "SEMI_CONDENSED",
+    "NORMAL",
+    "SEMI_EXPANDED",
+    "EXPANDED",
+    "EXTRA_EXPANDED",
+    "ULTRA_EXPANDED"
+  };
+} // namespace FontWidth
+
+namespace FontWeight
+{
+  /**
+   * @brief Enumeration type for the font's weight
+   */
+  enum Type
+  {
+    NONE,                      ///< Means not defined. Will use what is set as default, currently NORMAL.
+    THIN,
+    ULTRA_LIGHT,
+    EXTRA_LIGHT = ULTRA_LIGHT,
+    LIGHT,
+    DEMI_LIGHT,
+    SEMI_LIGHT = DEMI_LIGHT,
+    BOOK,
+    NORMAL,
+    REGULAR = NORMAL,
+    MEDIUM,
+    DEMI_BOLD,
+    SEMI_BOLD = DEMI_BOLD,
+    BOLD,
+    ULTRA_BOLD,
+    EXTRA_BOLD = ULTRA_BOLD,
+    BLACK,
+    HEAVY = BLACK,
+    EXTRA_BLACK = BLACK
+  };
+
+  const char* const Name[] =
+  {
+    "NONE",
+    "THIN",
+    "ULTRA_LIGHT",
+    "LIGHT",
+    "DEMI_LIGHT",
+    "BOOK",
+    "NORMAL",
+    "MEDIUM",
+    "DEMI_BOLD",
+    "BOLD",
+    "ULTRA_BOLD",
+    "BLACK"
+  };
+}
+
+namespace FontSlant
+{
+  /**
+   * @brief Enumeration type for the font's slant
+   */
+  enum Type
+  {
+    NONE,           ///< Means not defined. Will use what is set as default, currently NORMAL.
+    NORMAL,
+    ROMAN = NORMAL,
+    ITALIC,
+    OBLIQUE
+  };
+
+  const char* const Name[] =
+  {
+    "NONE",
+    "NORMAL",
+    "ITALIC",
+    "OBLIQUE"
+  };
+} // namespace FontSlant
+
+struct FontDescription
+{
+  enum Type
+  {
+    INVALID,     ///< Not valid font.
+    FACE_FONT,   ///< A face font.
+    BITMAP_FONT, ///< A bitmap font. Each glyph has a url with the bitmap.
+  };
+
+  FontDescription()
+  : path(),
+    family(),
+    width( FontWidth::NONE ),
+    weight( FontWeight::NONE ),
+    slant( FontSlant::NONE ),
+    type( INVALID )
+  {}
+
+  ~FontDescription()
+  {}
+
+  FontPath         path;   ///< The font's file name path.
+  FontFamily       family; ///< The font's family name.
+  FontWidth::Type  width;  ///< The font's width.
+  FontWeight::Type weight; ///< The font's weight.
+  FontSlant::Type  slant;  ///< The font's slant.
+  Type             type;   ///< The type of font.
+};
+
+typedef std::vector<FontDescription> FontList;
+
+DALI_ADAPTOR_API std::ostream& operator<<( std::ostream& o, const FontList& fontList );
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_TEXT_ABSTRACTION_FONT_LIST_H
diff --git a/dali/devel-api/text-abstraction/font-metrics.cpp b/dali/devel-api/text-abstraction/font-metrics.cpp
new file mode 100755 (executable)
index 0000000..e192a44
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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 <dali/devel-api/text-abstraction/font-metrics.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+FontMetrics::FontMetrics()
+: ascender{ 0.f },
+  descender{ 0.f },
+  height{ 0.f },
+  underlinePosition{ 0.f },
+  underlineThickness{ 0.f }
+{
+}
+
+FontMetrics::FontMetrics( float ascenderPixels,
+                          float descenderPixels,
+                          float heightPixels,
+                          float underlinePositionPixels,
+                          float underlineThicknessPixels )
+: ascender{ ascenderPixels },
+  descender{ descenderPixels },
+  height{ heightPixels },
+  underlinePosition{ underlinePositionPixels },
+  underlineThickness{ underlineThicknessPixels }
+{
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/devel-api/text-abstraction/font-metrics.h b/dali/devel-api/text-abstraction/font-metrics.h
new file mode 100755 (executable)
index 0000000..f314735
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef DALI_TEXT_ABSTRACTION_FONT_METRICS_H
+#define DALI_TEXT_ABSTRACTION_FONT_METRICS_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+/**
+ * The metrics for a Font expressed in pixels.
+ */
+struct DALI_ADAPTOR_API FontMetrics
+{
+  /**
+   * @brief Default constructor.
+   */
+  FontMetrics();
+
+  /**
+   * @brief Create the font metrics in pixels.
+   */
+  FontMetrics( float ascenderPixels,
+               float descenderPixels,
+               float heightPixels,
+               float underlinePositionPixels,
+               float underlineThicknessPixels );
+
+  float ascender;             ///< The ascender in pixels.
+  float descender;            ///< The descender in pixels.
+  float height;               ///< The height in pixels.
+  float underlinePosition;    ///< The underline position in pixels.
+  float underlineThickness;   ///< The vertical height of the underline in pixels.
+};
+
+} // Dali
+
+} // TextAbstraction
+
+#endif //DALI_TEXT_ABSTRACTION_FONT_METRICS_H
diff --git a/dali/devel-api/text-abstraction/glyph-info.cpp b/dali/devel-api/text-abstraction/glyph-info.cpp
new file mode 100755 (executable)
index 0000000..1e87831
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/text-abstraction/glyph-info.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+GlyphInfo::GlyphInfo()
+: fontId{ 0u },
+  index{ 0u },
+  width( 0.f ),
+  height{ 0.f },
+  xBearing{ 0.f },
+  yBearing{ 0.f },
+  advance{ 0.f },
+  scaleFactor{ 0.f },
+  isItalicRequired{ false },
+  isBoldRequired{ false }
+{
+}
+
+GlyphInfo::GlyphInfo( FontId font, GlyphIndex i )
+: fontId{ font },
+  index{ i },
+  width( 0.f ),
+  height{ 0.f },
+  xBearing{ 0.f },
+  yBearing{ 0.f },
+  advance{ 0.f },
+  scaleFactor{ 0.f },
+  isItalicRequired{ false },
+  isBoldRequired{ false }
+{
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/devel-api/text-abstraction/glyph-info.h b/dali/devel-api/text-abstraction/glyph-info.h
new file mode 100755 (executable)
index 0000000..fbc8fec
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef DALI_TEXT_ABSTRACTION_GLYPH_INFO_H
+#define DALI_TEXT_ABSTRACTION_GLYPH_INFO_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/dali-adaptor-common.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+/**
+ * The information describing a glyph (font ID, index, metrics)
+ * The metrics are in pixels.
+ */
+struct DALI_ADAPTOR_API GlyphInfo
+{
+  /**
+   * @brief Default constructor.
+   */
+  GlyphInfo();
+
+  /**
+   * @brief Creates the GlyphInfo without metrics.
+   */
+  GlyphInfo( FontId font, GlyphIndex i );
+
+  FontId fontId;           ///< Identifies the font containing the glyph
+  GlyphIndex index;        ///< Uniquely identifies a glyph for a given FontId
+  float width;             ///< The width of the glyph
+  float height;            ///< The height of the glyph
+  float xBearing;          ///< The distance from the cursor position to the leftmost border of the glyph
+  float yBearing;          ///< The distance from the baseline to the topmost border of the glyph
+  float advance;           ///< The distance to move the cursor for this glyph
+  float scaleFactor;       ///< The scaling applied (fixed-size fonts only)
+  bool isItalicRequired:1; ///< Whether the italic style is required.
+  bool isBoldRequired:1;   ///< Whether the bold style is required.
+};
+
+} // Dali
+
+} // TextAbstraction
+
+#endif //DALI_TEXT_ABSTRACTION_GLYPH_INFO_H
diff --git a/dali/devel-api/text-abstraction/script.cpp b/dali/devel-api/text-abstraction/script.cpp
new file mode 100644 (file)
index 0000000..a22d085
--- /dev/null
@@ -0,0 +1,927 @@
+/*
+ * 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali/devel-api/text-abstraction/script.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace
+{
+const unsigned int WHITE_SPACE_THRESHOLD  = 0x21; ///< All characters below 0x21 are considered white spaces.
+const unsigned int CHAR_LF   = 0x000A; ///< NL Line feed, new line.
+const unsigned int CHAR_VT   = 0x000B; ///< Vertical tab.
+const unsigned int CHAR_FF   = 0x000C; ///< NP Form feed, new page.
+const unsigned int CHAR_CR   = 0x000D; ///< Carriage return, new line.
+const unsigned int CHAR_NEL  = 0x0085; ///< Next line.
+const unsigned int CHAR_LS   = 0x2028; ///< Line separator.
+const unsigned int CHAR_PS   = 0x2029; ///< Paragraph separator
+
+const unsigned int CHAR_ZWS  = 0x200B; ///< Zero width space.
+const unsigned int CHAR_ZWNJ = 0x200C; ///< Zero width non joiner.
+const unsigned int CHAR_ZWJ  = 0x200D; ///< Zero width joiner.
+const unsigned int CHAR_LTRM = 0x200E; ///< Left to Right Mark.
+const unsigned int CHAR_RTLM = 0x200F; ///< Right to Left Mark.
+const unsigned int CHAR_TS   = 0x2009; ///< Thin Space.
+} // namespace
+
+bool IsRightToLeftScript( Script script )
+{
+  return ( ( ARABIC == script ) ||
+           ( HEBREW == script ) );
+}
+
+Script GetCharacterScript( Character character )
+{
+  // Latin script:   It contains punctuation characters and symbols which are not part of the latin script. https://en.wikipedia.org/wiki/Latin_script_in_Unicode
+  // 0x0000 - 0x007f C0 Controls and Basic Latin
+  //
+  //                 ASCII digits (not part of LATIN script):
+  //                 0x0030 - 0x0039
+  //
+  //                 ASCII punctuation and symbols (not part of LATIN script):
+  //                 0x0020 - 0x002F
+  //                 0x003A - 0x0040
+  //                 0x005B - 0x0060
+  //                 0x007B - 0x007E
+  //
+  //                 Controls (not part of LATIN script):
+  //                 0x007F
+  //
+  // 0x0080 - 0x00ff C1 Controls and Latin-1 Supplement
+  //
+  //                 Controls (not part of LATIN script):
+  //                 0x0080 - 0x009F
+  //
+  //                 Punctuations and symbols (not part of LATIN script):
+  //                 0x00A0 - 0x00BF
+  //
+  //                 Mathematical operators (not part of LATIN script):
+  //                 0x00D7
+  //                 0x00F7
+  //
+  // 0x0100 - 0x017f Latin Extended-A
+  // 0x0180 - 0x024f Latin Extended-B
+  // 0x0250 - 0x02af IPA Extensions
+  // 0x02b0 - 0x02ff Spacing Modifier Letters
+  //
+  //                 Punctuation (not part of LATIN script):
+  //                 0x02B9 - 0x02BF
+  //
+  // 0x1d00 - 0x1d7f Phonetic Extensions
+  //
+  //                 Uralic Phonetic (not part of LATIN script):
+  //                 0x1D26 - 0x1D2B
+  //
+  //                 Subscripts and superscripts
+  //                 0x1D5D - 0x1D61
+  //                 0x1D66 - 0x1D6A
+  //                 0x1D78
+  //
+  // 0x1d80 - 0x1dbf Phonetic Extensions Supplement
+  //
+  //                 0x1DBF (subscript or superscript. Not part of LATIN script )
+  //
+  // 0x1e00 - 0x1eff Latin Extended Additional
+  // 0x2070 - 0x209f Superscripts and Subscripts
+  //
+  //                 0x2070          (not part of LATIN script)
+  //                 0x2074 - 0x207E (not part of LATIN script)
+  //
+  // 0x2100 - 0x214f Letterlike symbols (not part of LATIN script)
+  //
+  //                 0x212A - 0x212B (are part of LATIN script)
+  //                 0x2132          (are part of LATIN script)
+  //                 0x214E          (are part of LATIN script)
+  //
+  // 0x2150 - 0x2189 Number Forms
+  //
+  //                 0x2150 - 0x215F Fractions (not part of LATIN script)
+  //                 0x2189          Fractions (not part of LATIN script)
+  //
+  // 0x2c60 - 0x2c7f Latin Extended-C
+  // 0xa720 - 0xa7ff Latin Extended-D
+  //
+  //                 0xA720 - 0xA721 Uralic Phonetic (not part of LATIN script)
+  //                 0xA788          (not part of LATIN script)
+  //                 0xA789 - 0xA78A Budu (not part of LATIN script)
+  //
+  // 0xab30 - 0xab6f Latin Extended-E
+  //
+  // 0xfb00 - 0xfb06 Latin Alphabetic Presentation Forms
+  // 0xff00 - 0xffef Halfwidth and Fullwidth Forms
+  //
+  //                 0xFF00 - 0xFF20 HWFW Symbols (not part of LATIN script)
+  //                 0xFF3B - 0xFF40 HWFW Symbols (not part of LATIN script)
+  //                 0xFF5B - 0xFFEF HWFW Symbols (not part of LATIN script)
+
+  // Brahmic scripts:
+  // 0x0900 - 0x097f Devanagari
+  // 0x0980 - 0x09ff Bengali
+  // 0x0a00 - 0x0a7f Gurmukhi
+  // 0x0a80 - 0x0aff Gujarati
+  // 0x0b00 - 0x0b7f Oriya
+  // 0x0b80 - 0x0bff Tamil
+  // 0x0c00 - 0x0c7f Telugu
+  // 0x0c80 - 0x0cff Kannada
+  // 0x0d00 - 0x0d7f Malayalam
+
+  // Sinhala script.
+  // 0x0d80 - 0x0dff Sinhala
+
+  // Arabic script.
+  // 0x0600 - 0x06ff Arabic
+  // 0x0750 - 0x077f Arabic Supplement
+  // 0x08A0 - 0x08ff Arabic Extended-A
+  // 0xfb50 - 0xfdff Arabic Presentation Forms-A
+  // 0xfe70 - 0xfeff Arabic Presentation Forms-B
+  // 0x1ee00 - 0x1eeff Arabic Mathematical Alphabetic Symbols
+
+  // CJK (Chinese, Japanese and Korean) and Vietnamese script.
+  // 0x2e80 - 0x2eff CJK Radicals Supplement
+  // 0x2f00 - 0x2fdf Kangxi Radicals
+  // 0x3000 - 0x303f CJK Symbols and Punctuation
+  // 0x3200 - 0x32ff Enclosed CJK Letters and Months
+  // 0x3400 - 0x4dbf CJK Unified Ideographs Extension A
+  // 0x4e00 - 0x62ff CJK Unified Ideographs
+  // 0x6300 - 0x77ff CJK Unified Ideographs
+  // 0x7800 - 0x8cff CJK Unified Ideographs
+  // 0x8d00 - 0x9fff CJK Unified Ideographs
+  // 0x20000 - 0x215ff CJK Unified Ideographs Extension B
+  // 0x21600 - 0x230ff CJK Unified Ideographs Extension B
+  // 0x23100 - 0x245ff CJK Unified Ideographs Extension B
+  // 0x24600 - 0x260ff CJK Unified Ideographs Extension B
+  // 0x26100 - 0x275ff CJK Unified Ideographs Extension B
+  // 0x27600 - 0x290ff CJK Unified Ideographs Extension B
+  // 0x29100 - 0x2a6df CJK Unified Ideographs Extension B
+  // 0x2a700 - 0x2b73f CJK Unified Ideographs Extension C
+  // 0x2b740 - 0x2b81f CJK Unified Ideographs Extension D
+
+  // Japanese scripts.
+  // 0x3040 - 0x309f Hiragana
+  // 0x30a0 - 0x30ff Katakana
+
+  // Hangul script
+  // 0x1100 - 0x11ff Hangul jamo
+  // 0x3130 - 0x318f Hangul Compatibility Jamo
+  // 0xa960 - 0xa97f Hangul Jamo Extended-A
+  // 0xac00 - 0xd7af Hangul Syllables
+  // 0xd7b0 - 0xd7ff Hangul Jamo Extended-B
+
+  // Bopomofo script
+  // 0x3100 - 0x312f Bopomofo
+  // 0x31a0 - 0x31bf Bopomofo Extended
+
+  // Khmer script
+  // 0x1780 - 0x17ff Khmer
+  // 0x19e0 - 0x19ff Khmer Symbols
+
+  // Lao script
+  // 0x0e80 - 0x0eff Lao
+
+  // Thai script
+  // 0x0e00 - 0x0e7f Thai
+
+  // Burmese script
+  // 0x1000 - 0x109f Myanmar
+
+  // Hebrew script
+  // 0x0591 - 0x05f4 Hebrew
+  // 0xfb1d - 0xfb4f Hebrew subset of Alphabetic Presentation Forms
+
+  // Cyrillic script
+  // 0x0400 - 0x04ff Cyrillic
+  // 0x0500 - 0x052f Cyrillic suplement
+  // 0x2de0 - 0x2dff Cyrillic Extended-A
+  // 0xa640 - 0xa69f Cyrillic Extended-B
+
+  // Georgian script
+  // 0x10a0 - 0x10ff Georgian
+  // 0x2d00 - 0x2d2f Georgian suplement
+
+  // Greek script
+  // 0x0370 - 0x03ff Greek & Coptic
+  // 0x1f00 - 0x1fff Greek Extended
+
+  // Armenian script
+  // 0x0530 - 0x058f Armenian
+  // 0xfb13 - 0xfb17 Armenian subset of Alphabetic prefentation forms
+
+  // Javanese script
+  // 0xa980 - 0xa9fd Javanese
+
+  // Sundanese script
+  // 0x1b80 - 0x1bbf Sundanese
+  // 0x1cc0 - 0x1ccf Sundanese supplement
+
+  // Ge'ez script (Ethiopic)
+  // 0x1200 - 0x137f Ethiopic
+  // 0x1380 - 0x139f Ethiopic supplement
+  // 0x2d80 - 0x2ddf Ethiopic Extended
+  // 0xab00 - 0xab2f Ethiopic Extended-A
+
+  // Baybayin Script
+  // 0x1700 - 0x171f Baybayin
+
+  // 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 ( 2700 - 27BF )
+  // 3. Transport and map symbols ( 1F680 - 1F6C0 )
+  // 4. Enclosed characters ( 24C2 - 1F251 )
+  // 5. Uncategorized :-S
+  // 6. Additional Emoticons ( 1F600 - 1F636 )
+  // 6b. Additional transport and map symbols ( 1F680 - 1F6FF ): http://unicode.org/charts/PDF/U1F680.pdf
+  // 6c. Other additional symbols ( 1F30D - 1F567 )
+  // 7. Supplemental Symbols and Pictographs ( 1F900–1F9FF ): http://unicode.org/charts/PDF/U1F900.pdf
+
+  // Symbols. Work around for these symbols.
+  // 0x25cb
+  // 0x25cf
+  // 0x25a1
+  // 0x25a0
+  // 0x2664
+  // 0x2661
+  // 0x2662
+  // 0x2667
+  // 0x2606
+  // 0x25aa
+  // 0x262a
+
+  if( IsCommonScript( character ) )
+  {
+    return COMMON;
+  }
+
+  if( character <= 0x0cff )
+  {
+    if( character <= 0x09ff )
+    {
+      if( character <= 0x077f )
+      {
+        if( ( 0x0030 <= character ) && ( character <= 0x0039 ) )
+        {
+          return ASCII_DIGITS;
+        }
+        if( character <= 0x007E )
+        {
+          if( ( 0x0020 <= character ) && ( character <= 0x002F ) )
+          {
+            return ASCII_PS;
+          }
+          if( ( 0x003A <= character ) && ( character <= 0x0040 ) )
+          {
+            return ASCII_PS;
+          }
+          if( ( 0x005B <= character ) && ( character <= 0x0060 ) )
+          {
+            return ASCII_PS;
+          }
+          if( ( 0x007B <= character ) && ( character <= 0x007E ) )
+          {
+            return ASCII_PS;
+          }
+        }
+        if( ( 0x007F <= character ) && ( character <= 0x009F ) )
+        {
+          // 0x007F is actually part of C0 Controls and Basic Latin. However, is the last and only control character of its block
+          // and the following characters of the next block are consecutive.
+          return C1_CONTROLS;
+        }
+        if( ( 0x00A0 <= character ) && ( character <= 0x00BF ) )
+        {
+          if( character == 0x00A9 )
+          {
+            return EMOJI; // 5. Uncategorized: copyright sign
+          }
+          if( character == 0x00AE )
+          {
+            return EMOJI; // 5. Uncategorized: registered sign
+          }
+
+          return C1_PS;
+        }
+        if( character == 0x00D7 )
+        {
+          return C1_MATH;
+        }
+        if( character == 0x00F7 )
+        {
+          return  C1_MATH;
+        }
+        if( character <= 0x02ff )
+        {
+          if( ( 0x02B9 <= character ) && ( character <= 0x02BF ) )
+          {
+            return SML_P;
+          }
+
+          return LATIN;
+        }
+        if( ( 0x0370 <= character ) && ( character <= 0x03ff ) )
+        {
+          return GREEK;
+        }
+        if( ( 0x0400 <= character ) && ( character <= 0x04ff ) )
+        {
+          return CYRILLIC;
+        }
+        if( ( 0x0500 <= character ) && ( character <= 0x052f ) )
+        {
+          return CYRILLIC;
+        }
+        if( ( 0x0530 <= character ) && ( character <= 0x058f ) )
+        {
+          return ARMENIAN;
+        }
+        if( ( 0x0591 <= character ) && ( character <= 0x05f4 ) )
+        {
+          return HEBREW;
+        }
+        if( ( 0x0600 <= character ) && ( character <= 0x06ff ) )
+        {
+          return ARABIC;
+        }
+        if( ( 0x0750 <= character ) && ( character <= 0x077f ) )
+        {
+          return ARABIC;
+        }
+      }
+      else // > 0x077f
+      {
+        if( ( 0x08A0 <= character ) && ( character <= 0x08ff ) )
+        {
+          return ARABIC;
+        }
+        if( ( 0x0900 <= character ) && ( character <= 0x097f ) )
+        {
+          return DEVANAGARI;
+        }
+        if( ( 0x0980 <= character ) && ( character <= 0x09ff ) )
+        {
+          return BENGALI;
+        }
+      }
+    }
+    else // > 0x09ff
+    {
+      if( character <= 0x0b7f )
+      {
+        if( ( 0x0a00 <= character ) && ( character <= 0x0a7f ) )
+        {
+          return GURMUKHI;
+        }
+        if( ( 0x0a80 <= character ) && ( character <= 0x0aff ) )
+        {
+          return GUJARATI;
+        }
+        if( ( 0x0b00 <= character ) && ( character <= 0x0b7f ) )
+        {
+          return ORIYA;
+        }
+      }
+      else // > 0x0b7f
+      {
+        if( ( 0x0b80 <= character ) && ( character <= 0x0bff ) )
+        {
+          return TAMIL;
+        }
+        if( ( 0x0c00 <= character ) && ( character <= 0x0c7f ) )
+        {
+          return TELUGU;
+        }
+        if( ( 0x0c80 <= character ) && ( character <= 0x0cff ) )
+        {
+          return KANNADA;
+        }
+      }
+    }
+  }
+  else // > 0x0cff
+  {
+    if( character <= 0x2c7f )
+    {
+      if( character <= 0x1eff )
+      {
+        if( ( 0x0d00 <= character ) && ( character <= 0x0d7f ) )
+        {
+          return MALAYALAM;
+        }
+        if( ( 0x0d80 <= character ) && ( character <= 0x0dff ) )
+        {
+          return SINHALA;
+        }
+        if( ( 0x0e00 <= character ) && ( character <= 0x0e7f ) )
+        {
+          return THAI;
+        }
+        if( ( 0x0e80 <= character ) && ( character <= 0x0eff ) )
+        {
+          return LAO;
+        }
+        if( ( 0x1000 <= character ) && ( character <= 0x109f ) )
+        {
+          return BURMESE;
+        }
+        if( ( 0x10a0 <= character ) && ( character <= 0x10ff ) )
+        {
+          return GEORGIAN;
+        }
+        if( ( 0x1100 <= character ) && ( character <= 0x11ff ) )
+        {
+          return HANGUL;
+        }
+        if( ( 0x1200 <= character ) && ( character <= 0x137f ) )
+        {
+          return GEEZ;
+        }
+        if( ( 0x1380 <= character ) && ( character <= 0x139f ) )
+        {
+          return GEEZ;
+        }
+        if( ( 0x1700 <= character ) && ( character <= 0x171f ) )
+        {
+          return BAYBAYIN;
+        }
+        if( ( 0x1780 <= character ) && ( character <= 0x17ff ) )
+        {
+          return KHMER;
+        }
+        if( ( 0x19e0 <= character ) && ( character <= 0x19ff ) )
+        {
+          return KHMER;
+        }
+        if( ( 0x1b80 <= character ) && ( character <= 0x1bbf ) )
+        {
+          return SUNDANESE;
+        }
+        if( ( 0x1c50 <= character ) && ( character <= 0x1c7f ) )
+        {
+          return OL_CHIKI;
+        }
+        if( ( 0x1cc0 <= character ) && ( character <= 0x1ccf ) )
+        {
+          return SUNDANESE;
+        }
+        if( ( 0x1d00 <= character ) && ( character <= 0x1eff ) )
+        {
+          if( ( 0x1D26 <= character ) && ( character <= 0x1D2B ) )
+          {
+            return PHONETIC_U;
+          }
+          if( ( 0x1D5D <= character ) && ( character <= 0x1D61 ) )
+          {
+            return PHONETIC_SS;
+          }
+          if( ( 0x1D66 <= character ) && ( character <= 0x1D6A ) )
+          {
+            return PHONETIC_SS;
+          }
+          if( character == 0x1D78 )
+          {
+            return PHONETIC_SS;
+          }
+          if( character == 0x1DBF)
+          {
+            return PHONETIC_SS;
+          }
+
+          return LATIN;
+        }
+      }
+      else // > 0x1eff
+      {
+        if( ( 0x1f00 <= character ) && ( character <= 0x1fff ) )
+        {
+          return GREEK;
+        }
+        if( character == 0x203c )
+        {
+          return EMOJI; // 5. Uncategorized: double exclamation mark
+        }
+        if( character == 0x2049 )
+        {
+          return EMOJI; // 5. Uncategorized: exclamation question mark
+        }
+        if( ( 0x2070 <= character ) && ( character <= 0x209f ) )
+        {
+          if( character == 0x2070 )
+          {
+            return NUMERIC_SS;
+          }
+          if( ( 0x2074 <= character ) && ( character <= 0x207E ) )
+          {
+            return NUMERIC_SS;
+          }
+
+          return LATIN;
+        }
+        if( character == 0x20e3 )
+        {
+          return EMOJI; // 5. Uncategorized: combining enclosing keycap
+        }
+        if( character == 0x2122 )
+        {
+          return EMOJI; // 5. Uncategorized: trade mark sign
+        }
+        if( character == 0x2139 )
+        {
+          return EMOJI; // 5. Uncategorized: information source
+        }
+        if( ( 0x2100 <= character ) && ( character <= 0x2189 ) )
+        {
+          if( ( 0x2100 <= character ) && ( character <= 0x214f ) )
+          {
+            if( ( 0x212A <= character ) && ( character <= 0x212B ) )
+            {
+              return LATIN;
+            }
+            if( character == 0x2132 )
+            {
+              return LATIN;
+            }
+            if( character == 0x214E )
+            {
+              return LATIN;
+            }
+
+            return LETTER_LIKE;
+          }
+          if( ( 0x2150 <= character ) && ( character <= 0x215F ) )
+          {
+            return FRACTIONS_NF;
+          }
+          if( character == 0x2189 )
+          {
+            return FRACTIONS_NF;
+          }
+
+          return LATIN;
+        }
+
+        // Symbols
+        if( ( 0x25cb == character ) ||
+            ( 0x25cf == character ) ||
+            ( 0x25a1 == character ) )
+        {
+          return SYMBOLS1;
+        }
+
+        if( 0x25a0 == character )
+        {
+          return SYMBOLS2;
+        }
+
+        if( ( 0x2664 == character ) ||
+            ( 0x2661 == character ) ||
+            ( 0x2662 == character ) ||
+            ( 0x2667 == character ) )
+        {
+          return SYMBOLS3;
+        }
+
+        if( ( 0x2606 == character ) ||
+            ( 0x25aa == character ) )
+        {
+          return SYMBOLS4;
+        }
+
+        if( 0x262a == character )
+        {
+          return SYMBOLS5;
+        }
+
+        // U+2194 5. Uncategorized: left right arrow
+        // U+2B55 5. Uncategorized: heavy large circle
+        if( ( 0x2194 <= character ) && ( character <= 0x2B55 ) )
+        {
+          return EMOJI;
+        }
+        if( ( 0x2c60 <= character ) && ( character <= 0x2c7f ) )
+        {
+          return LATIN;
+        }
+      }
+    }
+    else // > 0x2c7f
+    {
+      if( character <= 0xfdff )
+      {
+        if( ( 0x2d00 <= character ) && ( character <= 0x2d2f ) )
+        {
+          return GEORGIAN;
+        }
+        if( ( 0x2d80 <= character ) && ( character <= 0x2ddf ) )
+        {
+          return GEEZ;
+        }
+        if( ( 0x2de0 <= character ) && ( character <= 0x2dff ) )
+        {
+          return CYRILLIC;
+        }
+        if( ( 0x2e80 <= character ) && ( character <= 0x2eff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x2f00 <= character ) && ( character <= 0x2fdf ) )
+        {
+          return CJK;
+        }
+        if( ( 0x3000 <= character ) && ( character <= 0x303f ) )
+        {
+          return CJK;
+        }
+        if( ( 0x3040 <= character ) && ( character <= 0x309f ) )
+        {
+          return HIRAGANA;
+        }
+        if( ( 0x30a0 <= character ) && ( character <= 0x30ff ) )
+        {
+          return KATAKANA;
+        }
+        if( ( 0x3100 <= character ) && ( character <= 0x312f ) )
+        {
+          return BOPOMOFO;
+        }
+        if( ( 0x3130 <= character ) && ( character <= 0x318f ) )
+        {
+          return HANGUL;
+        }
+        if( ( 0x31a0 <= character ) && ( character <= 0x31bf ) )
+        {
+          return BOPOMOFO;
+        }
+        if( ( 0x3200 <= character ) && ( character <= 0x32ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x3400 <= character ) && ( character <= 0x4dbf ) )
+        {
+          return CJK;
+        }
+        if( ( 0x4e00 <= character ) && ( character <= 0x62ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x6300 <= character ) && ( character <= 0x77ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x7800 <= character ) && ( character <= 0x8cff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x8d00 <= character ) && ( character <= 0x9fff ) )
+        {
+          return CJK;
+        }
+        if( ( 0xa640 <= character ) && ( character <= 0xa69f ) )
+        {
+          return CYRILLIC;
+        }
+        if( ( 0xa720 <= character ) && ( character <= 0xa7ff ) )
+        {
+          if( character == 0xA720 )
+          {
+            return PHONETIC_U;
+          }
+          if( character == 0xA721 )
+          {
+            return PHONETIC_U;
+          }
+          if( character == 0xA788 )
+          {
+            return NON_LATIN_LED;
+          }
+          if( character == 0xA789 )
+          {
+            return NON_LATIN_LED;
+          }
+          if( character == 0xA78A )
+          {
+            return NON_LATIN_LED;
+          }
+
+          return LATIN;
+        }
+        if( ( 0xa960 <= character ) && ( character <= 0xa97f ) )
+        {
+          return HANGUL;
+        }
+        if( ( 0xa980 <= character ) && ( character <= 0xa9fd ) )
+        {
+          return JAVANESE;
+        }
+        if( ( 0xab00 <= character ) && ( character <= 0xab2f ) )
+        {
+          return GEEZ;
+        }
+        if( ( 0xab30 <= character ) && ( character <= 0xab6f ) )
+        {
+          return LATIN;
+        }
+        if( ( 0xaae0 <= character ) && ( character <= 0xaaff ) )
+        {
+          return MEITEI;
+        }
+        if( ( 0xabc0 <= character ) && ( character <= 0xabff ) )
+        {
+          return MEITEI;
+        }
+        if( ( 0xac00 <= character ) && ( character <= 0xd7af ) )
+        {
+          return HANGUL;
+        }
+        if( ( 0xd7b0 <= character ) && ( character <= 0xd7ff ) )
+        {
+          return HANGUL;
+        }
+        if( ( 0xfb00 <= character ) && ( character <= 0xfb06 ) )
+        {
+          return LATIN;
+        }
+        if( ( 0xfb13 <= character ) && ( character <= 0xfb17 ) )
+        {
+          return ARMENIAN;
+        }
+        if( ( 0xfb1d <= character ) && ( character <= 0xfb4f ) )
+        {
+          return HEBREW;
+        }
+        if( ( 0xfb50 <= character ) && ( character <= 0xfdff ) )
+        {
+          return ARABIC;
+        }
+      }
+      else // > 0xfdff
+      {
+        if( ( 0xfe70 <= character ) && ( character <= 0xfeff ) )
+        {
+          return ARABIC;
+        }
+        if( ( 0xff00 <= character ) && ( character <= 0xffef ) )
+        {
+          if( ( 0xFF00 <= character ) && ( character <= 0xFF20 ) )
+          {
+            return HWFW_S;
+          }
+          if( ( 0xFF3B <= character ) && ( character <= 0xFF40 ) )
+          {
+            return HWFW_S;
+          }
+          if( ( 0xFF5B <= character ) && ( character <= 0xFFEF ) )
+          {
+            return HWFW_S;
+          }
+
+          return LATIN;
+        }
+        if( ( 0x1ee00 <= character ) && ( character <= 0x1eeff ) )
+        {
+          return ARABIC;
+        }
+        // U+1f170 4. Enclosed characters: negative squared latin capital letter A
+        // U+1f6ff 6b. Additional transport and map symbols
+        if( ( 0x1f170 <= character ) && ( character <= 0x1f6ff ) )
+        {
+          return EMOJI;
+        }
+        // 7. Supplemental Symbols and Pictographs
+        if( ( 0x1f900 <= character ) && ( character <= 0x1f9ff ) )
+        {
+          return EMOJI;
+        }
+        if( ( 0x20000 <= character ) && ( character <= 0x215ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x21600 <= character ) && ( character <= 0x230ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x23100 <= character ) && ( character <= 0x245ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x24600 <= character ) && ( character <= 0x260ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x26100 <= character ) && ( character <= 0x275ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x27600 <= character ) && ( character <= 0x290ff ) )
+        {
+          return CJK;
+        }
+        if( ( 0x29100 <= character ) && ( character <= 0x2a6df ) )
+        {
+          return CJK;
+        }
+        if( ( 0x2a700 <= character ) && ( character <= 0x2b73f ) )
+        {
+          return CJK;
+        }
+        if( ( 0x2b740 <= character ) && ( character <= 0x2b81f ) )
+        {
+          return CJK;
+        }
+      }
+    }
+  }
+
+  return UNKNOWN;
+}
+
+bool IsWhiteSpace( Character character )
+{
+  return character < WHITE_SPACE_THRESHOLD;
+}
+
+bool IsNewParagraph( Character character )
+{
+  return ( ( CHAR_LF == character )  ||
+           ( CHAR_VT == character )  ||
+           ( CHAR_FF == character )  ||
+           ( CHAR_CR == character )  ||
+           ( CHAR_NEL == character ) ||
+           ( CHAR_LS == character )  ||
+           ( CHAR_PS == character ) );
+}
+
+bool IsZeroWidthNonJoiner( Character character )
+{
+  return CHAR_ZWNJ == character;
+}
+
+bool IsZeroWidthJoiner( Character character )
+{
+  return CHAR_ZWJ == character;
+}
+
+bool IsZeroWidthSpace( Character character )
+{
+  return CHAR_ZWS == character;
+}
+
+bool IsLeftToRightMark( Character character )
+{
+  return CHAR_LTRM == character;
+}
+
+bool IsRightToLeftMark( Character character )
+{
+  return CHAR_RTLM == character;
+}
+
+bool IsThinSpace( Character character )
+{
+  return CHAR_TS == character;
+}
+
+bool IsCommonScript( Character character )
+{
+  return ( IsWhiteSpace( character )         ||
+           IsZeroWidthNonJoiner( character ) ||
+           IsZeroWidthJoiner( character )    ||
+           IsZeroWidthSpace( character )     ||
+           IsLeftToRightMark( character )    ||
+           IsRightToLeftMark( character )    ||
+           IsThinSpace( character )          ||
+           IsNewParagraph( character ) );
+}
+
+bool HasLigatureMustBreak( Script script )
+{
+  return ( ( LATIN == script ) ||
+           ( ARABIC == script ) );
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/devel-api/text-abstraction/script.h b/dali/devel-api/text-abstraction/script.h
new file mode 100644 (file)
index 0000000..a89a52a
--- /dev/null
@@ -0,0 +1,295 @@
+#ifndef DALI_TOOLKIT_TEXT_ABSTRACTION_SCRIPT_H
+#define DALI_TOOLKIT_TEXT_ABSTRACTION_SCRIPT_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/dali-adaptor-common.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+/**
+ * @brief Script is the writing system used by a language.
+ * Typically one script can be used to write different languages although one language could be written in different scrips.
+ */
+enum Script
+{
+  COMMON,        ///< Valid for all scripts. i.e white space or '\n'.
+
+  ASCII_DIGITS,  ///< ASCII digits.
+  ASCII_PS,      ///< ASCII punctuation and symbols.
+
+  C1_CONTROLS,   ///< Controls of the C1 Controls and Latin-1 Supplement unicode block.
+  C1_PS,         ///< Punctuation and symbols of the C1 Controls and Latin-1 Supplement unicode block.
+  C1_MATH,       ///< Math symbols of the C1 Controls and Latin-1 Supplement unicode block.
+
+  SML_P,         ///< Punctuation symbols of the Spacing Modifier Letters unicode block.
+  PHONETIC_U,    ///< Uralic phonetic symbols of the Phonetic Extensions unicode block.
+  PHONETIC_SS,   ///< Subscripts and superscripts of the Phonetic Extensions unicode block.
+
+  NUMERIC_SS,    ///< Numeric subscripts and superscripts.
+
+  LETTER_LIKE,   ///< Symbols of the Letterlike unicode block.
+  NUMBER_FORMS,  ///< Number Forms unicode block.
+  FRACTIONS_NF,  ///< Numeric fraction symbols of the Number Forms unicode block.
+  NON_LATIN_LED, ///< Non latin symbols within the Latin Extended D unicode block.
+  HWFW_S,        ///< Non latin symbols within the Halfwidth and fullwidth unicode block.
+
+  CYRILLIC,      ///< The Cyrillic script. Used by Russian, Bulgarian, Ukrainian, Macedonian, ...
+  GREEK,         ///< The Greek script. Used by Greek.
+  LATIN,         ///< The latin script. Used by many western languages and others around the world.
+
+  ARABIC,        ///< The arabic script. Used by Arab and Urdu among others.
+  HEBREW,        ///< The Hebrew script. Used by the Hebrew, Yiddish, Ladino, and Judeo-Arabic.
+
+  ARMENIAN,      ///< The Armenian script. Used by Armenian.
+  GEORGIAN,      ///< The Georgian script. Used by Georgian.
+
+  CJK,           ///< The CJK script. Used by Chinese, Japanese, Korean and Vietnamese(old writing system).
+  HANGUL,        ///< The Hangul jamo script. Used by Korean.
+  HIRAGANA,      ///< The Hiragana script. Used by the Japanese.
+  KATAKANA,      ///< The Katakana script. Used by the Japanese.
+  BOPOMOFO,      ///< The Bopomofo script. Also called Zhuyin fuhao or Zhuyin. A phonetic notation used for the transcription of spoken Chinese.
+
+  BENGALI,       ///< The Bengali script. Used by Bangla, Assamese, Bishnupriya Manipuri, Daphla, Garo, Hallam, Khasi, Mizo, Munda, Naga, Rian, and Santali.
+  BURMESE,       ///< The Burmese script. Used by the Burmese (Myanmar) language.
+  DEVANAGARI,    ///< The devanagari script. Used by Hindi, Marathi, Sindhi, Nepali and Sanskrit.
+  GUJARATI,      ///< The Gujarati script. Used by Gujarati.
+  GURMUKHI,      ///< The Gurmukhi script. Used by Punjabi.
+  KANNADA,       ///< The Kannada script. Used by Kannada and Tulu.
+  MALAYALAM,     ///< The Malayalam script. Used by Malayalam.
+  ORIYA,         ///< The Oriya script. Used by Oriya (Odia), Khondi, and Santali.
+  SINHALA,       ///< The Sinhala script. Used by Sinhala and Pali.
+  TAMIL,         ///< The Tamil script. Used by Tamil, Badaga, and Saurashtra.
+  TELUGU,        ///< The Telugu script. Used by Telugu, Gondi, and Lambadi.
+
+  LAO,           ///< The Lao script. Used by the Lao language.
+  THAI,          ///< The Thai script. Used by the Thai language
+  KHMER,         ///< The Khmer script. Used by the Khmer language.
+  JAVANESE,      ///< The Javanese script. Used by the Javanese language.
+  SUNDANESE,     ///< The Sundanese script. Used by the Sundanese language.
+
+  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.
+
+  SYMBOLS1,      ///< Some symbols.
+  SYMBOLS2,      ///< Some symbols.
+  SYMBOLS3,      ///< Some symbols.
+  SYMBOLS4,      ///< Some symbols.
+  SYMBOLS5,      ///< Some symbols.
+
+  UNKNOWN        ///< The script is unknown.
+};
+
+const char* const ScriptName[] =
+{
+  "COMMON",        ///< Valid for all scripts. i.e white space or '\n'.
+
+  "ASCII_DIGITS",  ///< ASCII digits.
+  "ASCII_PS",      ///< ASCII punctuation and symbols.
+
+  "C1_CONTROLS",   ///< Controls of the C1 Controls and Latin-1 Supplement unicode block.
+  "C1_PS",         ///< Punctuation and symbols of the C1 Controls and Latin-1 Supplement unicode block.
+  "C1_MATH",       ///< Math symbols of the C1 Controls and Latin-1 Supplement unicode block.
+
+  "SML_P",         ///< Punctuation symbols of the Spacing Modifier Letters unicode block.
+  "PHONETIC_U",    ///< Uralic phonetic symbols of the Phonetic Extensions unicode block.
+  "PHONETIC_SS",   ///< Subscripts and superscripts of the Phonetic Extensions unicode block.
+
+  "NUMERIC_SS",    ///< Numeric subscripts and superscripts.
+
+  "LETTER_LIKE",   ///< Symbols of the Letterlike unicode block.
+  "NUMBER_FORMS",  ///< Number Forms unicode block.
+  "FRACTIONS_NF",  ///< Numeric fraction symbols of the Number Forms unicode block.
+  "NON_LATIN_LED", ///< Non latin symbols within the Latin Extended D unicode block.
+  "HWFW_S",        ///< Non latin symbols within the Halfwidth and fullwidth unicode block.
+
+  "CYRILLIC",      ///< The Cyrillic script. Used by Russian, Bulgarian, Ukrainian, Macedonian, ...
+  "GREEK",         ///< The Greek script. Used by Greek.
+  "LATIN",         ///< The latin script. Used by many western languages and others around the world.
+
+  "ARABIC",        ///< The arabic script. Used by Arab and Urdu among others.
+  "HEBREW",        ///< The Hebrew script. Used by the Hebrew, Yiddish, Ladino, and Judeo-Arabic.
+
+  "ARMENIAN",      ///< The Armenian script. Used by Armenian.
+  "GEORGIAN",      ///< The Georgian script. Used by Georgian.
+
+  "CJK",           ///< The CJK script. Used by Chinese, Japanese, Korean and Vietnamese(old writing system).
+  "HANGUL",        ///< The Hangul jamo script. Used by Korean.
+  "HIRAGANA",      ///< The Hiragana script. Used by the Japanese.
+  "KATAKANA",      ///< The Katakana script. Used by the Japanese.
+  "BOPOMOFO",      ///< The Bopomofo script. Also called Zhuyin fuhao or Zhuyin. A phonetic notation used for the transcription of spoken Chinese.
+
+  "BENGALI",       ///< The Bengali script. Used by Bangla, Assamese, Bishnupriya Manipuri, Daphla, Garo, Hallam, Khasi, Mizo, Munda, Naga, Rian, and Santali.
+  "BURMESE",       ///< The Burmese script. Used by the Burmese (Myanmar) language.
+  "DEVANAGARI",    ///< The devanagari script. Used by Hindi, Marathi, Sindhi, Nepali and Sanskrit.
+  "GUJARATI",      ///< The Gujarati script. Used by Gujarati.
+  "GURMUKHI",      ///< The Gurmukhi script. Used by Punjabi.
+  "KANNADA",       ///< The Kannada script. Used by Kannada and Tulu.
+  "MALAYALAM",     ///< The Malayalam script. Used by Malayalam.
+  "ORIYA",         ///< The Oriya script. Used by Oriya (Odia), Khondi, and Santali.
+  "SINHALA",       ///< The Sinhala script. Used by Sinhala and Pali.
+  "TAMIL",         ///< The Tamil script. Used by Tamil, Badaga, and Saurashtra.
+  "TELUGU",        ///< The Telugu script. Used by Telugu, Gondi, and Lambadi.
+
+  "LAO",           ///< The Lao script. Used by the Lao language.
+  "THAI",          ///< The Thai script. Used by the Thai language
+  "KHMER",         ///< The Khmer script. Used by the Khmer language.
+  "JAVANESE",      ///< The Javanese script. Used by the Javanese language.
+  "SUNDANESE",     ///< The Sundanese script. Used by the Sundanese language.
+
+  "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.
+
+  "SYMBOLS1",      ///< Some symbols.
+  "SYMBOLS2",      ///< Some symbols.
+  "SYMBOLS3",      ///< Some symbols.
+  "SYMBOLS4",      ///< Some symbols.
+  "SYMBOLS5",      ///< Some symbols.
+
+  "UNKNOWN"        ///< The script is unknown.
+};
+
+/**
+ * @brief Whether the script is a right to left script.
+ *
+ * @param[in] script The script.
+ *
+ * @return @e true if the script is right to left.
+ */
+DALI_ADAPTOR_API bool IsRightToLeftScript( Script script );
+
+/**
+ * @brief Retrieves a character's script.
+ *
+ * @param[in] character The character.
+ *
+ * @return The chraracter's script.
+ */
+DALI_ADAPTOR_API Script GetCharacterScript( Character character );
+
+/**
+ * @brief Whether the character is a white space.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is a white space.
+ */
+DALI_ADAPTOR_API bool IsWhiteSpace( Character character );
+
+/**
+ * @brief Whether the character is a new paragraph character.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is a new paragraph character.
+ */
+DALI_ADAPTOR_API bool IsNewParagraph( Character character );
+
+/**
+ * @brief Whether the character is a zero width non joiner.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is a zero width non joiner.
+ */
+DALI_ADAPTOR_API bool IsZeroWidthNonJoiner( Character character );
+
+/**
+ * @brief Whether the character is a zero width joiner.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is a zero width joiner.
+ */
+DALI_ADAPTOR_API bool IsZeroWidthJoiner( Character character );
+
+/**
+ * @brief Whether the character is a zero width space.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is a zero width space.
+ */
+DALI_ADAPTOR_API bool IsZeroWidthSpace( Character character );
+
+/**
+ * @brief Whether the character is a left to right mark.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is a left to right mark.
+ */
+DALI_ADAPTOR_API bool IsLeftToRightMark( Character character );
+
+/**
+ * @brief Whether the character is a right to left mark.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is a right to left mark.
+ */
+DALI_ADAPTOR_API bool IsRightToLeftMark( Character character );
+
+/**
+ * @brief Whether the character is a thin space.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is a thin space.
+ */
+DALI_ADAPTOR_API bool IsThinSpace( Character character );
+
+/**
+ * @brief Whether the character is common within all scripts.
+ *
+ * @param[in] character The character.
+ *
+ * @return @e true if the character is common within all scripts.
+ */
+DALI_ADAPTOR_API bool IsCommonScript( Character character );
+
+/**
+ * @brief Whether the script contains ligatures that must be 'broken' for selection or cursor position.
+ *
+ * i.e The latin script has the 'ff' or 'fi' ligatures that need to be broken to position the cursor
+ * between the two characters. Equally the arabic script has the 'ﻻ' ligature that needs to be broken.
+ *
+ * @param[in] script The script.
+ *
+ * @return @e true if the script has ligatures that must be 'broken'.
+ */
+DALI_ADAPTOR_API bool HasLigatureMustBreak( Script script );
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_ABSTRACTION_SCRIPT_H
diff --git a/dali/devel-api/text-abstraction/segmentation.cpp b/dali/devel-api/text-abstraction/segmentation.cpp
new file mode 100644 (file)
index 0000000..229fda3
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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 <dali/devel-api/text-abstraction/segmentation.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/text/text-abstraction/segmentation-impl.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+Segmentation::Segmentation()
+{
+}
+
+Segmentation::~Segmentation()
+{
+}
+
+Segmentation::Segmentation( Internal::Segmentation* implementation )
+: BaseHandle( implementation )
+{
+}
+
+Segmentation Segmentation::Get()
+{
+  return Internal::Segmentation::Get();
+}
+
+void Segmentation::GetLineBreakPositions( const Character* const text,
+                                          Length numberOfCharacters,
+                                          LineBreakInfo* breakInfo )
+{
+  GetImplementation( *this ).GetLineBreakPositions( text,
+                                                    numberOfCharacters,
+                                                    breakInfo );
+}
+
+void Segmentation::GetWordBreakPositions( const Character* const text,
+                                          Length numberOfCharacters,
+                                          WordBreakInfo* breakInfo )
+{
+  GetImplementation( *this ).GetWordBreakPositions( text,
+                                                    numberOfCharacters,
+                                                    breakInfo );
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/devel-api/text-abstraction/segmentation.h b/dali/devel-api/text-abstraction/segmentation.h
new file mode 100755 (executable)
index 0000000..3dfe71b
--- /dev/null
@@ -0,0 +1,134 @@
+#ifndef DALI_PLATFORM_TEXT_ABSTRACTION_SEGMENTATION_H
+#define DALI_PLATFORM_TEXT_ABSTRACTION_SEGMENTATION_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal DALI_INTERNAL
+{
+
+class Segmentation;
+
+} // Internal
+
+} // TextAbstraction
+
+namespace TextAbstraction
+{
+
+/**
+ *   Segmentation API
+ *
+ */
+class DALI_ADAPTOR_API Segmentation : public BaseHandle
+{
+
+public:
+
+  /**
+   * @brief Create an uninitialized TextAbstraction handle.
+   *
+   */
+  Segmentation();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~Segmentation();
+
+  /**
+   * @brief This constructor is used by Segmentation::Get().
+   *
+   * @param[in] implementation A pointer to the internal segmentation object.
+   */
+  explicit DALI_INTERNAL Segmentation( Internal::Segmentation* implementation );
+
+  /**
+   * @brief Retrieve a handle to the Segmentation instance.
+   *
+   * @return A handle to the Segmentation
+   */
+  static Segmentation Get();
+
+  /**
+   * @brief Retrieves the line break info.
+   *
+   * @pre @p breakInfo must have enough space allocated for @p numberOfCharacters.
+   *
+   * Possible values for LineBreakInfo are:
+   *
+   *  - 0 is a LINE_MUST_BREAK.  Text must be broken into a new line.
+   *  - 1 is a LINE_ALLOW_BREAK. Is possible to break the text into a new line.
+   *  - 2 is a LINE_NO_BREAK.    Text can't be broken into a new line.
+   *
+     @verbatim
+     i.e. Hello big\nworld produces:
+          2222212220 22220
+     @endverbatim
+   *
+   * @param[in] text Pointer to the first character of the text coded in UTF32.
+   * @param[in] numberOfCharacters The number of characters.
+   * @param[out] breakInfo The line break info.
+   */
+  void GetLineBreakPositions( const Character* const text,
+                              Length numberOfCharacters,
+                              LineBreakInfo* breakInfo );
+
+  /**
+   * @brief Retrieves the word break info.
+   *
+   * @pre @p breakInfo must have enough space allocated for @p numberOfCharacters.
+   *
+   * Possible values for WordBreakInfo are:
+   *
+   * - 0 is a WORD_BREAK.    Text can be broken into a new word.
+   * - 1 is a WORD_NO_BREAK. Text can't be broken into a new word.
+   *
+     @verbatim
+     i.e. Hello big\nworld produces:
+          1111001100 11110
+     @endverbatim
+   *
+   * @param[in] text Pointer to the first character of the text coded in UTF32.
+   * @param[in] numberOfCharacters The number of characters.
+   * @param[out] breakInfo The word break info.
+   */
+  void GetWordBreakPositions( const Character* const text,
+                              Length numberOfCharacters,
+                              WordBreakInfo* breakInfo );
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_PLATFORM_TEXT_ABSTRACTION_SEGMENTATION_H
diff --git a/dali/devel-api/text-abstraction/shaping.cpp b/dali/devel-api/text-abstraction/shaping.cpp
new file mode 100644 (file)
index 0000000..fc1a469
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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 <dali/devel-api/text-abstraction/shaping.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/text/text-abstraction/shaping-impl.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+Shaping::Shaping()
+{
+}
+
+Shaping::~Shaping()
+{
+}
+
+Shaping::Shaping( Internal::Shaping *impl )
+: BaseHandle( impl )
+{
+}
+
+Shaping Shaping::Get()
+{
+  return Internal::Shaping::Get();
+}
+
+Length Shaping::Shape( const Character* const text,
+                       Length numberOfCharacters,
+                       FontId fontId,
+                       Script script )
+{
+  return GetImplementation( *this ).Shape( text,
+                                           numberOfCharacters,
+                                           fontId,
+                                           script );
+}
+
+void Shaping::GetGlyphs( GlyphInfo* glyphInfo,
+                         CharacterIndex* glyphToCharacterMap )
+{
+  GetImplementation( *this ).GetGlyphs( glyphInfo,
+                                        glyphToCharacterMap );
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/devel-api/text-abstraction/shaping.h b/dali/devel-api/text-abstraction/shaping.h
new file mode 100644 (file)
index 0000000..5c7ee80
--- /dev/null
@@ -0,0 +1,129 @@
+#ifndef DALI_PLATFORM_TEXT_ABSTRACTION_SHAPING_H
+#define DALI_PLATFORM_TEXT_ABSTRACTION_SHAPING_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/text-abstraction/script.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-handle.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+struct GlyphInfo;
+
+namespace Internal DALI_INTERNAL
+{
+
+class Shaping;
+
+} // Internal
+
+/**
+ * @brief Shaping provides an interface to retrieve glyphs from complex text.
+ *
+ * This module shapes text for a unique font id and script. If the text contains different fonts and scripts
+ * it needs to be split in runs of consecutive characters with the same font id and script.
+ *
+ * @code
+ * Shaping shaping = Shaping::Get();
+ *
+ * // Shapes a number of characters with the given font id and script.
+ * const Length numberOfGlyphs = shaping.Shape( text, numberOfCharacters, fontId, script );
+ *
+ * // Allocate memory to retrieve the glyphs and the character to glyph conversion map.
+ * GlyphInfo* glyphInfo = reinterpret_cast<GlyphInfo*>( malloc( numberOfGlyphs * sizeof( GlyphInfo ) ) );
+ * CharacterIndex* glyphToCharacterMap = reinterpret_cast<CharacterIndex*>( malloc( numberOfGlyphs * sizeof( CharacterIndex ) ) );
+ *
+ * // Retrieve the glyphs and the conversion map.
+ * shaping.GetGlyphs( glyphInfo, glyphToCharacterMap );
+ * @endcode
+ */
+class DALI_ADAPTOR_API Shaping : public BaseHandle
+{
+
+public:
+
+  /**
+   * @brief Create an uninitialized Shaping handle.
+   *
+   */
+  Shaping();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~Shaping();
+
+  /**
+   * @brief This constructor is used by Shaping::Get().
+   *
+   * @param[in] implementation A pointer to the internal shaping object.
+   */
+  explicit DALI_INTERNAL Shaping( Internal::Shaping* implementation );
+
+  /**
+   * @brief Retrieve a handle to the Shaping instance.
+   *
+   * @return A handle to the Shaping.
+   */
+  static Shaping Get();
+
+  /**
+   * Shapes the text.
+   *
+   * Call GetGlyphs() to retrieve the glyphs.
+   *
+   * @param[in] text Pointer to the first character of the text coded in UTF32.
+   * @param[in] numberOfCharacters The number of characters to be shaped
+   * @param[in] fontId The font to be used to shape the text.
+   * @param[in] script The text's script.
+   *
+   * @return The size of the buffer required to get the shaped text.
+   */
+  Length Shape( const Character* const text,
+                Length numberOfCharacters,
+                FontId fontId,
+                Script script );
+
+  /**
+   * Gets the shaped text data.
+   *
+   * @pre @p glyphInfo and @p glyphToCharacterMap must have enough space allocated for the number of glyphs.
+   * Call first Shape() to shape the text and get the number of glyphs.
+   *
+   * @param[out] glyphInfo Vector with indices to the glyph within the font, glyph's metrics and advance.
+   * @param[out] glyphToCharacterMap The glyph to character conversion map.
+   */
+  void GetGlyphs( GlyphInfo* glyphInfo,
+                  CharacterIndex* glyphToCharacterMap );
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_PLATFORM_TEXT_ABSTRACTION_SHAPING_H
diff --git a/dali/devel-api/text-abstraction/text-abstraction-definitions.h b/dali/devel-api/text-abstraction/text-abstraction-definitions.h
new file mode 100755 (executable)
index 0000000..338d0c8
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef DALI_TEXT_ABSTRACTION_DEFINITIONS_H
+#define DALI_TEXT_ABSTRACTION_DEFINITIONS_H
+
+/*
+ * Copyright (c) 2019 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 <stdint.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+typedef uint32_t FontId;             ///< The unique identifier for a font face (generated by FontClient)
+typedef uint32_t PointSize26Dot6;    ///< The point size in 26.6 fractional points
+typedef uint32_t FaceIndex;          ///< Used with fonts which allow several font faces
+typedef uint32_t GlyphIndex;         ///< Uniquely identifies a glyph within a particular font
+typedef uint32_t Character;          ///< A UTF-32 representation of a character
+typedef uint32_t CharacterIndex;     ///< An index into an array of characters
+typedef uint32_t Length;             ///< The length of an array
+typedef uint32_t BidiInfoIndex;      ///< Index to the bidirectional info for a paragraph.
+typedef char     LineBreakInfo;      ///< Line break info (must break, allow break, no break).
+typedef char     WordBreakInfo;      ///< Word break info (break, no break).
+typedef bool     CharacterDirection; ///< The character's direction: @e false is left to right, @e true is right to left.
+typedef uint32_t ColorIndex;         ///< An index into an array of colors.
+
+/**
+ * @brief Enumerates the possible line break info values.
+ */
+enum
+{
+  LINE_MUST_BREAK  = 0u, ///< Text must be broken into a new line.
+  LINE_ALLOW_BREAK = 1u, ///< Is possible to break the text into a new line.
+  LINE_NO_BREAK    = 2u  ///< Text can't be broken into a new line.
+};
+
+/**
+ * @brief Enumerates the possible word break info values.
+ */
+enum
+{
+  WORD_BREAK    = 0u, ///< Text can be broken into a new word.
+  WORD_NO_BREAK = 1u, ///< Text can't be broken into a new word.
+};
+
+enum GlyphType
+{
+  BITMAP_GLYPH, ///< Glyph stored as pixels.
+  VECTOR_GLYPH  ///< Glyph stored as vectors (scalable). This feature requires highp shader support and is not available on all platforms.
+};
+
+struct VectorBlob
+{
+  unsigned char r;
+  unsigned char g;
+  unsigned char b;
+  unsigned char a;
+};
+
+/**
+* @brief Defines how a color is blended.
+*/
+enum class ColorBlendingMode
+{
+  NONE,     ///< No blend.
+  MULTIPLY  ///< The color is multiplied by another one.
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_TEXT_ABSTRACTION_DEFINITIONS_H
diff --git a/dali/devel-api/text-abstraction/text-abstraction.h b/dali/devel-api/text-abstraction/text-abstraction.h
new file mode 100755 (executable)
index 0000000..3a9309e
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef DALI_TEXT_ABSTRACTION_H
+#define DALI_TEXT_ABSTRACTION_H
+
+/*
+ * Copyright (c) 2019 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/devel-api/text-abstraction/bidirectional-support.h>
+#include <dali/devel-api/text-abstraction/bitmap-font.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/devel-api/text-abstraction/font-metrics.h>
+#include <dali/devel-api/text-abstraction/glyph-info.h>
+#include <dali/devel-api/text-abstraction/script.h>
+#include <dali/devel-api/text-abstraction/segmentation.h>
+#include <dali/devel-api/text-abstraction/shaping.h>
+
+#endif // DALI_TEXT_ABSTRACTION_H
diff --git a/dali/devel-api/text-abstraction/text-renderer-layout-helper.cpp b/dali/devel-api/text-abstraction/text-renderer-layout-helper.cpp
new file mode 100755 (executable)
index 0000000..5e17f9f
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali/devel-api/text-abstraction/text-renderer-layout-helper.h>
+
+// EXTERNAL INCLUDES
+#include <cmath>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+void TransformToArc( const CircularTextParameters& parameters, double& x, double& y )
+{
+  double yP = y;
+
+  // Does the italic synthesization for circular layout.
+  if( parameters.synthesizeItalic )
+  {
+    const double xP = -yP * sin( TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE );
+    yP *= cos( TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE );
+
+    x += xP;
+  }
+
+  double angle = 0.0;
+  double radius = parameters.radius;
+
+  // Transform to a circular layout.
+  if( parameters.isClockwise )
+  {
+    angle = parameters.beginAngle - parameters.invRadius * x;
+    radius -= yP;
+
+    x = radius * cos( angle );
+    y = -radius * sin( angle );
+  }
+  else
+  {
+    angle = parameters.beginAngle + parameters.invRadius * x;
+    radius += yP;
+
+    x = radius * cos( angle );
+    y = radius * sin( -angle );
+  }
+
+  // Transforms to the text area coordinate system.
+  x += parameters.centerX;
+  y += parameters.centerY;
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/devel-api/text-abstraction/text-renderer-layout-helper.h b/dali/devel-api/text-abstraction/text-renderer-layout-helper.h
new file mode 100755 (executable)
index 0000000..a502967
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef DALI_PLATFORM_TEXT_ABSTRACTION_TEXT_RENDERER_LAYOUT_HELPER_H
+#define DALI_PLATFORM_TEXT_ABSTRACTION_TEXT_RENDERER_LAYOUT_HELPER_H
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+/**
+ * @brief Parameters used to transform the vertices of the glyphs to wrap a circular path.
+ */
+struct DALI_ADAPTOR_API CircularTextParameters
+{
+  CircularTextParameters()
+  : centerX{ 0.0 },
+    centerY{ 0.0 },
+    radius{ 0.0 },
+    invRadius{ 0.0 },
+    beginAngle{ 0.0 },
+    isClockwise{ true },
+    synthesizeItalic{ false }
+  {}
+
+  double centerX;          ///< The 'x' center of the circular path.
+  double centerY;          ///< The 'y' center of the circular path.
+  double radius;           ///< The radius in pixels.
+  double invRadius;        ///< 1.0 / radius.
+  double beginAngle;       ///< The angle in radians where the circular text begins.
+  bool isClockwise:1;      ///< Whether the circular text layout is clockwise.
+  bool synthesizeItalic:1; ///< Whether to synthesize italic.
+};
+
+/**
+ * @brief Transforms a vertex to wrap a circular path.
+ *
+ * @param[in] parameters The parameters of the circular path.
+ * @param[in,out] x The 'x' coordinate of the vertex.
+ * @param[in,out] y The 'y' coordinate of the vertex.
+ */
+DALI_ADAPTOR_API void TransformToArc( const CircularTextParameters& parameters, double& x, double& y );
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_PLATFORM_TEXT_ABSTRACTION_TEXT_RENDERER_LAYOUT_HELPER_H
diff --git a/dali/devel-api/text-abstraction/text-renderer.cpp b/dali/devel-api/text-abstraction/text-renderer.cpp
new file mode 100755 (executable)
index 0000000..a4a68a6
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+* Copyright (c) 2019 Samsung Electronics Co., Ltd.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+// CLASS HEADER
+#include <dali/devel-api/text-abstraction/text-renderer.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/text/text-abstraction/text-renderer-impl.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+TextRenderer::TextRenderer()
+{
+}
+
+TextRenderer::~TextRenderer()
+{
+}
+
+TextRenderer TextRenderer::Get()
+{
+  return Internal::TextRenderer::Get();
+}
+
+Devel::PixelBuffer TextRenderer::Render(const Parameters& parameters)
+{
+  return GetImplementation(*this).Render(parameters);
+}
+
+TextRenderer::TextRenderer(Internal::TextRenderer *impl)
+: BaseHandle(impl)
+{
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/devel-api/text-abstraction/text-renderer.h b/dali/devel-api/text-abstraction/text-renderer.h
new file mode 100755 (executable)
index 0000000..9babd32
--- /dev/null
@@ -0,0 +1,169 @@
+#ifndef DALI_TOOLKIT_TEXT_ABSTRACTION_TEXT_RENDERER_H
+#define DALI_TOOLKIT_TEXT_ABSTRACTION_TEXT_RENDERER_H
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/object/base-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/glyph-info.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+  // Forward declaration
+  class TextRenderer;
+
+} // namespace Internal
+
+/**
+ * @brief Renders the given @e glyphs at the given @e positions into a pixel buffer.
+ *
+ * @note This class renders glyphs not characters.
+ *       Font selection, RTL reordering, shaping and layout
+ *       has to be done before calling the @e Render()
+ *       method of this class.
+ */
+class DALI_ADAPTOR_API TextRenderer : public BaseHandle
+{
+public:
+  /**
+   * @brief Parameters to render the text.
+   */
+  struct Parameters
+  {
+    /**
+     * @brief Enum with the possible pixel formats of the output pixel buffer.
+     */
+    enum PixelFormat
+    {
+      A8,      ///< Alpha channel, 8-bit color depth.
+      RGBA8888 ///< Red, Green, Blue and Alpha channels, 8-bit color depth per channel.
+    };
+
+    /**
+     * @brief Whether the circular layout is clockwise.
+     */
+    enum CircularLayout
+    {
+      CLOCKWISE,        ///< The text is laid clockwise on a circular path.
+      COUNTER_CLOCKWISE ///< The text is laid counter clockwise on a circular path.
+    };
+
+    /**
+     * @brief Parameters for the text renderer function.
+     */
+    Parameters( Vector<GlyphInfo>& glyphs,
+                Vector<Vector2>& positions,
+                Vector<Vector4>& colors,
+                Vector<ColorIndex>& colorIndices,
+                Vector<ColorBlendingMode>& blendingMode,
+                Vector<bool>& isEmoji )
+    : glyphs( glyphs ),
+      positions( positions ),
+      colors( colors ),
+      colorIndices( colorIndices ),
+      blendingMode( blendingMode ),
+      isEmoji( isEmoji ),
+      width{ 0u },
+      height{ 0u },
+      radius{ 0u },
+      circularWidth{ 0u },
+      circularHeight{ 0u },
+      centerX{ 0 },
+      centerY{ 0 },
+      beginAngle{ 0.f },
+      pixelFormat{ A8 },
+      circularLayout{ CLOCKWISE }
+    {}
+
+    Vector<GlyphInfo>& glyphs;               ///< The glyphs to be rendered.
+    Vector<Vector2>& positions;              ///< The position for each glyph.
+    Vector<Vector4>& colors;                 ///< Colors of the glyphs.
+    Vector<ColorIndex>& colorIndices;        ///< Indices to the vector of colors for each glyphs.
+    Vector<ColorBlendingMode>& blendingMode; ///< How each glyph is going to be blended with the color of the text.
+    Vector<bool>& isEmoji;                   ///< Whether each glyph is an emoji.
+    unsigned int width;                      ///< The width of the pixel buffer. @note Some implementations may change the width for performance reasons.
+    unsigned int height;                     ///< The height of the pixel buffer.
+    unsigned int radius;                     ///< The radius in pixels of the circular text.
+    unsigned int circularWidth;              ///< The width of the text laid out on an horizontal straight line.
+    unsigned int circularHeight;             ///< The height of the text laid out on an horizontal straight line.
+    int centerX;                             ///< The 'x' coordinate of the center. For circular layout.
+    int centerY;                             ///< The 'y' coordinate of the center. For circular layout.
+    float beginAngle;                        ///< The angle in radians where the circular text begins.
+    PixelFormat pixelFormat;                 ///< The pixel format of the pixel buffer.
+    CircularLayout circularLayout;           ///< The direction of the text's layout.
+  };
+
+public:
+
+  /**
+   * @brief Create an uninitialized TextRenderer handle.
+   *
+   */
+  TextRenderer();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~TextRenderer();
+
+  /**
+   * @brief Retrieve a handle to the TextRenderer instance.
+   *
+   * @return A handle to the TextRenderer.
+   */
+  static TextRenderer Get();
+
+  /**
+   * @brief Renders the given @e glyphs into a pixel buffer.
+   *
+   * @param[in] parameters Struct with the glyphs, positions and the size of the pixel buffer.
+   *
+   * @return The pixel buffer with the text rendered on it.
+   */
+  Devel::PixelBuffer Render(const Parameters& parameters);
+
+public: // Not intended for application developers.
+
+  /// @cond internal
+  /**
+   * @brief This constructor is used by TextRenderer::Get().
+   *
+   * @param[in] implementation A pointer to the internal text renderer object.
+   */
+  explicit DALI_INTERNAL TextRenderer(Internal::TextRenderer* implementation);
+  /// @endcond
+};
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_TOOLKIT_TEXT_ABSTRACTION_TEXT_RENDERER_H
diff --git a/dali/file.list b/dali/file.list
new file mode 100644 (file)
index 0000000..fde76da
--- /dev/null
@@ -0,0 +1,6 @@
+
+
+SET( adaptor_dali_header_file
+  ${adaptor_dali_header_dir}/dali.h
+)
+
diff --git a/dali/integration-api/adaptor-framework/adaptor.h b/dali/integration-api/adaptor-framework/adaptor.h
new file mode 100755 (executable)
index 0000000..b8eea93
--- /dev/null
@@ -0,0 +1,533 @@
+#ifndef DALI_INTEGRATION_ADAPTOR_H
+#define DALI_INTEGRATION_ADAPTOR_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/signals/callback.h>
+#include <dali/public-api/signals/dali-signal.h>
+#include <dali/public-api/math/uint-16-pair.h>
+#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/object/any.h>
+#include <dali/integration-api/processor-interface.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/window.h>
+#include <dali/public-api/adaptor-framework/application-configuration.h>
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/integration-api/adaptor-framework/log-factory-interface.h>
+
+namespace Dali
+{
+
+class RenderSurfaceInterface;
+
+using WindowContainer = std::vector<Window>;
+
+namespace Integration
+{
+class SceneHolder;
+}
+
+using SceneHolderList = std::vector<Dali::Integration::SceneHolder>;
+
+
+namespace Internal
+{
+namespace Adaptor
+{
+class GraphicsFactory;
+class Adaptor;
+}
+}
+
+/**
+ * @brief An Adaptor object is used to initialize and control how Dali runs.
+ *
+ * It provides a lifecycle interface that allows the application
+ * writer to provide their own main loop and other platform related
+ * features.
+ *
+ * The Adaptor class provides a means for initialising the resources required by the Dali::Core.
+ *
+ * When dealing with platform events, the application writer MUST ensure that Dali is called in a
+ * thread-safe manner.
+ *
+ * As soon as the Adaptor class is created and started, the application writer can initialise their
+ * Dali::Actor objects straight away or as required by the main loop they intend to use (there is no
+ * need to wait for an initialise signal as per the Dali::Application class).
+ *
+ * The Adaptor does emit a Resize signal which informs the user when the surface is resized.
+ * Tizen and Linux Adaptors should follow the example below:
+ *
+ * @code
+ * void CreateProgram(DaliAdaptor& adaptor)
+ * {
+ *   // Create Dali components...
+ *   // Can instantiate adaptor here instead, if required
+ * }
+ *
+ * int main ()
+ * {
+ *   // Initialise platform
+ *   MyPlatform.Init();
+ *
+ *   // Create an 800 by 1280 window positioned at (0,0).
+ *   Dali::PositionSize positionSize(0, 0, 800, 1280);
+ *   Dali::Window window = Dali::Window::New( positionSize, "My Application" );
+ *
+ *   // Create an adaptor which uses that window for rendering
+ *   Dali::Adaptor adaptor = Dali::Adaptor::New( window );
+ *   adaptor.Start();
+ *
+ *   CreateProgram(adaptor);
+ *   // Or use this as a callback function depending on the platform initialisation sequence.
+ *
+ *   // Start Main Loop of your platform
+ *   MyPlatform.StartMainLoop();
+ *
+ *   return 0;
+ * }
+ * @endcode
+ *
+ * If required, you can also connect class member functions to a signal:
+ *
+ * @code
+ * MyApplication application;
+ * adaptor.ResizedSignal().Connect(&application, &MyApplication::Resize);
+ * @endcode
+ *
+ * @see RenderSurface
+ */
+class DALI_ADAPTOR_API Adaptor
+{
+public:
+
+  typedef Signal< void (Adaptor&) > AdaptorSignalType; ///< Generic Type for adaptor signals
+  typedef Signal< void (Dali::Integration::SceneHolder&) > WindowCreatedSignalType;  ///< SceneHolder created signal type
+
+  using SurfaceSize = Uint16Pair; ///< Surface size type
+
+public:
+  /**
+   * @brief Create a new adaptor using the window.
+   *
+   * @param[in] window The window to draw onto
+   * @return a reference to the adaptor handle
+   */
+  static Adaptor& New( Window window );
+
+  /**
+   * @brief Create a new adaptor using the window.
+   *
+   * @param[in] window The window to draw onto
+   * @param[in] configuration The context loss configuration.
+   * @return a reference to the adaptor handle
+   */
+  static Adaptor& New( Window window, Configuration::ContextLoss configuration );
+
+  /**
+   * @brief Create a new adaptor using render surface.
+   *
+   * @param[in] window The window to draw onto
+   * @param[in] surface The surface to draw onto
+   * @return a reference to the adaptor handle
+   */
+  static Adaptor& New( Window window, const Dali::RenderSurfaceInterface& surface );
+
+  /**
+   * @brief Create a new adaptor using render surface.
+   *
+   * @param[in] window The window to draw onto
+   * @param[in] surface The surface to draw onto
+   * @param[in] configuration The context loss configuration.
+   * @return a reference to the adaptor handle
+   */
+  static Adaptor& New( Window window, const Dali::RenderSurfaceInterface& surface, Configuration::ContextLoss configuration = Configuration::APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS);
+
+  /**
+   * @brief Create a new adaptor using the SceneHolder.
+   *
+   * @param[in] sceneHolder The SceneHolder to draw onto
+   * @return a reference to the adaptor handle
+   */
+  static Adaptor& New( Dali::Integration::SceneHolder sceneHolder );
+
+  /**
+   * @brief Create a new adaptor using the SceneHolder.
+   *
+   * @param[in] sceneHolder The SceneHolder to draw onto
+   * @param[in] configuration The context loss configuration.
+   * @return a reference to the adaptor handle
+   */
+  static Adaptor& New( Dali::Integration::SceneHolder sceneHolder, Configuration::ContextLoss configuration );
+
+  /**
+   * @brief Create a new adaptor using render surface.
+   *
+   * @param[in] sceneHolder The SceneHolder to draw onto
+   * @param[in] surface The surface to draw onto
+   * @return a reference to the adaptor handle
+   */
+  static Adaptor& New( Dali::Integration::SceneHolder sceneHolder, const Dali::RenderSurfaceInterface& surface );
+
+  /**
+   * @brief Create a new adaptor using render surface.
+   *
+   * @param[in] sceneHolder The SceneHolder to draw onto
+   * @param[in] surface The surface to draw onto
+   * @param[in] configuration The context loss configuration.
+   * @return a reference to the adaptor handle
+   */
+  static Adaptor& New( Dali::Integration::SceneHolder sceneHolder, const Dali::RenderSurfaceInterface& surface, Configuration::ContextLoss configuration = Configuration::APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS);
+
+  /**
+   * @brief Virtual Destructor.
+   */
+  virtual ~Adaptor();
+
+public:
+
+  /**
+   * @brief Starts the Adaptor.
+   */
+  void Start();
+
+  /**
+   * @brief Pauses the Adaptor.
+   */
+  void Pause();
+
+  /**
+   * @brief Resumes the Adaptor, if previously paused.
+   *
+   * @note If the adaptor is not paused, this does not do anything.
+   */
+  void Resume();
+
+  /**
+   * @brief Stops the Adaptor.
+   */
+  void Stop();
+
+  /**
+   * @brief Ensures that the function passed in is called from the main loop when it is idle.
+   * @note Function must be called from the main event thread only.
+   *
+   * Callbacks of the following types may be used:
+   * @code
+   *   void MyFunction();
+   * @endcode
+   * This callback will be deleted once it is called.
+   *
+   * @code
+   *   bool MyFunction();
+   * @endcode
+   * This callback will be called repeatedly as long as it returns true. A return of 0 deletes this callback.
+   *
+   * @param[in] callback The function to call.
+   * @param[in] hasReturnValue Sould be set to true if the callback function has a return value.
+   * @return true if added successfully, false otherwise
+   *
+   * @note Ownership of the callback is passed onto this class.
+   */
+  bool AddIdle( CallbackBase* callback, bool hasReturnValue );
+
+  /**
+   * @brief Adds a new Window instance to the Adaptor
+   *
+   * @param[in]  childWindow The child window instance
+   * @param[in]  childWindowName The child window title/name
+   * @param[in]  childWindowClassName The class name that the child window belongs to
+   * @param[in]  childWindowMode The mode of the child window
+   */
+  bool AddWindow( Dali::Integration::SceneHolder childWindow,
+                  const std::string& childWindowName,
+                  const std::string& childWindowClassName,
+                  bool childWindowMode );
+
+  /**
+   * @brief Removes a previously added @p callback.
+   * @note Function must be called from the main event thread only.
+   *
+   * Does nothing if the @p callback doesn't exist.
+   *
+   * @param[in] callback The callback to be removed.
+   */
+  void RemoveIdle( CallbackBase* callback );
+
+  /**
+   * @brief Processes the idle callbacks.
+   *
+   * @note This function is intended to be used in the case there is no instance of a Dali::Application i.e. DALi is used in a implementation of a plugin of an application.
+   */
+  void ProcessIdle();
+
+  /**
+   * @brief Replaces the rendering surface
+   *
+   * @param[in] window The window to replace the surface for
+   * @param[in] surface to use
+   */
+  void ReplaceSurface( Window window, Dali::RenderSurfaceInterface& surface );
+
+  /**
+   * @brief Replaces the rendering surface
+   *
+   * @param[in] sceneHolder The SceneHolder to replace the surface for
+   * @param[in] surface to use
+   */
+  void ReplaceSurface( Dali::Integration::SceneHolder sceneHolder, Dali::RenderSurfaceInterface& surface );
+
+  /**
+   * @brief Get the render surface the adaptor is using to render to.
+   *
+   * @return reference to current render surface
+   */
+  Dali::RenderSurfaceInterface& GetSurface();
+
+  /**
+   * @brief Gets native window handle
+   *
+   * @return Native window handle
+   */
+  Any GetNativeWindowHandle();
+
+  /**
+   * @brief Retrieve native window handle that the given actor is added to.
+   *
+   * @param[in] actor The actor
+   * @return native window handle
+   */
+  Any GetNativeWindowHandle( Actor actor );
+
+  /**
+   * @brief Get the native display associated with the graphics backend
+   *
+   * @return A handle to the native display
+   */
+  Any GetGraphicsDisplay();
+
+  /**
+   * @brief Release any locks the surface may hold.
+   *
+   * For example, after compositing an offscreen surface, use this method to allow
+   * rendering to continue.
+   */
+  void ReleaseSurfaceLock();
+
+  /**
+   * @brief Set the number of frames per render.
+   *
+   * This enables an application to deliberately render with a reduced FPS.
+   * @param[in] numberOfVSyncsPerRender The number of vsyncs between successive renders.
+   * Suggest this is a power of two:
+   * 1 - render each vsync frame
+   * 2 - render every other vsync frame
+   * 4 - render every fourth vsync frame
+   * 8 - render every eighth vsync frame
+   */
+  void SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender );
+
+  /**
+   * @brief The callback is called from the Update/Render thread prior to rendering.
+   *
+   * @param[in] callback The function to call
+   *
+   * @note The function is called from the Update thread, so should do as little processing as possible.
+   * It is not possible to call any DALi event side APIs from within the callback; doing so will cause
+   * instability. Only 1 callback is supported. Setting the callback to NULL will remove the current callback.
+   *
+   * A callback of the following type should be used:
+   * @code
+   *   bool MyFunction();
+   * @endcode
+   * This callback will be called repeatedly as long as it returns true. A return of 0 deletes this callback.
+   */
+  void SetPreRenderCallback( CallbackBase* callback );
+
+  /**
+   * @brief Returns a reference to the instance of the adaptor used by the current thread.
+   *
+   * @return A reference to the adaptor.
+   * @pre The adaptor has been initialised.
+   * @note This is only valid in the main thread.
+   */
+  static Adaptor& Get();
+
+  /**
+   * @brief Checks whether the adaptor is available.
+   *
+   * @return true, if it is available, false otherwise.
+   */
+  static bool IsAvailable();
+
+  /**
+   * @brief Call this method to notify Dali when scene is created and initialized.
+   *
+   * Notify Adaptor that the scene has been created.
+   */
+  void NotifySceneCreated();
+
+  /**
+   * @brief Call this method to notify Dali when the system language changes.
+   *
+   * Use this only when NOT using Dali::Application, As Application created using
+   * Dali::Application will automatically receive notification of language change.
+   * When Dali::Application is not used, the application developer should
+   * use app-core to receive language change notifications and should update Dali
+   * by calling this method.
+   */
+  void NotifyLanguageChanged();
+
+  /**
+   * @brief Feed a touch point to the adaptor.
+   *
+   * @param[in] point touch point
+   * @param[in] timeStamp time value of event
+   */
+  void FeedTouchPoint( TouchPoint& point, int timeStamp );
+
+  /**
+   * @brief Feed a wheel event to the adaptor.
+   *
+   * @param[in]  wheelEvent wheel event
+   */
+  void FeedWheelEvent( WheelEvent& wheelEvent );
+
+  /**
+   * @brief Feed a key event to the adaptor.
+   *
+   * @param[in] keyEvent The key event holding the key information.
+   */
+  void FeedKeyEvent( KeyEvent& keyEvent );
+
+  /**
+   * @copydoc Dali::Core::SceneCreated();
+   */
+  void SceneCreated();
+
+  /**
+   * @brief Informs core the surface size has changed.
+   *
+   * @param[in] surface The current render surface
+   * @param[in] surfaceSize The new surface size
+   */
+  void SurfaceResizePrepare( Dali::RenderSurfaceInterface* surface, SurfaceSize surfaceSize );
+
+  /**
+   * @brief Informs ThreadController the surface size has changed.
+   *
+   * @param[in] surface The current render surface
+   * @param[in] surfaceSize The new surface size
+   */
+  void SurfaceResizeComplete( Dali::RenderSurfaceInterface* surface, SurfaceSize surfaceSize );
+
+  /**
+   * @brief Renders once more even if we're paused
+   * @note Will not work if the window is hidden.
+   */
+  void RenderOnce();
+
+  /**
+   * @brief The log factory allows installation of a logger function in worker threads.
+   * @return An interface to a logging factory
+   */
+  const LogFactoryInterface& GetLogFactory();
+
+  /**
+   * @brief Register a processor implementing the Integration::Processor interface with dali-core.
+   * @param[in] processor the Processor to register
+   * @note using this api does not maintain the processor's lifecycle, must be done elsewhere.
+   */
+  void RegisterProcessor( Integration::Processor& processor );
+
+  /**
+   * @brief Unregister a previously registered processor from dali-core.
+   * @param[in] processor the Processor to unregister
+   */
+  void UnregisterProcessor( Integration::Processor& processor );
+
+  /**
+   * @brief Get the list of windows created.
+   * @return The list of windows
+   */
+  Dali::WindowContainer GetWindows() const;
+
+  /**
+   * @brief Get the list of scene holders.
+   * @return The list of scene holers
+   */
+  SceneHolderList GetSceneHolders() const;
+
+  /**
+   * @brief Called when the window becomes fully or partially visible.
+   */
+  void OnWindowShown();
+
+  /**
+   * @brief Called when the window is fully hidden.
+   */
+  void OnWindowHidden();
+
+public:  // Signals
+
+  /**
+   * @brief The user should connect to this signal if they need to perform any
+   * special activities when the surface Dali is being rendered on is resized.
+   *
+   * @return The signal to connect to
+   */
+  AdaptorSignalType& ResizedSignal();
+
+  /**
+   * @brief This signal is emitted when the language is changed on the device.
+   *
+   * @return The signal to connect to
+   */
+  AdaptorSignalType& LanguageChangedSignal();
+
+  /**
+   * @brief This signal is emitted when a new window (scene holder) is created
+   *
+   * @return The signal to connect to
+   */
+  WindowCreatedSignalType& WindowCreatedSignal();
+
+private:
+
+  // Undefined
+  Adaptor(const Adaptor&);
+  Adaptor& operator=(Adaptor&);
+
+private:
+
+  /**
+   * @brief Create an uninitialized Adaptor.
+   */
+  Adaptor();
+
+  Internal::Adaptor::Adaptor* mImpl; ///< Implementation object
+  friend class Internal::Adaptor::Adaptor;
+};
+
+} // namespace Dali
+
+#endif // DALI_INTEGRATION_ADAPTOR_H
diff --git a/dali/integration-api/adaptor-framework/android/android-framework.cpp b/dali/integration-api/adaptor-framework/android/android-framework.cpp
new file mode 100644 (file)
index 0000000..3138264
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/integration-api/adaptor-framework/android/android-framework.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/android/android-framework-impl.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+
+AndroidFramework& AndroidFramework::New()
+{
+  return Internal::Adaptor::AndroidFramework::New();
+}
+
+void AndroidFramework::Delete()
+{
+  Internal::Adaptor::AndroidFramework::Delete();
+}
+
+void AndroidFramework::SetNativeApplication( android_app* application )
+{
+  mImpl->SetNativeApplication( application );
+}
+
+android_app* AndroidFramework::GetNativeApplication() const
+{
+  return mImpl->GetNativeApplication();
+}
+
+void AndroidFramework::SetJVM( JavaVM* jvm )
+{
+  mImpl->SetJVM( jvm );
+}
+
+JavaVM* AndroidFramework::GetJVM() const
+{
+  return mImpl->GetJVM();
+}
+
+void AndroidFramework::SetApplicationAssets( AAssetManager* assets )
+{
+  mImpl->SetApplicationAssets( assets );
+}
+
+AAssetManager* AndroidFramework::GetApplicationAssets() const
+{
+  return mImpl->GetApplicationAssets();
+}
+
+void AndroidFramework::SetInternalDataPath( const std::string& path )
+{
+  mImpl->SetInternalDataPath( path );
+}
+
+std::string AndroidFramework::GetInternalDataPath() const
+{
+  return mImpl->GetInternalDataPath();
+}
+
+void AndroidFramework::SetApplicationConfiguration( AConfiguration* configuration )
+{
+  mImpl->SetApplicationConfiguration( configuration );
+}
+
+AConfiguration* AndroidFramework::GetApplicationConfiguration() const
+{
+  return mImpl->GetApplicationConfiguration();
+}
+
+void AndroidFramework::SetApplicationWindow( ANativeWindow* window )
+{
+  mImpl->SetApplicationWindow( window );
+}
+
+ANativeWindow* AndroidFramework::GetApplicationWindow() const
+{
+  return mImpl->GetApplicationWindow();
+}
+
+void AndroidFramework::OnTerminate()
+{
+  mImpl->OnTerminate();
+}
+
+void AndroidFramework::OnPause()
+{
+  mImpl->OnPause();
+}
+
+void AndroidFramework::OnResume()
+{
+  mImpl->OnResume();
+}
+
+void AndroidFramework::OnWindowCreated( ANativeWindow* window )
+{
+  mImpl->OnWindowCreated( window );
+}
+
+void AndroidFramework::OnWindowDestroyed( ANativeWindow* window )
+{
+  mImpl->OnWindowDestroyed( window );
+}
+
+AndroidFramework::~AndroidFramework()
+{
+  delete mImpl;
+  mImpl = nullptr;
+}
+
+AndroidFramework& AndroidFramework::Get()
+{
+  return Internal::Adaptor::AndroidFramework::Get();
+}
+
+AndroidFramework::AndroidFramework()
+: mImpl( nullptr )
+{
+}
+
+} // namespace Integration
+
+} // namespace Dali
diff --git a/dali/integration-api/adaptor-framework/android/android-framework.h b/dali/integration-api/adaptor-framework/android/android-framework.h
new file mode 100644 (file)
index 0000000..e7e755f
--- /dev/null
@@ -0,0 +1,208 @@
+#ifndef DALI_INTEGRATION_ANDROID_FRAMEWORK_H
+#define DALI_INTEGRATION_ANDROID_FRAMEWORK_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+#include <jni.h>
+#include <android/asset_manager.h>
+#include <android/asset_manager_jni.h>
+#include <android/configuration.h>
+#include <android/native_window.h>
+#include <android/native_window_jni.h>
+
+#ifndef _ANDROID_NATIVE_APP_GLUE_H
+extern "C"
+{
+struct android_app;
+}
+#endif
+
+#include <dali/public-api/common/dali-common.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace Internal DALI_INTERNAL
+{
+
+namespace Adaptor
+{
+class AndroidFramework;
+}
+
+}
+
+namespace Integration
+{
+
+/**
+ * AndroidFramework provides setter/getter for Android native interfaces for Android DALi Adaptor.
+ * It is also used to pass Android application events to Android DALi Adaptor.
+ */
+class DALI_ADAPTOR_API AndroidFramework
+{
+public:
+  /**
+   * @brief Create a new Android framework instance. Can be only one per application.
+   *
+   * @return a reference to the framework
+   */
+  static AndroidFramework& New();
+
+  /**
+   * @brief Delete an Android framework instance.
+   */
+  static void Delete();
+
+  /**
+   * @brief Sets the Android native application glue struct
+   * @param[in] application A pointer to the application glue struct
+   */
+  void SetNativeApplication( android_app* application );
+
+  /**
+   * @brief Gets the Android native application glue struct
+   * @return the native application glue struct
+   */
+  android_app* GetNativeApplication() const;
+
+  /**
+   * @brief Sets the Android JVM
+   * @param[in] jvm A pointer to Android JVM
+   */
+  void SetJVM( JavaVM* jvm );
+
+  /**
+   * @brief Sets the JVM
+   * @return A pointer to JVM
+   */
+  JavaVM* GetJVM() const;
+
+  /**
+   *  Sets the Android application assets manager.
+   *  @param[in] assets A pointer to assets manager
+   */
+  void SetApplicationAssets( AAssetManager* assets );
+
+  /**
+   * @brief Gets the Android application assets manager.
+   * @return The application assets manager
+   */
+  AAssetManager* GetApplicationAssets() const;
+
+  /**
+   *  Sets the Android application internal data path.
+   *  @param[in] path A path to the application data path
+   */
+  void SetInternalDataPath( const std::string& path );
+
+  /**
+   *  Gets the Android application internal data path.
+   *  @return The application data path
+   */
+  std::string GetInternalDataPath() const;
+
+  /**
+   * @brief Sets the Android application configuration
+   * @param[in] configuration A pointer to Android application configuration
+   */
+  void SetApplicationConfiguration( AConfiguration* configuration );
+
+  /**
+   * @brief Gets the Android application configuration
+   * @return A Android application configuration
+   */
+  AConfiguration* GetApplicationConfiguration() const;
+
+  /**
+   * @brief Sets the Android application native window
+   * @return A native window
+   */
+  void SetApplicationWindow( ANativeWindow* window );
+
+  /**
+   * @brief Gets the Android application native window
+   * @param[in] window A native window
+   */
+  ANativeWindow* GetApplicationWindow() const;
+
+  /**
+   * Invoked when the Android application is to be terminated.
+   */
+  void OnTerminate();
+
+  /**
+   * Invoked when the Android application is to be paused.
+   */
+  void OnPause();
+
+  /**
+   * Invoked when the Android application is to be resumed.
+   */
+  void OnResume();
+
+  /**
+   * Invoked when the Android application native window is created.
+   */
+  void OnWindowCreated( ANativeWindow* window );
+
+  /**
+   * Invoked when the Android application native window is deleted.
+   */
+  void OnWindowDestroyed( ANativeWindow* window );
+
+  /**
+   * @brief Returns a reference to the instance of the Android framework used by the current thread.
+   *
+   * @return A reference to the framework.
+   * @note This is only valid in the main thread.
+   */
+  static AndroidFramework& Get();
+
+  /**
+   * @brief Virtual Destructor.
+   */
+  virtual ~AndroidFramework();
+
+  // Not copyable or movable
+  AndroidFramework( const AndroidFramework& ) = delete; ///< Deleted copy constructor
+  AndroidFramework( AndroidFramework&& ) = delete; ///< Deleted move constructor
+  AndroidFramework& operator=( const AndroidFramework& ) = delete; ///< Deleted copy assignment operator
+  AndroidFramework& operator=( AndroidFramework&& ) = delete; ///< Deleted move assignment operator
+
+private:
+
+  /**
+   * @brief Create an uninitialized AndroidFramework.
+   */
+  AndroidFramework();
+
+  Internal::Adaptor::AndroidFramework* mImpl; ///< Implementation object
+  friend class Internal::Adaptor::AndroidFramework;
+};
+
+} // namespace Integration
+
+} // namespace Dali
+
+#endif // DALI_INTEGRATION_ANDROID_FRAMEWORK_H
+
diff --git a/dali/integration-api/adaptor-framework/android/application-launcher.h b/dali/integration-api/adaptor-framework/android/application-launcher.h
new file mode 100644 (file)
index 0000000..4a6319f
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef DALI_INTEGRATION_APPLICATION_LAUNCHER_H
+#define DALI_INTEGRATION_APPLICATION_LAUNCHER_H
+
+/*
+ * Copyright (c) 2019 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 <jni.h>
+#include <dali/devel-api/adaptor-framework/application-devel.h>
+
+using namespace Dali;
+
+// Wraps DALi application instance for DaliView JNI interface
+struct ApplicationLauncher
+{
+  static RefObject* applicationObject;
+  ApplicationLauncher( Application& application )
+  {
+    applicationObject = application.GetObjectPtr();
+  }
+};
+
+// Static DALi application instance for DaliView
+RefObject* ApplicationLauncher::applicationObject;
+
+namespace
+{
+
+// JNI native "nativeOnCreate" callback when DaliView is created
+jlong OnCreate(JNIEnv *jenv, jobject obj)
+{
+  // Extra reference to prevent finalize clearing the app
+  ApplicationLauncher::applicationObject->Reference();
+
+  // not blocking, does nothing except for the setting of the running flag
+  DevelApplication::DownCast( ApplicationLauncher::applicationObject ).MainLoop();
+
+  return reinterpret_cast<jlong>( ApplicationLauncher::applicationObject );
+};
+
+}
+
+// JNI daliview library on load entry function. Registers nativeOnCreate callback for DaliView Java class.
+JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved)
+{
+  JNIEnv* env = nullptr;
+  if( vm->GetEnv( reinterpret_cast<void **>( &env ), JNI_VERSION_1_6) != JNI_OK )
+  {
+    return JNI_ERR;
+  }
+
+  // Find DaliView Java class. JNI_OnLoad is called from the correct class loader context for this to work.
+  jclass clazz = env->FindClass( "com/sec/daliview/DaliView" );
+  if( clazz == nullptr )
+  {
+    return JNI_ERR;
+  }
+
+  // Register your class' native methods.
+  static const JNINativeMethod methods[] =
+  {
+      { "nativeOnCreate", "()J", (void *)&OnCreate },
+  };
+
+  int rc = env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(JNINativeMethod));
+  if (rc != JNI_OK)
+    return rc;
+
+  return JNI_VERSION_1_6;
+};
+
+// This macro facilitates creation of DALi application and launch when DaliView is created.
+// The DALi application controller is passed to the application created by DaliView JNI library.
+#define RUN(Controller) Application application = Application::New(); \
+                        Controller controller( application ); \
+                        ApplicationLauncher launcher( application ); \
+
+#endif // DALI_INTEGRATION_APPLICATION_LAUNCHER_H
+
diff --git a/dali/integration-api/adaptor-framework/android/file.list b/dali/integration-api/adaptor-framework/android/file.list
new file mode 100644 (file)
index 0000000..68270fa
--- /dev/null
@@ -0,0 +1,11 @@
+
+
+SET( adaptor_integration_api_android_src_files
+  ${adaptor_integration_api_dir}/adaptor-framework/android/android-framework.cpp
+)
+
+SET( adaptor_integration_api_android_header_files
+  ${adaptor_integration_api_dir}/adaptor-framework/android/android-framework.h
+  ${adaptor_integration_api_dir}/adaptor-framework/android/application-launcher.h
+)
+
diff --git a/dali/integration-api/adaptor-framework/egl-interface.h b/dali/integration-api/adaptor-framework/egl-interface.h
new file mode 100644 (file)
index 0000000..a203fc6
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef DALI_INTEGRATION_EGL_INTERFACE_H
+#define DALI_INTEGRATION_EGL_INTERFACE_H
+
+/*
+ * Copyright (c) 2019 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 <dali/internal/graphics/common/egl-include.h>
+
+namespace Dali
+{
+
+enum ColorDepth
+{
+  COLOR_DEPTH_24 = 24,
+  COLOR_DEPTH_32 = 32
+};
+
+/**
+ * EglInterface provides an interface for managing EGL contexts
+ */
+class EglInterface
+{
+public:
+  /**
+    * Create the OpenGL context.
+    * @return true if successful
+    */
+  virtual bool CreateContext() = 0;
+
+  /**
+   * Make the OpenGL context current
+   */
+  virtual void MakeContextCurrent( EGLSurface eglSurface, EGLContext eglContext ) = 0;
+
+  /**
+   * Terminate GL
+   */
+  virtual void TerminateGles() = 0;
+
+  /**
+   * Performs an OpenGL swap buffers command
+   */
+  virtual void SwapBuffers( EGLSurface& eglSurface ) = 0;
+
+  /**
+   * Performs an OpenGL copy buffers command
+   */
+  virtual void CopyBuffers( EGLSurface& eglSurface ) = 0;
+
+  /**
+   * Performs an EGL wait GL command
+   */
+  virtual void WaitGL() = 0;
+
+protected:
+  /**
+   * Virtual protected destructor, no deletion through this interface
+   */
+  virtual ~EglInterface() {}
+};
+
+} // namespace Dali
+
+#endif // DALI_INTEGRATION_EGL_INTERFACE_H
diff --git a/dali/integration-api/adaptor-framework/log-factory-interface.h b/dali/integration-api/adaptor-framework/log-factory-interface.h
new file mode 100644 (file)
index 0000000..738ae05
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef DALI_ADAPTOR_LOG_FACTORY_INTERFACE_H
+#define DALI_ADAPTOR_LOG_FACTORY_INTERFACE_H
+
+/*
+ * Copyright (c) 2019 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.
+ */
+
+namespace Dali
+{
+
+class LogFactoryInterface
+{
+public:
+  /**
+   * @brief Install a log function for this thread.
+   *
+   * Only need to use once per thread, before any processing occurs.
+   */
+  virtual void InstallLogFunction() const = 0;
+};
+
+} // namespace Dali
+
+
+#endif //DALI_ADAPTOR_LOG_FACTORY_INTERFACE_H
diff --git a/dali/integration-api/adaptor-framework/native-render-surface-factory.h b/dali/integration-api/adaptor-framework/native-render-surface-factory.h
new file mode 100755 (executable)
index 0000000..17990e4
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef DALI_INTEGRATION_NATIVE_RENDER_SURFACE_FACTORY_H
+#define DALI_INTEGRATION_NATIVE_RENDER_SURFACE_FACTORY_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+class NativeRenderSurface;
+
+/**
+ * Factory function for native surface
+ * A native surface is created.
+ *
+ * @param [in] positionSize the position and size of the surface to create
+ * @param [in] isTransparent Whether the surface has an alpha channel
+ */
+NativeRenderSurface* CreateNativeSurface( PositionSize positionSize,
+                                          bool isTransparent );
+
+} // namespace Dali
+
+#endif // DALI_INTEGRATION_NATIVE_RENDER_SURFACE_FACTORY_H
diff --git a/dali/integration-api/adaptor-framework/native-render-surface.h b/dali/integration-api/adaptor-framework/native-render-surface.h
new file mode 100644 (file)
index 0000000..4d4ef37
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef DALI_NATIVE_RENDER_SURFACE_H
+#define DALI_NATIVE_RENDER_SURFACE_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/dali-adaptor-common.h>
+#include <dali/integration-api/adaptor-framework/render-surface-interface.h>
+
+namespace Dali
+{
+
+class TriggerEventInterface;
+
+/**
+ * Native interface of render surface.
+ */
+class DALI_ADAPTOR_API NativeRenderSurface : public Dali::RenderSurfaceInterface
+{
+public:
+
+  /**
+   * @brief Default constructor
+   */
+  NativeRenderSurface() = default;
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~NativeRenderSurface() = default;
+
+public: // API
+
+  /**
+   * @brief Get the render surface the adaptor is using to render to.
+   * @return reference to current render surface
+   */
+  virtual Any GetDrawable() = 0;
+
+  /**
+   * @brief Sets the render notification trigger to call when render thread is completed a frame
+   * @param renderNotification to use
+   */
+  virtual void SetRenderNotification( TriggerEventInterface* renderNotification ) = 0;
+
+  /**
+   * @brief Waits until surface is replaced
+   * After tbm surface is acquired in PostRender, this function is finished.
+   */
+  virtual void WaitUntilSurfaceReplaced() = 0;
+
+private: // from NativeRenderSurface
+
+  /**
+   * @brief Create a renderable
+   */
+  virtual void CreateNativeRenderable() = 0;
+
+  /**
+   * @brief Release a drawable
+   */
+  virtual void ReleaseDrawable() = 0;
+
+protected:
+
+  // Undefined
+  NativeRenderSurface(const NativeRenderSurface&) = delete;
+
+  // Undefined
+  NativeRenderSurface& operator=(const NativeRenderSurface& rhs) = delete;
+
+};
+
+} // namespace Dali
+
+#endif // DALI_NATIVE_RENDER_SURFACE_H
diff --git a/dali/integration-api/adaptor-framework/render-surface-interface.h b/dali/integration-api/adaptor-framework/render-surface-interface.h
new file mode 100644 (file)
index 0000000..25ad128
--- /dev/null
@@ -0,0 +1,234 @@
+#ifndef DALI_RENDER_SURFACE_INTERFACE_H
+#define DALI_RENDER_SURFACE_INTERFACE_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/core-enumerations.h>
+#include <dali/public-api/math/vector4.h>
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/object/any.h>
+
+namespace Dali
+{
+
+class DisplayConnection;
+class ThreadSynchronizationInterface;
+
+namespace Internal
+{
+namespace Adaptor
+{
+class AdaptorInternalServices;
+class GraphicsInterface;
+}
+}
+
+/**
+ * @brief The position and size of the render surface.
+ */
+typedef Dali::Rect<int> PositionSize;
+
+/**
+ * @brief Interface for a render surface onto which Dali draws.
+ *
+ * Dali::Adaptor requires a render surface to draw on to. This is
+ * usually a window in the native windowing system, or some other
+ * mapped pixel buffer.
+ *
+ * Dali::Application will automatically create a render surface using a window.
+ *
+ * The implementation of the factory method below should choose an appropriate
+ * implementation of RenderSurface for the given platform
+ */
+
+class RenderSurfaceInterface
+{
+public:
+
+  enum Type
+  {
+    WINDOW_RENDER_SURFACE,
+    PIXMAP_RENDER_SURFACE,
+    NATIVE_RENDER_SURFACE
+  };
+
+  /**
+   * @brief Constructor
+   * Inlined as this is a pure abstract interface
+   */
+  RenderSurfaceInterface()
+  : mAdaptor( nullptr ),
+    mGraphics( nullptr ),
+    mDisplayConnection( nullptr ),
+    mDepthBufferRequired( Integration::DepthBufferAvailable::FALSE ),
+    mStencilBufferRequired( Integration::StencilBufferAvailable::FALSE )
+  {}
+
+  /**
+   * @brief Virtual Destructor.
+   * Inlined as this is a pure abstract interface
+   */
+  virtual ~RenderSurfaceInterface() {}
+
+  /**
+   * @brief Return the size and position of the surface.
+   * @return The position and size
+   */
+  virtual Dali::PositionSize GetPositionSize() const = 0;
+
+  /**
+   * @brief Get DPI
+   * @param[out] dpiHorizontal set to the horizontal dpi
+   * @param[out] dpiVertical set to the vertical dpi
+   */
+  virtual void GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical ) = 0;
+
+  /**
+   * @brief InitializeGraphics the platform specific graphics surface interfaces
+   */
+  virtual void InitializeGraphics() = 0;
+
+  /**
+   * @brief Creates the Surface
+   */
+  virtual void CreateSurface() = 0;
+
+  /**
+   * @brief Destroys the Surface
+   */
+  virtual void DestroySurface() = 0;
+
+  /**
+   * @brief Replace the Surface
+   * @return true if context was lost
+   */
+  virtual bool ReplaceGraphicsSurface() = 0;
+
+  /**
+   * @brief Resizes the underlying surface.
+   * @param[in] The dimensions of the new position
+   */
+  virtual void MoveResize( Dali::PositionSize positionSize ) = 0;
+
+  /**
+   * @brief Called when Render thread has started
+   */
+  virtual void StartRender() = 0;
+
+  /**
+   * @brief Invoked by render thread before Core::Render
+   * If the operation fails, then Core::Render should not be called until there is
+   * a surface to render onto.
+   * @param[in] resizingSurface True if the surface is being resized
+   * @return True if the operation is successful, False if the operation failed
+   */
+  virtual bool PreRender( bool resizingSurface ) = 0;
+
+  /**
+   * @brief Invoked by render thread after Core::Render
+   * @param[in] renderToFbo True if render to FBO.
+   * @param[in] replacingSurface True if the surface is being replaced.
+   * @param[in] resizingSurface True if the surface is being resized.
+   */
+  virtual void PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface ) = 0;
+  /**
+   * @brief Invoked by render thread when the thread should be stop
+   */
+  virtual void StopRender() = 0;
+
+  /**
+   * @brief Invoked by Event Thread when the compositor lock should be released and rendering should resume.
+   */
+  virtual void ReleaseLock() = 0;
+
+  /**
+   * @brief Sets the ThreadSynchronizationInterface
+   *
+   * @param threadSynchronization The thread-synchronization implementation.
+   */
+  virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization ) = 0;
+
+  /**
+   * @brief Gets the surface type
+   */
+  virtual Dali::RenderSurfaceInterface::Type GetSurfaceType() = 0;
+
+  /**
+   * @brief Makes the graphics context current
+   */
+  virtual void MakeContextCurrent() = 0;
+
+  /**
+   * @brief Get whether the depth buffer is required
+   * @return TRUE if the depth buffer is required
+   */
+  virtual Integration::DepthBufferAvailable GetDepthBufferRequired() = 0;
+
+  /**
+   * @brief Get whether the stencil buffer is required
+   * @return TRUE if the stencil buffer is required
+   */
+  virtual Integration::StencilBufferAvailable GetStencilBufferRequired() = 0;
+
+public:
+
+  void SetAdaptor( Dali::Internal::Adaptor::AdaptorInternalServices& adaptor )
+  {
+    mAdaptor = &adaptor;
+  }
+
+  void SetGraphicsInterface( Dali::Internal::Adaptor::GraphicsInterface& graphics )
+  {
+    mGraphics = &graphics;
+  }
+
+  void SetDisplayConnection( Dali::DisplayConnection& displayConnection )
+  {
+    mDisplayConnection = &displayConnection;
+  }
+
+private:
+
+  /**
+   * @brief Undefined copy constructor. RenderSurface cannot be copied
+   */
+  RenderSurfaceInterface( const RenderSurfaceInterface& rhs );
+
+  /**
+   * @brief Undefined assignment operator. RenderSurface cannot be copied
+   */
+  RenderSurfaceInterface& operator=( const RenderSurfaceInterface& rhs );
+
+protected:
+
+  Dali::Internal::Adaptor::AdaptorInternalServices* mAdaptor;
+  Dali::Internal::Adaptor::GraphicsInterface* mGraphics;
+  Dali::DisplayConnection* mDisplayConnection;
+
+private:
+
+  Integration::DepthBufferAvailable mDepthBufferRequired;       ///< Whether the depth buffer is required
+  Integration::StencilBufferAvailable mStencilBufferRequired;   ///< Whether the stencil buffer is required
+
+  Vector4 mBackgroundColor;                                     ///< The background color of the surface
+};
+
+} // namespace Dali
+
+#endif // DALI_RENDER_SURFACE_INTERFACE_H
diff --git a/dali/integration-api/adaptor-framework/scene-holder-impl.cpp b/dali/integration-api/adaptor-framework/scene-holder-impl.cpp
new file mode 100644 (file)
index 0000000..2440b35
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/integration-api/adaptor-framework/scene-holder-impl.h>
+
+// EXTERNAL INCLUDES
+#include <sys/time.h>
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/actors/layer.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/events/key-event-integ.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/hover-event-integ.h>
+#include <dali/integration-api/events/wheel-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/adaptor/common/lifecycle-observer.h>
+#include <dali/internal/input/common/key-impl.h>
+#include <dali/internal/input/common/physical-keyboard-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Integration::Log::Filter* gTouchEventLogFilter  = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_TOUCH");
+#endif
+
+// Copied from x server
+static uint32_t GetCurrentMilliSeconds(void)
+{
+  struct timeval tv;
+
+  struct timespec tp;
+  static clockid_t clockid;
+
+  if (!clockid)
+  {
+#ifdef CLOCK_MONOTONIC_COARSE
+    if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
+      (tp.tv_nsec / 1000) <= 1000 && clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
+    {
+      clockid = CLOCK_MONOTONIC_COARSE;
+    }
+    else
+#endif
+    if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
+    {
+      clockid = CLOCK_MONOTONIC;
+    }
+    else
+    {
+      clockid = ~0L;
+    }
+  }
+  if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
+  {
+    return static_cast<uint32_t>( (tp.tv_sec * 1000 ) + (tp.tv_nsec / 1000000L) );
+  }
+
+  gettimeofday(&tv, NULL);
+  return static_cast<uint32_t>( (tv.tv_sec * 1000 ) + (tv.tv_usec / 1000) );
+}
+
+} // unnamed namespace
+
+uint32_t SceneHolder::mSceneHolderCounter = 0;
+
+class SceneHolder::SceneHolderLifeCycleObserver : public LifeCycleObserver
+{
+public:
+
+  SceneHolderLifeCycleObserver(Adaptor*& adaptor)
+  : mAdaptor( adaptor )
+  {
+  };
+
+private: // Adaptor::LifeCycleObserver interface
+
+  void OnStart() override {};
+  void OnPause() override {};
+  void OnResume() override {};
+  void OnStop() override {};
+  void OnDestroy() override
+  {
+    mAdaptor = nullptr;
+  };
+
+private:
+  Adaptor*& mAdaptor;
+};
+
+
+SceneHolder::SceneHolder()
+: mLifeCycleObserver( new SceneHolderLifeCycleObserver( mAdaptor ) ),
+  mId( mSceneHolderCounter++ ),
+  mSurface( nullptr ),
+  mAdaptor( nullptr ),
+  mIsBeingDeleted( false ),
+  mAdaptorStarted( false ),
+  mVisible( true )
+{
+}
+
+SceneHolder::~SceneHolder()
+{
+  if ( mAdaptor )
+  {
+    mAdaptor->RemoveObserver( *mLifeCycleObserver.get() );
+    mAdaptor->RemoveWindow( this );
+
+    mAdaptor = nullptr;
+  }
+
+  if ( mScene )
+  {
+    mScene.Discard();
+  }
+}
+
+void SceneHolder::Add( Dali::Actor actor )
+{
+  if ( mScene )
+  {
+    mScene.Add( actor );
+  }
+}
+
+void SceneHolder::Remove( Dali::Actor actor )
+{
+  if ( mScene )
+  {
+    mScene.Remove( actor );
+  }
+}
+
+Dali::Layer SceneHolder::GetRootLayer() const
+{
+  return mScene ? mScene.GetRootLayer() : Dali::Layer();
+}
+
+uint32_t SceneHolder::GetId() const
+{
+  return mId;
+}
+
+std::string SceneHolder::GetName() const
+{
+  return mName;
+}
+
+bool SceneHolder::IsVisible() const
+{
+  return mVisible;
+}
+
+Dali::Integration::Scene SceneHolder::GetScene()
+{
+  return mScene;
+}
+
+void SceneHolder::SetSurface(Dali::RenderSurfaceInterface* surface)
+{
+  mSurface.reset( surface );
+
+  mScene.SurfaceReplaced();
+
+  SurfaceResized();
+
+  unsigned int dpiHorizontal, dpiVertical;
+  dpiHorizontal = dpiVertical = 0;
+
+  mSurface->GetDpi( dpiHorizontal, dpiVertical );
+  mScene.SetDpi( Vector2( static_cast<float>( dpiHorizontal ), static_cast<float>( dpiVertical ) ) );
+
+  mSurface->SetAdaptor( *mAdaptor );
+
+  OnSurfaceSet( surface );
+}
+
+void SceneHolder::SurfaceResized()
+{
+  PositionSize surfacePositionSize = mSurface->GetPositionSize();
+  mScene.SurfaceResized( static_cast<float>( surfacePositionSize.width ), static_cast<float>( surfacePositionSize.height ) );
+}
+
+Dali::RenderSurfaceInterface* SceneHolder::GetSurface() const
+{
+  return mSurface.get();
+}
+
+void SceneHolder::SetBackgroundColor( const Vector4& color )
+{
+  if( mScene )
+  {
+    mScene.SetBackgroundColor( color );
+  }
+}
+
+Vector4 SceneHolder::GetBackgroundColor() const
+{
+  return mScene ? mScene.GetBackgroundColor() : Color::BLACK;
+}
+
+void SceneHolder::SetAdaptor(Dali::Adaptor& adaptor)
+{
+  // Avoid doing this more than once
+  if( mAdaptorStarted )
+  {
+    return;
+  }
+
+  mAdaptorStarted = true;
+
+  // Create the scene
+  PositionSize surfacePositionSize = mSurface->GetPositionSize();
+  mScene = Dali::Integration::Scene::New( Size(static_cast<float>( surfacePositionSize.width ), static_cast<float>( surfacePositionSize.height )) );
+
+  Internal::Adaptor::Adaptor& adaptorImpl = Internal::Adaptor::Adaptor::GetImplementation( adaptor );
+  mAdaptor = &adaptorImpl;
+
+  // Create an observer for the adaptor lifecycle
+  mAdaptor->AddObserver( *mLifeCycleObserver );
+
+  if ( mSurface )
+  {
+    unsigned int dpiHorizontal, dpiVertical;
+    dpiHorizontal = dpiVertical = 0;
+
+    mSurface->GetDpi( dpiHorizontal, dpiVertical );
+    mScene.SetDpi( Vector2( static_cast<float>( dpiHorizontal ), static_cast<float>( dpiVertical ) ) );
+
+    mSurface->SetAdaptor( *mAdaptor );
+  }
+
+  OnAdaptorSet( adaptor );
+}
+
+void SceneHolder::Pause()
+{
+  Reset();
+
+  OnPause();
+}
+
+void SceneHolder::Resume()
+{
+  Reset();
+
+  OnResume();
+}
+
+void SceneHolder::FeedTouchPoint( Dali::Integration::Point& point, int timeStamp )
+{
+  if( timeStamp < 1 )
+  {
+    timeStamp = GetCurrentMilliSeconds();
+  }
+
+  RecalculateTouchPosition( point );
+
+  Integration::TouchEvent touchEvent;
+  Integration::HoverEvent hoverEvent;
+  Integration::TouchEventCombiner::EventDispatchType type = mCombiner.GetNextTouchEvent(point, timeStamp, touchEvent, hoverEvent);
+  if( type != Integration::TouchEventCombiner::DispatchNone )
+  {
+    DALI_LOG_INFO( gTouchEventLogFilter, Debug::General, "%d: Device %d: Button state %d (%.2f, %.2f)\n", timeStamp, point.GetDeviceId(), point.GetState(), point.GetScreenPosition().x, point.GetScreenPosition().y );
+
+    // Signals can be emitted while processing core events, and the scene holder could be deleted in the signal callback.
+    // Keep the handle alive until the core events are processed.
+    Dali::BaseHandle sceneHolder( this );
+
+    // First the touch and/or hover event & related gesture events are queued
+    if( type == Integration::TouchEventCombiner::DispatchTouch || type == Integration::TouchEventCombiner::DispatchBoth )
+    {
+      mScene.QueueEvent( touchEvent );
+    }
+
+    if( type == Integration::TouchEventCombiner::DispatchHover || type == Integration::TouchEventCombiner::DispatchBoth )
+    {
+      mScene.QueueEvent( hoverEvent );
+    }
+
+    // Next the events are processed with a single call into Core
+    mAdaptor->ProcessCoreEvents();
+  }
+}
+
+void SceneHolder::FeedWheelEvent( Dali::Integration::WheelEvent& wheelEvent )
+{
+  // Signals can be emitted while processing core events, and the scene holder could be deleted in the signal callback.
+  // Keep the handle alive until the core events are processed.
+  Dali::BaseHandle sceneHolder( this );
+
+  mScene.QueueEvent( wheelEvent );
+  mAdaptor->ProcessCoreEvents();
+}
+
+void SceneHolder::FeedKeyEvent( Dali::Integration::KeyEvent& keyEvent )
+{
+  Dali::PhysicalKeyboard physicalKeyboard = PhysicalKeyboard::Get();
+  if( physicalKeyboard )
+  {
+    if( ! KeyLookup::IsDeviceButton( keyEvent.keyName.c_str() ) )
+    {
+      GetImplementation( physicalKeyboard ).KeyReceived( keyEvent.time > 1 );
+    }
+  }
+
+  // Signals can be emitted while processing core events, and the scene holder could be deleted in the signal callback.
+  // Keep the handle alive until the core events are processed.
+  Dali::BaseHandle sceneHolder( this );
+
+  // Create send KeyEvent to Core.
+  mScene.QueueEvent( keyEvent );
+  mAdaptor->ProcessCoreEvents();
+}
+
+Dali::Integration::SceneHolder SceneHolder::Get( Dali::Actor actor )
+{
+  SceneHolder* sceneHolderImpl = nullptr;
+
+  if ( Internal::Adaptor::Adaptor::IsAvailable() )
+  {
+    Dali::Internal::Adaptor::Adaptor& adaptor = Internal::Adaptor::Adaptor::GetImplementation( Internal::Adaptor::Adaptor::Get() );
+    sceneHolderImpl = adaptor.GetWindow( actor );
+  }
+
+  return Dali::Integration::SceneHolder( sceneHolderImpl );
+}
+
+void SceneHolder::Reset()
+{
+  mCombiner.Reset();
+
+  // Any touch listeners should be told of the interruption.
+  Integration::TouchEvent event;
+  Integration::Point point;
+  point.SetState( PointState::INTERRUPTED );
+  event.AddPoint( point );
+
+  // First the touch event & related gesture events are queued
+  mScene.QueueEvent( event );
+
+  // Next the events are processed with a single call into Core
+  mAdaptor->ProcessCoreEvents();
+}
+
+
+}// Adaptor
+
+}// Internal
+
+} // Dali
diff --git a/dali/integration-api/adaptor-framework/scene-holder-impl.h b/dali/integration-api/adaptor-framework/scene-holder-impl.h
new file mode 100644 (file)
index 0000000..3a830f9
--- /dev/null
@@ -0,0 +1,311 @@
+#ifndef DALI_INTEGRATION_INTERNAL_SCENEHOLDER_H
+#define DALI_INTEGRATION_INTERNAL_SCENEHOLDER_H
+
+/*
+ * Copyright (c) 2019 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 <memory>
+#include <vector>
+#include <atomic>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/common/intrusive-ptr.h>
+#include <dali/integration-api/scene.h>
+#include <dali/integration-api/events/key-event-integ.h>
+#include <dali/integration-api/events/point.h>
+#include <dali/integration-api/events/touch-event-combiner.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/render-surface-interface.h>
+#include <dali/integration-api/adaptor-framework/scene-holder.h>
+
+namespace Dali
+{
+
+class Any;
+class Adaptor;
+class Actor;
+class Layer;
+struct TouchPoint;
+struct WheelEvent;
+struct KeyEvent;
+
+namespace Integration
+{
+
+class Scene;
+struct Point;
+struct KeyEvent;
+struct WheelEvent;
+
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class Adaptor;
+class SceneHolder;
+using SceneHolderPtr = IntrusivePtr< SceneHolder >;
+
+/**
+ * @brief SceneHolder creates a Scene for rendering.
+ */
+class DALI_ADAPTOR_API SceneHolder : public BaseObject
+{
+
+public:
+
+  /**
+   * @copydoc Dali::Integration::SceneHolder::Add
+   */
+  void Add( Dali::Actor actor );
+
+  /**
+   * @copydoc Dali::Integration::SceneHolder::Remove
+   */
+  void Remove( Dali::Actor actor );
+
+  /**
+   * @copydoc Dali::Integration::SceneHolder::GetRootLayer
+   */
+  Dali::Layer GetRootLayer() const;
+
+  /**
+   * @brief Gets the window name.
+   * @return The name of the window
+   */
+  std::string GetName() const;
+
+  /**
+   * @brief Retrieve the unique ID of the window.
+   * @return The ID
+   */
+  uint32_t GetId() const;
+
+  /**
+   * @brief Retrieve the Scene.
+   * @return The Scene
+   */
+  Dali::Integration::Scene GetScene();
+
+  /**
+   * @brief Set the render surface
+   * @param[in] surface The render surface
+   */
+  void SetSurface( Dali::RenderSurfaceInterface* surface );
+
+  /**
+   * @brief Called when the surface set is resized.
+   */
+  void SurfaceResized();
+
+  /**
+   * @brief Get the render surface
+   * @return The render surface
+   */
+  Dali::RenderSurfaceInterface* GetSurface() const;
+
+  /**
+   * @brief Set the adaptor to the scene holder
+   * @param[in] adaptor An initialized adaptor
+   */
+  void SetAdaptor( Dali::Adaptor& adaptor );
+
+  /**
+   * @copydoc Dali::Integration::SceneHolder::SetBackgroundColor
+   */
+  void SetBackgroundColor( const Dali::Vector4& color );
+
+  /**
+   * @copydoc Dali::Integration::SceneHolder::GetBackgroundColor
+   */
+  Vector4 GetBackgroundColor() const;
+
+  /**
+   * @brief Pause the rendering of the scene holder.
+   */
+  void Pause();
+
+  /**
+   * @brief Resume the rendering of the scene holder (from pause).
+   */
+  void Resume();
+
+  /**
+   * @brief Checks whether this scene holder is being deleted in the event thread.
+   *
+   * @return true if this scene holder is being deleted in the event thread, or false if not.
+   */
+  bool IsBeingDeleted() const { return mIsBeingDeleted; }
+
+  /**
+   * @copydoc Dali::Integration::SceneHolder::FeedTouchPoint
+   */
+  void FeedTouchPoint( Dali::Integration::Point& point, int timeStamp );
+
+  /**
+   * @copydoc Dali::Integration::SceneHolder::FeedWheelEvent
+   */
+  void FeedWheelEvent( Dali::Integration::WheelEvent& wheelEvent );
+
+  /**
+   * @copydoc Dali::Integration::SceneHolder::FeedKeyEvent
+   */
+  void FeedKeyEvent( Dali::Integration::KeyEvent& keyEvent );
+
+  /**
+   * @copydoc Dali::Integration::SceneHolder::Get()
+   */
+  static Dali::Integration::SceneHolder Get( Dali::Actor actor );
+
+  /**
+   * @copydoc Dali::Integration::SceneHolder::KeyEventSignal()
+   */
+  Dali::Integration::SceneHolder::KeyEventSignalType& KeyEventSignal() { return mScene.KeyEventSignal(); }
+
+  /**
+   * @copydoc Dali::Integration::SceneHolder::KeyEventGeneratedSignal()
+   */
+  Dali::Integration::SceneHolder::KeyEventGeneratedSignalType& KeyEventGeneratedSignal() { return mScene.KeyEventGeneratedSignal(); }
+
+  /**
+   * @copydoc Dali::Integration::SceneHolder::TouchSignal()
+   */
+  Dali::Integration::SceneHolder::TouchSignalType& TouchSignal() { return mScene.TouchSignal(); }
+
+  /**
+   * @copydoc Dali::Integration::SceneHolder::WheelEventSignal()
+   */
+  Dali::Integration::SceneHolder::WheelEventSignalType& WheelEventSignal() { return mScene.WheelEventSignal(); }
+
+public: // The following methods can be overridden if required
+
+  /**
+   * @brief Returns whether the Scene is visible or not.
+   * @return True if the Scene is visible, false otherwise.
+   */
+  virtual bool IsVisible() const;
+
+public: // The following methods must be overridden
+
+  /**
+   * @copydoc Dali::Integration::SceneHolder::GetNativeHandle
+   */
+  virtual Dali::Any GetNativeHandle() const = 0;
+
+protected:
+
+  // Constructor
+  SceneHolder();
+
+  // Undefined
+  SceneHolder(const SceneHolder&) = delete;
+
+  // Undefined
+  SceneHolder& operator=(const SceneHolder& rhs) = delete;
+
+  /**
+   * virtual destructor
+   */
+  virtual ~SceneHolder();
+
+private: // The following methods can be overridden if required
+
+  /**
+   * @brief Called by the base class to inform deriving classes that the adaptor has been set.
+   * @param[in] adaptor The adaptor
+   */
+  virtual void OnAdaptorSet( Dali::Adaptor& adaptor ) {};
+
+  /**
+   * @brief Called by the base class to inform deriving classes that a new surface has been set.
+   * @param[in] surface The new render surface
+   */
+  virtual void OnSurfaceSet( Dali::RenderSurfaceInterface* surface ) {};
+
+  /**
+   * @brief Called by the base class to inform deriving classes that we are being paused.
+   */
+  virtual void OnPause() {};
+
+  /**
+   * @brief Called by the base class to inform deriving classes that we are resuming from a paused state.
+   */
+  virtual void OnResume() {};
+
+  /**
+   * Recalculate the touch position if required
+   * @param[in,out] point The touch point
+   */
+  virtual void RecalculateTouchPosition( Integration::Point& point ) {};
+
+private:
+
+  /**
+   * Resets the event handling.
+   */
+  void Reset();
+
+private:
+
+  static uint32_t                                 mSceneHolderCounter; ///< A counter to track the SceneHolder creation
+
+  class SceneHolderLifeCycleObserver;
+  std::unique_ptr< SceneHolderLifeCycleObserver > mLifeCycleObserver;  ///< The adaptor life cycle observer
+
+protected:
+
+  uint32_t                                        mId;                 ///< A unique ID to identify the SceneHolder starting from 0
+  Dali::Integration::Scene                        mScene;              ///< The Scene
+  std::string                                     mName;               ///< The name of the SceneHolder
+
+  std::unique_ptr< Dali::RenderSurfaceInterface > mSurface;            ///< The window rendering surface
+  Adaptor*                                        mAdaptor;            ///< The adaptor
+
+  Dali::Integration::TouchEventCombiner           mCombiner;           ///< Combines multi-touch events.
+
+  std::atomic<bool>                               mIsBeingDeleted;     ///< This is set only from the event thread and read only from the render thread
+
+  bool                                            mAdaptorStarted:1;   ///< Whether the adaptor has started or not
+  bool                                            mVisible:1;          ///< Whether the scene is visible or not
+};
+
+} // Adaptor
+
+} // Internal
+
+// Get impl of handle
+inline Internal::Adaptor::SceneHolder& GetImplementation( Dali::Integration::SceneHolder& sceneHolder )
+{
+  DALI_ASSERT_ALWAYS( sceneHolder && "SceneHolder handle is empty" );
+  Dali::RefObject& object = sceneHolder.GetBaseObject();
+  return static_cast<Internal::Adaptor::SceneHolder&>( object );
+}
+
+inline const Internal::Adaptor::SceneHolder& GetImplementation( const Dali::Integration::SceneHolder& sceneHolder )
+{
+  DALI_ASSERT_ALWAYS( sceneHolder && "SceneHolder handle is empty" );
+  const Dali::RefObject& object = sceneHolder.GetBaseObject();
+  return static_cast<const Internal::Adaptor::SceneHolder&>( object );
+}
+
+} // Dali
+
+#endif // DALI_INTEGRATION_INTERNAL_SCENEHOLDER_H
diff --git a/dali/integration-api/adaptor-framework/scene-holder.cpp b/dali/integration-api/adaptor-framework/scene-holder.cpp
new file mode 100644 (file)
index 0000000..a51a38d
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/integration-api/adaptor-framework/scene-holder.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/events/wheel-event.h>
+#include <dali/integration-api/events/key-event-integ.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/wheel-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/actors/layer.h>
+#include <dali/integration-api/adaptor-framework/scene-holder-impl.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+
+SceneHolder::SceneHolder()
+{
+}
+
+SceneHolder::~SceneHolder()
+{
+}
+
+SceneHolder::SceneHolder( const SceneHolder& handle )
+:BaseHandle(handle)
+{
+}
+
+SceneHolder::SceneHolder( Internal::Adaptor::SceneHolder* internal )
+: BaseHandle(internal)
+{
+}
+
+SceneHolder& SceneHolder::operator=( const SceneHolder& rhs )
+{
+  BaseHandle::operator=(rhs);
+  return *this;
+}
+
+void SceneHolder::Add( Actor actor )
+{
+  GetImplementation(*this).Add( actor );
+}
+
+void SceneHolder::Remove( Actor actor )
+{
+  GetImplementation(*this).Remove( actor );
+}
+
+Layer SceneHolder::GetRootLayer() const
+{
+  return GetImplementation(*this).GetRootLayer();
+}
+
+void SceneHolder::SetBackgroundColor( Vector4 color )
+{
+  GetImplementation(*this).SetBackgroundColor( color );
+}
+
+Vector4 SceneHolder::GetBackgroundColor() const
+{
+  return GetImplementation(*this).GetBackgroundColor();
+}
+
+Any SceneHolder::GetNativeHandle() const
+{
+  return GetImplementation(*this).GetNativeHandle();
+}
+
+void SceneHolder::FeedTouchPoint( Dali::TouchPoint& point, int timeStamp )
+{
+  Integration::Point convertedPoint( point );
+  GetImplementation(*this).FeedTouchPoint( convertedPoint, timeStamp );
+}
+
+void SceneHolder::FeedWheelEvent( Dali::WheelEvent& wheelEvent )
+{
+  Integration::WheelEvent event( static_cast< Integration::WheelEvent::Type >(wheelEvent.type), wheelEvent.direction, wheelEvent.modifiers, wheelEvent.point, wheelEvent.z, wheelEvent.timeStamp );
+  GetImplementation(*this).FeedWheelEvent( event );
+}
+
+void SceneHolder::FeedKeyEvent( Dali::KeyEvent& keyEvent )
+{
+  Integration::KeyEvent convertedEvent( keyEvent );
+  GetImplementation(*this).FeedKeyEvent( convertedEvent );
+}
+
+SceneHolder SceneHolder::Get( Actor actor )
+{
+  return Internal::Adaptor::SceneHolder::Get( actor );
+}
+
+SceneHolder::KeyEventSignalType& SceneHolder::KeyEventSignal()
+{
+  return GetImplementation(*this).KeyEventSignal();
+}
+
+SceneHolder::KeyEventGeneratedSignalType& SceneHolder::KeyEventGeneratedSignal()
+{
+  return GetImplementation(*this).KeyEventGeneratedSignal();
+}
+
+SceneHolder::TouchSignalType& SceneHolder::TouchSignal()
+{
+  return GetImplementation(*this).TouchSignal();
+}
+
+SceneHolder::WheelEventSignalType& SceneHolder::WheelEventSignal()
+{
+  return GetImplementation(*this).WheelEventSignal();
+}
+
+}// Integration
+
+} // Dali
diff --git a/dali/integration-api/adaptor-framework/scene-holder.h b/dali/integration-api/adaptor-framework/scene-holder.h
new file mode 100644 (file)
index 0000000..905ed6b
--- /dev/null
@@ -0,0 +1,235 @@
+#ifndef DALI_INTEGRATION_SCENEHOLDER_H
+#define DALI_INTEGRATION_SCENEHOLDER_H
+
+/*
+ * Copyright (c) 2019 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-adaptor-common.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/math/vector4.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+namespace Dali
+{
+
+class Actor;
+class Layer;
+class Any;
+class TouchData;
+struct TouchPoint;
+struct WheelEvent;
+struct KeyEvent;
+
+namespace Internal DALI_INTERNAL
+{
+
+namespace Adaptor
+{
+
+class SceneHolder;
+
+}
+
+}
+
+namespace Integration
+{
+
+/**
+ * @brief SceneHolder is responsible for creating a Scene for rendering.
+ */
+class DALI_ADAPTOR_API SceneHolder : public BaseHandle
+{
+public:
+
+  typedef Signal< void (const Dali::KeyEvent&) > KeyEventSignalType;          ///< Key event signal type
+
+  typedef Signal< bool (const Dali::KeyEvent&) > KeyEventGeneratedSignalType; ///< Key event generated signal type
+
+  typedef Signal< void (const Dali::TouchData&) > TouchSignalType;            ///< Touch signal type
+
+  typedef Signal< void (const Dali::WheelEvent&) > WheelEventSignalType;      ///< Touched signal type
+
+  /**
+   * @brief Create an uninitialized SceneHolder handle.
+   */
+  SceneHolder();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~SceneHolder();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @param [in] handle A reference to the copied handle
+   */
+  SceneHolder( const SceneHolder& 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
+   */
+  SceneHolder& operator=( const SceneHolder& rhs );
+
+  /**
+   * @brief Adds a child Actor to the SceneHolder.
+   *
+   * The child will be referenced.
+   * @param[in] actor The child
+   * @pre The actor has been initialized.
+   * @pre The actor does not have a parent.
+   */
+  void Add( Actor actor );
+
+  /**
+   * @brief Removes a child Actor from the SceneHolder.
+   *
+   * The child will be unreferenced.
+   * @param[in] actor The child
+   * @pre The actor has been added to the SceneHolder.
+   */
+  void Remove( Actor actor );
+
+  /**
+   * @brief Returns the Scene's Root Layer.
+   *
+   * @return The root layer
+   */
+  Layer GetRootLayer() const;
+
+  /**
+   * @brief Sets the background color.
+   *
+   * @param[in] color The new background color
+   */
+  void SetBackgroundColor( Vector4 color );
+
+  /**
+   * @brief Gets the background color.
+   *
+   * @return The background color
+   */
+  Vector4 GetBackgroundColor() const;
+
+  /**
+   * @brief Gets the native handle.
+   *
+   * When users call this function, it wraps the actual type used by the underlying system.
+   *
+   * @return The native handle or an empty handle
+   */
+  Any GetNativeHandle() const;
+
+  /**
+   * @brief Feed (Send) touch event to core
+   * @param[in] point The touch point
+   * @param[in] timeStamp The time stamp
+   */
+  void FeedTouchPoint( Dali::TouchPoint& point, int timeStamp );
+
+  /**
+   * @brief Feed (Send) wheel event to core
+   * @param[in] wheelEvent The wheel event
+   */
+  void FeedWheelEvent( Dali::WheelEvent& wheelEvent );
+
+  /**
+   * @brief Feed (Send) key event to core
+   * @param[in] keyEvent The key event holding the key information.
+   */
+  void FeedKeyEvent( Dali::KeyEvent& keyEvent );
+
+  /**
+   * @brief Retrieve the SceneHolder that the given actor is added to.
+   *
+   * @param[in] actor The actor
+   * @return The SceneHolder the actor is added to or an empty handle if the actor is not added to any SceneHolder.
+   */
+  static SceneHolder Get( Actor actor );
+
+  /**
+   * @brief This signal is emitted when key event is received.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(const KeyEvent& event);
+   * @endcode
+   * @return The signal to connect to
+   */
+  KeyEventSignalType& KeyEventSignal();
+
+  /**
+   * @brief This signal is emitted when key event is received.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   bool YourCallbackName(const KeyEvent& event);
+   * @endcode
+   * @return The signal to connect to
+   */
+  KeyEventGeneratedSignalType& KeyEventGeneratedSignal();
+
+  /**
+   * @brief This signal is emitted when the screen is touched and when the touch ends
+   * (i.e. the down & up touch events only).
+   *
+   * If there are multiple touch points, then this will be emitted when the first touch occurs and
+   * then when the last finger is lifted.
+   * An interrupted event will also be emitted (if it occurs).
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( TouchData event );
+   * @endcode
+   * @return The touch signal to connect to
+   * @note Motion events are not emitted.
+   */
+  TouchSignalType& TouchSignal();
+
+  /**
+   * @brief This signal is emitted when wheel event is received.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(const WheelEvent& event);
+   * @endcode
+   * @return The signal to connect to
+   */
+  WheelEventSignalType& WheelEventSignal();
+
+public: // Not intended for application developers
+
+  /**
+   * @brief This constructor is used internally to create additional SceneHolder handles.
+   *
+   * @param[in] sceneHolder A pointer to a newly allocated Dali resource
+   */
+  explicit SceneHolder( Internal::Adaptor::SceneHolder* sceneHolder );
+
+};
+
+} // namespace Integration
+
+} // namespace Dali
+
+#endif // DALI_INTEGRATION_SCENEHOLDER_H
diff --git a/dali/integration-api/adaptor-framework/thread-synchronization-interface.h b/dali/integration-api/adaptor-framework/thread-synchronization-interface.h
new file mode 100644 (file)
index 0000000..c752369
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef DALI_INTEGRATION_THREAD_SYNCHRONIZATION_INTERFACE_H
+#define DALI_INTEGRATION_THREAD_SYNCHRONIZATION_INTERFACE_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+
+namespace Dali
+{
+
+/**
+ * @brief Interface for the ThreadSyncrhonization handler.
+ *
+ * This handler ensure the threads are synchronized properly.
+ */
+class ThreadSynchronizationInterface
+{
+public:
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Called by the Event Thread if post-rendering is required
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * @brief Surface informs that the post-render has been completed.
+   *
+   * @note Should only be called by the Event Thread if post-rendering is required.
+   */
+  virtual void PostRenderComplete() = 0;
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // Called by the Render Thread if post-rendering is required
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * @brief Called just before the post rendering is done by the surface.
+   *
+   * @note Should only be called by the Render Thread if post-rendering is required.
+   */
+  virtual void PostRenderStarted() = 0;
+
+  /**
+   * @brief Blocks the render thread until the post rendering has been completed by the surface.
+   *
+   * @note Should only be called by the Render Thread if post-rendering is required.
+   */
+  virtual void PostRenderWaitForCompletion() = 0;
+
+protected:
+
+  /**
+   * @brief Protected constructor, no creation through this interface
+   */
+  ThreadSynchronizationInterface( ) { }
+
+  /**
+   * Virtual protected destructor, no deletion through this interface
+   */
+  virtual ~ThreadSynchronizationInterface() { }
+
+private:
+
+  // Undefined copy constructor.
+  ThreadSynchronizationInterface( const ThreadSynchronizationInterface& );
+
+  // Undefined assignment operator.
+  ThreadSynchronizationInterface& operator=( const ThreadSynchronizationInterface& );
+};
+
+} // namespace Dali
+
+#endif // DALI_INTEGRATION_THREAD_SYNCHRONIZATION_INTERFACE_H
diff --git a/dali/integration-api/adaptor-framework/trigger-event-factory.h b/dali/integration-api/adaptor-framework/trigger-event-factory.h
new file mode 100644 (file)
index 0000000..0127de5
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef DALI_INTEGRATION_TRIGGER_EVENT_FACTORY_H
+#define DALI_INTEGRATION_TRIGGER_EVENT_FACTORY_H
+
+/*
+ * Copyright (c) 2019 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/signals/callback.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/integration-api/adaptor-framework/trigger-event-interface.h>
+
+namespace Dali
+{
+
+/**
+ * @brief Trigger interface factory class
+ *
+ */
+class DALI_ADAPTOR_API TriggerEventFactory
+{
+public:
+
+  /**
+   * @copydoc TriggerEventFactoryInterface::CreateTriggerEvent
+   */
+  static TriggerEventInterface* CreateTriggerEvent( CallbackBase* callback, TriggerEventInterface::Options options );
+
+  /**
+   * @copydoc TriggerEventFactoryInterface::DestroyTriggerEvent
+   */
+  static void DestroyTriggerEvent( TriggerEventInterface* triggerEventInterface );
+
+};
+
+} // namespace Dali
+
+#endif // DALI_INTEGRATION_TRIGGER_EVENT_FACTORY_H
diff --git a/dali/integration-api/adaptor-framework/trigger-event-interface.h b/dali/integration-api/adaptor-framework/trigger-event-interface.h
new file mode 100644 (file)
index 0000000..679f8e8
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef DALI_INTEGRATION_TRIGGER_EVENT_INTERFACE_H
+#define DALI_INTEGRATION_TRIGGER_EVENT_INTERFACE_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+
+namespace Dali
+{
+
+/**
+ * @brief Interface for a trigger event class.
+ *
+ * The trigger event is a way of running a function call back on the main event thread of Dali.
+ * To create a trigger event use the factory interface.
+ */
+class TriggerEventInterface
+{
+
+public:
+
+  /**
+   * @brief trigger event options
+   */
+  enum Options
+  {
+    KEEP_ALIVE_AFTER_TRIGGER,
+    DELETE_AFTER_TRIGGER,  // automatically delete the trigger event object, after Trigger() is called.
+  };
+
+  /**
+   * @brief Triggers the event.
+   * This method cannot ever block, it needs to return immediately.
+   * This can be called from one thread in order to wake up another thread.
+   */
+  virtual void Trigger() = 0;
+
+protected:
+
+  /**
+   * @brief Constructor
+   */
+  TriggerEventInterface( )
+  {
+  }
+
+public:
+  /**
+   * @brief Virtual destructor
+   */
+  virtual ~TriggerEventInterface()
+  {
+  }
+
+private:
+
+  // Undefined copy constructor.
+  TriggerEventInterface( const TriggerEventInterface& );
+
+  // Undefined assignment operator.
+  TriggerEventInterface& operator=( const TriggerEventInterface& );
+
+
+};
+
+} // namespace Dali
+
+#endif // DALI_INTEGRATION_TRIGGER_EVENT_INTERFACE_H
diff --git a/dali/integration-api/file.list b/dali/integration-api/file.list
new file mode 100644 (file)
index 0000000..0a5b4df
--- /dev/null
@@ -0,0 +1,22 @@
+
+
+SET( adaptor_integration_api_src_files
+  ${adaptor_integration_api_dir}/adaptor-framework/scene-holder.cpp
+  ${adaptor_integration_api_dir}/adaptor-framework/scene-holder-impl.cpp
+)
+
+
+SET( adaptor_integration_api_header_files
+  ${adaptor_integration_api_dir}/adaptor-framework/adaptor.h
+  ${adaptor_integration_api_dir}/adaptor-framework/egl-interface.h
+  ${adaptor_integration_api_dir}/adaptor-framework/log-factory-interface.h
+  ${adaptor_integration_api_dir}/adaptor-framework/native-render-surface.h
+  ${adaptor_integration_api_dir}/adaptor-framework/native-render-surface-factory.h
+  ${adaptor_integration_api_dir}/adaptor-framework/render-surface-interface.h
+  ${adaptor_integration_api_dir}/adaptor-framework/scene-holder.h
+  ${adaptor_integration_api_dir}/adaptor-framework/scene-holder-impl.h
+  ${adaptor_integration_api_dir}/adaptor-framework/thread-synchronization-interface.h
+  ${adaptor_integration_api_dir}/adaptor-framework/trigger-event-interface.h
+  ${adaptor_integration_api_dir}/adaptor-framework/trigger-event-factory.h
+)
+
diff --git a/dali/internal/accessibility/common/accessibility-adaptor-impl.cpp b/dali/internal/accessibility/common/accessibility-adaptor-impl.cpp
new file mode 100644 (file)
index 0000000..d3eb43b
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/common/accessibility-adaptor-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/hover-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/system/common/system-settings.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // unnamed namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gAccessibilityAdaptorLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ACCESSIBILITY_ADAPTOR");
+#endif
+
+} // unnamed namespace
+
+AccessibilityAdaptor::AccessibilityAdaptor()
+: mReadPosition(),
+  mActionHandler( NULL ),
+  mIsEnabled( false )
+{
+  mAccessibilityGestureDetector = new AccessibilityGestureDetector();
+}
+
+void AccessibilityAdaptor::EnableAccessibility()
+{
+  if(mIsEnabled == false)
+  {
+    mIsEnabled = true;
+
+    if( mActionHandler )
+    {
+      mActionHandler->ChangeAccessibilityStatus();
+    }
+  }
+}
+
+void AccessibilityAdaptor::DisableAccessibility()
+{
+  if(mIsEnabled == true)
+  {
+    mIsEnabled = false;
+
+    if( mActionHandler )
+    {
+      mActionHandler->ChangeAccessibilityStatus();
+    }
+
+    // Destroy the TtsPlayer if exists.
+    if ( Adaptor::IsAvailable() )
+    {
+      Dali::Adaptor& adaptor = Dali::Adaptor::Get();
+      Adaptor& adaptorImpl = Adaptor::GetImplementation( adaptor );
+      adaptorImpl.DestroyTtsPlayer( Dali::TtsPlayer::SCREEN_READER );
+    }
+  }
+}
+
+bool AccessibilityAdaptor::IsEnabled() const
+{
+  return mIsEnabled;
+}
+
+Vector2 AccessibilityAdaptor::GetReadPosition() const
+{
+  return mReadPosition;
+}
+
+void AccessibilityAdaptor::SetActionHandler(AccessibilityActionHandler& handler)
+{
+  mActionHandler = &handler;
+}
+
+void AccessibilityAdaptor::SetGestureHandler(AccessibilityGestureHandler& handler)
+{
+  if( mAccessibilityGestureDetector )
+  {
+    mAccessibilityGestureDetector->SetGestureHandler(handler);
+  }
+}
+
+bool AccessibilityAdaptor::HandleActionNextEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionNext(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPreviousEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPrevious(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionActivateEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionActivate();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain)
+{
+  bool ret = false;
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %d , %d\n", __FUNCTION__, __LINE__, x, y);
+
+  mReadPosition.x = static_cast< float > (x);
+  mReadPosition.y = static_cast< float > (y);
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionRead( allowReadAgain );
+    DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+  }
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadNextEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadNext(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadPreviousEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadPrevious(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionUpEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionUp();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionDownEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionDown();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionClearFocusEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->ClearAccessibilityFocus();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionScrollEvent(const TouchPoint& point, uint32_t timeStamp)
+{
+  bool ret = false;
+
+  // We always need to emit a scroll signal, whether it's only a hover or not,
+  // so always send the action to the action handler.
+  if( mActionHandler )
+  {
+    Dali::TouchEvent event(timeStamp);
+    event.points.push_back(point);
+    ret = mActionHandler->AccessibilityActionScroll( event );
+  }
+
+  Integration::TouchEvent touchEvent;
+  Integration::HoverEvent hoverEvent;
+  Integration::TouchEventCombiner::EventDispatchType type = mCombiner.GetNextTouchEvent( Integration::Point( point ), timeStamp, touchEvent, hoverEvent );
+  if( type == Integration::TouchEventCombiner::DispatchTouch || type == Integration::TouchEventCombiner::DispatchBoth ) // hover event is ignored
+  {
+    // Process the touch event in accessibility gesture detector
+    if( mAccessibilityGestureDetector )
+    {
+      mAccessibilityGestureDetector->SendEvent( touchEvent );
+      ret = true;
+    }
+  }
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionTouchEvent(const TouchPoint& point, uint32_t timeStamp)
+{
+  bool ret = false;
+
+  Dali::TouchEvent touchEvent(timeStamp);
+  touchEvent.points.push_back(point);
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionTouch(touchEvent);
+  }
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionBackEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionBack();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+void AccessibilityAdaptor::HandleActionEnableEvent()
+{
+  EnableAccessibility();
+}
+
+void AccessibilityAdaptor::HandleActionDisableEvent()
+{
+  DisableAccessibility();
+}
+
+bool AccessibilityAdaptor::HandleActionScrollUpEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionScrollUp();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+
+bool AccessibilityAdaptor::HandleActionScrollDownEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionScrollDown();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPageLeftEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPageLeft();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPageRightEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPageRight();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPageUpEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPageUp();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionPageDownEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPageDown();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionMoveToFirstEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionMoveToFirst();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionMoveToLastEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionMoveToLast();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadFromTopEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadFromTop();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadFromNextEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadFromNext();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionZoomEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionZoom();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionReadPauseResumeEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadPauseResume();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptor::HandleActionStartStopEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionStartStop();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+AccessibilityAdaptor::~AccessibilityAdaptor()
+{
+  // Do any platform specific clean-up in OnDestroy()
+  OnDestroy();
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/accessibility/common/accessibility-adaptor-impl.h b/dali/internal/accessibility/common/accessibility-adaptor-impl.h
new file mode 100644 (file)
index 0000000..d59f69f
--- /dev/null
@@ -0,0 +1,294 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_H
+#define DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_H
+
+/*
+ * Copyright (c) 2019 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/object/base-object.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/public-api/events/touch-point.h>
+#include <dali/integration-api/events/touch-event-combiner.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/accessibility-adaptor.h>
+#include <dali/devel-api/adaptor-framework/accessibility-action-handler.h>
+#include <dali/devel-api/adaptor-framework/accessibility-gesture-handler.h>
+#include <dali/internal/accessibility/common/accessibility-gesture-detector.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * This class detects to accessibility action
+ */
+class AccessibilityAdaptor : public Dali::BaseObject
+{
+public:
+
+  /**
+   * Constructor.
+   */
+  AccessibilityAdaptor();
+
+  /**
+   * @brief Get an instance of the AccessibilityAdaptor.
+   *
+   * @note This singleton-style getter can be reimplemented for different platforms.
+   * @return The instance of the AccessibilityAdaptor.
+   */
+  static Dali::AccessibilityAdaptor Get();
+
+  /**
+   * Turn on accessibility action
+   * This method should be called by vconf callback
+   */
+  void EnableAccessibility();
+
+  /**
+   * Turn off accessibility action
+   * This method should be called by vconf callback
+   */
+  void DisableAccessibility();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::IsEnabled()
+   */
+  bool IsEnabled() const;
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::GetReadPosition() const
+   */
+  Vector2 GetReadPosition() const;
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::SetActionHandler()
+   */
+  void SetActionHandler(AccessibilityActionHandler& handler);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::SetGestureHandler()
+   */
+  void SetGestureHandler(AccessibilityGestureHandler& handler);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionNextEvent()
+   */
+  virtual bool HandleActionNextEvent( bool allowEndFeedback = true);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionPreviousEvent()
+   */
+  virtual bool HandleActionPreviousEvent( bool allowEndFeedback = true);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionActivateEvent()
+   */
+  virtual bool HandleActionActivateEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadEvent()
+   */
+  virtual bool HandleActionReadEvent( unsigned int x, unsigned int y, bool allowReadAgain );
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadNextEvent()
+   */
+  virtual bool HandleActionReadNextEvent( bool allowEndFeedback = true);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadPreviousEvent()
+   */
+  virtual bool HandleActionReadPreviousEvent( bool allowEndFeedback = true);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionUpEvent()
+   */
+  virtual bool HandleActionUpEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionDownEvent()
+   */
+  virtual bool HandleActionDownEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionClearFocusEvent()
+   */
+  bool HandleActionClearFocusEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionScrollEvent()
+   */
+  bool HandleActionScrollEvent(const TouchPoint& point, uint32_t timeStamp);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionTouchEvent()
+   */
+  bool HandleActionTouchEvent(const TouchPoint& point, uint32_t timeStamp);
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionBackEvent()
+   */
+  bool HandleActionBackEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionEnableEvent()
+   */
+  void HandleActionEnableEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionDisableEvent()
+   */
+  void HandleActionDisableEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionScrollUpEvent()
+   */
+  bool HandleActionScrollUpEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionScrollDownEvent()
+   */
+  bool HandleActionScrollDownEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionPageLeftEvent()
+   */
+  bool HandleActionPageLeftEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionPageRightEvent()
+   */
+  bool HandleActionPageRightEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionPageUpEvent()
+   */
+  bool HandleActionPageUpEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionPageDownEvent()
+   */
+  bool HandleActionPageDownEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionMoveToFirstEvent()
+   */
+  bool HandleActionMoveToFirstEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionMoveToLastEvent()
+   */
+  bool HandleActionMoveToLastEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadFromTopEvent()
+   */
+  bool HandleActionReadFromTopEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadFromNextEvent()
+   */
+  bool HandleActionReadFromNextEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionZoomEvent()
+   */
+  bool HandleActionZoomEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadPauseResumeEvent()
+   */
+  bool HandleActionReadPauseResumeEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionStartStopEvent()
+   */
+  bool HandleActionStartStopEvent();
+
+protected:
+
+  /**
+   * Destructor.
+   */
+  virtual ~AccessibilityAdaptor();
+
+private:
+
+  /**
+   * @brief Called when the singleton is destroyed.
+   *
+   * @note This can be reimplemented for different platforms.
+   * @return The instance of the AccessibilityAdaptor.
+   */
+  static void OnDestroy();
+
+  // Undefined
+  AccessibilityAdaptor( const AccessibilityAdaptor& );
+  AccessibilityAdaptor& operator=( AccessibilityAdaptor& );
+
+protected:
+
+  Dali::Integration::TouchEventCombiner mCombiner; ///< Combines multi-touch events.
+
+  Vector2 mReadPosition; ///< ActionRead position
+
+  AccessibilityActionHandler* mActionHandler; ///< The pointer of accessibility action handler
+
+  AccessibilityGestureDetectorPtr mAccessibilityGestureDetector; ///< The accessibility gesture detector
+
+  bool mIsEnabled        : 1; ///< enable/disable the accessibility action
+
+public:
+
+  // Helpers for public-api forwarding methods
+
+  inline static Internal::Adaptor::AccessibilityAdaptor& GetImplementation(Dali::AccessibilityAdaptor& adaptor)
+  {
+    DALI_ASSERT_ALWAYS( adaptor && "AccessibilityAdaptor handle is empty" );
+
+    BaseObject& handle = adaptor.GetBaseObject();
+
+    return static_cast<Internal::Adaptor::AccessibilityAdaptor&>(handle);
+  }
+
+  inline static const Internal::Adaptor::AccessibilityAdaptor& GetImplementation(const Dali::AccessibilityAdaptor& adaptor)
+  {
+    DALI_ASSERT_ALWAYS( adaptor && "AccessibilityAdaptor handle is empty" );
+
+    const BaseObject& handle = adaptor.GetBaseObject();
+
+    return static_cast<const Internal::Adaptor::AccessibilityAdaptor&>(handle);
+  }
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_H
diff --git a/dali/internal/accessibility/common/accessibility-gesture-detector.cpp b/dali/internal/accessibility/common/accessibility-gesture-detector.cpp
new file mode 100644 (file)
index 0000000..b872077
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/common/accessibility-gesture-detector.h>
+
+// EXTERNAL INCLUDES
+#include <cmath>
+
+#include <dali/public-api/events/touch-point.h>
+
+#include <dali/integration-api/events/touch-event-integ.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+  const float MINIMUM_MOTION_DISTANCE_BEFORE_PAN( 15.0f );
+  const float MINIMUM_MOTION_DISTANCE_BEFORE_PAN_SQUARED( MINIMUM_MOTION_DISTANCE_BEFORE_PAN * MINIMUM_MOTION_DISTANCE_BEFORE_PAN );
+  const float MINIMUM_MOTION_DISTANCE_TO_THRESHOLD_ADJUSTMENTS_RATIO( 2.0f / 3.0f );
+  const unsigned long MAXIMUM_TIME_DIFF_ALLOWED( 500 );
+  const unsigned long MINIMUM_TIME_BEFORE_THRESHOLD_ADJUSTMENTS( 100 );
+  const unsigned int MINIMUM_MOTION_EVENTS_BEFORE_PAN(2);
+  const unsigned int MINIMUM_TOUCHES_BEFORE_PAN(1);
+  const unsigned int MAXIMUM_TOUCHES_BEFORE_PAN(1);
+} // unnamed namespace
+
+
+AccessibilityGestureDetector::AccessibilityGestureDetector()
+: mState( Clear ),
+  mScene(nullptr),
+  mGestureHandler(nullptr),
+  mPanning(false),
+  mThresholdAdjustmentsRemaining( 0 ),
+  mThresholdTotalAdjustments( MINIMUM_MOTION_DISTANCE_BEFORE_PAN * MINIMUM_MOTION_DISTANCE_TO_THRESHOLD_ADJUSTMENTS_RATIO ),
+  mPrimaryTouchDownTime( 0 ),
+  mMinimumTouchesRequired( MINIMUM_TOUCHES_BEFORE_PAN ),
+  mMaximumTouchesRequired( MAXIMUM_TOUCHES_BEFORE_PAN ),
+  mMinimumDistanceSquared( MINIMUM_MOTION_DISTANCE_BEFORE_PAN_SQUARED ),
+  mMinimumMotionEvents( MINIMUM_MOTION_EVENTS_BEFORE_PAN ),
+  mMotionEvents( 0 )
+{
+}
+
+AccessibilityGestureDetector::~AccessibilityGestureDetector()
+{
+}
+
+void AccessibilityGestureDetector::SetGestureHandler(AccessibilityGestureHandler& handler)
+{
+  mGestureHandler = &handler;
+}
+
+void AccessibilityGestureDetector::EmitPan(const AccessibilityGestureEvent gesture)
+{
+  if( mGestureHandler )
+  {
+    if(gesture.state == AccessibilityGestureEvent::Started)
+    {
+      mPanning = true;
+    }
+
+    if( mPanning )
+    {
+      mGestureHandler->HandlePanGesture(gesture);
+
+      if( (gesture.state == AccessibilityGestureEvent::Finished) ||
+          (gesture.state == AccessibilityGestureEvent::Cancelled) )
+      {
+        mPanning = false;
+      }
+    }
+  }
+}
+
+void AccessibilityGestureDetector::SendEvent(const Integration::TouchEvent& event)
+{
+  PointState::Type primaryPointState(event.points[0].GetState());
+
+  if (primaryPointState == PointState::INTERRUPTED)
+  {
+    if ( ( mState == Started ) || ( mState == Possible ) )
+    {
+      // If our pan had started and we are interrupted, then tell Core that pan is cancelled.
+      mTouchEvents.push_back(event);
+      SendPan(AccessibilityGestureEvent::Cancelled, event);
+    }
+    mState = Clear; // We should change our state to Clear.
+    mTouchEvents.clear();
+  }
+  else
+  {
+    switch (mState)
+    {
+      case Clear:
+      {
+        if ( ( primaryPointState == PointState::DOWN ) || ( primaryPointState == PointState::STATIONARY ) )
+        {
+          mPrimaryTouchDownLocation = event.points[0].GetScreenPosition();
+          mPrimaryTouchDownTime = event.time;
+          mMotionEvents = 0;
+          if (event.GetPointCount() == mMinimumTouchesRequired)
+          {
+            // We have satisfied the minimum touches required for a pan, tell core that a gesture may be possible and change our state accordingly.
+            mState = Possible;
+            SendPan(AccessibilityGestureEvent::Possible, event);
+          }
+
+          mTouchEvents.push_back(event);
+        }
+        break;
+      }
+
+      case Possible:
+      {
+        unsigned int pointCount(event.GetPointCount());
+        if ( (pointCount >= mMinimumTouchesRequired)&&(pointCount <= mMaximumTouchesRequired) )
+        {
+          if (primaryPointState == PointState::MOTION)
+          {
+            mTouchEvents.push_back(event);
+            mMotionEvents++;
+
+            Vector2 delta(event.points[0].GetScreenPosition() - mPrimaryTouchDownLocation);
+
+            if ( ( mMotionEvents >= mMinimumMotionEvents ) &&
+                 ( delta.LengthSquared() >= static_cast<float>( mMinimumDistanceSquared ) ) )
+            {
+              // If the touch point(s) have moved enough distance to be considered a pan, then tell Core that the pan gesture has started and change our state accordingly.
+              mState = Started;
+              SendPan(AccessibilityGestureEvent::Started, event);
+            }
+          }
+          else if (primaryPointState == PointState::UP)
+          {
+            Vector2 delta(event.points[0].GetScreenPosition() - mPrimaryTouchDownLocation);
+            if (delta.LengthSquared() >= static_cast<float>( mMinimumDistanceSquared ) )
+            {
+              SendPan(AccessibilityGestureEvent::Started, event);
+              mTouchEvents.push_back(event);
+              SendPan(AccessibilityGestureEvent::Finished, event);
+            }
+            else
+            {
+              // If we have lifted the primary touch point then tell core the pan is cancelled and change our state to Clear.
+              SendPan(AccessibilityGestureEvent::Cancelled, event);
+            }
+            mState = Clear;
+            mTouchEvents.clear();
+          }
+        }
+        else
+        {
+          // We do not satisfy pan conditions, tell Core our Gesture has been cancelled.
+          SendPan(AccessibilityGestureEvent::Cancelled, event);
+
+          if (pointCount == 1 && primaryPointState == PointState::UP)
+          {
+            // If we have lifted the primary touch point, then change our state to Clear...
+            mState = Clear;
+            mTouchEvents.clear();
+          }
+          else
+          {
+            // ...otherwise change it to Failed.
+            mState = Failed;
+          }
+        }
+        break;
+      }
+
+      case Started:
+      {
+        mTouchEvents.push_back(event);
+
+        unsigned int pointCount(event.GetPointCount());
+        if ( (pointCount >= mMinimumTouchesRequired)&&(pointCount <= mMaximumTouchesRequired) )
+        {
+          switch (primaryPointState)
+          {
+            case PointState::MOTION:
+              // Pan is continuing, tell Core.
+              SendPan(AccessibilityGestureEvent::Continuing, event);
+              break;
+
+            case PointState::UP:
+              // Pan is finally finished when our primary point is lifted, tell Core and change our state to Clear.
+              SendPan(AccessibilityGestureEvent::Finished, event);
+              mState = Clear;
+              mTouchEvents.clear();
+              break;
+
+            case PointState::STATIONARY:
+              if (pointCount == mMinimumTouchesRequired)
+              {
+                Integration::PointContainerConstIterator iter = event.points.begin() + 1; // We already know the state of the first point
+                for(; iter != event.points.end(); ++iter)
+                {
+                  if(iter->GetState() == PointState::UP)
+                  {
+                    // The number of touch points will be less than the minimum required.  Inform core and change our state to Finished.
+                    SendPan(AccessibilityGestureEvent::Finished, event);
+                    mState = Finished;
+                    break;
+                  }
+                }
+              }
+              break;
+
+            default:
+              break;
+          }
+        }
+        else
+        {
+          // We have gone outside of the pan requirements, inform Core that the gesture is finished.
+          SendPan(AccessibilityGestureEvent::Finished, event);
+
+          if (pointCount == 1 && primaryPointState == PointState::UP)
+          {
+            // If this was the primary point being released, then we change our state back to Clear...
+            mState = Clear;
+            mTouchEvents.clear();
+          }
+          else
+          {
+            // ...otherwise we change it to Finished.
+            mState = Finished;
+          }
+        }
+        break;
+      }
+
+      case Finished:
+      case Failed:
+      {
+        if (primaryPointState == PointState::UP)
+        {
+          // Change our state back to clear when the primary touch point is released.
+          mState = Clear;
+          mTouchEvents.clear();
+        }
+        break;
+      }
+    }
+  }
+}
+
+void AccessibilityGestureDetector::SendPan(AccessibilityGestureEvent::State state, const Integration::TouchEvent& currentEvent)
+{
+  AccessibilityGestureEvent gesture(state);
+  gesture.currentPosition = currentEvent.points[0].GetScreenPosition();
+  gesture.numberOfTouches = currentEvent.GetPointCount();
+
+  if ( mTouchEvents.size() > 1 )
+  {
+    // Get the second last event in the queue, the last one is the current event
+    const Integration::TouchEvent& previousEvent( *( mTouchEvents.rbegin() + 1 ) );
+
+    Vector2 previousPosition( mPreviousPosition );
+    uint32_t previousTime( previousEvent.time );
+
+    // If we've just started then we want to remove the threshold from Core calculations.
+    if ( state == AccessibilityGestureEvent::Started )
+    {
+      previousPosition = mPrimaryTouchDownLocation;
+      previousTime = mPrimaryTouchDownTime;
+
+      // If it's a slow pan, we do not want to phase in the threshold over the first few pan-events
+      // A slow pan is defined as one that starts the specified number of milliseconds after the down-event
+      if ( ( currentEvent.time - previousTime ) > MINIMUM_TIME_BEFORE_THRESHOLD_ADJUSTMENTS )
+      {
+        mThresholdAdjustmentsRemaining = mThresholdTotalAdjustments;
+        mThresholdAdjustmentPerFrame = ( gesture.currentPosition - previousPosition ) / static_cast<float>( mThresholdTotalAdjustments );
+      }
+      else
+      {
+        mThresholdAdjustmentsRemaining = 0;
+        mThresholdAdjustmentPerFrame = Vector2::ZERO;
+      }
+    }
+
+    gesture.previousPosition = previousPosition;
+    gesture.timeDelta = currentEvent.time - previousTime;
+
+    // Apply the threshold with a phased approach
+    if ( mThresholdAdjustmentsRemaining > 0 )
+    {
+      --mThresholdAdjustmentsRemaining;
+      gesture.currentPosition -= mThresholdAdjustmentPerFrame * static_cast<float>( mThresholdAdjustmentsRemaining );
+    }
+
+    mPreviousPosition = gesture.currentPosition;
+  }
+  else
+  {
+    gesture.previousPosition = gesture.currentPosition;
+    gesture.timeDelta = 0;
+  }
+
+  gesture.time = currentEvent.time;
+
+  EmitPan(gesture);
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/accessibility/common/accessibility-gesture-detector.h b/dali/internal/accessibility/common/accessibility-gesture-detector.h
new file mode 100644 (file)
index 0000000..616d76e
--- /dev/null
@@ -0,0 +1,135 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_GESTURE_DETECTOR_H
+#define DALI_INTERNAL_ACCESSIBILITY_GESTURE_DETECTOR_H
+
+/*
+ * Copyright (c) 2019 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
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/accessibility-gesture-handler.h>
+#include <dali/devel-api/adaptor-framework/accessibility-gesture-event.h>
+#include <dali/integration-api/scene.h>
+#include <dali/public-api/events/touch-event.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+struct TouchEvent;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Detects an accessibility pan gesture and sends it to the gesture handler.
+ */
+class AccessibilityGestureDetector : public RefObject
+{
+public:
+
+  /**
+   * Constructor
+   */
+  AccessibilityGestureDetector();
+
+  /**
+   * Virtual destructor.
+   */
+  virtual ~AccessibilityGestureDetector();
+
+  /**
+   * Set the handler to handle accessibility gestures.
+   * @param[in] handler The Accessibility gesture handler.
+   * @note Handlers should remove themselves when they are destroyed.
+   */
+  void SetGestureHandler(AccessibilityGestureHandler& handler);
+
+  void SendEvent(const Integration::TouchEvent& event);
+
+  void SendEvent(Integration::Scene& scene, const Integration::TouchEvent& event)
+  {
+    mScene = &scene;
+    SendEvent(event);
+  }
+
+private:
+
+  /**
+   * Emits the pan gesture event (performs some smoothing operation).
+   * @param[in]  state         The state of the pan.
+   * @param[in]  currentEvent  The latest touch event.
+   */
+  void SendPan(AccessibilityGestureEvent::State state, const Integration::TouchEvent& currentEvent);
+
+  /**
+   * Emits the pan gesture event to the gesture handler.
+   * @param[in] gesture The pan gesture event.
+   */
+  void EmitPan(const AccessibilityGestureEvent gesture);
+
+private:
+
+  /**
+   * Internal state machine.
+   */
+  enum State
+  {
+    Clear,    ///< No gesture detected.
+    Possible, ///< The current touch event data suggests that a gesture is possible.
+    Started,  ///< A gesture has been detected.
+    Finished, ///< A previously started pan gesture has finished.
+    Failed,   ///< Current touch event data suggests a pan gesture is not possible.
+  };
+
+  State mState; ///< The current state of the detector.
+
+  Integration::Scene* mScene;
+  AccessibilityGestureHandler* mGestureHandler; ///< The pointer of accessibility gesture handler
+  bool mPanning;    ///< Keep track of panning state, when panning is occuring, this is true.
+
+  std::vector<Integration::TouchEvent> mTouchEvents;     ///< A container of all touch events after an initial down event.
+
+  Vector2 mPrimaryTouchDownLocation;    ///< The initial touch down point.
+  Vector2 mThresholdAdjustmentPerFrame; ///< The adjustment per frame at the start of a slow pan.
+  Vector2 mPreviousPosition;            ///< The previous position.
+
+  unsigned int mThresholdAdjustmentsRemaining; ///< No. of threshold adjustments still to apply (for a slow-pan).
+  unsigned int mThresholdTotalAdjustments;     ///< The total number of adjustments required.
+
+  uint32_t mPrimaryTouchDownTime;       ///< The initial touch down time.
+  unsigned int mMinimumTouchesRequired; ///< The minimum touches required before a pan should be emitted.
+  unsigned int mMaximumTouchesRequired; ///< The maximum touches after which a pan should not be emitted.
+  unsigned int mMinimumDistanceSquared; ///< The minimum distance squared before pan should start.
+  unsigned int mMinimumMotionEvents;    ///< The minimum motion events before pan should start.
+  unsigned int mMotionEvents;           ///< The motion events received so far (before pan is emitted).
+};
+
+using AccessibilityGestureDetectorPtr = Dali::IntrusivePtr<AccessibilityGestureDetector>;
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_GESTURE_DETECTOR_H
diff --git a/dali/internal/accessibility/common/tts-player-factory.cpp b/dali/internal/accessibility/common/tts-player-factory.cpp
new file mode 100644 (file)
index 0000000..1e4c884
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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/internal/accessibility/common/tts-player-factory.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class TtsPlayer;
+namespace TtsPlayerFactory
+{
+/**
+ * Factory function that ought to be overriden by platform implementation.
+ * @return dummy implementation of Tts Player
+ */
+__attribute__((weak))
+std::unique_ptr<TtsPlayer> New(Dali::TtsPlayer::Mode mode)
+{
+  return std::unique_ptr<TtsPlayer>(new Internal::Adaptor::TtsPlayer());
+}
+}
+
+}
+
+}
+
+}
\ No newline at end of file
diff --git a/dali/internal/accessibility/common/tts-player-factory.h b/dali/internal/accessibility/common/tts-player-factory.h
new file mode 100644 (file)
index 0000000..aac8e85
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_COMMON_TTS_PLAYER_FACTORY_H
+#define DALI_INTERNAL_ACCESSIBILITY_COMMON_TTS_PLAYER_FACTORY_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/internal/accessibility/common/tts-player-impl.h>
+#include <memory>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class TtsPlayer;
+namespace TtsPlayerFactory
+{
+
+/**
+ * Factory function that ought to be overriden by platform implementation.
+ * @return
+ */
+std::unique_ptr<TtsPlayer> New(Dali::TtsPlayer::Mode mode);
+
+} // namespace TtsPlayerFactory
+
+} // namespaceAdaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_COMMON_TTS_PLAYER_FACTORY_H
diff --git a/dali/internal/accessibility/common/tts-player-impl.cpp b/dali/internal/accessibility/common/tts-player-impl.cpp
new file mode 100644 (file)
index 0000000..16a6b4a
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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/internal/accessibility/common/tts-player-impl.h>
+#include <dali/internal/accessibility/common/tts-player-factory.h>
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+Dali::TtsPlayer TtsPlayer::New(Dali::TtsPlayer::Mode mode)
+{
+  return Dali::TtsPlayer(TtsPlayerFactory::New(mode).release());
+}
+
+void TtsPlayer::Play(const std::string &text)
+{
+
+}
+
+void TtsPlayer::Stop()
+{
+
+}
+
+void TtsPlayer::Pause()
+{
+
+}
+
+void TtsPlayer::Resume()
+{
+
+}
+
+Dali::TtsPlayer::State TtsPlayer::GetState()
+{
+  return Dali::TtsPlayer::State();
+}
+
+Dali::TtsPlayer::StateChangedSignalType& TtsPlayer::StateChangedSignal()
+{
+  static Dali::TtsPlayer::StateChangedSignalType signal;
+  return signal;
+}
+
+}
+}
+}
\ No newline at end of file
diff --git a/dali/internal/accessibility/common/tts-player-impl.h b/dali/internal/accessibility/common/tts-player-impl.h
new file mode 100644 (file)
index 0000000..0f7d93d
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_COMMON_TTS_PLAYER_IMPL_H
+#define DALI_INTERNAL_ACCESSIBILITY_COMMON_TTS_PLAYER_IMPL_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/tts-player.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Text-to-speech player
+ */
+class TtsPlayer : public Dali::BaseObject
+{
+
+public:
+
+  /**
+   * Create a TtsPlayer with the given mode.
+   * This should only be called once by the Adaptor class for each given mode.
+   * @param mode the mode of tts-player
+   * @return A newly created TtsPlayer.
+   */
+  static Dali::TtsPlayer New(Dali::TtsPlayer::Mode mode);
+
+  /**
+   * @copydoc TtsPlayer::Play()
+   */
+  virtual void Play(const std::string& text);
+
+  /**
+   * @copydoc TtsPlayer::Stop()
+   */
+  virtual void Stop();
+
+  /**
+   * @copydoc TtsPlayer::Pause()
+   */
+  virtual void Pause();
+
+  /**
+   * @copydoc TtsPlayer::Resume()
+   */
+  virtual void Resume();
+
+  /**
+   * @copydoc TtsPlayer::GetState()
+   */
+  virtual Dali::TtsPlayer::State GetState();
+
+  /**
+   * @copydoc TtsPlayer::StateChangedSignal()
+   */
+  virtual Dali::TtsPlayer::StateChangedSignalType& StateChangedSignal();
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::TtsPlayer& GetImplementation(Dali::TtsPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "TtsPlayer handle is empty" );
+
+  BaseObject& handle = player.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::TtsPlayer&>(handle);
+}
+
+inline const Internal::Adaptor::TtsPlayer& GetImplementation(const Dali::TtsPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "TtsPlayer handle is empty" );
+
+  const BaseObject& handle = player.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::TtsPlayer&>(handle);
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_COMMON_TTS_PLAYER_IMPL_H
diff --git a/dali/internal/accessibility/file.list b/dali/internal/accessibility/file.list
new file mode 100755 (executable)
index 0000000..d2ff157
--- /dev/null
@@ -0,0 +1,74 @@
+
+# module: accessibility, backend: common
+SET( adaptor_accessibility_common_src_files
+    ${adaptor_accessibility_dir}/common/tts-player-factory.cpp
+    ${adaptor_accessibility_dir}/common/tts-player-impl.cpp
+    ${adaptor_accessibility_dir}/common/accessibility-adaptor-impl.cpp
+    ${adaptor_accessibility_dir}/common/accessibility-gesture-detector.cpp
+)
+
+# module: accessibility, backend: tizen-wayland
+SET( adaptor_accessibility_tizen_wayland_src_files
+    ${adaptor_accessibility_dir}/tizen-wayland/tts-player-factory-tizen.cpp
+    ${adaptor_accessibility_dir}/tizen-wayland/tts-player-impl-tizen.cpp
+    ${adaptor_accessibility_dir}/tizen-wayland/atspi/atspi-accessibility-tizen.cpp
+    ${adaptor_accessibility_dir}/tizen-wayland/atspi/accessibility-impl.cpp
+    ${adaptor_accessibility_dir}/tizen-wayland/atspi/accessible.cpp
+    ${adaptor_accessibility_dir}/tizen-wayland/atspi/bridge-accessible.cpp
+    ${adaptor_accessibility_dir}/tizen-wayland/atspi/bridge-action.cpp
+    ${adaptor_accessibility_dir}/tizen-wayland/atspi/bridge-base.cpp
+    ${adaptor_accessibility_dir}/tizen-wayland/atspi/bridge-collection.cpp
+    ${adaptor_accessibility_dir}/tizen-wayland/atspi/bridge-component.cpp
+    ${adaptor_accessibility_dir}/tizen-wayland/atspi/bridge-editable-text.cpp
+    ${adaptor_accessibility_dir}/tizen-wayland/atspi/bridge-impl.cpp
+    ${adaptor_accessibility_dir}/tizen-wayland/atspi/bridge-object.cpp
+    ${adaptor_accessibility_dir}/tizen-wayland/atspi/bridge-text.cpp
+    ${adaptor_accessibility_dir}/tizen-wayland/atspi/bridge-value.cpp
+    ${adaptor_accessibility_dir}/tizen-wayland/atspi/component.cpp
+    ${adaptor_accessibility_dir}/tizen-wayland/atspi/dbus-tizen.cpp
+)
+
+# module: accessibility, backend: tizen-common profile
+SET( adaptor_accessibility_tizen_common_src_files
+    ${adaptor_accessibility_dir}/tizen-wayland/tizen-common/accessibility-adaptor-impl-tizen.cpp
+)
+
+# module: accessibility, backend: tizen-ivi profile
+SET( adaptor_accessibility_tizen_ivi_src_files
+    ${adaptor_accessibility_dir}/tizen-wayland/tizen-ivi/accessibility-adaptor-impl-ivi.cpp
+)
+
+# module: accessibility, backend: tizen-mobile profile
+SET( adaptor_accessibility_tizen_mobile_src_files
+    ${adaptor_accessibility_dir}/tizen-wayland/tizen-mobile/accessibility-adaptor-impl-mobile.cpp
+)
+
+# module: accessibility, backend: tizen-tv profile
+SET( adaptor_accessibility_tizen_tv_src_files
+    ${adaptor_accessibility_dir}/tizen-wayland/tizen-tv/accessibility-adaptor-impl-tv.cpp
+)
+
+# module: accessibility, backend: tizen-wearable profile
+SET( adaptor_accessibility_tizen_wearable_src_files
+    ${adaptor_accessibility_dir}/tizen-wayland/tizen-wearable/accessibility-adaptor-impl-wearable.cpp
+)
+
+# module: accessibility, backend: ubuntu
+SET( adaptor_accessibility_ubuntu_src_files
+    ${adaptor_accessibility_dir}/generic/accessibility-adaptor-impl-generic.cpp
+    ${adaptor_accessibility_dir}/generic/atspi-accessibility-generic.cpp
+    ${adaptor_accessibility_dir}/generic/tts-player-factory-generic.cpp
+    ${adaptor_accessibility_dir}/generic/tts-player-impl-generic.cpp
+)
+
+# module: accessibility, backend: android
+SET( adaptor_accessibility_android_src_files
+    ${adaptor_accessibility_dir}/generic/accessibility-adaptor-impl-generic.cpp
+    ${adaptor_accessibility_dir}/generic/tts-player-factory-generic.cpp
+    ${adaptor_accessibility_dir}/generic/tts-player-impl-generic.cpp
+)
+
+# module: accessibility, backend: windows
+SET( adaptor_accessibility_windows_src_files
+    ${adaptor_accessibility_dir}/generic/accessibility-adaptor-impl-generic.cpp
+)
diff --git a/dali/internal/accessibility/generic/accessibility-adaptor-impl-generic.cpp b/dali/internal/accessibility/generic/accessibility-adaptor-impl-generic.cpp
new file mode 100644 (file)
index 0000000..62cfcbf
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/common/accessibility-adaptor-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/common/singleton-service.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+Dali::AccessibilityAdaptor AccessibilityAdaptor::Get()
+{
+  Dali::AccessibilityAdaptor adaptor;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::AccessibilityAdaptor ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      adaptor = Dali::AccessibilityAdaptor( dynamic_cast< AccessibilityAdaptor* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      adaptor = Dali::AccessibilityAdaptor( new AccessibilityAdaptor() );
+      service.Register( typeid( adaptor ), adaptor );
+    }
+  }
+
+  return adaptor;
+}
+
+void AccessibilityAdaptor::OnDestroy()
+{
+  // Nothing to do here
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/accessibility/generic/atspi-accessibility-generic.cpp b/dali/internal/accessibility/generic/atspi-accessibility-generic.cpp
new file mode 100755 (executable)
index 0000000..f606d01
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019 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/dali-adaptor-common.h>
+#include <dali/devel-api/adaptor-framework/atspi-accessibility.h>
+#include <dali/integration-api/debug.h>
+
+void Dali::AtspiAccessibility::Pause()
+{
+  DALI_LOG_ERROR("[ERROR] This is NOT supported\n");
+}
+
+void Dali::AtspiAccessibility::Resume()
+{
+  DALI_LOG_ERROR("[ERROR] This is NOT supported\n");
+}
+
+void Dali::AtspiAccessibility::Say( const std::string &text, bool discardable, std::function<void(std::string)> callback )
+{
+  DALI_LOG_ERROR("[ERROR] This is NOT supported\n");
+}
+
+int Dali::AtspiAccessibility::SetForcefully( bool turnOn )
+{
+  DALI_LOG_ERROR("[ERROR] This is NOT supported\n");
+  return -1;
+}
+
+int Dali::AtspiAccessibility::GetStatus()
+{
+  DALI_LOG_ERROR("[ERROR] This is NOT supported\n");
+  return -1;
+}
diff --git a/dali/internal/accessibility/generic/tts-player-factory-generic.cpp b/dali/internal/accessibility/generic/tts-player-factory-generic.cpp
new file mode 100644 (file)
index 0000000..ac70139
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019 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/internal/accessibility/common/tts-player-factory.h>
+#include <dali/internal/accessibility/generic/tts-player-impl-generic.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class TtsPlayer;
+namespace TtsPlayerFactory
+{
+
+std::unique_ptr<TtsPlayer> New(Dali::TtsPlayer::Mode mode)
+{
+  return TtsPlayerGeneric::New(mode);
+}
+
+} // namespace TtsPlayerFactory
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/accessibility/generic/tts-player-impl-generic.cpp b/dali/internal/accessibility/generic/tts-player-impl-generic.cpp
new file mode 100644 (file)
index 0000000..5200af5
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/generic/tts-player-impl-generic.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+
+#include <memory>
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* TtsPlayerGeneric::gLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_TTS_PLAYER");
+#endif
+
+std::unique_ptr<TtsPlayerGeneric> TtsPlayerGeneric::New(Dali::TtsPlayer::Mode mode)
+{
+  return std::unique_ptr<TtsPlayerGeneric>(new TtsPlayerGeneric(mode));
+}
+
+TtsPlayerGeneric::TtsPlayerGeneric(Dali::TtsPlayer::Mode mode)
+: mStateChangedSignal()
+{
+  DALI_LOG_ERROR("TTS is not implemented in GENERIC profile.\n");
+}
+
+TtsPlayerGeneric::~TtsPlayerGeneric()
+{
+}
+
+void TtsPlayerGeneric::Play(const std::string& text)
+{
+}
+
+void TtsPlayerGeneric::Stop()
+{
+}
+
+void TtsPlayerGeneric::Pause()
+{
+}
+
+void TtsPlayerGeneric::Resume()
+{
+}
+
+Dali::TtsPlayer::State TtsPlayerGeneric::GetState()
+{
+  return Dali::TtsPlayer::UNAVAILABLE;
+}
+
+Dali::TtsPlayer::StateChangedSignalType& TtsPlayerGeneric::StateChangedSignal()
+{
+  return mStateChangedSignal;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/accessibility/generic/tts-player-impl-generic.h b/dali/internal/accessibility/generic/tts-player-impl-generic.h
new file mode 100644 (file)
index 0000000..c310a93
--- /dev/null
@@ -0,0 +1,115 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_GENERIC_TTS_PLAYER_IMPL_GENERIC_H
+#define DALI_INTERNAL_ACCESSIBILITY_GENERIC_TTS_PLAYER_IMPL_GENERIC_H
+
+/*
+ * Copyright (c) 2019 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 <memory>
+
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/base-object.h>
+
+#include <dali/internal/accessibility/common/tts-player-impl.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Text-to-speech player
+ */
+class TtsPlayerGeneric : public Dali::Internal::Adaptor::TtsPlayer
+{
+
+public:
+
+  /**
+   * Create a TtsPlayer with the given mode.
+   * This should only be called once by the Adaptor class for each given mode.
+   * @param mode the mode of tts-player
+   * @return A newly created TtsPlayer.
+   */
+  static std::unique_ptr<TtsPlayerGeneric> New(Dali::TtsPlayer::Mode mode);
+
+  /**
+   * @copydoc TtsPlayer::Play()
+   */
+  void Play(const std::string& text) override;
+
+  /**
+   * @copydoc TtsPlayer::Stop()
+   */
+  void Stop() override;
+
+  /**
+   * @copydoc TtsPlayer::Pause()
+   */
+  void Pause() override;
+
+  /**
+   * @copydoc TtsPlayer::Resume()
+   */
+  void Resume() override;
+
+  /**
+   * @copydoc TtsPlayer::GetState()
+   */
+  Dali::TtsPlayer::State GetState() override;
+
+  /**
+   * @copydoc TtsPlayer::StateChangedSignal()
+   */
+  Dali::TtsPlayer::StateChangedSignalType& StateChangedSignal() override;
+
+  /**
+   * Private Constructor; see also TtsPlayer::New()
+   * @param mode the mode of tts-player
+   */
+  TtsPlayerGeneric(Dali::TtsPlayer::Mode mode);
+
+  /**
+   * Destructor
+   */
+  virtual ~TtsPlayerGeneric();
+
+private:
+
+  Dali::TtsPlayer::StateChangedSignalType mStateChangedSignal; ///< Signal emitted when the TTS state changes (non-functional, for interface compatibility).
+
+#if defined(DEBUG_ENABLED)
+public:
+  static Debug::Filter* gLogFilter;
+#endif
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_GENERIC_TTS_PLAYER_IMPL_GENERIC_H
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/accessibility-common.h b/dali/internal/accessibility/tizen-wayland/atspi/accessibility-common.h
new file mode 100644 (file)
index 0000000..80f7f17
--- /dev/null
@@ -0,0 +1,375 @@
+#ifndef DALI_INTERNAL_ATSPI_ACCESSIBILITY_COMMON_H
+#define DALI_INTERNAL_ATSPI_ACCESSIBILITY_COMMON_H
+
+/*
+ * Copyright (c) 2019 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/debug.h>
+#include <iomanip>
+#include <sstream>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/internal/accessibility/tizen-wayland/atspi/dbus.h>
+#include <dali/internal/accessibility/tizen-wayland/atspi/dbus-locators.h>
+#include <dali/internal/accessibility/tizen-wayland/atspi/accessibility-impl.h>
+
+#define A11yDbusName "org.a11y.Bus"
+#define A11yDbusPath "/org/a11y/bus"
+#define A11yDbusStatusInterface "org.a11y.Status"
+#define AtspiDbusNameRegistry "org.a11y.atspi.Registry"
+#define AtspiDbusPathRoot "/org/a11y/atspi/accessible/root"
+#define AtspiDbusInterfaceSocket "org.a11y.atspi.Socket"
+#define AtspiPath "/org/a11y/atspi/accessible"
+#define AtspiDbusInterfaceAccessible "org.a11y.atspi.Accessible"
+#define AtspiDbusInterfaceAction "org.a11y.atspi.Action"
+#define AtspiDbusInterfaceApplication "org.a11y.atspi.Application"
+#define AtspiDbusInterfaceCollection "org.a11y.atspi.Collection"
+#define AtspiDbusInterfaceComponent "org.a11y.atspi.Component"
+#define AtspiDbusInterfaceDocument "org.a11y.atspi.Document"
+#define AtspiDbusInterfaceEditableText "org.a11y.atspi.EditableText"
+#define AtspiDbusInterfaceEventKeyboard "org.a11y.atspi.Event.Keyboard"
+#define AtspiDbusInterfaceEventMouse "org.a11y.atspi.Event.Mouse"
+#define AtspiDbusInterfaceEventObject "org.a11y.atspi.Event.Object"
+#define AtspiDbusInterfaceHyperlink "org.a11y.atspi.Hyperlink"
+#define AtspiDbusInterfaceHypertext "org.a11y.atspi.Hypertext"
+#define AtspiDbusInterfaceImage "org.a11y.atspi.Image"
+#define AtspiDbusInterfaceSelection "org.a11y.atspi.Selection"
+#define AtspiDbusInterfaceTable "org.a11y.atspi.Table"
+#define AtspiDbusInterfaceTableCell "org.a11y.atspi.TableCell"
+#define AtspiDbusInterfaceText "org.a11y.atspi.Text"
+#define AtspiDbusInterfaceValue "org.a11y.atspi.Value"
+#define AtspiDbusInterfaceSocket "org.a11y.atspi.Socket"
+#define AtspiDbusInterfaceEventWindow "org.a11y.atspi.Event.Window"
+
+#define AtspiDbusPathDec "/org/a11y/atspi/registry/deviceeventcontroller"
+#define AtspiDbusInterfaceDec "org.a11y.atspi.DeviceEventController"
+#define AtspiDbusInterfaceDeviceEventListener "org.a11y.atspi.DeviceEventListener"
+
+#define DirectReadingDBusName "org.tizen.ScreenReader"
+#define DirectReadingDBusPath "/org/tizen/DirectReading"
+#define DirectReadingDBusInterface "org.tizen.DirectReading"
+
+struct ObjectPath;
+
+/**
+ * @brief Enumeration used for quering Accessibility objects
+ */
+enum class MatchType : int32_t
+{
+  INVALID,
+  ALL,
+  ANY,
+  NONE,
+  EMPTY
+};
+
+/**
+ * @brief Enumeration used for quering Accessibility objects
+ * SortOrder::Canonical uses breadth-first search and sort objects in order of indexes in parent
+ * SortOrder::ReverseCanonical uses SortOrder::Canonical and reverse collection
+ * The rest of orders is not supported.
+ */
+enum class SortOrder : uint32_t
+{
+  INVALID,
+  CANONICAL,
+  FLOW,
+  TAB,
+  REVERSE_CANONICAL,
+  REVERSE_FLOW,
+  REVERSE_TAB,
+  LAST_DEFINED
+};
+
+namespace DBus
+{
+
+class CurrentBridgePtr
+{
+  static Dali::Accessibility::Bridge*& get()
+  {
+    static thread_local Dali::Accessibility::Bridge* b = nullptr;
+    return b;
+  }
+  Dali::Accessibility::Bridge* prev;
+  CurrentBridgePtr( const CurrentBridgePtr& ) = delete;
+  CurrentBridgePtr( CurrentBridgePtr&& ) = delete;
+  CurrentBridgePtr& operator=( const CurrentBridgePtr& ) = delete;
+  CurrentBridgePtr& operator=( CurrentBridgePtr&& ) = delete;
+
+public:
+  CurrentBridgePtr( Dali::Accessibility::Bridge* b )
+  : prev( get() )
+  {
+    get() = b;
+  }
+
+  ~CurrentBridgePtr()
+  {
+    get() = prev;
+  }
+
+  static Dali::Accessibility::Bridge* current()
+  {
+    return get();
+  }
+};
+
+namespace detail
+{
+
+template < typename T >
+struct signature_accessible_impl
+{
+
+using subtype = std::pair< std::string, ObjectPath >;
+
+  /**
+   * @brief Returns name of type marshalled, for informative purposes
+   */
+  static std::string name()
+  {
+    return "AtspiAccessiblePtr";
+  }
+
+  /**
+   * @brief Returns DBUS' signature of type marshalled
+   */
+  static std::string sig()
+  {
+    return "(so)";
+  }
+
+  /**
+   * @brief Marshals value v as marshalled type into message
+   */
+  static void set( const DBusWrapper::MessageIterPtr& iter, T* t )
+  {
+    if( t )
+    {
+      auto v = t->GetAddress();
+      signature< subtype >::set( iter, { v.GetBus(), ObjectPath{std::string{ ATSPI_PREFIX_PATH } +v.GetPath()} } );
+    }
+    else
+    {
+      signature< subtype >::set( iter, { "", ObjectPath{ ATSPI_NULL_PATH } } );
+    }
+  }
+
+  /**
+   * @brief Marshals value from marshalled type into variable v
+   */
+  static bool get( const DBusWrapper::MessageIterPtr& iter, T*& v )
+  {
+    subtype tmp;
+    if( !signature< subtype >::get( iter, tmp ) )
+    {
+      return false;
+    }
+
+    if( tmp.second.value == ATSPI_NULL_PATH )
+    {
+      v = nullptr;
+      return true;
+    }
+
+    if( tmp.second.value.substr( 0, strlen( ATSPI_PREFIX_PATH ) ) != ATSPI_PREFIX_PATH )
+    {
+      return false;
+    }
+
+    auto b = CurrentBridgePtr::current();
+    if( b->GetBusName() != tmp.first )
+    {
+      return false;
+    }
+
+    v = b->FindByPath( tmp.second.value.substr( strlen( ATSPI_PREFIX_PATH ) ) );
+    return v != nullptr;
+  }
+};
+
+template <>
+struct signature< Dali::Accessibility::Accessible* > : public signature_accessible_impl< Dali::Accessibility::Accessible >
+{
+};
+
+template <>
+struct signature< Dali::Accessibility::Address >
+{
+using subtype = std::pair< std::string, ObjectPath >;
+
+  /**
+   * @brief Returns name of type marshalled, for informative purposes
+   */
+  static std::string name()
+  {
+    return "AtspiAccessiblePtr";
+  }
+
+  /**
+   * @brief Returns DBUS' signature of type marshalled
+   */
+  static std::string sig()
+  {
+    return "(so)";
+  }
+
+  /**
+   * @brief Marshals value v as marshalled type into message
+   */
+  static void set( const DBusWrapper::MessageIterPtr& iter, const Dali::Accessibility::Address& v )
+  {
+    if( v )
+    {
+      signature< subtype >::set( iter, { v.GetBus(), ObjectPath{ std::string{ ATSPI_PREFIX_PATH } + v.GetPath() } } );
+    }
+    else
+    {
+      signature< subtype >::set( iter, { v.GetBus(), ObjectPath{ ATSPI_NULL_PATH } } );
+    }
+  }
+
+  /**
+   * @brief Marshals value from marshalled type into variable v
+   */
+  static bool get( const DBusWrapper::MessageIterPtr& iter, Dali::Accessibility::Address& v )
+  {
+    subtype tmp;
+    if( !signature< subtype >::get( iter, tmp ) )
+    {
+      return false;
+    }
+
+    if( tmp.second.value == ATSPI_NULL_PATH )
+    {
+      v = {};
+      return true;
+    }
+    if( tmp.second.value.substr( 0, strlen( ATSPI_PREFIX_PATH ) ) != ATSPI_PREFIX_PATH )
+    {
+      return false;
+    }
+    
+  v = { std::move( tmp.first ), tmp.second.value.substr( strlen( ATSPI_PREFIX_PATH ) ) };
+  return true;
+  }
+};
+
+template <>
+struct signature< Dali::Accessibility::States >
+{
+using subtype = std::array< uint32_t, 2 >;
+
+  /**
+   * @brief Returns name of type marshalled, for informative purposes
+   */
+  static std::string name()
+  {
+    return signature< subtype >::name();
+  }
+
+  /**
+   * @brief Returns DBUS' signature of type marshalled
+   */
+  static std::string sig()
+  {
+    return signature< subtype >::sig();
+  }
+
+  /**
+   * @brief Marshals value v as marshalled type into message
+   */
+  static void set( const DBusWrapper::MessageIterPtr& iter, const Dali::Accessibility::States& v )
+  {
+    signature< subtype >::set( iter, v.GetRawData() );
+  }
+
+  /**
+   * @brief Marshals value from marshalled type into variable v
+   */
+  static bool get( const DBusWrapper::MessageIterPtr& iter, Dali::Accessibility::States& v )
+  {
+    subtype tmp;
+    if( !signature< subtype >::get( iter, tmp ) )
+    {
+      return false;
+    }
+    v = Dali::Accessibility::States{ tmp };
+    return true;
+  }
+};
+}
+}
+
+struct _Logger
+{
+  const char* file;
+  int line;
+  std::ostringstream tmp;
+
+  _Logger( const char* f, int l )
+  : file( f ),
+    line( l ){}
+
+  ~_Logger()
+  {
+    Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s:%d: %s", file, line, tmp.str().c_str() );
+  }
+
+  template < typename T >
+  _Logger& operator<<( T&& t )
+  {
+    tmp << std::forward< T >( t );
+    return *this;
+  }
+};
+
+struct _LoggerEmpty
+{
+  template < typename T >
+  _LoggerEmpty& operator<<( T&& t )
+  {
+    return *this;
+  }
+};
+
+struct _LoggerScope
+{
+  const char* file;
+  int line;
+
+  _LoggerScope( const char* f, int l )
+  : file( f ),
+    line( l )
+  {
+    Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s:%d: +", file, line );
+  }
+
+  ~_LoggerScope()
+  {
+    Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s:%d: -", file, line );
+  }
+};
+
+#define LOG() _Logger( __FILE__, __LINE__ )
+#define SCOPE() _LoggerScope _l##__LINE__( __FILE__, __LINE__ )
+
+#endif // DALI_INTERNAL_ATSPI_ACCESSIBILITY_COMMON_H
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/accessibility-impl.cpp b/dali/internal/accessibility/tizen-wayland/atspi/accessibility-impl.cpp
new file mode 100644 (file)
index 0000000..30b9179
--- /dev/null
@@ -0,0 +1,778 @@
+/*
+ * Copyright 2019  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
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/object/object-registry.h>
+#include <dali/public-api/object/type-info.h>
+#include <dali/public-api/object/type-registry-helper.h>
+#include <dali/devel-api/actors/actor-devel.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/internal/accessibility/tizen-wayland/atspi/accessibility-impl.h>
+
+using namespace Dali::Accessibility;
+using namespace Dali;
+
+const std::string& Dali::Accessibility::Address::GetBus() const
+{
+  return mBus.empty() && Bridge::GetCurrentBridge() ? Bridge::GetCurrentBridge()->GetBusName() : mBus;
+}
+
+std::string EmptyAccessibleWithAddress::GetRoleName()
+{
+  return "";
+}
+
+std::string Accessible::GetLocalizedRoleName()
+{
+  return GetRoleName();
+}
+
+std::string Accessible::GetRoleName()
+{
+  switch( GetRole() )
+  {
+    case Role::INVALID:
+    {
+      return "invalid";
+    }
+    case Role::ACCELERATOR_LABEL:
+    {
+      return "accelerator label";
+    }
+    case Role::ALERT:
+    {
+      return "alert";
+    }
+    case Role::ANIMATION:
+    {
+      return "animation";
+    }
+    case Role::ARROW:
+    {
+      return "arrow";
+    }
+    case Role::CALENDAR:
+    {
+      return "calendar";
+    }
+    case Role::CANVAS:
+    {
+      return "canvas";
+    }
+    case Role::CHECK_BOX:
+    {
+      return "check box";
+    }
+    case Role::CHECK_MENU_ITEM:
+    {
+      return "check menu item";
+    }
+    case Role::COLOR_CHOOSER:
+    {
+      return "color chooser";
+    }
+    case Role::COLUMN_HEADER:
+    {
+      return "column header";
+    }
+    case Role::COMBO_BOX:
+    {
+      return "combo box";
+    }
+    case Role::DATE_EDITOR:
+    {
+      return "date editor";
+    }
+    case Role::DESKTOP_ICON:
+    {
+      return "desktop icon";
+    }
+    case Role::DESKTOP_FRAME:
+    {
+      return "desktop frame";
+    }
+    case Role::DIAL:
+    {
+      return "dial";
+    }
+    case Role::DIALOG:
+    {
+      return "dialog";
+    }
+    case Role::DIRECTORY_PANE:
+    {
+      return "directory pane";
+    }
+    case Role::DRAWING_AREA:
+    {
+      return "drawing area";
+    }
+    case Role::FILE_CHOOSER:
+    {
+      return "file chooser";
+    }
+    case Role::FILLER:
+    {
+      return "filler";
+    }
+    case Role::FOCUS_TRAVERSABLE:
+    {
+      return "focus traversable";
+    }
+    case Role::FONT_CHOOSER:
+    {
+      return "font chooser";
+    }
+    case Role::FRAME:
+    {
+      return "frame";
+    }
+    case Role::GLASS_PANE:
+    {
+      return "glass pane";
+    }
+    case Role::HTML_CONTAINER:
+    {
+      return "html container";
+    }
+    case Role::ICON:
+    {
+      return "icon";
+    }
+    case Role::IMAGE:
+    {
+      return "image";
+    }
+    case Role::INTERNAL_FRAME:
+    {
+      return "internal frame";
+    }
+    case Role::LABEL:
+    {
+      return "label";
+    }
+    case Role::LAYERED_PANE:
+    {
+      return "layered pane";
+    }
+    case Role::LIST:
+    {
+      return "list";
+    }
+    case Role::LIST_ITEM:
+    {
+      return "list item";
+    }
+    case Role::MENU:
+    {
+      return "menu";
+    }
+    case Role::MENU_BAR:
+    {
+      return "menu bar";
+    }
+    case Role::MENU_ITEM:
+    {
+      return "menu item";
+    }
+    case Role::OPTION_PANE:
+    {
+      return "option pane";
+    }
+    case Role::PAGE_TAB:
+    {
+      return "page tab";
+    }
+    case Role::PAGE_TAB_LIST:
+    {
+      return "page tab list";
+    }
+    case Role::PANEL:
+    {
+      return "panel";
+    }
+    case Role::PASSWORD_TEXT:
+    {
+      return "password text";
+    }
+    case Role::POPUP_MENU:
+    {
+      return "popup menu";
+    }
+    case Role::PROGRESS_BAR:
+    {
+      return "progress bar";
+    }
+    case Role::PUSH_BUTTON:
+    {
+      return "push button";
+    }
+    case Role::RADIO_BUTTON:
+    {
+      return "radio button";
+    }
+    case Role::RADIO_MENU_ITEM:
+    {
+      return "radio menu item";
+    }
+    case Role::ROOT_PANE:
+    {
+      return "root pane";
+    }
+    case Role::ROW_HEADER:
+    {
+      return "row header";
+    }
+    case Role::SCROLL_BAR:
+    {
+      return "scroll bar";
+    }
+    case Role::SCROLL_PANE:
+    {
+      return "scroll pane";
+    }
+    case Role::SEPARATOR:
+    {
+      return "separator";
+    }
+    case Role::SLIDER:
+    {
+      return "slider";
+    }
+    case Role::SPIN_BUTTON:
+    {
+      return "spin button";
+    }
+    case Role::SPLIT_PANE:
+    {
+      return "split pane";
+    }
+    case Role::STATUS_BAR:
+    {
+      return "status bar";
+    }
+    case Role::TABLE:
+    {
+      return "table";
+    }
+    case Role::TABLE_CELL:
+    {
+      return "table cell";
+    }
+    case Role::TABLE_COLUMN_HEADER:
+    {
+      return "table column header";
+    }
+    case Role::TABLE_ROW_HEADER:
+    {
+      return "table row header";
+    }
+    case Role::TEAROFF_MENU_ITEM:
+    {
+      return "tearoff menu item";
+    }
+    case Role::TERMINAL:
+    {
+      return "terminal";
+    }
+    case Role::TEXT:
+    {
+      return "text";
+    }
+    case Role::TOGGLE_BUTTON:
+    {
+      return "toggle button";
+    }
+    case Role::TOOL_BAR:
+    {
+      return "tool bar";
+    }
+    case Role::TOOL_TIP:
+    {
+      return "tool tip";
+    }
+    case Role::TREE:
+    {
+      return "tree";
+    }
+    case Role::TREE_TABLE:
+    {
+      return "tree table";
+    }
+    case Role::UNKNOWN:
+    {
+      return "unknown";
+    }
+    case Role::VIEWPORT:
+    {
+      return "viewport";
+    }
+    case Role::WINDOW:
+    {
+      return "window";
+    }
+    case Role::EXTENDED:
+    {
+      return "extended";
+    }
+    case Role::HEADER:
+    {
+      return "header";
+    }
+    case Role::FOOTER:
+    {
+      return "footer";
+    }
+    case Role::PARAGRAPH:
+    {
+      return "paragraph";
+    }
+    case Role::RULER:
+    {
+      return "ruler";
+    }
+    case Role::APPLICATION:
+    {
+      return "application";
+    }
+    case Role::AUTOCOMPLETE:
+    {
+      return "autocomplete";
+    }
+    case Role::EDITBAR:
+    {
+      return "edit bar";
+    }
+    case Role::EMBEDDED:
+    {
+      return "embedded";
+    }
+    case Role::ENTRY:
+    {
+      return "entry";
+    }
+    case Role::CHART:
+    {
+      return "chart";
+    }
+    case Role::CAPTION:
+    {
+      return "caution";
+    }
+    case Role::DOCUMENT_FRAME:
+    {
+      return "document frame";
+    }
+    case Role::HEADING:
+    {
+      return "heading";
+    }
+    case Role::PAGE:
+    {
+      return "page";
+    }
+    case Role::SECTION:
+    {
+      return "section";
+    }
+    case Role::REDUNDANT_OBJECT:
+    {
+      return "redundant object";
+    }
+    case Role::FORM:
+    {
+      return "form";
+    }
+    case Role::LINK:
+    {
+      return "link";
+    }
+    case Role::INPUT_METHOD_WINDOW:
+    {
+      return "input method window";
+    }
+    case Role::TABLE_ROW:
+    {
+      return "table row";
+    }
+    case Role::TREE_ITEM:
+    {
+      return "tree item";
+    }
+    case Role::DOCUMENT_SPREADSHEET:
+    {
+      return "document spreadsheet";
+    }
+    case Role::DOCUMENT_PRESENTATION:
+    {
+      return "document presentation";
+    }
+    case Role::DOCUMENT_TEXT:
+    {
+      return "document text";
+    }
+    case Role::DOCUMENT_WEB:
+    {
+      return "document web";
+    }
+    case Role::DOCUMENT_EMAIL:
+    {
+      return "document email";
+    }
+    case Role::COMMENT:
+    {
+      return "comment";
+    }
+    case Role::LIST_BOX:
+    {
+      return "list box";
+    }
+    case Role::GROUPING:
+    {
+      return "grouping";
+    }
+    case Role::IMAGE_MAP:
+    {
+      return "image map";
+    }
+    case Role::NOTIFICATION:
+    {
+      return "notification";
+    }
+    case Role::INFO_BAR:
+    {
+      return "info bar";
+    }
+    case Role::LEVEL_BAR:
+    {
+      return "level bar";
+    }
+    case Role::TITLE_BAR:
+    {
+      return "title bar";
+    }
+    case Role::BLOCK_QUOTE:
+    {
+      return "block quote";
+    }
+    case Role::AUDIO:
+    {
+      return "audio";
+    }
+    case Role::VIDEO:
+    {
+      return "video";
+    }
+    case Role::DEFINITION:
+    {
+      return "definition";
+    }
+    case Role::ARTICLE:
+    {
+      return "article";
+    }
+    case Role::LANDMARK:
+    {
+      return "landmark";
+    }
+    case Role::LOG:
+    {
+      return "log";
+    }
+    case Role::MARQUEE:
+    {
+      return "marquee";
+    }
+    case Role::MATH:
+    {
+      return "math";
+    }
+    case Role::RATING:
+    {
+      return "rating";
+    }
+    case Role::TIMER:
+    {
+      return "timer";
+    }
+    case Role::STATIC:
+    {
+      return "static";
+    }
+    case Role::MATH_FRACTION:
+    {
+      return "math fraction";
+    }
+    case Role::MATH_ROOT:
+    {
+      return "math root";
+    }
+    case Role::SUBSCRIPT:
+    {
+      return "subscript";
+    }
+    case Role::SUPERSCRIPT:
+    {
+      return "superscript";
+    }
+    case Role::MAX_COUNT:
+    {
+      break;
+    }
+  }
+  return "";
+}
+
+Dali::Actor Accessible::GetCurrentlyHighlightedActor()
+{
+  return IsUp() ? Bridge::GetCurrentBridge()->data->currentlyHighlightedActor : Dali::Actor{};
+}
+
+void Accessible::SetCurrentlyHighlightedActor(Dali::Actor actor)
+{
+  if (IsUp())
+  {
+    Bridge::GetCurrentBridge()->data->currentlyHighlightedActor = actor;
+  }
+}
+
+Dali::Actor Accessible::GetHighlightActor()
+{
+  return IsUp() ? Bridge::GetCurrentBridge()->data->highlightActor : Dali::Actor{};
+}
+
+void Accessible::SetHighlightActor(Dali::Actor actor)
+{
+  if (IsUp())
+  {
+    Bridge::GetCurrentBridge()->data->highlightActor = actor;
+  }
+}
+
+void Bridge::ForceDown()
+{
+  auto highlighted = Accessible::GetCurrentlyHighlightedActor();
+  if( highlighted )
+  {
+    auto p = dynamic_cast< Component* >( Accessible::Get( highlighted ) );
+    if( p )
+    {
+      p->ClearHighlight();
+    }
+  }
+  data = {};
+}
+
+void Bridge::SetIsOnRootLevel( Accessible* o )
+{
+  o->isOnRootLevel = true;
+}
+
+namespace
+{
+class NonControlAccessible : public virtual Accessible, public virtual Collection, public virtual Component
+{
+public:
+  Dali::Actor actor;
+  bool root = false;
+
+  NonControlAccessible( Dali::Actor actor, bool root ) : actor( actor ), root( root )
+  {
+  }
+
+  Dali::Rect<> GetExtents( Dali::Accessibility::CoordType ctype ) override
+  {
+    Vector2 screenPosition = actor.GetProperty( Dali::DevelActor::Property::SCREEN_POSITION ).Get< Vector2 >();
+    Vector3 size = actor.GetCurrentSize() * actor.GetCurrentWorldScale();
+    bool positionUsesAnchorPoint = actor.GetProperty( Dali::DevelActor::Property::POSITION_USES_ANCHOR_POINT ).Get< bool >();
+    Vector3 anchorPointOffSet = size * ( positionUsesAnchorPoint ? actor.GetCurrentAnchorPoint() : AnchorPoint::TOP_LEFT );
+    Vector2 position = Vector2( screenPosition.x - anchorPointOffSet.x, screenPosition.y - anchorPointOffSet.y );
+
+    return { position.x, position.y, size.x, size.y };
+  }
+  Dali::Accessibility::ComponentLayer GetLayer() override
+  {
+    return Dali::Accessibility::ComponentLayer::WINDOW;
+  }
+  int16_t GetMdiZOrder()
+  {
+    return 0;
+  }
+  double GetAlpha()
+  {
+    return 0;
+  }
+  bool GrabFocus() override
+  {
+    return false;
+  }
+  bool GrabHighlight() override
+  {
+    return false;
+  }
+  bool ClearHighlight() override
+  {
+    return false;
+  }
+  int GetHighlightIndex() override
+  {
+    return 0;
+  }
+  bool IsScrollable() override
+  {
+    return false;
+  }
+  std::string GetName() override
+  {
+    return actor.GetName();
+  }
+  std::string GetDescription() override
+  {
+    return "";
+  }
+  Accessible* GetParent() override
+  {
+    if( GetIsOnRootLevel() )
+    {
+      auto b = GetBridgeData();
+      return b->bridge->GetApplication();
+    }
+    return Get( actor.GetParent() );
+  }
+  size_t GetChildCount() override
+  {
+    return static_cast< size_t >( actor.GetChildCount() );
+  }
+  Accessible* GetChildAtIndex( size_t index ) override
+  {
+    auto s = static_cast< size_t >( actor.GetChildCount() );
+    if( index >= s )
+    {
+      throw std::domain_error{"invalid index " + std::to_string( index ) + " for object with " + std::to_string( s ) + " children"};
+    }
+    return Get( actor.GetChildAt( static_cast< unsigned int >( index ) ) );
+  }
+  size_t GetIndexInParent() override
+  {
+    auto parent = actor.GetParent();
+    if( !parent )
+    {
+      return 0;
+    }
+    auto size = static_cast< size_t >( parent.GetChildCount() );
+    for( auto i = 0u; i < size; ++i )
+    {
+      if( parent.GetChildAt( i ) == actor )
+      {
+        return i;
+      }
+    }
+    throw std::domain_error{"actor is not a child of it's parent"};
+  }
+  Role GetRole() override
+  {
+    return root ? Role::WINDOW : Role::REDUNDANT_OBJECT;
+  }
+  States GetStates() override
+  {
+    States s;
+    if( root )
+    {
+      s[State::HIGHLIGHTABLE] = true;
+      s[State::ENABLED] = true;
+      s[State::SENSITIVE] = true;
+      s[State::SHOWING] = true;
+      s[State::VISIBLE] = true;
+      s[State::ACTIVE] = true;
+    }
+    else
+    {
+      auto t = GetParent()->GetStates();
+      s[State::SHOWING] = t[State::SHOWING];
+      s[State::VISIBLE] = t[State::VISIBLE];
+    }
+    return s;
+  }
+  Attributes GetAttributes() override
+  {
+    Dali::TypeInfo type;
+    actor.GetTypeInfo( type );
+    return { {"t", type.GetName()}, };
+  }
+
+  bool DoGesture(const GestureInfo &gestureInfo) override
+  {
+    return false;
+  }
+
+  std::vector<Relation> GetRelationSet() override
+  {
+    return {};
+  }
+};
+
+using NonControlAccessiblesType = std::unordered_map< const Dali::RefObject*, std::unique_ptr< NonControlAccessible > >;
+
+NonControlAccessiblesType nonControlAccessibles;
+
+std::function< Accessible*( Dali::Actor ) > convertingFunctor = []( Dali::Actor ) -> Accessible*
+{
+  return nullptr;
+};
+
+}
+
+void Accessible::RegisterControlAccessibilityGetter( std::function< Accessible*( Dali::Actor ) > functor )
+{
+  convertingFunctor = functor;
+}
+
+Accessible* Accessible::Get( Dali::Actor actor, bool root )
+{
+  if( !actor )
+  {
+    return nullptr;
+  }
+  auto accessible = convertingFunctor( actor );
+  if( !accessible )
+  {
+    if( nonControlAccessibles.empty() )
+    {
+      auto registry = Dali::Stage::GetCurrent().GetObjectRegistry();
+      registry.ObjectDestroyedSignal().Connect( []( const Dali::RefObject* obj )
+      {
+        nonControlAccessibles.erase( obj );
+      }
+      );
+    }
+    auto it = nonControlAccessibles.emplace( &actor.GetBaseObject(), nullptr );
+    if( it.second )
+    {
+      it.first->second.reset( new NonControlAccessible( actor, root ) );
+    }
+    accessible = it.first->second.get();
+  }
+  return accessible;
+}
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/accessibility-impl.h b/dali/internal/accessibility/tizen-wayland/atspi/accessibility-impl.h
new file mode 100644 (file)
index 0000000..534cf70
--- /dev/null
@@ -0,0 +1,1028 @@
+#ifndef DALI_INTERNAL_ATSPI_ACCESSIBILITY_IMPL_H
+#define DALI_INTERNAL_ATSPI_ACCESSIBILITY_IMPL_H
+
+/*
+ * Copyright (c) 2019 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/actors/actor.h>
+#include <dali/public-api/math/rect.h>
+#include <atomic>
+#include <bitset>
+#include <exception>
+#include <functional>
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+#include <stdexcept>
+
+//INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/atspi-accessibility.h>
+#include <dali/internal/accessibility/tizen-wayland/atspi/accessibility.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+namespace Accessibility
+{
+class Accessible;
+class Text;
+class Value;
+class Component;
+class Collection;
+class Action;
+
+/**
+ * @brief Base class for different accessibility bridges
+ *
+ * Bridge is resposible for initializing and managing connection on accessibility bus.
+ * Accessibility clients will not get any information about UI without initialized and upraised bridge.
+ * Concrete implementation depends on the accessibility technology available on the platform.
+ *
+ * @note This class is singleton.
+ */
+struct Bridge
+{
+  enum class ForceUpResult
+  {
+    JUST_STARTED,
+    ALREADY_UP
+  };
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~Bridge() = default;
+
+  /**
+   * @brief Get bus name which bridge is initialized on
+   */
+  virtual const std::string& GetBusName() const = 0;
+
+  /**
+   * @brief Registers top level window
+   *
+   * Hierarchy of objects visible for accessibility clients is based on tree-like
+   * structure created from Actors objects. This method allows to connect chosen
+   * object as direct ancestor of application and therefore make it visible for
+   * accessibility clients.
+   */
+  virtual void AddTopLevelWindow( Accessible* ) = 0;
+
+  /**
+   * @brief Removes top level window
+   *
+   * Hierarchy of objects visible for accessibility clients is based on tree-like
+   * structure created from Actors objects. This method removes previously added
+   * window from visible accessibility objects.
+   */
+  virtual void RemoveTopLevelWindow( Accessible* ) = 0;
+
+  /**
+   * @brief Adds popup window
+   *
+   * Hierarchy of objects visible for accessibility clients is based on tree-like
+   * structure created from Actors objects. This method adds new popup to the tree.
+   */
+  virtual void AddPopup( Accessible* ) = 0;
+
+  /**
+   * @brief Removes popup window
+   *
+   * Hierarchy of objects visible for accessibility clients is based on tree-like
+   * structure created from Actors objects. This method removes previously added
+   * popup window.
+   */
+  virtual void RemovePopup( Accessible* ) = 0;
+
+  /**
+   * @brief Set name of current application which will be visible on accessibility bus
+   */
+  virtual void SetApplicationName( std::string ) = 0;
+
+  /**
+   * @brief Get object being root of accessibility tree
+   *
+   * @return handler to accessibility object
+   */
+  virtual Accessible* GetApplication() const = 0;
+
+  /**
+   * @brief Find an object in accessibility tree
+   *
+   * @param[in] s path to object
+   *
+   * @return handler to accessibility object
+   */
+  virtual Accessible* FindByPath( const std::string& s) const = 0;
+
+  /**
+   * @brief Show application on accessibility bus
+   */
+  virtual void ApplicationShown() = 0;
+
+  /**
+   * @brief Hide application on accessibility bus
+   */
+  virtual void ApplicationHidden() = 0;
+
+  /**
+   * @brief Initialize accessibility bus
+   */
+  virtual void Initialize() = 0;
+
+  /**
+   * @brief Terminate accessibility bus
+   */
+  virtual void Terminate() = 0;
+
+  /**
+   * @brief This method is called, when bridge is being activated.
+   */
+  virtual ForceUpResult ForceUp()
+  {
+    if( data )
+    {
+      return ForceUpResult::ALREADY_UP;
+    }
+    data = std::make_shared< Data >();
+    data->bridge = this;
+    return ForceUpResult::JUST_STARTED;
+  }
+
+  /**
+   * @brief This method is called, when bridge is being deactivated.
+   */
+  virtual void ForceDown() = 0;
+
+  /**
+   * @brief Check if bridge is activated or not.
+   * @return True if brige is activated.
+   */
+  bool IsUp() const
+  {
+    return bool(data);
+  }
+
+  /**
+   * @brief Emits caret-moved event on at-spi bus.
+   **/
+  virtual void EmitCaretMoved( Accessible* obj, unsigned int cursorPosition ) = 0;
+
+  /**
+   * @brief Emits active-descendant-changed event on at-spi bus.
+   **/
+  virtual void EmitActiveDescendantChanged( Accessible* obj, Accessible *child ) = 0;
+
+  /**
+   * @brief Emits text-changed event on at-spi bus.
+   **/
+  virtual void EmitTextChanged( Accessible* obj, TextChangedState state, unsigned int position, unsigned int length, const std::string &content ) = 0;
+
+  /**
+   * @brief Emits state-changed event on at-spi bus.
+   **/
+  virtual void EmitStateChanged( Accessible* obj, State state, int val1, int val2 = 0 ) = 0;
+
+  /**
+   * @brief Emits window event on at-spi bus.
+   **/
+  virtual void Emit( Accessible* obj, WindowEvent we, unsigned int detail1 = 0 ) = 0;
+
+  /**
+   * @brief Emits property-changed event on at-spi bus.
+   **/
+  virtual void Emit( Accessible* obj, ObjectPropertyChangeEvent event ) = 0;
+
+  /**
+   * @brief Emits bounds-changed event on at-spi bus.
+   **/
+  virtual void EmitBoundsChanged( Accessible* obj, Rect<> rect ) = 0;
+
+  /**
+   * @brief Emits key event on at-spi bus.
+   *
+   * Screen-reader might receive this event and reply, that given keycode is consumed. In that case
+   * further processing of the keycode should be ignored.
+   **/
+  virtual Consumed Emit( KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText ) = 0;
+
+  /**
+   * @brief Reads given text by screen reader
+   *
+   * @param text The text to read
+   * @param discardable If TRUE, reading can be discarded by subsequent reading requests,
+   * if FALSE the reading must finish before next reading request can be started
+   * @param callback the callback function that is called on reading signals emitted
+   * during processing of this reading request.
+   * Callback can be one of the following signals:
+   * ReadingCancelled, ReadingStopped, ReadingSkipped
+   */
+  virtual void Say( const std::string& text, bool discardable, std::function<void(std::string)> callback ) = 0;
+
+  /**
+   * @brief Force accessibility client to pause.
+   */
+  virtual void Pause() = 0;
+
+  /**
+   * @brief Force accessibility client to resume.
+   */
+  virtual void Resume() = 0;
+
+  /**
+   * @brief Get screen reader status.
+   */
+  virtual bool GetScreenReaderEnabled() = 0;
+
+  /**
+   * @brief Get ATSPI status.
+   */
+  virtual bool GetIsEnabled() = 0;
+
+  /**
+   * @brief Returns instance of bridge singleton object.
+   **/
+  static Bridge* GetCurrentBridge();
+
+protected:
+  struct Data
+  {
+    std::unordered_set< Accessible* > knownObjects;
+    std::string busName;
+    Bridge* bridge = nullptr;
+    Actor highlightActor, currentlyHighlightedActor;
+  };
+  std::shared_ptr< Data > data;
+  friend class Accessible;
+
+  /**
+   * @brief Registers accessible object to be known in bridge object
+   *
+   * Bridge must known about all currently alive accessible objects, as some requst
+   * might come and object will be identified by number id (it's memory address).
+   * To avoid memory corruption number id is checked against set of known objects.
+   **/
+  void RegisterOnBridge( Accessible* );
+
+  /**
+   * @brief Tells bridge, that given object is considered root (doesn't have any parents).
+   *
+   * All root objects will have the same parent - application object. Application object
+   * is controlled by bridge and private.
+   **/
+  void SetIsOnRootLevel( Accessible* );
+};
+
+/**
+ * @brief Check if ATSPI is activated or not.
+ * @return True if ATSPI is activated.
+ */
+inline bool IsUp()
+{
+  if( Bridge::GetCurrentBridge() == nullptr )
+  {
+    return false;
+  }
+  if( Bridge::GetCurrentBridge()->GetIsEnabled() == false )
+  {
+    return false;
+  }
+  return Bridge::GetCurrentBridge()->IsUp();
+}
+
+/**
+ * @brief Basic interface implemented by all accessibility objects
+ */
+class Accessible
+{
+public:
+  virtual ~Accessible();
+
+  using utf8_t = unsigned char;
+
+  /**
+   * @brief Calculaties word boundaries in given utf8 text.
+   *
+   * s and length represents source text pointer and it's length respectively. langauge represents
+   * language to use. Word boundaries are returned as non-zero values in table breaks, which
+   * must be of size at least length.
+   **/
+  void FindWordSeparationsUtf8( const utf8_t *s, size_t length, const char *language, char *breaks );
+
+  /**
+   * @brief Calculaties line boundaries in given utf8 text.
+   *
+   * s and length represents source text pointer and it's length respectively. langauge represents
+   * language to use. Line boundaries are returned as non-zero values in table breaks, which
+   * must be of size at least length.
+   **/
+  void FindLineSeparationsUtf8( const utf8_t *s, size_t length, const char *language, char *breaks );
+
+  /**
+   * @brief Helper function for emiting active-descendant-changed event
+   **/
+  void EmitActiveDescendantChanged( Accessible* obj, Accessible *child );
+
+  /**
+   * @brief Helper function for emiting state-changed event
+   **/
+  void EmitStateChanged( State state, int newValue1, int newValue2 = 0 );
+
+  /**
+   * @brief Helper function for emiting bounds-changed event
+   **/
+  void EmitBoundsChanged( Rect<> rect );
+
+  /**
+   * @brief Emit "showing" event.
+   * The method inform accessibility clients about "showing" state
+   *
+   * @param[in] showing flag pointing if object is showing
+   */
+  void EmitShowing( bool showing );
+
+  /**
+   * @brief Emit "visible" event.
+   * The method inform accessibility clients about "visible" state
+   *
+   * @param[in] visible flag pointing if object is visible
+   */
+  void EmitVisible( bool visible );
+
+  /**
+   * @brief Emit "highlighted" event.
+   * The method inform accessibility clients about "highlighted" state
+   *
+   * @param[in] set flag pointing if object is highlighted
+   */
+  void EmitHighlighted( bool set );
+
+  /**
+   * @brief Emit "focused" event.
+   * The method inform accessibility clients about "focused" state
+   *
+   * @param[in] set flag pointing if object is focused
+   */
+  void EmitFocused( bool set );
+
+  /**
+   * @brief Emit "text inserted" event
+   *
+   * @param[in] position caret position
+   * @param[in] length text length
+   * @param[in] content inserted text
+   */
+  void EmitTextInserted( unsigned int position, unsigned int length, const std::string &content );
+
+  /**
+   * @brief Emit "text deleted" event
+   *
+   * @param[in] position caret position
+   * @param[in] length text length
+   * @param[in] content deleted text
+   */
+  void EmitTextDeleted( unsigned int position, unsigned int length, const std::string &content );
+
+  /**
+   * @brief Emit "caret moved" event
+   *
+   * @param[in] cursorPosition new caret position
+   */
+  void EmitTextCaretMoved( unsigned int cursorPosition );
+
+  /**
+   * @brief Emit "highlighted" event
+   *
+   * @param[in] we enumerated window event
+   * @param[in] detail1 additional parameter which interpretation depends on chosen event
+   */
+  void Emit( WindowEvent we, unsigned int detail1 = 0 );
+
+  /**
+   * @brief Emits property-changed event
+   * @param[in] Property changed event
+   **/
+  void Emit( ObjectPropertyChangeEvent event );
+
+  /**
+   * @brief Get accessibility name
+   *
+   * @return string with name
+   */
+  virtual std::string GetName() = 0;
+
+  /**
+   * @brief Get accessibility description
+   *
+   * @return string with description
+   */
+  virtual std::string GetDescription() = 0;
+
+  /**
+   * @brief Get parent
+   *
+   * @return handler to accessibility object
+   */
+  virtual Accessible* GetParent() = 0;
+
+  /**
+   * @brief Get count of children
+   *
+   * @return unsigned integer value
+   */
+  virtual size_t GetChildCount() = 0;
+
+  /**
+   * @brief Get collection with all children
+   *
+   * @return collection of accessibility objects
+   */
+  virtual std::vector< Accessible* > GetChildren();
+
+  /**
+   * @brief Get nth child
+   *
+   * @return accessibility object
+   */
+  virtual Accessible* GetChildAtIndex( size_t index ) = 0;
+
+  /**
+   * @brief Get index that current object has in its parent's children collection
+   *
+   * @return unsigned integer index
+   */
+  virtual size_t GetIndexInParent() = 0;
+
+  /**
+   * @brief Get accessibility role
+   *
+   * @return Role enumeration
+   *
+   * @see Dali::Accessibility::Role
+   */
+  virtual Role GetRole() = 0;
+
+  /**
+   * @brief Get name of accessibility role
+   *
+   * @return string with human readable role converted from enumeration
+   *
+   * @see Dali::Accessibility::Role
+   * @see Accessibility::Accessible::GetRole
+   */
+  virtual std::string GetRoleName();
+
+  /**
+   * @brief Get localized name of accessibility role
+   *
+   * @return string with human readable role translated according to current
+   * translation domain
+   *
+   * @see Dali::Accessibility::Role
+   * @see Accessibility::Accessible::GetRole
+   * @see Accessibility::Accessible::GetRoleName
+   *
+   * @note translation is not supported in this version
+   */
+  virtual std::string GetLocalizedRoleName();
+
+  /**
+   * @brief Get accessibility states
+   *
+   * @return collection of states
+   *
+   * @note States class is instatation of ArrayBitset template class
+   *
+   * @see Dali::Accessibility::State
+   * @see Dali::Accessibility::ArrayBitset
+   */
+  virtual States GetStates() = 0;
+
+  /**
+   * @brief Get accessibility attributes
+   *
+   * @return map of attributes and their values
+   */
+  virtual Attributes GetAttributes() = 0;
+
+  /**
+   * @brief Check if this is proxy
+   *
+   * @return True if this is proxy
+   */
+  virtual bool IsProxy();
+
+  /**
+   * @brief Get unique address on accessibility bus
+   *
+   * @return class containing address
+   *
+   * @see Dali::Accessibility::Address
+   */
+  virtual Address GetAddress();
+
+  /**
+   * @brief Get accessibility object, which is "default label" for this object
+   */
+  virtual Accessible* GetDefaultLabel();
+
+  /**
+   * @brief Depute an object to perform provided gesture
+   *
+   * @param[in] gestureInfo structure describing the gesture
+   *
+   * @return true on success, false otherwise
+   *
+   * @see Dali::Accessibility::GestureInfo
+   */
+  virtual bool DoGesture(const GestureInfo &gestureInfo) = 0;
+
+  /**
+   * @brief Re-emits selected states of an Accessibility Object
+   *
+   * @param[in] states chosen states to re-emit
+   * @param[in] doRecursive if true all children of the Accessibility Object will also re-emit the states
+   */
+  void NotifyAccessibilityStateChange( Dali::Accessibility::States states, bool doRecursive );
+
+  /**
+   * @brief Get information about current object and all relations that connects
+   * it with other accessibility objects
+   *
+   * @return iterable collection of Relation objects
+   *
+   * @see Dali::Accessibility::Relation
+   */
+  virtual std::vector<Relation> GetRelationSet() = 0;
+
+  /**
+   * @brief Get all implemented interfaces
+   *
+   * @return collection of strings with implemented interfaces
+   */
+  std::vector< std::string > GetInterfaces();
+
+  /**
+   * @brief Check if object is on root level
+   */
+  bool GetIsOnRootLevel() const { return isOnRootLevel; }
+
+  /**
+   * @brief The method registers functor resposible for converting Actor into Accessible
+   * @param functor returning Accessible handle from Actor object
+   */
+  static void RegisterControlAccessibilityGetter( std::function< Accessible*( Dali::Actor ) > functor);
+
+  /**
+   * @brief Acquire Accessible object from Actor object
+   *
+   * @param[in] actor Actor object
+   * @param[in] root true, if it's top level object (window)
+   *
+   * @return handle to Accessible object
+   */
+  static Accessible* Get( Dali::Actor actor, bool root = false );
+
+protected:
+  Accessible();
+  Accessible( const Accessible& ) = delete;
+  Accessible( Accessible&& ) = delete;
+  Accessible& operator=( const Accessible& ) = delete;
+  Accessible& operator=( Accessible&& ) = delete;
+  std::shared_ptr< Bridge::Data > GetBridgeData();
+  static Dali::Actor GetHighlightActor();
+  static void SetHighlightActor(Dali::Actor actor);
+  static Dali::Actor GetCurrentlyHighlightedActor();
+  static void SetCurrentlyHighlightedActor(Dali::Actor);
+
+private:
+  friend class Bridge;
+
+  std::weak_ptr< Bridge::Data > bridgeData;
+  bool isOnRootLevel = false;
+};
+
+/**
+ * @brief Interface enabling to perform provided actions
+ */
+class Action : public virtual Accessible
+{
+public:
+  /**
+   * @brief Get name of action with given index
+   *
+   * @param[in] index index of action
+   *
+   * @return string with name of action
+   */
+  virtual std::string GetActionName( size_t index ) = 0;
+
+  /**
+   * @brief Get translated name of action with given index
+   *
+   * @param[in] index index of action
+   *
+   * @return string with name of action translated according to current translation domain
+   *
+   * @note translation is not supported in this version
+   */
+  virtual std::string GetLocalizedActionName( size_t index ) = 0;
+
+  /**
+   * @brief Get description of action with given index
+   *
+   * @param[in] index index of action
+   *
+   * @return string with description of action
+   */
+  virtual std::string GetActionDescription( size_t index ) = 0;
+
+  /**
+   * @brief Get key code binded to action with given index
+   *
+   * @param[in] index index of action
+   *
+   * @return string with key name
+   */
+  virtual std::string GetActionKeyBinding( size_t index ) = 0;
+
+  /**
+   * @brief Get number of provided actions
+   *
+   * @return unsigned integer with number of actions
+   */
+  virtual size_t GetActionCount() = 0;
+
+  /**
+   * @brief Perform an action with given index
+   *
+   * @param index index of action
+   *
+   * @return true on success, false otherwise
+   */
+  virtual bool DoAction( size_t index ) = 0;
+
+  /**
+   * @brief Perform an action with given name
+   *
+   * @param name name of action
+   *
+   * @return true on success, false otherwise
+   */
+  virtual bool DoAction( const std::string& name ) = 0;
+
+};
+
+/**
+ * @brief Interface enabling advanced quering of accessibility objects
+ *
+ * @note since all mathods can be implemented inside bridge,
+ * none methods have to be overrided
+ */
+class Collection : public virtual Accessible
+{
+public:
+};
+
+/**
+ * @brief Interface representing objects having screen coordinates
+ */
+class Component : public virtual Accessible
+{
+public:
+  /**
+   * @brief Get rectangle describing size
+   *
+   * @param[in] ctype enumeration with type of coordinate systems
+   *
+   * @return Rect<> object
+   *
+   * @see Dali::Rect
+   */
+  virtual Rect<> GetExtents( CoordType ctype ) = 0;
+
+  /**
+   * @brief Get layer current object is localized on
+   *
+   * @return enumeration pointing layer
+   *
+   * @see Dali::Accessibility::ComponentLayer
+   */
+  virtual ComponentLayer GetLayer() = 0;
+
+  /**
+   * @brief Get value of z-order
+   *
+   * @return value of z-order
+   */
+  virtual int16_t GetMdiZOrder() = 0;
+
+  /**
+   * @brief Set current object as "focused"
+   *
+   * @return true on success, false otherwise
+   */
+  virtual bool GrabFocus() = 0;
+
+  /**
+   * @brief Get value of alpha channel
+   *
+   * @return alpha channel value in range [0.0, 1.0]
+   */
+  virtual double GetAlpha() = 0;
+
+  /**
+   * @brief Set current object as "highlighted"
+   *
+   * The method assings "highlighted" state, simultaneously removing it
+   * from currently highlighted object.
+   *
+   * @return true on success, false otherwise
+   */
+  virtual bool GrabHighlight() = 0;
+
+  /**
+   * @brief Set current object as "unhighlighted"
+   *
+   * The method removes "highlighted" state from object.
+   *
+   * @return true on success, false otherwise
+   *
+   * @see Dali:Accessibility::State
+   */
+  virtual bool ClearHighlight() = 0;
+
+  /**
+   * @brief Get index of "highlighted" object
+   *
+   * @return The index of "highlighted" object
+   *
+   * @see Dali:Accessibility::State
+   */
+  virtual int GetHighlightIndex() = 0;
+
+  /**
+   * @brief Check whether object can be scrolled
+   *
+   * @return true if object is scrollable, false otherwise
+   *
+   * @see Dali:Accessibility::State
+   */
+  virtual bool IsScrollable();
+
+  /**
+   * @brief Get Accessible object containing given point
+   *
+   * @param[in] p two-dimensional point
+   * @param[in] ctype enumeration with type of coordinate system
+   *
+   * @return handle to last child of current object which contains given point
+   *
+   * @see Dali::Accessibility::Point
+   */
+  virtual Accessible* GetAccessibleAtPoint( Point p, CoordType ctype );
+
+  /**
+   * @brief Check if current object contains given point
+   *
+   * @param[in] p two-dimensional point
+   * @param[in] ctype enumeration with type of coordinate system
+   *
+   * @return handle to Accessible object
+   *
+   * @see Dali::Accessibility::Point
+   */
+  virtual bool Contains( Point p, CoordType ctype );
+};
+
+/**
+ * @brief Interface representing objects which can store numeric value
+ */
+class Value : public virtual Accessible
+{
+public:
+  /**
+   * @brief Get the lowest possible value
+   *
+   * @return double value
+  */
+  virtual double GetMinimum() = 0;
+
+  /**
+   * @brief Get current value
+   *
+   * @return double value
+  */
+  virtual double GetCurrent() = 0;
+
+  /**
+   * @brief Get the highest possible value
+   *
+   * @return double value
+  */
+  virtual double GetMaximum() = 0;
+
+  /**
+   * @brief Set value
+   *
+   * @param[in] val double value
+   *
+   * @return true if value could have been assigned, false otherwise
+  */
+  virtual bool SetCurrent( double val) = 0;
+
+  /**
+   * @brief Get the lowest increment that can be distinguished
+   *
+   * @return double value
+  */
+  virtual double GetMinimumIncrement() = 0;
+};
+
+/**
+ * @brief Interface representing objects which can store immutable texts
+ *
+ * @see Dali::Accessibility::EditableText
+ */
+class Text : public virtual Accessible
+{
+public:
+  /**
+   * @brief Get stored text in given range
+   *
+   * @param[in] startOffset index of first character
+   * @param[in] endOffset index of first character after the last one expected
+   *
+   * @return substring of stored text
+   */
+  virtual std::string GetText( size_t startOffset, size_t endOffset ) = 0;
+
+  /**
+   * @brief Get number of all stored characters
+   *
+   * @return number of characters
+   */
+  virtual size_t GetCharacterCount() = 0;
+
+  /**
+   * @brief Get caret offset
+   *
+   * @return Value of caret offset
+   */
+  virtual size_t GetCaretOffset() = 0;
+
+  /**
+   * @brief Set caret offset
+   *
+   * @param[in] caret offset
+   *
+   * @return True if successful
+   */
+  virtual bool SetCaretOffset(size_t offset) = 0;
+
+  /**
+   * @brief Get substring of stored text truncated in concrete gradation
+   *
+   * @param[in] offset position in stored text
+   * @param[in] boundary enumeration describing text gradation
+   *
+   * @return Range structure containing acquired text and offsets in original string
+   *
+   * @see Dali::Accessibility::Range
+   */
+  virtual Range GetTextAtOffset( size_t offset, TextBoundary boundary ) = 0;
+
+  /**
+   * @brief Get selected text
+   *
+   * @param[in] selectionNum selection index
+   * @note Currently only one selection (i.e. with index = 0) is supported
+   *
+   * @return Range structure containing acquired text and offsets in original string
+   *
+   * @see Dali::Accessibility::Range
+   */
+  virtual Range GetSelection( size_t selectionNum ) = 0;
+
+  /**
+   * @brief Remove selection
+   *
+   * @param[in] selectionNum selection index
+   * @note Currently only one selection (i.e. with index = 0) is supported
+   *
+   * @return bool on success, false otherwise
+   */
+  virtual bool RemoveSelection( size_t selectionNum ) = 0;
+
+  /**
+   * @brief Get selected text
+   *
+   * @param[in] selectionNum selection index
+   * @param[in] startOffset index of first character
+   * @param[in] endOffset index of first character after the last one expected
+   *
+   * @note Currently only one selection (i.e. with index = 0) is supported
+   *
+   * @return true on success, false otherwise
+   */
+  virtual bool SetSelection( size_t selectionNum, size_t startOffset, size_t endOffset ) = 0;
+};
+
+/**
+ * @brief Interface representing objects which can store editable texts
+ *
+ * @note Paste method is entirely implemented inside bridge
+ *
+ * @see Dali::Accessibility::EditableText
+ */
+class EditableText : public virtual Accessible
+{
+public:
+  /**
+   * @brief Copy text in range to system clipboard
+   *
+   * @param[in] startPosition index of first character
+   * @param[in] endPosition index of first character after the last one expected
+   *
+   * @return true on success, false otherwise
+   */
+  virtual bool CopyText( size_t startPosition, size_t endPosition ) = 0;
+
+  /**
+   * @brief Cut text in range to system clipboard
+   *
+   * @param[in] startPosition index of first character
+   * @param[in] endPosition index of first character after the last one expected
+   *
+   * @return true on success, false otherwise
+   */
+  virtual bool CutText( size_t startPosition, size_t endPosition ) = 0;
+};
+
+/**
+ * @brief minimalistic, always empty Accessible object with settable address
+ *
+ * For those situations, where you want to return address in different bridge
+ * (embedding for example), but the object itself ain't planned to be used otherwise.
+ * This object has null parent, no children, empty name and so on
+ */
+class EmptyAccessibleWithAddress : public virtual Accessible
+{
+public:
+  EmptyAccessibleWithAddress() = default;
+  EmptyAccessibleWithAddress( Address address ) : address( std::move( address ) ) {}
+
+  void SetAddress( Address address ) { this->address = std::move( address ); }
+
+  std::string GetName() override { return ""; }
+  std::string GetDescription() override { return ""; }
+  Accessible* GetParent() override { return nullptr; }
+  size_t GetChildCount() override { return 0; }
+  std::vector< Accessible* > GetChildren() override { return {}; }
+  Accessible* GetChildAtIndex( size_t index ) override
+  {
+    throw std::domain_error{"out of bounds index (" + std::to_string( index ) + ") - no children"};
+  }
+  size_t GetIndexInParent() override { return static_cast< size_t >( -1 ); }
+  Role GetRole() override { return {}; }
+  std::string GetRoleName() override;
+  States GetStates() override { return {}; }
+  Attributes GetAttributes() override { return {}; }
+  Address GetAddress() override
+  {
+    return address;
+  }
+  bool DoGesture(const GestureInfo &gestureInfo) override
+  {
+    return false;
+  }
+  std::vector<Relation> GetRelationSet() override
+  {
+    return {};
+  }
+
+private:
+  Address address;
+};
+
+}
+}
+
+#endif // DALI_INTERNAL_ATSPI_ACCESSIBILITY_IMPL_H
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/accessibility-optional.h b/dali/internal/accessibility/tizen-wayland/atspi/accessibility-optional.h
new file mode 100644 (file)
index 0000000..d7abacd
--- /dev/null
@@ -0,0 +1,280 @@
+#ifndef DALI_INTERNAL_ATSPI_ACCESSIBILITY_OPTIONAL_H
+#define DALI_INTERNAL_ATSPI_ACCESSIBILITY_OPTIONAL_H
+
+/*
+ * Copyright 2019  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 <cassert>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+/**
+ * Minimalistic implementation of standard library std::optional (c++17) for c++11 compiler.
+ *
+ * After project conversion to C++17 standard, this template class will be deleted and
+ * Optional will point to std::optional.
+ *
+ * Allowed operations (note, to make code simplier, than original, value class must have accessible copy and move constructor):
+ *  - constructing empty (valueless) object
+ *  - copying Optional (with and without value)
+ *  - moving Optional (with and without value)
+ *  - querying, if Optional has value (via explicit operator bool), for example:
+ *        Optional<int> v = ...;
+ *        if (v) ... // if v has value, then do something
+ *  - accessing value (via operator *), for example:
+ *        Optional<int> v = ...;
+ *        auto z = *v; // z now has the same int, as v (copied)
+ *        auto &y = *v; // y now has REFERENCE to int inside v, so modifying y modifies v
+ */
+
+template < typename A >
+class Optional
+{
+  union
+  {
+    A place;
+  };
+  bool hasValue = false;
+
+public:
+  /**
+   * @brief Empty constructor.
+   * Creates empty Optional object, which will be false in boolean context.
+   * So:
+   *   \code{.cpp}
+   *   Optional<int> o;
+   *   if (o) printf("1\n");
+   *   \endcode
+   * won't print 1.
+   */
+  Optional() {}
+
+  /**
+   * @brief Single element constructor, when implicit convertion can be applied.
+   * This constructor will be selected, when type of given argument (U) is
+   * implicitly convertable to expected type A. In other words following
+   * code must be valid:
+   *   \code{.cpp}
+   *   A foo() {
+   *     return U();
+   *   }
+   *   \endcode
+   * @param a value held by Optional object will be initialized from a.
+   */
+  template < typename U = A, typename std::enable_if<
+                                 std::is_convertible< U&&, A >::value &&
+                                 std::is_constructible< A, U&& >::value &&
+                                 !std::is_same< typename std::decay< U >::type, Optional< A > >::value,
+                                 int* >::type = nullptr >
+  constexpr Optional( U&& a )
+  : place( std::forward< U >( a ) ),
+    hasValue( true )
+  {
+  }
+
+  /**
+   * @brief Single element constructor, when only explicit convertion can be applied.
+   * This constructor will be selected, when type of given argument (U) is
+   * convertable to expected type A.
+   * @param a value held by Optional object will be initialized from a.
+   */
+  template < typename U = A, typename std::enable_if<
+                                 !std::is_convertible< U&&, A >::value &&
+                                 std::is_constructible< A, U&& >::value &&
+                                 !std::is_same< typename std::decay< U >::type, Optional< A > >::value,
+                                 int* >::type = nullptr >
+  explicit constexpr Optional( U&& a )
+  : place( std::forward< U >( a ) ),
+    hasValue( true )
+  {
+  }
+
+  /**
+   * @brief Copy constructor.
+   * @param v Optional value to copy from. Will cause to copy data held by object v,
+   * if v has data.
+   */
+  Optional( const Optional& v ) : hasValue( v.hasValue )
+  {
+    if( hasValue )
+    {
+      new( &place ) A( v.place );
+    }
+  }
+
+  /**
+   * @brief Move constructor.
+   * @param v Optional value to copy from. Will move data help by v, if any.
+   * After construction \code{.cpp} bool(v) \endcode will be false.
+   */
+  Optional( Optional&& v ) : hasValue( v.hasValue )
+  {
+    if( hasValue )
+    {
+      new( &place ) A( std::move( v.place ) );
+    }
+  }
+
+  /**
+   * @brief Destructor.
+   */
+  ~Optional()
+  {
+    if( hasValue )
+    {
+      place.~A();
+    }
+  }
+
+  /**
+   * @brief Explicit bool operator
+   * Will return true if and only if object is helding data.
+   */
+  explicit operator bool() const
+  {
+    return hasValue;
+  }
+
+  /**
+   * @brief Accessor (*) operator
+   * Will return modifiable reference to held object. Will assert, if not object is held.
+   */
+  A& operator*()
+  {
+    assert( hasValue );
+    return place;
+  }
+
+  /**
+   * @brief Accessor (*) const operator
+   * Will return const reference to held object. Will assert, if not object is held.
+   */
+  const A& operator*() const
+  {
+    assert( hasValue );
+    return place;
+  }
+
+  /**
+   * @brief Accessor (->) operator
+   * Will return pointer to held object allowing access to the value's members.
+   * Will assert, if not object is held.
+   */
+  A* operator->()
+  {
+    assert( hasValue );
+    return &place;
+  }
+
+  /**
+   * @brief Accessor (->) operator
+   * Will return pointer to (const) held object allowing access to the value's members.
+   * Will assert, if not object is held.
+   */
+  const A* operator->() const
+  {
+    assert( hasValue );
+    return &place;
+  }
+
+  /**
+   * @brief Assignment operator
+   * Will copy held value from v, if any.
+   * @param v Value to copy from
+   */
+  Optional& operator=( const Optional& v )
+  {
+    if( this != &v )
+    {
+      if( hasValue != v.hasValue )
+      {
+        if( v.hasValue )
+        {
+          new( &place ) A( v.place );
+        }
+        else
+        {
+          place.~A();
+        }
+        hasValue = v.hasValue;
+      }
+      else if( hasValue )
+      {
+        place = v.place;
+      }
+    }
+    return *this;
+  }
+
+  /**
+   * @brief Assignment move operator
+   * Will move held value from v, if any. In all cases v won't held a value
+   * after assignment is done.
+   * @param v Value to copy from
+   */
+  Optional& operator=( Optional&& v )
+  {
+    if( this != &v )
+    {
+      if( hasValue != v.hasValue )
+      {
+        if( v.hasValue )
+        {
+          new( &place ) A( std::move( v.place ) );
+        }
+        else
+        {
+          place.~A();
+        }
+        hasValue = v.hasValue;
+      }
+      else if( hasValue )
+      {
+        place = std::move( v.place );
+      }
+    }
+    return *this;
+  }
+
+  /**
+   * @brief Assignment operator from value of type held.
+   * Will initialize held value from given parameter a.
+   * Type of the parameter must be the same (barring cv convertions),
+   * as the type of the value held.
+   * @param a Value to copy from
+   */
+  template < class U, class = typename std::enable_if<
+                          std::is_same< typename std::remove_reference< U >::type, A >::value &&
+                          std::is_constructible< A, U >::value &&
+                          std::is_assignable< A&, U >::value >::type >
+  Optional& operator=( U&& a )
+  {
+    if( hasValue )
+    {
+      place = std::forward< U >( a );
+    }
+    else
+    {
+      hasValue = true;
+      new( &place ) A( std::forward< U >( a ) );
+    }
+    return *this;
+  }
+};
+
+#endif // DALI_INTERNAL_ATSPI_ACCESSIBILITY_OPTIONAL_H
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/accessibility.h b/dali/internal/accessibility/tizen-wayland/atspi/accessibility.h
new file mode 100644 (file)
index 0000000..9e88cf5
--- /dev/null
@@ -0,0 +1,819 @@
+#ifndef DALI_ATSPI_ACCESSIBILITY_H\r
+#define DALI_ATSPI_ACCESSIBILITY_H\r
+/*\r
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// EXTERNAL INCLUDES\r
+\r
+#include <atomic>\r
+#include <bitset>\r
+#include <exception>\r
+#include <functional>\r
+#include <memory>\r
+#include <string>\r
+#include <map>\r
+#include <unordered_map>\r
+#include <vector>\r
+#include <list>\r
+#include <cassert>\r
+#include <sstream>\r
+#include <string.h>\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali/public-api/dali-adaptor-common.h>\r
+\r
+namespace Dali\r
+{\r
+namespace Accessibility\r
+{\r
+\r
+/**\r
+ * @brief Enumeration describing a relation between accessible objects\r
+ * 1 to 0..N relation model is supported. By default relation is not symmetrical.\r
+ * Symmetry must be explicitly maintained.\r
+ */\r
+enum class RelationType : uint32_t\r
+{\r
+  NULL_OF, ///< Null Relation.\r
+  LABEL_FOR, ///< Label For.\r
+  LABELLED_BY, ///< Labelled By.\r
+  CONTROLLER_FOR, ///< Controller For.\r
+  CONTROLLED_BY, ///< Controlled By.\r
+  MEMBER_OF, ///< Member Of.\r
+  TOOLTIP_FOR, ///< ToolTip For.\r
+  NODE_CHILD_OF, ///< Node Child Of.\r
+  NODE_PARENT_OF, ///< Node Parent Of.\r
+  EXTENDED, ///< Extended.\r
+  FLOWS_TO, ///< Flows To.\r
+  FLOWS_FROM, ///< Flows From.\r
+  SUBWINDOW_OF, ///< Sub Window Of.\r
+  EMBEDS, ///< Embeds.\r
+  EMBEDDED_BY, ///< Embedded By.\r
+  POPUP_FOR, ///< Popup For\r
+  PARENT_WINDOW_OF, ///< Parent Window Of.\r
+  DESCRIPTION_FOR, ///< Description For.\r
+  DESCRIBED_BY, ///< Described By.\r
+  DETAILS, ///< Details.\r
+  DETAILS_FOR, ///< Details For.\r
+  ERROR_MESSAGE, ///< Error Message.\r
+  ERROR_FOR, ///< Error For.\r
+  MAX_COUNT\r
+};\r
+\r
+/**\r
+ * @brief Enumeration describing if coordinates are relative to screen or window\r
+ * @see Accessibility::Component::GetExtents\r
+ * @see Accessibility::Component::Contains\r
+ */\r
+enum class CoordType\r
+{\r
+  SCREEN, ///< Screen.\r
+  WINDOW ///< Window.\r
+};\r
+\r
+/**\r
+ * @brief Enumeration indicating relative stacking order\r
+ * ComponentLayer allows to describe visibility of all parts of UI\r
+ * basing on the concrete stacking order\r
+ * @see Accessibility::Component::GetLayer\r
+ * @note currently only ComponentLayer::Window is supported\r
+ */\r
+enum class ComponentLayer\r
+{\r
+  INVALID, ///< Invalid.\r
+  BACKGROUND, ///< Background.\r
+  CANVAS, ///< Canvas.\r
+  WIDGET, ///< Widget.\r
+  MDI, ///< MDI.\r
+  POPUP, ///< Popup.\r
+  OVERLAY, ///< Overlay.\r
+  WINDOW, ///< Window.\r
+  MAX_COUNT\r
+};\r
+\r
+/**\r
+ * @brief Enumeration describing role of the Accessibility object\r
+ * Object can be described by only one role.\r
+ * @see Accessibility::Accessible::GetRole\r
+ */\r
+enum class Role : uint32_t\r
+{\r
+  INVALID,\r
+  ACCELERATOR_LABEL,\r
+  ALERT,\r
+  ANIMATION,\r
+  ARROW,\r
+  CALENDAR,\r
+  CANVAS,\r
+  CHECK_BOX,\r
+  CHECK_MENU_ITEM,\r
+  COLOR_CHOOSER,\r
+  COLUMN_HEADER,\r
+  COMBO_BOX,\r
+  DATE_EDITOR,\r
+  DESKTOP_ICON,\r
+  DESKTOP_FRAME,\r
+  DIAL,\r
+  DIALOG,\r
+  DIRECTORY_PANE,\r
+  DRAWING_AREA,\r
+  FILE_CHOOSER,\r
+  FILLER,\r
+  FOCUS_TRAVERSABLE,\r
+  FONT_CHOOSER,\r
+  FRAME,\r
+  GLASS_PANE,\r
+  HTML_CONTAINER,\r
+  ICON,\r
+  IMAGE,\r
+  INTERNAL_FRAME,\r
+  LABEL,\r
+  LAYERED_PANE,\r
+  LIST,\r
+  LIST_ITEM,\r
+  MENU,\r
+  MENU_BAR,\r
+  MENU_ITEM,\r
+  OPTION_PANE,\r
+  PAGE_TAB,\r
+  PAGE_TAB_LIST,\r
+  PANEL,\r
+  PASSWORD_TEXT,\r
+  POPUP_MENU,\r
+  PROGRESS_BAR,\r
+  PUSH_BUTTON,\r
+  RADIO_BUTTON,\r
+  RADIO_MENU_ITEM,\r
+  ROOT_PANE,\r
+  ROW_HEADER,\r
+  SCROLL_BAR,\r
+  SCROLL_PANE,\r
+  SEPARATOR,\r
+  SLIDER,\r
+  SPIN_BUTTON,\r
+  SPLIT_PANE,\r
+  STATUS_BAR,\r
+  TABLE,\r
+  TABLE_CELL,\r
+  TABLE_COLUMN_HEADER,\r
+  TABLE_ROW_HEADER,\r
+  TEAROFF_MENU_ITEM,\r
+  TERMINAL,\r
+  TEXT,\r
+  TOGGLE_BUTTON,\r
+  TOOL_BAR,\r
+  TOOL_TIP,\r
+  TREE,\r
+  TREE_TABLE,\r
+  UNKNOWN,\r
+  VIEWPORT,\r
+  WINDOW,\r
+  EXTENDED,\r
+  HEADER,\r
+  FOOTER,\r
+  PARAGRAPH,\r
+  RULER,\r
+  APPLICATION,\r
+  AUTOCOMPLETE,\r
+  EDITBAR,\r
+  EMBEDDED,\r
+  ENTRY,\r
+  CHART,\r
+  CAPTION,\r
+  DOCUMENT_FRAME,\r
+  HEADING,\r
+  PAGE,\r
+  SECTION,\r
+  REDUNDANT_OBJECT,\r
+  FORM,\r
+  LINK,\r
+  INPUT_METHOD_WINDOW,\r
+  TABLE_ROW,\r
+  TREE_ITEM,\r
+  DOCUMENT_SPREADSHEET,\r
+  DOCUMENT_PRESENTATION,\r
+  DOCUMENT_TEXT,\r
+  DOCUMENT_WEB,\r
+  DOCUMENT_EMAIL,\r
+  COMMENT,\r
+  LIST_BOX,\r
+  GROUPING,\r
+  IMAGE_MAP,\r
+  NOTIFICATION,\r
+  INFO_BAR,\r
+  LEVEL_BAR,\r
+  TITLE_BAR,\r
+  BLOCK_QUOTE,\r
+  AUDIO,\r
+  VIDEO,\r
+  DEFINITION,\r
+  ARTICLE,\r
+  LANDMARK,\r
+  LOG,\r
+  MARQUEE,\r
+  MATH,\r
+  RATING,\r
+  TIMER,\r
+  STATIC,\r
+  MATH_FRACTION,\r
+  MATH_ROOT,\r
+  SUBSCRIPT,\r
+  SUPERSCRIPT,\r
+  MAX_COUNT\r
+};\r
+\r
+/**\r
+ * @brief Enumeration describing states of the Accessibility object\r
+ * Object can be in many states at the same time.\r
+ * @see Accessibility::Accessible::GetStates\r
+ */\r
+enum class State : uint32_t\r
+{\r
+  INVALID,\r
+  ACTIVE,\r
+  ARMED,\r
+  BUSY,\r
+  CHECKED,\r
+  COLLAPSED,\r
+  DEFUNCT,\r
+  EDITABLE,\r
+  ENABLED,\r
+  EXPANDABLE,\r
+  EXPANDED,\r
+  FOCUSABLE,\r
+  FOCUSED,\r
+  HAS_TOOLTIP,\r
+  HORIZONTAL,\r
+  ICONIFIED,\r
+  MODAL,\r
+  MULTI_LINE,\r
+  MULTI_SELECTABLE,\r
+  OPAQUE,\r
+  PRESSED,\r
+  RESIZEABLE,\r
+  SELECTABLE,\r
+  SELECTED,\r
+  SENSITIVE,\r
+  SHOWING,\r
+  SINGLE_LINE,\r
+  STALE,\r
+  TRANSIENT,\r
+  VERTICAL,\r
+  VISIBLE,\r
+  MANAGES_DESCENDANTS,\r
+  INDETERMINATE,\r
+  REQUIRED,\r
+  TRUNCATED,\r
+  ANIMATED,\r
+  INVALID_ENTRY,\r
+  SUPPORTS_AUTOCOMPLETION,\r
+  SELECTABLE_TEXT,\r
+  IS_DEFAULT,\r
+  VISITED,\r
+  CHECKABLE,\r
+  HAS_POPUP,\r
+  READ_ONLY,\r
+  HIGHLIGHTED,\r
+  HIGHLIGHTABLE,\r
+  MAX_COUNT\r
+};\r
+\r
+/**\r
+ * @brief Enumeration describing change of text object\r
+ */\r
+enum class TextChangedState : uint32_t\r
+{\r
+  INSERT,\r
+  DELETE,\r
+  MAX_COUNT\r
+};\r
+\r
+/**\r
+ * @brief Enumeration describing change of object property\r
+ */\r
+enum class ObjectPropertyChangeEvent\r
+{\r
+  NAME,\r
+  DESCRIPTION,\r
+  VALUE,\r
+  ROLE,\r
+  PARENT,\r
+};\r
+\r
+/**\r
+ * @brief Enumeration describing change of window object\r
+ * @see Accessibility::Accessible::Emit\r
+ */\r
+enum class WindowEvent\r
+{\r
+  PROPERTY_CHANGE,\r
+  MINIMIZE,\r
+  MAXIMIZE,\r
+  RESTORE,\r
+  CLOSE,\r
+  CREATE,\r
+  REPARENT,\r
+  DESKTOP_CREATE,\r
+  DESKTOP_DESTROY,\r
+  DESTROY,\r
+  ACTIVATE,\r
+  DEACTIVATE,\r
+  RAISE,\r
+  LOWER,\r
+  MOVE,\r
+  RESIZE,\r
+  SHADE,\r
+  UU_SHADE,\r
+  RESTYLE,\r
+};\r
+\r
+/**\r
+ * @brief Enumeration used to acquire bounded text from accessible object having textual content.\r
+ * @see Accessibility::Text::GetTextAtOffset\r
+ * @note Currently only TextBoundary::Character is supported\r
+ */\r
+enum class TextBoundary : uint32_t\r
+{\r
+  CHARACTER, ///> Only one character is acquired.\r
+  WORD, ///> Not supported.\r
+  SENTENCE, ///> Not supported.\r
+  LINE, ///> Not supported.\r
+  PARAGRAPH, ///> Not supported.\r
+  MAX_COUNT\r
+};\r
+\r
+/**\r
+ * @brief Enumeration describing type of gesture\r
+ * @see Accessibility::Accessible::DoGesture\r
+ */\r
+enum class Gesture : int32_t\r
+{\r
+  ONE_FINGER_HOVER,\r
+  TWO_FINGER_HOVER,\r
+  THREE_FINGER_HOVER,\r
+  ONE_FINGER_FLICK_LEFT,\r
+  ONE_FINGER_FLICK_RIGHT,\r
+  ONE_FINGER_FLICK_UP,\r
+  ONE_FINGER_FLICK_DOWN,\r
+  TWO_FINGERS_FLICK_LEFT,\r
+  TWO_FINGERS_FLICK_RIGHT,\r
+  TWO_FINGERS_FLICK_UP,\r
+  TWO_FINGERS_FLICK_DOWN,\r
+  THREE_FINGERS_FLICK_LEFT,\r
+  THREE_FINGERS_FLICK_RIGHT,\r
+  THREE_FINGERS_FLICK_UP,\r
+  THREE_FINGERS_FLICK_DOWN,\r
+  ONE_FINGER_SINGLE_TAP,\r
+  ONE_FINGER_DOUBLE_TAP,\r
+  ONE_FINGER_TRIPLE_TAP,\r
+  TWO_FINGERS_SINGLE_TAP,\r
+  TWO_FINGERS_DOUBLE_TAP,\r
+  TWO_FINGERS_TRIPLE_TAP,\r
+  THREE_FINGERS_SINGLE_TAP,\r
+  THREE_FINGERS_DOUBLE_TAP,\r
+  THREE_FINGERS_TRIPLE_TAP,\r
+  ONE_FINGER_FLICK_LEFT_RETURN,\r
+  ONE_FINGER_FLICK_RIGHT_RETURN,\r
+  ONE_FINGER_FLICK_UP_RETURN,\r
+  ONE_FINGER_FLICK_DOWN_RETURN,\r
+  TWO_FINGERS_FLICK_LEFT_RETURN,\r
+  TWO_FINGERS_FLICK_RIGHT_RETURN,\r
+  TWO_FINGERS_FLICK_UP_RETURN,\r
+  TWO_FINGERS_FLICK_DOWN_RETURN,\r
+  THREE_FINGERS_FLICK_LEFT_RETURN,\r
+  THREE_FINGERS_FLICK_RIGHT_RETURN,\r
+  THREE_FINGERS_FLICK_UP_RETURN,\r
+  THREE_FINGERS_FLICK_DOWN_RETURN,\r
+  ONE_FINGER_DOUBLE_TAP_N_HOLD,\r
+  TWO_FINGERS_DOUBLE_TAP_N_HOLD,\r
+  THREE_FINGERS_DOUBLE_TAP_N_HOLD,\r
+  MAX_COUNT\r
+};\r
+\r
+/**\r
+ * @brief Enumeration indicating current state of gesture\r
+ * @see Dali::Accessibility::GestureInfo\r
+ */\r
+enum class GestureState : int32_t\r
+{\r
+  BEGIN,\r
+  ONGOING,\r
+  ENDED,\r
+  ABORTED\r
+};\r
+\r
+/**\r
+ * @brief Enumeration of ReadingInfoType\r
+ */\r
+enum class ReadingInfoType\r
+{\r
+  NAME,\r
+  ROLE,\r
+  DESCRIPTION,\r
+  STATE\r
+};\r
+\r
+/**\r
+ * @brief Helper class for storing values treated as bit sets\r
+ * This class provides all bitset-like methods for bitset size larger, than long long int\r
+ * @see Dali::Accessibility::Accessible::GetStates\r
+ * @see Dali::Accessibility::Accessible::GetRoles\r
+ */\r
+template < size_t I, typename S >\r
+class BitSets\r
+{\r
+  std::array< uint32_t, I > data;\r
+\r
+  void _set()\r
+  {\r
+  }\r
+\r
+  static constexpr bool _accepts()\r
+  {\r
+    return true;\r
+  }\r
+\r
+  template < typename T > static constexpr bool _accepts()\r
+  {\r
+    return std::is_enum< T >::value;\r
+  }\r
+\r
+  template < typename T, typename T2, typename ... ARGS > static constexpr bool _accepts()\r
+  {\r
+    return std::is_enum< T >::value && _accepts< T2, ARGS... >();\r
+  }\r
+\r
+  template < typename T, typename ... ARGS > void _set(T t, ARGS ... args)\r
+  {\r
+    (*this)[t] = true;\r
+    _set(args...);\r
+  }\r
+public:\r
+  BitSets()\r
+  {\r
+    for( auto& u : data )\r
+    {\r
+      u = 0;\r
+    }\r
+  }\r
+  BitSets(const BitSets&) = default;\r
+  BitSets(BitSets&&) = default;\r
+\r
+  template < typename T, typename ... ARGS, typename std::enable_if< _accepts< T, ARGS... >() >::type * = nullptr >BitSets( T t, ARGS ... args )\r
+  {\r
+    for( auto& u : data )\r
+    u = 0;\r
+    _set( t, args... );\r
+  }\r
+\r
+  explicit BitSets( std::array< uint32_t, I > d )\r
+  {\r
+    for( auto i = 0u; i < I; ++i )\r
+    {\r
+      data[i] = d[i];\r
+    }\r
+  }\r
+\r
+  explicit BitSets( std::array< int32_t, I > d )\r
+  {\r
+    for( auto i = 0u; i < I; ++i )\r
+    {\r
+      data[i] = static_cast<uint32_t>( d[i] );\r
+    }\r
+  }\r
+\r
+  BitSets& operator = (const BitSets&) = default;\r
+  BitSets& operator = (BitSets&&) = default;\r
+\r
+  struct reference\r
+  {\r
+    std::array< uint32_t, I >& data;\r
+    size_t pos;\r
+\r
+    reference& operator=( reference r )\r
+    {\r
+      (*this) = static_cast<bool>( r );\r
+      return *this;\r
+    }\r
+\r
+    reference& operator=( bool v )\r
+    {\r
+      if( v )\r
+      {\r
+        data[pos / 32] |= 1 << (pos & 31);\r
+      }\r
+      else\r
+      {\r
+        data[pos / 32] &= ~(1 << (pos & 31));\r
+      }\r
+      return *this;\r
+    }\r
+\r
+    operator bool() const\r
+    {\r
+      auto i = static_cast<size_t>( pos );\r
+      return (data[i / 32] & (1 << (i & 31))) != 0;\r
+    }\r
+  };\r
+\r
+  reference operator[]( S index )\r
+  {\r
+    return { data, static_cast<size_t>( index ) };\r
+  }\r
+\r
+  bool operator[]( S index ) const\r
+  {\r
+    auto i = static_cast<size_t>( index );\r
+    return ( data[i / 32] & ( 1 << (i & 31) ) ) != 0;\r
+  }\r
+\r
+  std::array< uint32_t, I > GetRawData() const\r
+  {\r
+    return data;\r
+  }\r
+\r
+  BitSets operator|( BitSets b ) const\r
+  {\r
+    BitSets r;\r
+    for( auto i = 0u; i < I; ++i )\r
+    {\r
+      r.data[i] = data[i] | b.data[i];\r
+    }\r
+    return r;\r
+  }\r
+\r
+  BitSets operator^( BitSets b ) const\r
+  {\r
+    BitSets r;\r
+    for( auto i = 0u; i < I; ++i )\r
+    {\r
+      r.data[i] = data[i] ^ b.data[i];\r
+    }\r
+    return r;\r
+  }\r
+\r
+  BitSets operator&( BitSets b ) const\r
+  {\r
+    BitSets r;\r
+    for( auto i = 0u; i < I; ++i )\r
+    {\r
+      r.data[i] = data[i] & b.data[i];\r
+    }\r
+    return r;\r
+  }\r
+\r
+  bool operator==( BitSets b ) const\r
+  {\r
+    for( auto i = 0u; i < I; ++i )\r
+    {\r
+      if( data[i] != b.data[i] )\r
+      {\r
+        return false;\r
+      }\r
+    }\r
+    return true;\r
+  }\r
+\r
+  bool operator!=(BitSets b) const\r
+  {\r
+    return !((*this) == b);\r
+  }\r
+\r
+  explicit operator bool() const\r
+  {\r
+    for( auto& u : data )\r
+    {\r
+      if( u )\r
+      {\r
+        return true;\r
+      }\r
+    }\r
+    return false;\r
+  }\r
+\r
+  size_t size() const\r
+  {\r
+    return I;\r
+  }\r
+};\r
+\r
+using ReadingInfoTypes = BitSets<1, ReadingInfoType>;\r
+using States = BitSets< 2, State >;\r
+using Attributes = std::unordered_map< std::string, std::string >;\r
+\r
+/**\r
+ * @brief Class representing unique object address on accessibility bus\r
+ * @see Dali::Accessibility::Accessible::GetAddress\r
+ */\r
+class Address\r
+{\r
+public:\r
+  Address() = default;\r
+\r
+  Address( std::string bus, std::string path )\r
+  : mBus(std::move(bus)),\r
+    mPath(std::move(path))\r
+  {\r
+  }\r
+\r
+  explicit operator bool() const\r
+  {\r
+    return !mPath.empty();\r
+  }\r
+\r
+  std::string ToString() const\r
+  {\r
+    return *this ? mBus + ":" + mPath : "::null";\r
+  }\r
+\r
+  const std::string& GetBus() const;\r
+\r
+  const std::string& GetPath() const\r
+  {\r
+    return mPath;\r
+  }\r
+\r
+  bool operator == ( const Address& a ) const\r
+  {\r
+    return mBus == a.mBus && mPath == a.mPath;\r
+  }\r
+\r
+  bool operator != ( const Address& a ) const\r
+  {\r
+    return !(*this == a);\r
+  }\r
+\r
+private:\r
+  mutable std::string mBus, mPath;\r
+};\r
+\r
+/**\r
+ * @brief Enumeration describing type of key event\r
+ * @see Adaptor::AccessibilityObserver::OnAccessibleKeyEvent\r
+ */\r
+enum class KeyEventType\r
+{\r
+  KEY_PRESSED,\r
+  KEY_RELEASED,\r
+};\r
+\r
+/**\r
+ * @brief Enumeration with human readable values describing state of event\r
+ * @see Dali::Accessibility::Bridge::Emit\r
+ */\r
+enum class Consumed\r
+{\r
+  NO,\r
+  YES\r
+};\r
+\r
+/**\r
+ * @brief Helper class representing two dimensional point with integer coordinates\r
+ */\r
+struct Point\r
+{\r
+  int x = 0;\r
+  int y = 0;\r
+\r
+  Point() = default;\r
+\r
+  Point( int x, int y )\r
+  : x(x),\r
+    y(y)\r
+  {\r
+  }\r
+\r
+  bool operator==(Point p) const\r
+  {\r
+    return x == p.x && y == p.y;\r
+  }\r
+  bool operator!=(Point p) const\r
+  {\r
+    return !(*this == p);\r
+  }\r
+};\r
+\r
+/**\r
+* @brief Helper class representing size of rectangle object with usage of two integer values\r
+*/\r
+struct Size\r
+{\r
+  int width = 0;\r
+  int height = 0;\r
+\r
+  Size() = default;\r
+\r
+  Size(int w, int h)\r
+  : width(w),\r
+    height(h)\r
+  {\r
+  }\r
+\r
+  bool operator==( Size p ) const\r
+  {\r
+    return width == p.width && height == p.height;\r
+  }\r
+\r
+  bool operator!=( Size p ) const\r
+  {\r
+    return !(*this == p);\r
+  }\r
+};\r
+\r
+/**\r
+ * @brief Helper class used to store data related with Accessibility::Text interface\r
+ * @see Dali::Accessibility::Text::GetTextAtOffset\r
+ * @see Dali::Accessibility::Text::GetSelection\r
+ */\r
+struct Range\r
+{\r
+  int32_t startOffset = 0;\r
+  int32_t endOffset = 0;\r
+  std::string content;\r
+\r
+  Range() = default;\r
+\r
+  Range(size_t start, size_t end)\r
+  : startOffset(start),\r
+    endOffset(end)\r
+  {\r
+  }\r
+\r
+  Range(size_t start, size_t end, std::string content)\r
+  : startOffset(start),\r
+    endOffset(end),\r
+    content(content)\r
+  {\r
+  }\r
+};\r
+\r
+/**\r
+ * @brief Structure containing all values needed to invoke Accessible::DoGesture\r
+ * type : numerated gesture type\r
+ * xBeg, yBeg : point where gesture begins\r
+ * xEnd, yEnd : point where gesture ends\r
+ * state : enumerated state of gesture\r
+ * eventTime : time when event occured\r
+ * @see Dali::Accessibility::Accessible::DoGesture\r
+ */\r
+struct GestureInfo\r
+{\r
+  GestureInfo() = default;\r
+  GestureInfo(Gesture type, int32_t xBeg, int32_t xEnd, int32_t yBeg, int32_t yEnd, GestureState state, uint32_t eventTime)\r
+  : type(type),\r
+    xBeg(xBeg),\r
+    xEnd(xEnd),\r
+    yBeg(yBeg),\r
+    yEnd(yEnd),\r
+    state(state),\r
+    eventTime(eventTime)\r
+  {\r
+  }\r
+\r
+  Gesture type{};\r
+  int32_t xBeg{};\r
+  int32_t xEnd{};\r
+  int32_t yBeg{};\r
+  int32_t yEnd{};\r
+  GestureState state{};\r
+  uint32_t eventTime{};\r
+};\r
+\r
+/**\r
+ * @brief Class representing accessibility relations\r
+ * Class connecting one source object with multiple target objects with usage\r
+ * of specific relation type.\r
+ * @note std::string representing source and targets are string values of Accessibility::Address\r
+ * @see Dali::Accessibility::Accessible::Address\r
+ * @see Dali::Accessibility::Accessible::RelationType\r
+ */\r
+struct Relation\r
+{\r
+Relation(RelationType relationType, std::vector<Address> targets)\r
+: relationType(relationType),\r
+  targets(targets)\r
+{\r
+}\r
+\r
+RelationType relationType;\r
+std::vector<Address> targets;\r
+};\r
+\r
+} // namespace Accessibility\r
+} // namespace Dali\r
+\r
+#endif // DALI_ATSPI_ACCESSIBILITY_H\r
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/accessible.cpp b/dali/internal/accessibility/tizen-wayland/atspi/accessible.cpp
new file mode 100644 (file)
index 0000000..4419f2c
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2019 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
+
+ //INTERNAL INCLUDES
+#include <dali/internal/accessibility/tizen-wayland/atspi/accessibility-common.h>
+#include <third-party/libunibreak/wordbreak.h>
+#include <third-party/libunibreak/linebreak.h>
+
+using namespace Dali::Accessibility;
+
+std::vector< std::string > Accessible::GetInterfaces()
+{
+    std::vector< std::string > tmp;
+    tmp.push_back(AtspiDbusInterfaceAccessible);
+    if (dynamic_cast<Collection*>(this))
+    {
+        tmp.push_back(AtspiDbusInterfaceCollection);
+    }
+    if (dynamic_cast<Text*>(this))
+    {
+        tmp.push_back(AtspiDbusInterfaceText);
+    }
+    if (dynamic_cast<Value*>(this))
+    {
+        tmp.push_back(AtspiDbusInterfaceValue);
+    }
+    if (dynamic_cast<Component*>(this))
+    {
+        tmp.push_back(AtspiDbusInterfaceComponent);
+    }
+    if (auto d = dynamic_cast<Action*>(this))
+    {
+        if (d->GetActionCount() > 0)
+        {
+            tmp.push_back(AtspiDbusInterfaceAction);
+        }
+    }
+    return tmp;
+}
+
+Accessible::Accessible()
+{
+}
+
+Accessible::~Accessible()
+{
+    auto b = bridgeData.lock();
+    if (b)
+        b->knownObjects.erase(this);
+}
+
+void Accessible::EmitActiveDescendantChanged(Accessible* obj, Accessible* child)
+{
+    if (auto b = GetBridgeData())
+    {
+        b->bridge->EmitActiveDescendantChanged(obj, child);
+    }
+}
+
+void Accessible::EmitStateChanged(State state, int newValue1, int newValue2)
+{
+    if (auto b = GetBridgeData())
+    {
+        b->bridge->EmitStateChanged(this, state, newValue1, newValue2);
+    }
+}
+
+void Accessible::EmitShowing(bool showing)
+{
+    if (auto b = GetBridgeData())
+    {
+        b->bridge->EmitStateChanged(this, State::SHOWING, showing ? 1 : 0, 0);
+    }
+}
+
+void Accessible::EmitVisible(bool visible)
+{
+    if (auto b = GetBridgeData())
+    {
+        b->bridge->EmitStateChanged(this, State::VISIBLE, visible ? 1 : 0, 0);
+    }
+}
+
+void Accessible::EmitHighlighted(bool set)
+{
+    if (auto b = GetBridgeData())
+    {
+        b->bridge->EmitStateChanged(this, State::HIGHLIGHTED, set ? 1 : 0, 0);
+    }
+}
+
+void Accessible::EmitFocused(bool set)
+{
+    if (auto b = GetBridgeData()) {
+        b->bridge->EmitStateChanged(this, State::FOCUSED, set ? 1 : 0, 0);
+    }
+}
+void Accessible::EmitTextInserted(unsigned int position, unsigned int length, const std::string& content)
+{
+    if (auto b = GetBridgeData()) {
+        b->bridge->EmitTextChanged(this, TextChangedState::INSERT, position, length, content);
+    }
+}
+void Accessible::EmitTextDeleted(unsigned int position, unsigned int length, const std::string& content)
+{
+    if (auto b = GetBridgeData()) {
+        b->bridge->EmitTextChanged(this, TextChangedState::DELETE, position, length, content);
+    }
+}
+void Accessible::EmitTextCaretMoved(unsigned int cursorPosition)
+{
+    if (auto b = GetBridgeData()) {
+        b->bridge->EmitCaretMoved(this, cursorPosition);
+    }
+}
+void Accessible::Emit(WindowEvent we, unsigned int detail1)
+{
+    if (auto b = GetBridgeData())
+    {
+        b->bridge->Emit(this, we, detail1);
+    }
+}
+void Accessible::Emit(ObjectPropertyChangeEvent ev)
+{
+    if (auto b = GetBridgeData())
+    {
+        b->bridge->Emit(this, ev);
+    }
+}
+
+void Accessible::EmitBoundsChanged(Rect<> rect)
+{
+    if (auto b = GetBridgeData())
+    {
+        b->bridge->EmitBoundsChanged(this, rect);
+    }
+}
+
+std::vector< Accessible* > Accessible::GetChildren()
+{
+    std::vector< Accessible* > tmp(GetChildCount());
+    for (auto i = 0u; i < tmp.size(); ++i)
+    {
+        tmp[i] = GetChildAtIndex(i);
+    }
+    return tmp;
+}
+
+std::shared_ptr< Bridge::Data > Accessible::GetBridgeData()
+{
+    auto b = bridgeData.lock();
+    if (!b)
+    {
+        auto p = Bridge::GetCurrentBridge();
+        b = p->data;
+    }
+    return b;
+}
+
+Address Accessible::GetAddress()
+{
+    auto b = bridgeData.lock();
+    if (!b)
+    {
+        b = GetBridgeData();
+        if (b)
+            b->bridge->RegisterOnBridge(this);
+    }
+    std::ostringstream tmp;
+    tmp << this;
+    return { b ? b->busName : "", tmp.str() };
+}
+
+void Bridge::RegisterOnBridge(Accessible* obj)
+{
+    assert(!obj->bridgeData.lock() || obj->bridgeData.lock() == data);
+    if (!obj->bridgeData.lock())
+    {
+        assert(data);
+        data->knownObjects.insert(obj);
+        obj->bridgeData = data;
+    }
+}
+
+bool Accessible::IsProxy()
+{
+    return false;
+}
+
+Accessible* Accessible::GetDefaultLabel()
+{
+    return this;
+}
+
+void Accessible::NotifyAccessibilityStateChange(Dali::Accessibility::States states, bool doRecursive)
+{
+    if (auto b = GetBridgeData())
+    {
+        auto s = GetStates() & states;
+        for (auto i = 0u; i < s.size(); i++)
+        {
+            auto index = static_cast<Dali::Accessibility::State>(i);
+            if (s[index])
+                b->bridge->EmitStateChanged(this, index, 1, 0);
+        }
+        if (doRecursive)
+        {
+            auto children = GetChildren();
+            for (auto c : children)
+                c->NotifyAccessibilityStateChange(states, doRecursive);
+        }
+    }
+}
+
+void Accessible::FindWordSeparationsUtf8(const utf8_t* s, size_t length, const char* language, char* breaks)
+{
+    set_wordbreaks_utf8(s, length, language, breaks);
+}
+
+void Accessible::FindLineSeparationsUtf8(const utf8_t* s, size_t length, const char* language, char* breaks)
+{
+    set_linebreaks_utf8(s, length, language, breaks);
+}
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/atspi-accessibility-tizen.cpp b/dali/internal/accessibility/tizen-wayland/atspi/atspi-accessibility-tizen.cpp
new file mode 100755 (executable)
index 0000000..dd5cb7c
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2019 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/devel-api/adaptor-framework/atspi-accessibility.h>
+#include <dali/internal/accessibility/tizen-wayland/atspi/accessibility-impl.h>
+#include <dali/internal/accessibility/tizen-wayland/atspi/accessibility-common.h>
+
+#include <mutex>
+#include <Eldbus.h>
+#include <Ecore_Input.h>
+#include <dali/integration-api/debug.h>
+
+void Dali::AtspiAccessibility::Pause()
+{
+  if( auto bridge = Dali::Accessibility::Bridge::GetCurrentBridge() )
+  {
+    bridge->Pause();
+  }
+}
+
+void Dali::AtspiAccessibility::Resume()
+{
+  if( auto bridge = Dali::Accessibility::Bridge::GetCurrentBridge() )
+  {
+    bridge->Resume();
+  }
+}
+
+void Dali::AtspiAccessibility::Say( const std::string& text, bool discardable, std::function<void( std::string )> callback )
+{
+  if( auto bridge = Dali::Accessibility::Bridge::GetCurrentBridge() )
+  {
+    bridge->Say(text, discardable, callback);
+  }
+}
+
+int Dali::AtspiAccessibility::SetForcefully( bool turnOn )
+{
+  if( turnOn )
+  {
+    if( auto bridge = Dali::Accessibility::Bridge::GetCurrentBridge() )
+    {
+      bridge->Initialize();
+      auto ret = bridge->ForceUp();
+      return (int)ret;
+    }
+  }
+  else
+  {
+    if( auto bridge = Dali::Accessibility::Bridge::GetCurrentBridge() )
+    {
+      bridge->ForceDown();
+      return 0;
+    }
+  }
+  return -1;
+}
+
+int Dali::AtspiAccessibility::GetStatus()
+{
+  //0(ATSPI OFF, ScreenReader OFF), 1(ATSPI ON, ScreenReader OFF), 2 (ATSPI OFF, ScreenReader ON), 3(ATSPI ON, ScreenReader ON)
+  if( auto bridge = Dali::Accessibility::Bridge::GetCurrentBridge() )
+  {
+    if( bridge->GetScreenReaderEnabled() )
+    {
+      if( bridge->GetIsEnabled() )
+      {
+        return 3;
+      }
+      else
+      {
+        return 2;
+      }
+    }
+    else
+    {
+      if( bridge->GetIsEnabled() )
+      {
+        return 1;
+      }
+      else
+      {
+        return 0;
+      }
+    }
+  }
+  return -1;
+}
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-accessible.cpp b/dali/internal/accessibility/tizen-wayland/atspi/bridge-accessible.cpp
new file mode 100644 (file)
index 0000000..dd3bd71
--- /dev/null
@@ -0,0 +1,756 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-accessible.h>
+
+// EXTERNAL INCLUDES
+#include <iostream>
+
+//comment out 2 lines below to get more logs
+#undef LOG
+#define LOG() _LoggerEmpty()
+
+using namespace Dali::Accessibility;
+
+#define GET_NAVIGABLE_AT_POINT_MAX_RECURSION_DEPTH 10000
+
+BridgeAccessible::BridgeAccessible()
+{
+}
+
+void BridgeAccessible::RegisterInterfaces()
+{
+  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceAccessible};
+  AddGetPropertyToInterface( desc, "ChildCount", &BridgeAccessible::GetChildCount );
+  AddGetPropertyToInterface( desc, "Name", &BridgeAccessible::GetName );
+  AddGetPropertyToInterface( desc, "Description", &BridgeAccessible::GetDescription );
+  AddGetPropertyToInterface( desc, "Parent", &BridgeAccessible::GetParent );
+  AddFunctionToInterface( desc, "GetRole", &BridgeAccessible::GetRole );
+  AddFunctionToInterface( desc, "GetRoleName", &BridgeAccessible::GetRoleName );
+  AddFunctionToInterface( desc, "GetLocalizedRoleName", &BridgeAccessible::GetLocalizedRoleName );
+  AddFunctionToInterface( desc, "GetState", &BridgeAccessible::GetStates );
+  AddFunctionToInterface( desc, "GetAttributes", &BridgeAccessible::GetAttributes );
+  AddFunctionToInterface( desc, "GetInterfaces", &BridgeAccessible::GetInterfaces );
+  AddFunctionToInterface( desc, "GetChildAtIndex", &BridgeAccessible::GetChildAtIndex );
+  AddFunctionToInterface( desc, "GetChildren", &BridgeAccessible::GetChildren );
+  AddFunctionToInterface( desc, "GetIndexInParent", &BridgeAccessible::GetIndexInParent );
+  AddFunctionToInterface( desc, "GetNavigableAtPoint", &BridgeAccessible::GetNavigableAtPoint );
+  AddFunctionToInterface( desc, "GetNeighbor", &BridgeAccessible::GetNeighbor );
+  AddFunctionToInterface( desc, "GetDefaultLabelInfo", &BridgeAccessible::GetDefaultLabelInfo );
+  AddFunctionToInterface( desc, "DoGesture", &BridgeAccessible::DoGesture );
+  AddFunctionToInterface( desc, "GetReadingMaterial", &BridgeAccessible::GetReadingMaterial );
+  AddFunctionToInterface( desc, "GetRelationSet", &BridgeAccessible::GetRelationSet );
+  dbusServer.addInterface( "/", desc, true );
+}
+
+static bool AcceptObjectCheckRole( Component* obj )
+{
+  if( !obj )
+    return false;
+  switch( obj->GetRole() )
+  {
+    case Role::APPLICATION:
+    case Role::FILLER:
+    case Role::SCROLL_PANE:
+    case Role::SPLIT_PANE:
+    case Role::WINDOW:
+    case Role::IMAGE:
+    case Role::IMAGE_MAP:
+    case Role::LIST:
+    case Role::ICON:
+    case Role::TOOL_BAR:
+    case Role::REDUNDANT_OBJECT:
+    case Role::COLOR_CHOOSER:
+    case Role::TREE_TABLE:
+    case Role::PAGE_TAB_LIST:
+    case Role::PAGE_TAB:
+    case Role::SPIN_BUTTON:
+    case Role::INPUT_METHOD_WINDOW:
+    case Role::EMBEDDED:
+    case Role::INVALID:
+    case Role::NOTIFICATION:
+    case Role::DATE_EDITOR:
+    case Role::TABLE:
+    {
+      return false;
+    }
+    default:
+    {
+      break;
+    }
+  }
+
+  return true;
+}
+
+static bool AcceptObjectCheckRelations( Component* obj)
+{
+  auto r = obj->GetRelationSet();
+
+  for (const auto& it : r)
+    if (it.relationType == RelationType::CONTROLLED_BY)
+      return false;
+
+  return true;
+}
+
+static Component* GetScrollableParent( Accessible* obj )
+{
+  while( obj )
+  {
+    obj = obj->GetParent();
+    auto comp = dynamic_cast< Component* >( obj );
+    if( comp && comp->IsScrollable() )
+      return comp;
+  }
+  return nullptr;
+}
+
+static bool ObjectIsItem( Component* obj )
+{
+  if( !obj )
+    return false;
+  auto role = obj->GetRole();
+  return role == Role::LIST_ITEM || role == Role::MENU_ITEM;
+}
+
+static bool ObjectIsCollapsed( Component* obj )
+{
+  if( !obj )
+    return false;
+  const auto states = obj->GetStates();
+  return states[State::EXPANDABLE] && !states[State::EXPANDED];
+}
+
+static bool OobjectIsZeroSize( Component* obj )
+{
+  if( !obj )
+    return false;
+  auto extents = obj->GetExtents( CoordType::WINDOW );
+  return extents.height == 0 || extents.width == 0;
+}
+
+static bool AcceptObject( Component* obj )
+{
+  if( !obj )
+    return false;
+  const auto states = obj->GetStates();
+  if( !states[State::VISIBLE] )
+    return false;
+  if( !AcceptObjectCheckRole( obj ) )
+    return false;
+  if ( !AcceptObjectCheckRelations( obj ) )
+    return false;
+  //   if (CALL(get_object_in_relation_by_type, obj, ATSPI_RELATION_CONTROLLED_BY) != NULL) return 0;
+  if ( !AcceptObjectCheckRelations( obj ) )
+    return false;
+  if( !states[State::HIGHLIGHTABLE] )
+    return false;
+
+  if( GetScrollableParent( obj ) != nullptr )
+  {
+    auto parent = dynamic_cast< Component* >( obj->GetParent() );
+
+    if( parent )
+    {
+      return !ObjectIsItem( obj ) || !ObjectIsCollapsed( parent );
+    }
+  }
+  else
+  {
+    if( OobjectIsZeroSize( obj ) )
+    {
+      return false;
+    }
+    if( !states[State::SHOWING] )
+    {
+      return false;
+    }
+  }
+  return true;
+}
+
+static bool AcceptObject( Accessible* obj )
+{
+  auto c = dynamic_cast< Component* >( obj );
+  return AcceptObject( c );
+}
+
+static std::string objDump( Component* obj )
+{
+  if ( !obj )
+    return "nullptr";
+  std::ostringstream o;
+  auto e = obj->GetExtents( CoordType::SCREEN );
+  o << "name: " << obj->GetName() << " extent: (" << e.x << ", "
+      << e.y << "), [" << e.width << ", " << e.height << "]";
+  return o.str();
+}
+
+Component * BridgeAccessible::GetObjectInRelation( Accessible * obj, RelationType ralationType )
+{
+  if ( !obj )
+    return nullptr;
+  for ( auto &relation : obj->GetRelationSet() )
+  {
+    if ( relation.relationType == ralationType )
+    {
+      for ( auto &address : relation.targets )
+      {
+        auto component = dynamic_cast<Component*>( Find( address ) );
+        if ( component )
+          return component;
+      }
+    }
+  }
+  return nullptr;
+}
+
+static std::string makeIndent( unsigned int maxRecursionDepth )
+{
+  return std::string( GET_NAVIGABLE_AT_POINT_MAX_RECURSION_DEPTH - maxRecursionDepth, ' ' );
+}
+
+Component* BridgeAccessible::CalculateNavigableAccessibleAtPoint( Accessible* root, Point p, CoordType cType, unsigned int maxRecursionDepth )
+{
+  if( !root || maxRecursionDepth == 0 )
+    return nullptr;
+  auto root_component = dynamic_cast< Component* >( root );
+  LOG() << "CalculateNavigableAccessibleAtPoint: checking: " << makeIndent(maxRecursionDepth) << objDump(root_component);
+
+  if( root_component && !root_component->Contains( p, cType ) )
+    return nullptr;
+
+  auto children = root->GetChildren();
+  for( auto childIt = children.rbegin(); childIt != children.rend(); childIt++ )
+  {
+    //check recursively all children first
+    auto result = CalculateNavigableAccessibleAtPoint( *childIt, p, cType, maxRecursionDepth - 1 );
+    if( result )
+      return result;
+  }
+  if( root_component )
+  {
+    //Found a candidate, all its children are already checked
+    auto controledBy = GetObjectInRelation( root_component, RelationType::CONTROLLED_BY );
+    if ( !controledBy )
+      controledBy = root_component;
+
+    if ( controledBy->IsProxy() || AcceptObject( controledBy ) )
+    {
+      LOG() << "CalculateNavigableAccessibleAtPoint: found:    " << makeIndent(maxRecursionDepth) << objDump( root_component );
+      return controledBy;
+    }
+  }
+  return nullptr;
+}
+
+BridgeAccessible::ReadingMaterialType BridgeAccessible::GetReadingMaterial()
+{
+  auto self = FindSelf();
+  auto attributes = self->GetAttributes();
+  auto name = self->GetName();
+  std::string labeledByName = "";
+  std::string textIfceName = "";
+  auto role = static_cast< uint32_t >( self->GetRole() );
+  auto states = self->GetStates();
+  auto localizedName = self->GetLocalizedRoleName();
+  auto childCount = static_cast< int32_t >( self->GetChildCount() );
+
+  double currentValue = 0.0;
+  double minimumIncrement = 0.0;
+  double maximumValue = 0.0;
+  double minimumValue = 0.0;
+
+  auto description = self->GetDescription();
+  auto indexInParent = static_cast< int32_t >( self->GetIndexInParent() );
+  bool isSelectedInParent = false;
+  bool hasCheckBoxChild = false;
+  int32_t firstSelectedChildIndex = 0;
+  int32_t selectedChildCount = 0;
+
+  for( auto i = 0u; i < static_cast< size_t >( childCount ); ++i )
+  {
+    auto q = self->GetChildAtIndex( i );
+    auto s = q->GetStates();
+    if( s[State::SELECTABLE] )
+    {
+      ++selectedChildCount;
+      if( s[State::SELECTED] )
+      {
+        if( firstSelectedChildIndex < 0 )
+          firstSelectedChildIndex = static_cast< int32_t >( i );
+      }
+    }
+    if( q->GetRole() == Role::CHECK_BOX )
+      hasCheckBoxChild = true;
+  }
+
+  int32_t listChildrenCount = 0;
+  Accessible* parent = self->GetParent();
+  auto parentStateSet = parent ? parent->GetStates() : States{};
+  auto parentChildCount = parent ? static_cast< int32_t >( parent->GetChildCount() ) : 0;
+  auto parentRole = static_cast< uint32_t >( parent ? parent->GetRole() : Role{} );
+  Accessible* describedByObject = nullptr;
+
+  return {
+      attributes,
+      name,
+      labeledByName,
+      textIfceName,
+      role,
+      states,
+      localizedName,
+      childCount,
+      currentValue,
+      minimumIncrement,
+      maximumValue,
+      minimumValue,
+      description,
+      indexInParent,
+      isSelectedInParent,
+      hasCheckBoxChild,
+      listChildrenCount,
+      firstSelectedChildIndex,
+      parent,
+      parentStateSet,
+      parentChildCount,
+      parentRole,
+      selectedChildCount,
+      describedByObject};
+}
+
+DBus::ValueOrError< bool > BridgeAccessible::DoGesture( Dali::Accessibility::Gesture type, int32_t xBeg, int32_t xEnd, int32_t yBeg, int32_t yEnd, Dali::Accessibility::GestureState state, uint32_t eventTime )
+{
+ return FindSelf()->DoGesture( Dali::Accessibility::GestureInfo {type, xBeg, xEnd, yBeg, yEnd, state, eventTime});
+}
+
+DBus::ValueOrError< Accessible*, uint8_t, Accessible* > BridgeAccessible::GetNavigableAtPoint( int32_t x, int32_t y, uint32_t coordType )
+{
+  Accessible* deputy = nullptr;
+  auto accessible = FindSelf();
+  auto cType = static_cast< CoordType >( coordType );
+  LOG() << "GetNavigableAtPoint: " << x << ", " << y << " type: " << coordType;
+  auto component = CalculateNavigableAccessibleAtPoint( accessible, {x, y}, cType, GET_NAVIGABLE_AT_POINT_MAX_RECURSION_DEPTH );
+  bool recurse = false;
+  if( component )
+  {
+    const auto states = component->GetStates();
+    if( states[State::MODAL] )
+    {
+      component = nullptr;
+    }
+  }
+  if( component )
+  {
+    recurse = component->IsProxy();
+  }
+  //TODO: add deputy
+  return {component, recurse, deputy};
+}
+
+static bool CheckChainEndWithAttribute( Accessible* obj, unsigned char forward )
+{
+  if( !obj )
+    return false;
+  auto attrs = obj->GetAttributes();
+  for( auto& attr : attrs )
+  {
+    if( attr.first == "relation_chain_end" )
+    {
+      if( ( attr.second == "prev,end" && forward == 0 ) || ( attr.second == "next,end" && forward == 1 ) || attr.second == "prev,next,end" )
+      {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+static Accessible* DeputyOfProxyInParentGet( Accessible* obj )
+{
+  return nullptr;
+}
+
+Accessible* BridgeAccessible::GetCurrentlyHighlighted()
+{
+  //TODO: add currently highlighted object
+  return nullptr;
+}
+
+std::vector< Accessible* > BridgeAccessible::ValidChildrenGet( const std::vector< Accessible* >& children, Accessible* start, Accessible* root )
+{
+  return children;
+}
+
+static bool DeputyIs( Accessible* obj )
+{
+  //TODO: add deputy
+  return false;
+}
+
+static Accessible* ProxyInParentGet( Accessible* obj )
+{
+  if( !obj )
+    return nullptr;
+  auto children = obj->GetChildren();
+  for( auto& child : children )
+  {
+    if( child->IsProxy() )
+      return child;
+  }
+  return nullptr;
+}
+
+static bool ObjectRoleIsAcceptableWhenNavigatingNextPrev( Accessible* obj )
+{
+  if( !obj )
+    return false;
+  auto role = obj->GetRole();
+  return role != Role::POPUP_MENU && role != Role::DIALOG;
+}
+
+template < class T >
+struct CycleDetection
+{
+  CycleDetection( const T value ) : key( value ), currentSearchSize( 1 ), counter( 1 ) {}
+  bool check( const T value )
+  {
+    if( key == value )
+      return true;
+    if( --counter == 0 )
+    {
+      currentSearchSize <<= 1;
+      if( currentSearchSize == 0 )
+        return true; // UNDEFINED BEHAVIOR
+      counter = currentSearchSize;
+      key = value;
+    }
+    return false;
+  }
+  T key;
+  unsigned int currentSearchSize;
+  unsigned int counter;
+};
+
+static Accessible* FindNonDefunctChild( const std::vector< Accessible* >& children, unsigned int currentIndex, unsigned char forward )
+{
+  unsigned int childrenCount = children.size();
+  for( ; currentIndex < childrenCount; forward ? ++currentIndex : --currentIndex )
+  {
+    Accessible* n = children[currentIndex];
+    if( n && !n->GetStates()[State::DEFUNCT] )
+      return n;
+  }
+  return nullptr;
+}
+
+static Accessible* DirectionalDepthFirstSearchTryNonDefunctChild( Accessible* node, const std::vector< Accessible* >& children, unsigned char forward )
+{
+  if( !node )
+    return nullptr;
+  auto childrenCount = children.size();
+  if( childrenCount > 0 )
+  {
+    const bool isShowing = GetScrollableParent( node ) == nullptr ? node->GetStates()[State::SHOWING] : true;
+    if( isShowing )
+    {
+      return FindNonDefunctChild( children, forward ? 0 : childrenCount - 1, forward );
+    }
+  }
+  return nullptr;
+}
+
+Accessible* BridgeAccessible::GetNextNonDefunctSibling( Accessible* obj, Accessible* start, Accessible* root, unsigned char forward )
+{
+  if( !obj )
+    return nullptr;
+  auto parent = obj->GetParent();
+  if( !parent )
+    return nullptr;
+
+  auto children = ValidChildrenGet( parent->GetChildren(), start, root );
+
+  unsigned int children_count = children.size();
+  if( children_count == 0 )
+  {
+    return nullptr;
+  }
+  unsigned int current = 0;
+  for( ; current < children_count && children[current] != obj; ++current )
+    ;
+  if( current >= children_count )
+  {
+    return nullptr;
+  }
+  forward ? ++current : --current;
+  auto ret = FindNonDefunctChild( children, current, forward );
+  return ret;
+}
+
+Accessible* BridgeAccessible::DirectionalDepthFirstSearchTryNonDefunctSibling( bool& all_children_visited, Accessible* node, Accessible* start, Accessible* root, unsigned char forward )
+{
+  while( true )
+  {
+    Accessible* sibling = GetNextNonDefunctSibling( node, start, root, forward );
+    if( sibling )
+    {
+      node = sibling;
+      all_children_visited = false;
+      break;
+    }
+    // walk up...
+    node = node->GetParent();
+    if( node == nullptr || node == root )
+      return nullptr;
+
+    // in backward traversing stop the walk up on parent
+    if( !forward )
+      break;
+  }
+  return node;
+}
+
+Accessible* BridgeAccessible::CalculateNeighbor( Accessible* root, Accessible* start, unsigned char forward, BridgeAccessible::GetNeighborSearchMode search_mode )
+{
+  if( start && CheckChainEndWithAttribute( start, forward ) )
+    return start;
+  if( root && root->GetStates()[State::DEFUNCT] )
+    return NULL;
+  if( start && start->GetStates()[State::DEFUNCT] )
+  {
+    start = NULL;
+    forward = 1;
+  }
+
+  if( search_mode == BridgeAccessible::GetNeighborSearchMode::recurseToOutside )
+  {
+    // This only works if we navigate backward, and it is not possible to
+    // find in embedded process. In this case the deputy should be used */
+    return DeputyOfProxyInParentGet( start );
+  }
+
+  Accessible* node = start ? start : root;
+  if( !node )
+    return nullptr;
+
+  // initialization of all-children-visited flag for start node - we assume
+  // that when we begin at start node and we navigate backward, then all children
+  // are visited, so navigation will ignore start's children and go to
+  // previous sibling available.
+  // Regarding condtion (start != root):
+  // The last object can be found only if all_children_visited is false.
+  // The start is same with root, when looking for the last object.
+  bool all_children_visited = ( start != root ) && ( search_mode != BridgeAccessible::GetNeighborSearchMode::recurseFromRoot && !forward );
+  // true, if starting element should be ignored. this is only used in rare case of
+  // recursive search failing to find an object.
+  // consider tree, where element A on bus BUS_A has child B on bus BUS_B. when going "next" from
+  // element A algorithm has to descend into BUS_B and search element B and its children. this is done
+  // by returning to our caller object B with special flag set (meaning - continue the search from B on bus BUS_B).
+  // if next object will be found there (on BUS_B), then search ends. but if not, then our caller will find it out
+  // and will call us again with object A and flag search_mode set to NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING.
+  // this flag means, that object A was already checked previously and we should skip it and its children.
+  bool force_next = ( search_mode == BridgeAccessible::GetNeighborSearchMode::continueAfterFailedRecursion );
+
+  CycleDetection< Accessible* > cycleDetection( node );
+  while( node )
+  {
+    if( node->GetStates()[State::DEFUNCT] )
+      return nullptr;
+
+    // always accept proxy object from different world
+    if( !force_next && node->IsProxy() )
+      return node;
+
+    auto children = node->GetChildren();
+    children = ValidChildrenGet( children, start, root );
+
+    // do accept:
+    // 1. not start node
+    // 2. parent after all children in backward traversing
+    // 3. Nodes with roles: ATSPI_ROLE_PAGE_TAB, ATSPI_ROLE_POPUP_MENU and ATSPI_ROLE_DIALOG, only when looking for first or last element.
+    //    Objects with those roles shouldnt be reachable, when navigating next / prev.
+    bool all_children_visited_or_moving_forward = ( children.size() == 0 || forward || all_children_visited );
+    if( !force_next && node != start && all_children_visited_or_moving_forward && AcceptObject( node ) )
+    {
+      if( start == NULL || ObjectRoleIsAcceptableWhenNavigatingNextPrev( node ) )
+        return node;
+    }
+
+    Accessible* next_related_in_direction = !force_next ? GetObjectInRelation( node, forward ? RelationType::FLOWS_TO : RelationType::FLOWS_FROM ) : nullptr;
+    // force_next means that the search_mode is NEIGHBOR_SEARCH_MODE_CONTINUE_AFTER_FAILED_RECURSING
+    // in this case the node is elm_layout which is parent of proxy object.
+    // There is an access object working for the proxy object, and the access
+    // object could have relation information. This relation information should
+    // be checked first before using the elm_layout as a node.
+    if( force_next && forward )
+    {
+      auto deputy = DeputyOfProxyInParentGet( node );
+      next_related_in_direction =
+          GetObjectInRelation( deputy, RelationType::FLOWS_TO );
+    }
+
+    if( next_related_in_direction && start && start->GetStates()[State::DEFUNCT] )
+    {
+      next_related_in_direction = NULL;
+    }
+
+    unsigned char want_cycle_detection = 0;
+    if( next_related_in_direction )
+    {
+      // Check next_related_in_direction is deputy object
+      Accessible* parent;
+      if( !forward )
+      {
+        // If the prev object is deputy, then go to inside of its proxy first
+        if( DeputyIs( next_related_in_direction ) )
+        {
+          parent = next_related_in_direction->GetParent();
+          next_related_in_direction = ProxyInParentGet( parent );
+        }
+      }
+      else
+      {
+        // If current object is deputy, and it has relation next object,
+        // then do not use the relation next object, and use proxy first
+        if( DeputyIs( node ) )
+        {
+          parent = node->GetParent();
+          next_related_in_direction = ProxyInParentGet( parent );
+        }
+      }
+      node = next_related_in_direction;
+      want_cycle_detection = 1;
+    }
+    else
+    {
+      auto child = !force_next && !all_children_visited ? DirectionalDepthFirstSearchTryNonDefunctChild( node, children, forward ) : nullptr;
+      if( child )
+      {
+        want_cycle_detection = 1;
+      }
+      else
+      {
+        if( !force_next && node == root )
+          return NULL;
+        all_children_visited = true;
+        child = DirectionalDepthFirstSearchTryNonDefunctSibling( all_children_visited, node, start, root, forward );
+      }
+      node = child;
+    }
+    force_next = 0;
+    if( want_cycle_detection && cycleDetection.check( node ) )
+    {
+      return NULL;
+    }
+  }
+  return NULL;
+}
+
+DBus::ValueOrError< Accessible*, uint8_t > BridgeAccessible::GetNeighbor( std::string rootPath, int32_t direction, int32_t search_mode )
+{
+  auto start = FindSelf();
+  rootPath = StripPrefix( rootPath );
+  auto root = !rootPath.empty() ? Find( rootPath ) : nullptr;
+  auto accessible = CalculateNeighbor( root, start, direction == 1, static_cast< GetNeighborSearchMode >( search_mode ) );
+  unsigned char recurse = 0;
+  if( accessible )
+  {
+    recurse = accessible->IsProxy();
+  }
+  return {accessible, recurse};
+}
+
+Accessible* BridgeAccessible::GetParent()
+{
+  // NOTE: currently bridge supports single application root element.
+  // only element set as application root might return nullptr from GetParent
+  // if you want more, then you need to change setApplicationRoot to
+  // add/remove ApplicationRoot and make roots a vector.
+  auto p = FindSelf()->GetParent();
+  assert( p );
+  return p;
+}
+DBus::ValueOrError< std::vector< Accessible* > > BridgeAccessible::GetChildren()
+{
+  return FindSelf()->GetChildren();
+}
+std::string BridgeAccessible::GetDescription()
+{
+  return FindSelf()->GetDescription();
+}
+DBus::ValueOrError< uint32_t > BridgeAccessible::GetRole()
+{
+  return static_cast< unsigned int >( FindSelf()->GetRole() );
+}
+DBus::ValueOrError< std::string > BridgeAccessible::GetRoleName()
+{
+  return FindSelf()->GetRoleName();
+}
+DBus::ValueOrError< std::string > BridgeAccessible::GetLocalizedRoleName()
+{
+  return FindSelf()->GetLocalizedRoleName();
+}
+DBus::ValueOrError< int32_t > BridgeAccessible::GetIndexInParent()
+{
+  return FindSelf()->GetIndexInParent();
+}
+DBus::ValueOrError< std::array< uint32_t, 2 > > BridgeAccessible::GetStates()
+{
+  return FindSelf()->GetStates().GetRawData();
+}
+DBus::ValueOrError< std::unordered_map< std::string, std::string > > BridgeAccessible::GetAttributes()
+{
+  return FindSelf()->GetAttributes();
+}
+DBus::ValueOrError< std::vector< std::string > > BridgeAccessible::GetInterfaces()
+{
+  return FindSelf()->GetInterfaces();
+}
+int BridgeAccessible::GetChildCount()
+{
+  return FindSelf()->GetChildCount();
+}
+DBus::ValueOrError< Accessible* > BridgeAccessible::GetChildAtIndex( int index )
+{
+  if( index < 0 )
+    throw std::domain_error{"negative index (" + std::to_string( index ) + ")"};
+  return FindSelf()->GetChildAtIndex( static_cast< size_t >( index ) );
+}
+
+std::string BridgeAccessible::GetName()
+{
+  return FindSelf()->GetName();
+}
+
+DBus::ValueOrError< Accessible*, uint32_t , std::unordered_map< std::string, std::string > > BridgeAccessible::GetDefaultLabelInfo()
+{
+  auto defaultLabel = FindSelf()->GetDefaultLabel();
+  return {defaultLabel, static_cast< uint32_t >( defaultLabel->GetRole() ) , defaultLabel->GetAttributes()};
+}
+
+DBus::ValueOrError<std::vector< BridgeAccessible::Relation >> BridgeAccessible::GetRelationSet()
+{
+  auto relations = FindSelf()->GetRelationSet();
+  std::vector< BridgeAccessible::Relation > ret;
+
+  for (auto &it : relations)
+    ret.emplace_back(Relation{static_cast<uint32_t>(it.relationType), it.targets});
+
+  return ret;
+}
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-accessible.h b/dali/internal/accessibility/tizen-wayland/atspi/bridge-accessible.h
new file mode 100644 (file)
index 0000000..9abdd36
--- /dev/null
@@ -0,0 +1,105 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_ACCESSIBLE_H
+#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_ACCESSIBLE_H
+
+/*
+ * Copyright (c) 2019 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 <array>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+// INTERNAL INCLUDES
+#include "bridge-base.h"
+
+class BridgeAccessible : public virtual BridgeBase
+{
+protected:
+  BridgeAccessible();
+
+  void RegisterInterfaces();
+
+public:
+  enum class GetNeighborSearchMode
+  {
+    normal = 0,
+    recurseFromRoot = 1,
+    continueAfterFailedRecursion = 2,
+    recurseToOutside = 3,
+  };
+  int GetChildCount();
+  DBus::ValueOrError< Dali::Accessibility::Accessible* > GetChildAtIndex( int index );
+  Dali::Accessibility::Accessible* GetParent();
+  DBus::ValueOrError< std::vector< Dali::Accessibility::Accessible* > > GetChildren();
+  std::string GetName();
+  std::string GetDescription();
+  DBus::ValueOrError< uint32_t > GetRole();
+  DBus::ValueOrError< std::string > GetRoleName();
+  DBus::ValueOrError< std::string > GetLocalizedRoleName();
+  DBus::ValueOrError< int32_t > GetIndexInParent();
+  DBus::ValueOrError< std::array< uint32_t, 2 > > GetStates();
+  DBus::ValueOrError< std::unordered_map< std::string, std::string > > GetAttributes();
+  DBus::ValueOrError< std::vector< std::string > > GetInterfaces();
+  DBus::ValueOrError< Dali::Accessibility::Accessible*, uint8_t, Dali::Accessibility::Accessible* > GetNavigableAtPoint( int32_t x, int32_t y, uint32_t coordType );
+  DBus::ValueOrError< Dali::Accessibility::Accessible*, uint8_t > GetNeighbor( std::string root_path, int32_t direction, int32_t search_mode );
+  DBus::ValueOrError< Dali::Accessibility::Accessible*, uint32_t , std::unordered_map< std::string, std::string > > GetDefaultLabelInfo();
+  using ReadingMaterialType = DBus::ValueOrError<
+      std::unordered_map< std::string, std::string >, // attributes
+      std::string,                                    // name
+      std::string,                                    // labeledByName
+      std::string,                                    // textIfceName
+      uint32_t,
+      Dali::Accessibility::States,
+      std::string,                      // localized name
+      int32_t,                          // child count
+      double,                           // current value
+      double,                           // minimum increment
+      double,                           // maximum value
+      double,                           // minimum value
+      std::string,                      // description
+      int32_t,                          // index in parent
+      bool,                             // isSelectedInParent
+      bool,                             // hasCheckBoxChild
+      int32_t,                          // listChildrenCount
+      int32_t,                          // firstSelectedChildIndex
+      Dali::Accessibility::Accessible*, // parent
+      Dali::Accessibility::States,      // parentStateSet
+      int32_t,                          // parentChildCount
+      uint32_t,                         // parentRole
+      int32_t,                          // selectedChildCount,
+      Dali::Accessibility::Accessible*  // describedByObject
+      >;
+
+  ReadingMaterialType GetReadingMaterial();
+
+  DBus::ValueOrError< bool > DoGesture( Dali::Accessibility::Gesture type, int32_t xBeg, int32_t xEnd, int32_t yBeg, int32_t yEnd, Dali::Accessibility::GestureState state, uint32_t eventTime );
+
+  using Relation = std::tuple< uint32_t, std::vector< Dali::Accessibility::Address > >;
+  DBus::ValueOrError<std::vector< Relation >> GetRelationSet();
+
+private:
+  Dali::Accessibility::Accessible* CalculateNeighbor( Dali::Accessibility::Accessible* root, Dali::Accessibility::Accessible* start, unsigned char forward, GetNeighborSearchMode search_mode );
+  std::vector< Dali::Accessibility::Accessible* > ValidChildrenGet( const std::vector< Dali::Accessibility::Accessible* >& children, Dali::Accessibility::Accessible* start, Dali::Accessibility::Accessible* root );
+  Dali::Accessibility::Accessible* GetCurrentlyHighlighted();
+  Dali::Accessibility::Accessible* DirectionalDepthFirstSearchTryNonDefunctSibling( bool& all_children_visited, Dali::Accessibility::Accessible* node, Dali::Accessibility::Accessible* start, Dali::Accessibility::Accessible* root, unsigned char forward );
+  Dali::Accessibility::Accessible* GetNextNonDefunctSibling( Dali::Accessibility::Accessible* obj, Dali::Accessibility::Accessible* start, Dali::Accessibility::Accessible* root, unsigned char forward );
+  Dali::Accessibility::Component* CalculateNavigableAccessibleAtPoint( Dali::Accessibility::Accessible* root, Dali::Accessibility::Point p, Dali::Accessibility::CoordType cType, unsigned int maxRecursionDepth );
+  Dali::Accessibility::Component * GetObjectInRelation(Dali::Accessibility::Accessible * obj, Dali::Accessibility::RelationType ralationType);
+};
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_ACCESSIBLE_H
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-action.cpp b/dali/internal/accessibility/tizen-wayland/atspi/bridge-action.cpp
new file mode 100644 (file)
index 0000000..a632f30
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-action.h>
+
+// EXTERNAL INCLUDES
+#include <iostream>
+
+using namespace Dali::Accessibility;
+
+void BridgeAction::RegisterInterfaces()
+{
+  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceAction};
+
+  AddGetPropertyToInterface( desc, "NActions", &BridgeAction::GetActionCount );
+
+  AddFunctionToInterface( desc, "GetName", &BridgeAction::GetActionName );
+  AddFunctionToInterface( desc, "GetLocalizedName", &BridgeAction::GetLocalizedActionName );
+  AddFunctionToInterface( desc, "GetDescription", &BridgeAction::GetActionDescription );
+  AddFunctionToInterface( desc, "GetKeyBinding", &BridgeAction::GetActionKeyBinding );
+  AddFunctionToInterface( desc, "DoAction", &BridgeAction::DoAction );
+  AddFunctionToInterface( desc, "DoActionName", &BridgeAction::DoActionName );
+  dbusServer.addInterface( "/", desc, true );
+}
+
+Action* BridgeAction::FindSelf() const
+{
+  auto s = BridgeBase::FindSelf();
+  assert( s );
+  auto s2 = dynamic_cast< Action* >( s );
+  if( !s2 )
+    throw std::domain_error{"object " + s->GetAddress().ToString() + " doesn't have Action interface"};
+  return s2;
+}
+
+DBus::ValueOrError< std::string > BridgeAction::GetActionName( int32_t index )
+{
+  return FindSelf()->GetActionName( index );
+}
+
+DBus::ValueOrError< std::string > BridgeAction::GetLocalizedActionName( int32_t index )
+{
+  return FindSelf()->GetLocalizedActionName( index );
+}
+
+DBus::ValueOrError< std::string > BridgeAction::GetActionDescription( int32_t index )
+{
+  return FindSelf()->GetActionDescription( index );
+}
+
+DBus::ValueOrError< std::string > BridgeAction::GetActionKeyBinding( int32_t index )
+{
+  return FindSelf()->GetActionKeyBinding( index );
+}
+
+DBus::ValueOrError< int32_t > BridgeAction::GetActionCount()
+{
+  return FindSelf()->GetActionCount();
+  ;
+}
+
+DBus::ValueOrError< bool > BridgeAction::DoAction( int32_t index )
+{
+  return FindSelf()->DoAction( index );
+}
+
+DBus::ValueOrError< bool > BridgeAction::DoActionName( std::string name )
+{
+  auto self = FindSelf();
+  auto cnt = self->GetActionCount();
+  for( auto i = 0u; i < cnt; ++i )
+  {
+    if( self->GetActionName( i ) == name )
+    {
+      return self->DoAction( i );
+    }
+  }
+  throw std::domain_error{"object " + self->GetAddress().ToString() + " doesn't have action '" + name + "'"};
+}
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-action.h b/dali/internal/accessibility/tizen-wayland/atspi/bridge-action.h
new file mode 100644 (file)
index 0000000..1a8213e
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_ACTION_H
+#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_ACTION_H
+
+/*
+ * Copyright (c) 2019 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 <tuple>
+#include <vector>
+
+// INTERNAL INCLUDES
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-base.h>
+
+class BridgeAction : public virtual BridgeBase
+{
+protected:
+  BridgeAction() = default;
+
+  void RegisterInterfaces();
+
+  Dali::Accessibility::Action* FindSelf() const;
+
+public:
+  DBus::ValueOrError< std::string > GetActionName( int32_t index );
+  DBus::ValueOrError< std::string > GetLocalizedActionName( int32_t index );
+  DBus::ValueOrError< std::string > GetActionDescription( int32_t index );
+  DBus::ValueOrError< std::string > GetActionKeyBinding( int32_t index );
+  DBus::ValueOrError< int32_t > GetActionCount();
+  DBus::ValueOrError< bool > DoAction( int32_t index );
+  DBus::ValueOrError< bool > DoActionName( std::string name );
+};
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_ACTION_H
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-base.cpp b/dali/internal/accessibility/tizen-wayland/atspi/bridge-base.cpp
new file mode 100644 (file)
index 0000000..6b122aa
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-base.h>
+
+// EXTERNAL INCLUDES
+#include <atomic>
+#include <cstdlib>
+#include <memory>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/timer.h>
+
+using namespace Dali::Accessibility;
+
+static Dali::Timer tickTimer;
+
+BridgeBase::~BridgeBase()
+{
+}
+
+BridgeBase::BridgeBase()
+{
+}
+
+void BridgeBase::addFilteredEvent( FilteredEvents kind, Dali::Accessibility::Accessible* obj, float delay, std::function<void()> functor )
+{
+  if( delay < 0 )
+  {
+    delay = 0;
+  }
+
+  auto it = filteredEvents.insert({ { kind, obj }, { static_cast<unsigned int>(delay * 10), {} } });
+  if (it.second)
+  {
+    functor();
+  }
+  else
+  {
+    it.first->second.second = std::move(functor);
+  }
+
+  if (!tickTimer)
+  {
+    tickTimer = Dali::Timer::New(100);
+    tickTimer.TickSignal().Connect(this, &BridgeBase::tickFilteredEvents);
+  }
+}
+
+bool BridgeBase::tickFilteredEvents()
+{
+  for(auto it = filteredEvents.begin(); it != filteredEvents.end(); )
+  {
+    if (it->second.first)
+    {
+      --it->second.first;
+    }
+    else
+    {
+      if (it->second.second)
+      {
+        it->second.second();
+        it->second.second = {};
+      }
+      else
+      {
+        it = filteredEvents.erase(it);
+        continue;
+      }
+    }
+    ++it;
+  }
+  return !filteredEvents.empty();
+}
+
+BridgeBase::ForceUpResult BridgeBase::ForceUp()
+{
+  if( Bridge::ForceUp() == ForceUpResult::ALREADY_UP )
+  {
+    return ForceUpResult::ALREADY_UP;
+  }
+  auto proxy = DBus::DBusClient{dbusLocators::atspi::BUS, dbusLocators::atspi::OBJ_PATH, dbusLocators::atspi::BUS_INTERFACE, DBus::ConnectionType::SESSION};
+  auto addr = proxy.method< std::string() >( dbusLocators::atspi::GET_ADDRESS ).call();
+
+  if( !addr )
+  {
+    throw std::domain_error{std::string( "failed at call '" ) + dbusLocators::atspi::GET_ADDRESS + "': " + addr.getError().message};
+  }
+
+  con = DBusWrapper::Installed()->eldbus_address_connection_get_impl( std::get< 0 >( addr ) );
+  data->busName = DBus::getConnectionName( con );
+  dbusServer = { con };
+
+  {
+    DBus::DBusInterfaceDescription desc{"org.a11y.atspi.Cache"};
+    AddFunctionToInterface( desc, "GetItems", &BridgeBase::GetItems );
+    dbusServer.addInterface( "/org/a11y/atspi/cache", desc );
+  }
+  {
+    DBus::DBusInterfaceDescription desc{"org.a11y.atspi.Application"};
+    AddGetSetPropertyToInterface( desc, "Id", &BridgeBase::IdGet, &BridgeBase::IdSet );
+    dbusServer.addInterface( AtspiPath, desc );
+  }
+
+  return ForceUpResult::JUST_STARTED;
+}
+
+void BridgeBase::ForceDown()
+{
+  Bridge::ForceDown();
+  dbusServer = {};
+  con = {};
+}
+
+const std::string& BridgeBase::GetBusName() const
+{
+  static std::string empty;
+  return data ? data->busName : empty;
+}
+
+Accessible* BridgeBase::FindByPath( const std::string& name ) const
+{
+  try
+  {
+    return Find( name );
+  }
+  catch( std::domain_error )
+  {
+    return nullptr;
+  }
+}
+
+void BridgeBase::AddPopup( Accessible* obj )
+{
+  if( std::find( popups.begin(), popups.end(), obj ) != popups.end() )
+  {
+    return;
+  }
+  popups.push_back( obj );
+  if (IsUp())
+  {
+    obj->Emit( WindowEvent::ACTIVATE, 0 );
+  }
+}
+
+void BridgeBase::RemovePopup( Accessible* obj )
+{
+  auto it = std::find( popups.begin(), popups.end(), obj );
+  if( it == popups.end() )
+  {
+    return;
+  }
+  popups.erase( it );
+  if (IsUp())
+  {
+    obj->Emit( WindowEvent::DEACTIVATE, 0 );
+    if( popups.empty() )
+    {
+      application.children.back()->Emit( WindowEvent::ACTIVATE, 0 );
+    }
+    else
+    {
+      popups.back()->Emit( WindowEvent::ACTIVATE, 0 );
+    }
+  }
+}
+
+void BridgeBase::AddTopLevelWindow( Accessible* root )
+{
+  application.children.push_back( root );
+  SetIsOnRootLevel( root );
+}
+
+void BridgeBase::RemoveTopLevelWindow( Accessible* root )
+{
+  for(auto i = 0u; i < application.children.size(); ++i)
+  {
+    if( application.children[i] == root )
+    {
+      application.children.erase(application.children.begin() + i);
+      break;
+    }
+  }
+}
+
+std::string BridgeBase::StripPrefix( const std::string& path )
+{
+  auto size = strlen( AtspiPath );
+  return path.substr( size + 1 );
+}
+
+Accessible* BridgeBase::Find( const std::string& path ) const
+{
+  if( path == "root" )
+  {
+    return &application;
+  }
+  void* p;
+  std::istringstream tmp{ path };
+  if (! ( tmp >> p) )
+  {
+    throw std::domain_error{"invalid path '" + path + "'"};
+  }
+  auto it = data->knownObjects.find( static_cast<Accessible*>( p ) );
+  if( it == data->knownObjects.end() )
+  {
+    throw std::domain_error{"unknown object '" + path + "'"};
+  }
+  return static_cast<Accessible*>( p );
+}
+
+Accessible* BridgeBase::Find( const Address& ptr ) const
+{
+  assert( ptr.GetBus() == data->busName );
+  return Find( ptr.GetPath() );
+}
+
+Accessible* BridgeBase::FindSelf() const
+{
+  auto pth = DBus::DBusServer::getCurrentObjectPath();
+  auto size = strlen( AtspiPath );
+  if( pth.size() <= size )
+  {
+    throw std::domain_error{"invalid path '" + pth + "'"};
+  }
+  if( pth.substr( 0, size ) != AtspiPath )
+  {
+    throw std::domain_error{"invalid path '" + pth + "'"};
+  }
+  if( pth[size] != '/' )
+  {
+    throw std::domain_error{"invalid path '" + pth + "'"};
+  }
+  return Find( StripPrefix( pth ) );
+}
+
+void BridgeBase::IdSet( int id )
+{
+  this->id = id;
+}
+
+int BridgeBase::IdGet()
+{
+  return this->id;
+}
+
+auto BridgeBase::GetItems() -> DBus::ValueOrError< std::vector< CacheElementType > >
+{
+  auto root = &application;
+
+  std::vector< CacheElementType > res;
+
+  std::function< void(Accessible*) > proc =
+    [&]( Accessible* item )
+    {
+      res.emplace_back( std::move( CreateCacheElement( root ) ) );
+      for( auto i = 0u; i < item->GetChildCount(); ++i )
+      {
+        proc( item->GetChildAtIndex( i ) );
+      }
+    };
+
+  return res;
+}
+
+auto BridgeBase::CreateCacheElement( Accessible* item ) -> CacheElementType
+{
+  if( !item )
+  {
+    return {};
+  }
+
+  auto root = &application;
+  auto parent = item->GetParent();
+
+  std::vector< Address > children;
+  for( auto i = 0u; i < item->GetChildCount(); ++i )
+  {
+    children.emplace_back( item->GetChildAtIndex( i )->GetAddress() );
+  }
+
+  return std::make_tuple(
+    item->GetAddress(),
+    root->GetAddress(),
+    parent ? parent->GetAddress() : Address{},
+    children,
+    item->GetInterfaces(),
+    item->GetName(),
+    item->GetRole(),
+    item->GetDescription(),
+    item->GetStates().GetRawData()
+  );
+}
+
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-base.h b/dali/internal/accessibility/tizen-wayland/atspi/bridge-base.h
new file mode 100644 (file)
index 0000000..64a046f
--- /dev/null
@@ -0,0 +1,294 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H
+#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H
+
+/*
+ * Copyright (c) 2019 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/signals/connection-tracker.h>
+#include <memory>
+
+// INTERNAL INCLUDES
+#include <dali/internal/accessibility/tizen-wayland/atspi/accessibility-common.h>
+
+class AppAccessible : public virtual Dali::Accessibility::Accessible, public virtual Dali::Accessibility::Collection
+{
+public:
+  Dali::Accessibility::EmptyAccessibleWithAddress parent;
+  std::vector< Dali::Accessibility::Accessible* > children;
+  std::string name;
+
+  std::string GetName() override
+  {
+    return name;
+  }
+
+  std::string GetDescription() override
+  {
+    return "";
+  }
+
+  Dali::Accessibility::Accessible* GetParent() override
+  {
+    return &parent;
+  }
+
+  size_t GetChildCount() override
+  {
+    return children.size();
+  }
+
+  Dali::Accessibility::Accessible* GetChildAtIndex( size_t index ) override
+  {
+    auto s = children.size();
+    if( index >= s )
+      throw std::domain_error{"invalid index " + std::to_string( index ) + " for object with " + std::to_string( s ) + " children"};
+    return children[index];
+  }
+
+  size_t GetIndexInParent() override
+  {
+    throw std::domain_error{"can't call GetIndexInParent on application object"};
+  }
+
+  Dali::Accessibility::Role GetRole() override
+  {
+    return Dali::Accessibility::Role::APPLICATION;
+  }
+
+  Dali::Accessibility::States GetStates() override
+  {
+    return {};
+  }
+
+  Dali::Accessibility::Attributes GetAttributes() override
+  {
+    return {};
+  }
+
+  Dali::Accessibility::Accessible* getActiveWindow()
+  {
+    return children.empty() ? nullptr : children[0];
+  }
+
+  bool DoGesture(const Dali::Accessibility::GestureInfo &gestureInfo) override
+  {
+      return false;
+  }
+
+  std::vector<Dali::Accessibility::Relation> GetRelationSet() override
+  {
+      return {};
+  }
+
+  Dali::Accessibility::Address GetAddress() override {
+    return { "", "root" };
+  }
+
+};
+
+
+enum class FilteredEvents {
+  boundsChanged
+};
+
+
+namespace std {
+  template <> struct hash<std::pair<FilteredEvents, Dali::Accessibility::Accessible*>> {
+    size_t operator () (std::pair<FilteredEvents, Dali::Accessibility::Accessible*> v) const {
+      return (static_cast<size_t>(v.first) * 131) ^ reinterpret_cast<size_t>(v.second);
+    }
+  };
+}
+
+
+class BridgeBase : public Dali::Accessibility::Bridge, public Dali::ConnectionTracker
+{
+  std::unordered_map<std::pair<FilteredEvents, Dali::Accessibility::Accessible*>, std::pair<unsigned int, std::function<void()>>> filteredEvents;
+
+  bool tickFilteredEvents();
+
+public:
+
+  void addFilteredEvent(FilteredEvents kind, Dali::Accessibility::Accessible* obj, float delay, std::function<void()> functor);
+
+  const std::string& GetBusName() const override;
+  void AddTopLevelWindow( Dali::Accessibility::Accessible* window ) override;
+  void RemoveTopLevelWindow( Dali::Accessibility::Accessible* window ) override;
+  void AddPopup( Dali::Accessibility::Accessible* ) override;
+  void RemovePopup( Dali::Accessibility::Accessible* ) override;
+
+  Dali::Accessibility::Accessible* GetApplication() const override
+  {
+    return &application;
+  }
+
+  template < typename SELF, typename... RET, typename... ARGS >
+  void AddFunctionToInterface(
+      DBus::DBusInterfaceDescription& desc, const std::string& funcName,
+      DBus::ValueOrError< RET... > ( SELF::*funcPtr )( ARGS... ) )
+  {
+    if ( auto self = dynamic_cast< SELF* >( this ) )
+      desc.addMethod< DBus::ValueOrError< RET... >( ARGS... ) >( funcName,
+                                                               [=]( ARGS... args ) -> DBus::ValueOrError< RET... > {
+                                                                 try
+                                                                 {
+                                                                   return ( self->*funcPtr )( std::move( args )... );
+                                                                 }
+                                                                 catch( std::domain_error& e )
+                                                                 {
+                                                                   return DBus::Error{e.what()};
+                                                                 }
+                                                               } );
+  }
+
+  template < typename T, typename SELF >
+  void AddGetPropertyToInterface( DBus::DBusInterfaceDescription& desc,
+                                  const std::string& funcName, T ( SELF::*funcPtr )() )
+  {
+    if ( auto self = dynamic_cast< SELF* >( this ) )
+      desc.addProperty< T >( funcName,
+                           [=]() -> DBus::ValueOrError< T > {
+                             try
+                             {
+                               return ( self->*funcPtr )();
+                             }
+                             catch( std::domain_error& e )
+                             {
+                               return DBus::Error{e.what()};
+                             }
+                           },
+                           {} );
+  }
+
+  template < typename T, typename SELF >
+  void AddSetPropertyToInterface( DBus::DBusInterfaceDescription& desc,
+                                  const std::string& funcName, void ( SELF::*funcPtr )( T ) )
+  {
+    if ( auto self = dynamic_cast< SELF* >( this ) )
+      desc.addProperty< T >( funcName, {},
+                           [=]( T t ) -> DBus::ValueOrError< void > {
+                             try
+                             {
+                               ( self->*funcPtr )( std::move( t ) );
+                               return {};
+                             }
+                             catch( std::domain_error& e )
+                             {
+                               return DBus::Error{e.what()};
+                             }
+                           } );
+  }
+
+  template < typename T, typename T1, typename SELF >
+  void AddGetSetPropertyToInterface( DBus::DBusInterfaceDescription& desc,
+                                     const std::string& funcName, T1 ( SELF::*funcPtrGet )(), DBus::ValueOrError< void > ( SELF::*funcPtrSet )( T ) )
+  {
+    if ( auto self = dynamic_cast< SELF* >( this ) )
+      desc.addProperty< T >( funcName,
+                           [=]() -> DBus::ValueOrError< T > {
+                             try
+                             {
+                               return ( self->*funcPtrGet )();
+                             }
+                             catch( std::domain_error& e )
+                             {
+                               return DBus::Error{e.what()};
+                             }
+                           },
+                           [=]( T t ) -> DBus::ValueOrError< void > {
+                             try
+                             {
+                               ( self->*funcPtrSet )( std::move( t ) );
+                               return {};
+                             }
+                             catch( std::domain_error& e )
+                             {
+                               return DBus::Error{e.what()};
+                             }
+                           } );
+  }
+  template < typename T, typename T1, typename SELF >
+  void AddGetSetPropertyToInterface( DBus::DBusInterfaceDescription& desc,
+                                     const std::string& funcName, T1 ( SELF::*funcPtrGet )(), void ( SELF::*funcPtrSet )( T ) )
+  {
+    if ( auto self = dynamic_cast< SELF* >( this ) )
+      desc.addProperty< T >( funcName,
+                           [=]() -> DBus::ValueOrError< T > {
+                             try
+                             {
+                               return ( self->*funcPtrGet )();
+                             }
+                             catch( std::domain_error& e )
+                             {
+                               return DBus::Error{e.what()};
+                             }
+                           },
+                           [=]( T t ) -> DBus::ValueOrError< void > {
+                             try
+                             {
+                               ( self->*funcPtrSet )( std::move( t ) );
+                               return {};
+                             }
+                             catch( std::domain_error& e )
+                             {
+                               return DBus::Error{e.what()};
+                             }
+                           } );
+  }
+  static std::string StripPrefix( const std::string& path );
+
+  Dali::Accessibility::Accessible* Find( const std::string& path ) const;
+  Dali::Accessibility::Accessible* Find( const Dali::Accessibility::Address& ptr ) const;
+  Dali::Accessibility::Accessible* FindSelf() const;
+  Dali::Accessibility::Accessible* FindByPath( const std::string& name ) const override;
+  void SetApplicationName( std::string name ) override
+  {
+    application.name = std::move( name );
+  }
+
+protected:
+  mutable AppAccessible application;
+  std::vector<Dali::Accessibility::Accessible*> popups;
+private:
+  void IdSet( int id );
+  int IdGet();
+
+  using CacheElementType = std::tuple<
+      Dali::Accessibility::Address, Dali::Accessibility::Address, Dali::Accessibility::Address,
+      std::vector< Dali::Accessibility::Address >,
+      std::vector< std::string >,
+      std::string,
+      Dali::Accessibility::Role,
+      std::string,
+      std::array< uint32_t, 2 > >;
+  DBus::ValueOrError< std::vector< CacheElementType > > GetItems();
+  CacheElementType CreateCacheElement( Dali::Accessibility::Accessible* item );
+
+protected:
+  BridgeBase();
+  virtual ~BridgeBase();
+
+  ForceUpResult ForceUp() override;
+  void ForceDown() override;
+
+  DBus::DBusServer dbusServer;
+  DBusWrapper::ConnectionPtr con;
+  int id = 0;
+};
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_BASE_H
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-collection.cpp b/dali/internal/accessibility/tizen-wayland/atspi/bridge-collection.cpp
new file mode 100644 (file)
index 0000000..0271c4a
--- /dev/null
@@ -0,0 +1,386 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-collection.h>
+
+// EXTERNAL INCLUDES
+#include <algorithm>
+#include <iostream>
+#include <unordered_set>
+#include <vector>
+
+using namespace Dali::Accessibility;
+
+void BridgeCollection::RegisterInterfaces()
+{
+  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceCollection};
+  AddFunctionToInterface( desc, "GetMatches", &BridgeCollection::GetMatches );
+  dbusServer.addInterface( "/", desc, true );
+}
+
+Collection* BridgeCollection::FindSelf() const
+{
+  auto s = BridgeBase::FindSelf();
+  assert( s );
+  auto s2 = dynamic_cast< Collection* >( s );
+  if( !s2 )
+    throw std::domain_error{"object " + s->GetAddress().ToString() + " doesn't have Collection interface"};
+  return s2;
+}
+
+enum
+{
+  ATSPI_Collection_MATCH_INVALID,
+  ATSPI_Collection_MATCH_ALL,
+  ATSPI_Collection_MATCH_ANY,
+  ATSPI_Collection_MATCH_NONE,
+  ATSPI_Collection_MATCH_EMPTY,
+  ATSPI_Collection_MATCH_LAST_DEFINED,
+};
+
+struct BridgeCollection::Comparer
+{
+  using Mode = MatchType;
+
+  enum class CompareFuncExit
+  {
+    FIRST_FOUND,
+    FIRST_NOT_FOUND
+  };
+
+  static Mode ConvertToMatchType( int32_t mode )
+  {
+    switch( mode )
+    {
+      case ATSPI_Collection_MATCH_INVALID:
+      {
+        return Mode::INVALID;
+      }
+      case ATSPI_Collection_MATCH_ALL:
+      {
+        return Mode::ALL;
+      }
+      case ATSPI_Collection_MATCH_ANY:
+      {
+        return Mode::ANY;
+      }
+      case ATSPI_Collection_MATCH_NONE:
+      {
+        return Mode::NONE;
+      }
+      case ATSPI_Collection_MATCH_EMPTY:
+      {
+        return Mode::EMPTY;
+      }
+    }
+    return Mode::INVALID;
+  }
+
+  struct ComparerInterfaces
+  {
+    std::unordered_set< std::string > object;
+    std::vector< std::string > requested;
+    Mode mode = Mode::INVALID;
+
+    ComparerInterfaces( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::InterfacesMatchType >( *rule ) ) )
+    {
+      requested = {std::get< Index::Interfaces >( *rule ).begin(), std::get< Index::Interfaces >( *rule ).end()};
+    }
+    void Update( Accessible* obj )
+    {
+      object.clear();
+      for( auto& q : obj->GetInterfaces() )
+        object.insert( std::move( q ) );
+    }
+    bool RequestEmpty() const { return requested.empty(); }
+    bool ObjectEmpty() const { return object.empty(); }
+    bool Compare( CompareFuncExit exit )
+    {
+      bool foundAny = false;
+      for( auto& iname : requested )
+      {
+        bool found = ( object.find( iname ) != object.end() );
+        if( found )
+          foundAny = true;
+        if( found == ( exit == CompareFuncExit::FIRST_FOUND ) )
+          return found;
+      }
+      return foundAny;
+    }
+  };
+  struct ComparerAttributes
+  {
+    std::unordered_map< std::string, std::string > requested, object;
+    Mode mode = Mode::INVALID;
+
+    ComparerAttributes( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::AttributesMatchType >( *rule ) ) )
+    {
+      requested = std::get< Index::Attributes >( *rule );
+    }
+    void Update( Accessible* obj )
+    {
+      object = obj->GetAttributes();
+    }
+    bool RequestEmpty() const { return requested.empty(); }
+    bool ObjectEmpty() const { return object.empty(); }
+    bool Compare( CompareFuncExit exit )
+    {
+      bool foundAny = false;
+      for( auto& iname : requested )
+      {
+        auto it = object.find( iname.first );
+        bool found = it != object.end() && iname.second == it->second;
+        if( found )
+          foundAny = true;
+        if( found == ( exit == CompareFuncExit::FIRST_FOUND ) )
+        {
+          return found;
+        }
+      }
+      return foundAny;
+    }
+  };
+  struct ComparerRoles
+  {
+    using Roles = BitSets< 4, Role >;
+    Roles requested, object;
+    Mode mode = Mode::INVALID;
+
+    ComparerRoles( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::RolesMatchType >( *rule ) ) )
+    {
+      requested = Roles{std::get< Index::Roles >( *rule )};
+    }
+    void Update( Accessible* obj )
+    {
+      object = {};
+      object[obj->GetRole()] = true;
+      assert( object );
+    }
+    bool RequestEmpty() const { return !requested; }
+    bool ObjectEmpty() const { return !object; }
+    bool Compare( CompareFuncExit exit )
+    {
+      switch( mode )
+      {
+        case Mode::INVALID:
+        {
+          return true;
+        }
+        case Mode::EMPTY:
+        case Mode::ALL:
+        {
+          return requested == ( object & requested );
+        }
+        case Mode::ANY:
+        {
+          return bool( object & requested );
+        }
+        case Mode::NONE:
+        {
+          return bool( object & requested );
+        }
+      }
+      return false;
+    }
+  };
+  struct ComparerStates
+  {
+    States requested, object;
+    Mode mode = Mode::INVALID;
+
+    ComparerStates( MatchRule* rule ) : mode( ConvertToMatchType( std::get< Index::StatesMatchType >( *rule ) ) )
+    {
+      requested = States{std::get< Index::States >( *rule )};
+    }
+    void Update( Accessible* obj )
+    {
+      object = obj->GetStates();
+    }
+    bool RequestEmpty() const { return !requested; }
+    bool ObjectEmpty() const { return !object; }
+    bool Compare( CompareFuncExit exit )
+    {
+      switch( mode )
+      {
+        case Mode::INVALID:
+        {
+          return true;
+        }
+        case Mode::EMPTY:
+        case Mode::ALL:
+        {
+          return requested == ( object & requested );
+        }
+        case Mode::ANY:
+        {
+          return bool( object & requested );
+        }
+        case Mode::NONE:
+        {
+          return bool( object & requested );
+        }
+      }
+      return false;
+    }
+  };
+
+  template < typename T >
+  bool compareFunc( T& cmp, Accessible* obj )
+  {
+    if( cmp.mode == Mode::INVALID )
+      return true;
+    cmp.Update( obj );
+    switch( cmp.mode )
+    {
+      case Mode::ANY:
+      {
+        if( cmp.RequestEmpty() || cmp.ObjectEmpty() )
+          return false;
+        break;
+      }
+      case Mode::ALL:
+      {
+        if( cmp.RequestEmpty() )
+          return true;
+        if( cmp.ObjectEmpty() )
+          return false;
+        break;
+      }
+      case Mode::NONE:
+      {
+        if( cmp.RequestEmpty() || cmp.ObjectEmpty() )
+          return true;
+        break;
+      }
+      case Mode::EMPTY:
+      {
+        if( cmp.RequestEmpty() && cmp.ObjectEmpty() )
+          return true;
+        if( cmp.RequestEmpty() || cmp.ObjectEmpty() )
+          return false;
+        break;
+      }
+      case Mode::INVALID:
+      {
+        return true;
+      }
+    }
+
+    switch( cmp.mode )
+    {
+      case Mode::EMPTY:
+      case Mode::ALL:
+      {
+        if( !cmp.Compare( CompareFuncExit::FIRST_NOT_FOUND ) )
+          return false;
+        break;
+      }
+      case Mode::ANY:
+      {
+        if( cmp.Compare( CompareFuncExit::FIRST_FOUND ) )
+          return true;
+        break;
+      }
+      case Mode::NONE:
+      {
+        if( cmp.Compare( CompareFuncExit::FIRST_FOUND ) )
+          return false;
+        break;
+      }
+      case Mode::INVALID:
+      {
+        return true;
+      }
+    }
+    switch( cmp.mode )
+    {
+      case Mode::EMPTY:
+      case Mode::ALL:
+      case Mode::NONE:
+      {
+        return true;
+      }
+      case Mode::ANY:
+      {
+        return false;
+      }
+      case Mode::INVALID:
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  ComparerInterfaces ci;
+  ComparerAttributes ca;
+  ComparerRoles cr;
+  ComparerStates cs;
+
+  Comparer( MatchRule* mr ) : ci( mr ), ca( mr ), cr( mr ), cs( mr ) {}
+
+  bool operator()( Accessible* obj )
+  {
+    return compareFunc( ci, obj ) &&
+           compareFunc( ca, obj ) &&
+           compareFunc( cr, obj ) &&
+           compareFunc( cs, obj );
+  }
+};
+
+void BridgeCollection::VisitNodes( Accessible* obj, std::vector< Accessible* >& result, Comparer& cmp, size_t maxCount )
+{
+  if( result.size() >= maxCount )
+    return;
+
+  if( cmp( obj ) )
+    result.emplace_back( obj );
+
+  for( auto i = 0u; i < obj->GetChildCount(); ++i )
+    VisitNodes( obj->GetChildAtIndex( i ), result, cmp, maxCount );
+}
+
+DBus::ValueOrError< std::vector< Accessible* > > BridgeCollection::GetMatches( MatchRule rule, uint32_t sortBy, int32_t count, bool traverse )
+{
+  std::vector< Accessible* > res;
+  auto self = BridgeBase::FindSelf();
+  auto matcher = Comparer{&rule};
+  VisitNodes( self, res, matcher, count );
+
+  switch( static_cast< SortOrder >( sortBy ) )
+  {
+    case SortOrder::CANONICAL:
+    {
+      break;
+    }
+
+    case SortOrder::REVERSE_CANONICAL:
+    {
+      std::reverse( res.begin(), res.end() );
+      break;
+    }
+
+    default:
+    {
+      throw std::domain_error{"unsupported sorting order"};
+    }
+      //TODO: other cases
+  }
+
+  return res;
+}
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-collection.h b/dali/internal/accessibility/tizen-wayland/atspi/bridge-collection.h
new file mode 100644 (file)
index 0000000..eb46db6
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_COLLECTION_H
+#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_COLLECTION_H
+
+/*
+ * Copyright (c) 2019 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 <array>
+#include <tuple>
+#include <unordered_map>
+#include <vector>
+
+// INTERNAL INCLUDES
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-base.h>
+
+class BridgeCollection : public virtual BridgeBase
+{
+private:
+  struct Comparer;
+  static void VisitNodes( Dali::Accessibility::Accessible* obj, std::vector< Dali::Accessibility::Accessible* >& result, Comparer& cmp, size_t maxCount );
+
+protected:
+  BridgeCollection() = default;
+
+  void RegisterInterfaces();
+
+  Dali::Accessibility::Collection* FindSelf() const;
+
+public:
+  using MatchRule = std::tuple<
+      std::array< int32_t, 2 >, int32_t,
+      std::unordered_map< std::string, std::string >, int32_t,
+      std::array< int32_t, 4 >, int32_t,
+      std::vector< std::string >, int32_t,
+      bool >;
+  struct Index
+  {
+    enum
+    {
+      States,
+      StatesMatchType,
+      Attributes,
+      AttributesMatchType,
+      Roles,
+      RolesMatchType,
+      Interfaces,
+      InterfacesMatchType,
+    };
+  };
+
+  DBus::ValueOrError< std::vector< Dali::Accessibility::Accessible* > > GetMatches( MatchRule rule, uint32_t sortBy, int32_t count, bool traverse );
+};
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_COLLECTION_H
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-component.cpp b/dali/internal/accessibility/tizen-wayland/atspi/bridge-component.cpp
new file mode 100644 (file)
index 0000000..b772147
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-component.h>
+
+// EXTERNAL INCLUDES
+#include <iostream>
+
+#define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties"
+
+using namespace Dali::Accessibility;
+
+BridgeComponent::BridgeComponent()
+{
+}
+
+void BridgeComponent::RegisterInterfaces()
+{
+  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceComponent};
+  AddFunctionToInterface( desc, "Contains", &BridgeComponent::Contains );
+  AddFunctionToInterface( desc, "GetAccessibleAtPoint", &BridgeComponent::GetAccessibleAtPoint );
+  AddFunctionToInterface( desc, "GetExtents", &BridgeComponent::GetExtents );
+  AddFunctionToInterface( desc, "GetPosition", &BridgeComponent::GetPosition );
+  AddFunctionToInterface( desc, "GetSize", &BridgeComponent::GetSize );
+  AddFunctionToInterface( desc, "GetLayer", &BridgeComponent::GetLayer );
+  AddFunctionToInterface( desc, "GetAlpha", &BridgeComponent::GetAlpha );
+  AddFunctionToInterface( desc, "GetMDIZOrder", &BridgeComponent::GetMdiZOrder );
+  AddFunctionToInterface( desc, "GrabHighlight", &BridgeComponent::GrabHighlight );
+  AddFunctionToInterface( desc, "GrabFocus", &BridgeComponent::GrabFocus );
+  AddFunctionToInterface( desc, "ClearHighlight", &BridgeComponent::ClearHighlight );
+  dbusServer.addInterface( "/", desc, true );
+}
+
+Component* BridgeComponent::FindSelf() const
+{
+  auto s = BridgeBase::FindSelf();
+  assert( s );
+  auto s2 = dynamic_cast< Component* >( s );
+  if( !s2 )
+    throw std::domain_error{"object " + s->GetAddress().ToString() + " doesn't have Component interface"};
+  return s2;
+}
+
+DBus::ValueOrError< bool > BridgeComponent::Contains( int32_t x, int32_t y, uint32_t coordType )
+{
+  return FindSelf()->Contains( {x, y}, static_cast< CoordType >( coordType ) );
+}
+DBus::ValueOrError< Accessible* > BridgeComponent::GetAccessibleAtPoint( int32_t x, int32_t y, uint32_t coordType )
+{
+  return FindSelf()->GetAccessibleAtPoint( {x, y}, static_cast< CoordType >( coordType ) );
+}
+DBus::ValueOrError< std::tuple< int32_t, int32_t, int32_t, int32_t > > BridgeComponent::GetExtents( uint32_t coordType )
+{
+  auto p = FindSelf()->GetExtents( static_cast< CoordType >( coordType ) );
+  return std::tuple< int32_t, int32_t, int32_t, int32_t >{p.x, p.y, p.width, p.height};
+}
+DBus::ValueOrError< int32_t, int32_t > BridgeComponent::GetPosition( uint32_t coordType )
+{
+  auto p = FindSelf()->GetExtents( static_cast< CoordType >( coordType ) );
+  return { static_cast<int32_t>(p.x), static_cast<int32_t>(p.y) };
+}
+DBus::ValueOrError< int32_t, int32_t > BridgeComponent::GetSize( uint32_t coordType )
+{
+  auto p = FindSelf()->GetExtents( static_cast< CoordType >( coordType ) );
+  return { static_cast<int32_t>(p.width), static_cast<int32_t>(p.height) };
+}
+DBus::ValueOrError< ComponentLayer > BridgeComponent::GetLayer()
+{
+  return FindSelf()->GetLayer();
+}
+DBus::ValueOrError< double > BridgeComponent::GetAlpha()
+{
+  return FindSelf()->GetAlpha();
+}
+DBus::ValueOrError< bool > BridgeComponent::GrabFocus()
+{
+  return FindSelf()->GrabFocus();
+}
+DBus::ValueOrError< bool > BridgeComponent::GrabHighlight()
+{
+  return FindSelf()->GrabHighlight();
+}
+DBus::ValueOrError< bool > BridgeComponent::ClearHighlight()
+{
+  return FindSelf()->ClearHighlight();
+}
+DBus::ValueOrError< int16_t > BridgeComponent::GetMdiZOrder()
+{
+  return FindSelf()->GetMdiZOrder();
+}
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-component.h b/dali/internal/accessibility/tizen-wayland/atspi/bridge-component.h
new file mode 100644 (file)
index 0000000..49b14d1
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_COMPONENT_H
+#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_COMPONENT_H
+
+/*
+ * Copyright (c) 2019 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 <array>
+#include <string>
+#include <tuple>
+#include <unordered_map>
+#include <vector>
+
+// INTERNAL INCLUDES
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-base.h>
+
+class BridgeComponent : public virtual BridgeBase
+{
+protected:
+  BridgeComponent();
+
+  void RegisterInterfaces();
+
+  Dali::Accessibility::Component* FindSelf() const;
+
+public:
+  DBus::ValueOrError< bool > Contains( int32_t x, int32_t y, uint32_t coordType );
+  DBus::ValueOrError< Dali::Accessibility::Accessible* > GetAccessibleAtPoint( int32_t x, int32_t y, uint32_t coordType );
+  DBus::ValueOrError< std::tuple< int32_t, int32_t, int32_t, int32_t > > GetExtents( uint32_t coordType );
+  DBus::ValueOrError< int32_t, int32_t > GetPosition( uint32_t coordType );
+  DBus::ValueOrError< int32_t, int32_t > GetSize( uint32_t coordType );
+  DBus::ValueOrError< Dali::Accessibility::ComponentLayer > GetLayer();
+  DBus::ValueOrError< double > GetAlpha();
+  DBus::ValueOrError< bool > GrabFocus();
+  DBus::ValueOrError< bool > GrabHighlight();
+  DBus::ValueOrError< bool > ClearHighlight();
+  DBus::ValueOrError< int16_t > GetMdiZOrder();
+};
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_COMPONENT_H
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-editable-text.cpp b/dali/internal/accessibility/tizen-wayland/atspi/bridge-editable-text.cpp
new file mode 100644 (file)
index 0000000..875c953
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-editable-text.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/clipboard/common/clipboard-impl.h>
+
+using namespace Dali::Accessibility;
+
+void BridgeEditableText::RegisterInterfaces()
+{
+  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceEditableText};
+  AddFunctionToInterface( desc, "CopyText", &BridgeEditableText::CopyText );
+  AddFunctionToInterface( desc, "CutText", &BridgeEditableText::CutText );
+  AddFunctionToInterface( desc, "PasteText", &BridgeEditableText::PasteText );
+  dbusServer.addInterface( "/", desc, true );
+}
+
+EditableText* BridgeEditableText::FindSelf() const
+{
+  auto s = BridgeBase::FindSelf();
+  assert( s );
+  auto s2 = dynamic_cast< EditableText* >( s );
+  if( !s2 )
+    throw std::domain_error{"object " + s->GetAddress().ToString() + " doesn't have Text interface"};
+  return s2;
+}
+
+DBus::ValueOrError< bool > BridgeEditableText::CopyText( int32_t startPos, int32_t endPos )
+{
+  return FindSelf()->CopyText( startPos, endPos );
+}
+
+DBus::ValueOrError< bool > BridgeEditableText::CutText( int32_t startPos, int32_t endPos )
+{
+  return FindSelf()->CutText( startPos, endPos );
+}
+
+DBus::ValueOrError< bool > BridgeEditableText::PasteText( int32_t pos )
+{
+  // auto imfManager = Dali::Internal::Adaptor::ImfManager::Get();
+  // imfManager.SetCursorPosition( pos );
+  // auto clipboard = Dali::Internal::Adaptor::Clipboard::Get();
+  // clipboard.RequestItem();
+  // return true;
+  return false;
+}
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-editable-text.h b/dali/internal/accessibility/tizen-wayland/atspi/bridge-editable-text.h
new file mode 100644 (file)
index 0000000..8538c27
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_EDITABLE_TEXT_H
+#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_EDITABLE_TEXT_H
+
+/*
+ * Copyright (c) 2019 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 <dali/internal/accessibility/tizen-wayland/atspi/bridge-base.h>
+
+class BridgeEditableText : public virtual BridgeBase
+{
+protected:
+  BridgeEditableText() = default;
+
+  void RegisterInterfaces();
+
+  Dali::Accessibility::EditableText* FindSelf() const;
+
+public:
+  DBus::ValueOrError< bool > CopyText( int32_t startPos, int32_t endPos );
+  DBus::ValueOrError< bool > CutText( int32_t startPos, int32_t endPos );
+  DBus::ValueOrError< bool > PasteText( int32_t pos );
+};
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_EDITABLE_TEXT_H
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-impl.cpp b/dali/internal/accessibility/tizen-wayland/atspi/bridge-impl.cpp
new file mode 100644 (file)
index 0000000..44daa00
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2019 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
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <iostream>
+#include <unordered_map>
+
+// INTERNAL INCLUDES
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-accessible.h>
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-action.h>
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-collection.h>
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-component.h>
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-object.h>
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-value.h>
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-text.h>
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-editable-text.h>
+
+using namespace Dali::Accessibility;
+
+class BridgeImpl : public virtual BridgeBase,
+                   public BridgeAccessible,
+                   public BridgeObject,
+                   public BridgeComponent,
+                   public BridgeCollection,
+                   public BridgeAction,
+                   public BridgeValue,
+                   public BridgeText,
+                   public BridgeEditableText
+{
+  DBus::DBusClient listenOnAtspiEnabledSignalClient;
+  DBus::DBusClient registryClient, directReadingClient;
+  bool screenReaderEnabled = false;
+  bool isEnabled = false;
+  bool isShown = false;
+  std::unordered_map <int32_t, std::function<void(std::string)>> directReadingCallbacks;
+  Dali::Actor highlightedActor;
+  std::function<void(Dali::Actor)> highlightClearAction;
+
+public:
+  BridgeImpl()
+  {
+    listenOnAtspiEnabledSignalClient = DBus::DBusClient{ A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION };
+
+    listenOnAtspiEnabledSignalClient.addPropertyChangedEvent< bool >( "ScreenReaderEnabled", [this]( bool res )
+      {
+        screenReaderEnabled = res;
+        if( screenReaderEnabled || isEnabled )
+        {
+          ForceUp();
+        }
+        else
+        {
+          ForceDown();
+        }
+      }
+    );
+
+    listenOnAtspiEnabledSignalClient.addPropertyChangedEvent< bool >( "IsEnabled", [this]( bool res )
+      {
+        isEnabled = res;
+        if( screenReaderEnabled || isEnabled )
+        {
+          ForceUp();
+        }
+        else
+        {
+          ForceDown();
+        }
+      }
+    );
+  }
+
+  Consumed Emit( KeyEventType type, unsigned int keyCode, const std::string& keyName, unsigned int timeStamp, bool isText ) override
+  {
+    if (!IsUp())
+    {
+      return Consumed::NO;
+    }
+
+    unsigned int evType = 0;
+
+    switch( type )
+    {
+      case KeyEventType::KEY_PRESSED:
+      {
+        evType = 0;
+        break;
+      }
+      case KeyEventType::KEY_RELEASED:
+      {
+        evType = 1;
+        break;
+      }
+      default:
+      {
+        return Consumed::NO;
+      }
+    }
+    auto m = registryClient.method< bool( std::tuple< uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool > ) >( "NotifyListenersSync" );
+    auto result = m.call( std::tuple< uint32_t, int32_t, int32_t, int32_t, int32_t, std::string, bool >{evType, 0, static_cast< int32_t >( keyCode ), 0, static_cast< int32_t >( timeStamp ), keyName, isText ? 1 : 0} );
+    if( !result )
+    {
+      LOG() << result.getError().message;
+      return Consumed::NO;
+    }
+    return std::get< 0 >( result ) ? Consumed::YES : Consumed::NO;
+  }
+
+  void Pause() override
+  {
+    auto r = directReadingClient.method< DBus::ValueOrError< void >( bool ) > ( "PauseResume" ).call( true );
+    if (!r)
+    {
+      LOG() << "Direct reading command failed (" << r.getError().message << ")";
+    }
+  }
+
+  void Resume() override
+  {
+    auto r = directReadingClient.method< DBus::ValueOrError< void >( bool ) > ( "PauseResume" ).call( false );
+    if (!r)
+    {
+      LOG() << "Direct reading command failed (" << r.getError().message << ")";
+    }
+  }
+
+  void Say( const std::string& text, bool discardable, std::function< void(std::string) > callback ) override
+  {
+    auto commandId = directReadingClient.method< DBus::ValueOrError< std::string, bool, int32_t >( std::string, bool ) > ( "ReadCommand" ).call( text, discardable );
+    if ( !commandId )
+    {
+      LOG() << "Direct reading command failed (" << commandId.getError().message << ")";
+    }
+    else if( callback )
+    {
+      directReadingCallbacks.emplace( std::get< 2 >( commandId ), callback);
+    }
+  }
+
+  void ForceDown() override
+  {
+    if (data)
+    {
+      if (data->currentlyHighlightedActor && data->highlightActor)
+      {
+        data->currentlyHighlightedActor.Remove(data->highlightActor);
+      }
+      data->currentlyHighlightedActor = {};
+      data->highlightActor = {};
+    }
+    highlightedActor = {};
+    highlightClearAction = {};
+    BridgeAccessible::ForceDown();
+    registryClient = {};
+    directReadingClient = {};
+    directReadingCallbacks.clear();
+  }
+
+  void Terminate() override
+  {
+    if (data)
+    {
+      data->currentlyHighlightedActor = {};
+      data->highlightActor = {};
+    }
+    ForceDown();
+    listenOnAtspiEnabledSignalClient = {};
+    dbusServer = {};
+    con = {};
+  }
+
+  ForceUpResult ForceUp() override
+  {
+    if( BridgeAccessible::ForceUp() == ForceUpResult::ALREADY_UP )
+    {
+      return ForceUpResult::ALREADY_UP;
+    }
+
+    BridgeObject::RegisterInterfaces();
+    BridgeAccessible::RegisterInterfaces();
+    BridgeComponent::RegisterInterfaces();
+    BridgeCollection::RegisterInterfaces();
+    BridgeAction::RegisterInterfaces();
+    BridgeValue::RegisterInterfaces();
+    BridgeText::RegisterInterfaces();
+    BridgeEditableText::RegisterInterfaces();
+
+    RegisterOnBridge( &application );
+
+    registryClient = { AtspiDbusNameRegistry, AtspiDbusPathDec, AtspiDbusInterfaceDec, con };
+    directReadingClient = DBus::DBusClient{ DirectReadingDBusName, DirectReadingDBusPath, DirectReadingDBusInterface, con };
+    directReadingClient.addSignal< void(int32_t, std::string) >( "ReadingStateChanged", [=]( int32_t id, std::string readingState )
+      {
+        auto it = directReadingCallbacks.find( id );
+        if (it != directReadingCallbacks.end())
+        {
+          it->second( readingState );
+          directReadingCallbacks.erase( it );
+        }
+      }
+    );
+
+    auto proxy = DBus::DBusClient{AtspiDbusNameRegistry, AtspiDbusPathRoot, AtspiDbusInterfaceSocket, con};
+    Address root{"", "root"};
+    auto res = proxy.method< Address( Address ) >( "Embed" ).call( root );
+    if (!res)
+    {
+      LOG() << "Call to Embed failed: " << res.getError().message;
+    }
+    assert( res );
+    application.parent.SetAddress( std::move( std::get< 0 >( res ) ) );
+    if (isShown)
+    {
+      EmitActivate();
+    }
+    return ForceUpResult::JUST_STARTED;
+  }
+
+  void EmitActivate()
+  {
+    auto win = application.getActiveWindow();
+    if (win)
+    {
+      win->Emit( WindowEvent::ACTIVATE, 0 );
+    }
+  }
+
+  void EmitDeactivate()
+  {
+    auto win = application.getActiveWindow();
+    if (win)
+    {
+      win->Emit( WindowEvent::DEACTIVATE, 0 );
+    }
+  }
+
+  void ApplicationHidden() override
+  {
+    if ( isShown && IsUp() )
+    {
+      EmitDeactivate();
+    }
+    isShown = false;
+  }
+
+  void ApplicationShown() override
+  {
+    if ( !isShown && IsUp() )
+    {
+      EmitActivate();
+    }
+    isShown = true;
+  }
+
+  void Initialize() override
+  {
+    auto req = DBus::DBusClient{A11yDbusName, A11yDbusPath, A11yDbusStatusInterface, DBus::ConnectionType::SESSION};
+    auto p = req.property< bool >( "ScreenReaderEnabled" ).get();
+    if( p )
+    {
+      screenReaderEnabled = std::get< 0 >( p );
+    }
+    p = req.property< bool >( "IsEnabled" ).get();
+    if( p )
+    {
+      isEnabled = std::get< 0 >( p );
+    }
+    if( screenReaderEnabled || isEnabled )
+    {
+      ForceUp();
+    }
+  }
+
+  bool GetScreenReaderEnabled()
+  {
+    return screenReaderEnabled;
+  }
+
+  bool GetIsEnabled()
+  {
+    return isEnabled;
+  }
+
+};
+
+Bridge* Bridge::GetCurrentBridge()
+{
+  static BridgeImpl *bridge = new BridgeImpl;
+  return bridge;
+}
+
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-object.cpp b/dali/internal/accessibility/tizen-wayland/atspi/bridge-object.cpp
new file mode 100644 (file)
index 0000000..6b936fd
--- /dev/null
@@ -0,0 +1,571 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-object.h>
+
+// EXTERNAL INCLUDES
+#include <iostream>
+#include <string>
+
+using namespace Dali::Accessibility;
+
+BridgeObject::BridgeObject()
+{
+}
+
+void BridgeObject::RegisterInterfaces()
+{
+  // DBus::DBusInterfaceDescription desc{ AtspiDbusInterfaceEventObject };
+  // stateChanged = addSignal<std::string, int, int, DBus::EldbusVariant<int>, Accessible*>(desc, "StateChanged");
+  // dbusServer.addInterface("/", desc, true);
+}
+
+void BridgeObject::EmitActiveDescendantChanged( Accessible* obj, Accessible *child )
+{
+  if (!IsUp()) return;
+  auto index = child->GetIndexInParent();
+
+  auto addr = obj->GetAddress();
+  const auto prefixPath = "/org/a11y/atspi/accessible/";
+  const auto nullPath = "/org/a11y/atspi/null";
+  std::string p;
+  if( addr )
+    p = prefixPath + addr.GetPath();
+  else
+    p = nullPath;
+  dbusServer.emit2< std::string, int, int, DBus::EldbusVariant< Address >, Address >(
+      p,
+      AtspiDbusInterfaceEventObject,
+      "ActiveDescendantChanged",
+      "",
+      index,
+      0,
+      { child->GetAddress() },
+      {"", "root"} );
+}
+
+void BridgeObject::Emit( Accessible* obj, Dali::Accessibility::ObjectPropertyChangeEvent ev )
+{
+  if (!IsUp()) return;
+  const char* name = nullptr;
+  switch( ev )
+  {
+    case ObjectPropertyChangeEvent::NAME:
+    {
+      name = "accessible-name";
+      break;
+    }
+    case ObjectPropertyChangeEvent::DESCRIPTION:
+    {
+      name = "accessible-description";
+      break;
+    }
+    case ObjectPropertyChangeEvent::VALUE:
+    {
+      name = "accessible-value";
+      break;
+    }
+    case ObjectPropertyChangeEvent::PARENT:
+    {
+      name = "accessible-parent";
+      break;
+    }
+    case ObjectPropertyChangeEvent::ROLE:
+    {
+      name = "accessible-role";
+      break;
+    }
+  }
+  if( name )
+  {
+    auto addr = obj->GetAddress();
+    std::string p;
+    if( addr )
+      p = ATSPI_PREFIX_PATH + addr.GetPath();
+    else
+      p = ATSPI_NULL_PATH;
+    dbusServer.emit2< std::string, int, int, DBus::EldbusVariant< int >, Address >(
+        p,
+        AtspiDbusInterfaceEventObject,
+        "PropertyChange",
+        name,
+        0,
+        0,
+        {0},
+        {"", "root"} );
+  }
+}
+
+void BridgeObject::Emit( Accessible* obj, WindowEvent we, unsigned int detail1 )
+{
+  if (!IsUp()) return;
+  const char* name = nullptr;
+  switch( we )
+  {
+    case WindowEvent::PROPERTY_CHANGE:
+    {
+      name = "PropertyChange";
+      break;
+    }
+    case WindowEvent::MINIMIZE:
+    {
+      name = "Minimize";
+      break;
+    }
+    case WindowEvent::MAXIMIZE:
+    {
+      name = "Maximize";
+      break;
+    }
+    case WindowEvent::RESTORE:
+    {
+      name = "Restore";
+      break;
+    }
+    case WindowEvent::CLOSE:
+    {
+      name = "Close";
+      break;
+    }
+    case WindowEvent::CREATE:
+    {
+      name = "Create";
+      break;
+    }
+    case WindowEvent::REPARENT:
+    {
+      name = "Reparent";
+      break;
+    }
+    case WindowEvent::DESKTOP_CREATE:
+    {
+      name = "DesktopCreate";
+      break;
+    }
+    case WindowEvent::DESKTOP_DESTROY:
+    {
+      name = "DesktopDestroy";
+      break;
+    }
+    case WindowEvent::DESTROY:
+    {
+      name = "Destroy";
+      break;
+    }
+    case WindowEvent::ACTIVATE:
+    {
+      name = "Activate";
+      break;
+    }
+    case WindowEvent::DEACTIVATE:
+    {
+      name = "Deactivate";
+      break;
+    }
+    case WindowEvent::RAISE:
+    {
+      name = "Raise";
+      break;
+    }
+    case WindowEvent::LOWER:
+    {
+      name = "Lower";
+      break;
+    }
+    case WindowEvent::MOVE:
+    {
+      name = "Move";
+      break;
+    }
+    case WindowEvent::RESIZE:
+    {
+      name = "Resize";
+      break;
+    }
+    case WindowEvent::SHADE:
+    {
+      name = "Shade";
+      break;
+    }
+    case WindowEvent::UU_SHADE:
+    {
+      name = "uUshade";
+      break;
+    }
+    case WindowEvent::RESTYLE:
+    {
+      name = "Restyle";
+      break;
+    }
+  }
+  if( name )
+  {
+    auto addr = obj->GetAddress();
+    std::string p;
+    if( addr )
+      p = ATSPI_PREFIX_PATH + addr.GetPath();
+    else
+      p = ATSPI_NULL_PATH;
+    dbusServer.emit2< std::string, int, int, DBus::EldbusVariant< int >, Address >(
+        p,
+        AtspiDbusInterfaceEventWindow,
+        name,
+        "",
+        detail1,
+        0,
+        {0},
+        {"", "root"} );
+  }
+}
+
+void BridgeObject::EmitStateChanged( Accessible* obj, State state, int newValue1, int newValue2 )
+{
+  if (!IsUp()) return;
+  const char* stateName = nullptr;
+  switch( state )
+  {
+    case State::INVALID:
+    {
+      stateName = "invalid";
+      break;
+    }
+    case State::ACTIVE:
+    {
+      stateName = "active";
+      break;
+    }
+    case State::ARMED:
+    {
+      stateName = "armed";
+      break;
+    }
+    case State::BUSY:
+    {
+      stateName = "busy";
+      break;
+    }
+    case State::CHECKED:
+    {
+      stateName = "checked";
+      break;
+    }
+    case State::COLLAPSED:
+    {
+      stateName = "collapsed";
+      break;
+    }
+    case State::DEFUNCT:
+    {
+      stateName = "defunct";
+      break;
+    }
+    case State::EDITABLE:
+    {
+      stateName = "editable";
+      break;
+    }
+    case State::ENABLED:
+    {
+      stateName = "enabled";
+      break;
+    }
+    case State::EXPANDABLE:
+    {
+      stateName = "expandable";
+      break;
+    }
+    case State::EXPANDED:
+    {
+      stateName = "expanded";
+      break;
+    }
+    case State::FOCUSABLE:
+    {
+      stateName = "focusable";
+      break;
+    }
+    case State::FOCUSED:
+    {
+      stateName = "focused";
+      break;
+    }
+    case State::HAS_TOOLTIP:
+    {
+      stateName = "has-tooltip";
+      break;
+    }
+    case State::HORIZONTAL:
+    {
+      stateName = "horizontal";
+      break;
+    }
+    case State::ICONIFIED:
+    {
+      stateName = "iconified";
+      break;
+    }
+    case State::MODAL:
+    {
+      stateName = "modal";
+      break;
+    }
+    case State::MULTI_LINE:
+    {
+      stateName = "multi-line";
+      break;
+    }
+    case State::MULTI_SELECTABLE:
+    {
+      stateName = "multiselectable";
+      break;
+    }
+    case State::OPAQUE:
+    {
+      stateName = "opaque";
+      break;
+    }
+    case State::PRESSED:
+    {
+      stateName = "pressed";
+      break;
+    }
+    case State::RESIZEABLE:
+    {
+      stateName = "resizable";
+      break;
+    }
+    case State::SELECTABLE:
+    {
+      stateName = "selectable";
+      break;
+    }
+    case State::SELECTED:
+    {
+      stateName = "selected";
+      break;
+    }
+    case State::SENSITIVE:
+    {
+      stateName = "sensitive";
+      break;
+    }
+    case State::SHOWING:
+    {
+      stateName = "showing";
+      break;
+    }
+    case State::SINGLE_LINE:
+    {
+      stateName = "single-line";
+      break;
+    }
+    case State::STALE:
+    {
+      stateName = "stale";
+      break;
+    }
+    case State::TRANSIENT:
+    {
+      stateName = "transient";
+      break;
+    }
+    case State::VERTICAL:
+    {
+      stateName = "vertical";
+      break;
+    }
+    case State::VISIBLE:
+    {
+      stateName = "visible";
+      break;
+    }
+    case State::MANAGES_DESCENDANTS:
+    {
+      stateName = "manages-descendants";
+      break;
+    }
+    case State::INDETERMINATE:
+    {
+      stateName = "indeterminate";
+      break;
+    }
+    case State::REQUIRED:
+    {
+      stateName = "required";
+      break;
+    }
+    case State::TRUNCATED:
+    {
+      stateName = "truncated";
+      break;
+    }
+    case State::ANIMATED:
+    {
+      stateName = "animated";
+      break;
+    }
+    case State::INVALID_ENTRY:
+    {
+      stateName = "invalid-entry";
+      break;
+    }
+    case State::SUPPORTS_AUTOCOMPLETION:
+    {
+      stateName = "supports-autocompletion";
+      break;
+    }
+    case State::SELECTABLE_TEXT:
+    {
+      stateName = "selectable-text";
+      break;
+    }
+    case State::IS_DEFAULT:
+    {
+      stateName = "is-default";
+      break;
+    }
+    case State::VISITED:
+    {
+      stateName = "visited";
+      break;
+    }
+    case State::CHECKABLE:
+    {
+      stateName = "checkable";
+      break;
+    }
+    case State::HAS_POPUP:
+    {
+      stateName = "has-popup";
+      break;
+    }
+    case State::READ_ONLY:
+    {
+      stateName = "read-only";
+      break;
+    }
+    case State::HIGHLIGHTED:
+    {
+      stateName = "highlighted";
+      break;
+    }
+    case State::HIGHLIGHTABLE:
+    {
+      stateName = "highlightable";
+      break;
+    }
+    case State::MAX_COUNT:
+    {
+      break;
+    }
+  }
+  if( stateName )
+  {
+    auto addr = obj->GetAddress();
+    std::string p;
+    if( addr )
+      p = ATSPI_PREFIX_PATH + addr.GetPath();
+    else
+      p = ATSPI_NULL_PATH;
+    dbusServer.emit2< std::string, int, int, DBus::EldbusVariant< int >, Address >(
+        p,
+        AtspiDbusInterfaceEventObject,
+        "StateChanged",
+        stateName,
+        newValue1,
+        newValue2,
+        {0},
+        {"", "root"} );
+  }
+}
+
+void BridgeObject::EmitBoundsChanged( Accessible* obj, Dali::Rect<> rect )
+{
+  auto addr = obj->GetAddress();
+  const auto prefixPath = "/org/a11y/atspi/accessible/";
+  const auto nullPath = "/org/a11y/atspi/null";
+  std::string p;
+  if( addr )
+    p = prefixPath + addr.GetPath();
+  else
+    p = nullPath;
+  DBus::EldbusVariant< std::tuple<int32_t, int32_t, int32_t, int32_t> > tmp {
+    std::tuple<int32_t, int32_t, int32_t, int32_t>{ rect.x, rect.y, rect.width, rect.height } };
+  addFilteredEvent(FilteredEvents::boundsChanged, obj, 1.0f, [=]() {
+    dbusServer.emit2< std::string, int, int, DBus::EldbusVariant< std::tuple<int32_t, int32_t, int32_t, int32_t> >, Address >(
+      p,
+      AtspiDbusInterfaceEventObject,
+      "BoundsChanged",
+      "",
+      0,
+      0,
+      tmp,
+      {"", "root"} );
+  });
+}
+
+void BridgeObject::EmitCaretMoved( Accessible* obj, unsigned int cursorPosition )
+{
+  auto addr = obj->GetAddress();
+  std::string p = addr ? ATSPI_PREFIX_PATH + addr.GetPath() : ATSPI_NULL_PATH;
+  dbusServer.emit2< std::string, int, int, DBus::EldbusVariant< int >, Address >(
+    p,
+    AtspiDbusInterfaceEventObject,
+    "TextCaretMoved",
+    "",
+    cursorPosition,
+    0,
+    {0},
+    {"", "root"} );
+}
+
+void BridgeObject::EmitTextChanged( Accessible* obj, TextChangedState state, unsigned int position, unsigned int length, const std::string &content )
+{
+  const char* stateName = nullptr;
+  switch( state )
+  {
+    case TextChangedState::INSERT:
+    {
+      stateName = "insert";
+      break;
+    }
+    case TextChangedState::DELETE:
+    {
+      stateName = "delete";
+      break;
+    }
+    case TextChangedState::MAX_COUNT:
+    {
+      break;
+    }
+  }
+  if( stateName )
+  {
+    auto addr = obj->GetAddress();
+    std::string p = addr ? ATSPI_PREFIX_PATH + addr.GetPath() : ATSPI_NULL_PATH;
+    dbusServer.emit2< std::string, int, int, DBus::EldbusVariant< std::string >, Address >(
+        p,
+        AtspiDbusInterfaceEventObject,
+        "TextChanged",
+        stateName,
+        position,
+        length,
+        {content},
+        {"", "root"} );
+  }
+}
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-object.h b/dali/internal/accessibility/tizen-wayland/atspi/bridge-object.h
new file mode 100644 (file)
index 0000000..2f0e572
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_OBJECT_H
+#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_OBJECT_H
+
+/*
+ * Copyright (c) 2019 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 <array>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+// INTERNAL INCLUDES
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-base.h>
+#include <dali/public-api/math/rect.h>
+
+class BridgeObject : public virtual BridgeBase
+{
+protected:
+  BridgeObject();
+
+  void RegisterInterfaces();
+
+  DBus::DBusInterfaceDescription::SignalId stateChanged;
+
+  void EmitActiveDescendantChanged( Dali::Accessibility::Accessible* obj, Dali::Accessibility::Accessible *child ) override;
+  void EmitCaretMoved( Dali::Accessibility::Accessible* obj, unsigned int cursorPosition ) override;
+  void EmitTextChanged( Dali::Accessibility::Accessible* obj, Dali::Accessibility::TextChangedState state, unsigned int position, unsigned int length, const std::string &content ) override;
+  void EmitStateChanged( Dali::Accessibility::Accessible* obj, Dali::Accessibility::State state, int val1, int val2 ) override;
+  void Emit( Dali::Accessibility::Accessible* obj, Dali::Accessibility::WindowEvent we, unsigned int detail1 ) override;
+  void Emit( Dali::Accessibility::Accessible* obj, Dali::Accessibility::ObjectPropertyChangeEvent we ) override;
+  void EmitBoundsChanged( Dali::Accessibility::Accessible* obj, Dali::Rect<> rect ) override;
+
+public:
+  int GetChildCount();
+  DBus::ValueOrError< Dali::Accessibility::Accessible* > GetChildAtIndex( int index );
+  Dali::Accessibility::Accessible* GetParent();
+  DBus::ValueOrError< std::vector< Dali::Accessibility::Accessible* > > GetChildren();
+  std::string GetName();
+  std::string GetDescription();
+  DBus::ValueOrError< uint32_t > GetRole();
+  DBus::ValueOrError< std::string > GetRoleName();
+  DBus::ValueOrError< std::string > GetLocalizedRoleName();
+  DBus::ValueOrError< int32_t > GetIndexInParent();
+  DBus::ValueOrError< std::array< uint32_t, 2 > > GetStates();
+  DBus::ValueOrError< std::unordered_map< std::string, std::string > > GetAttributes();
+  DBus::ValueOrError< std::vector< std::string > > GetInterfaces();
+};
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_OBJECT_H
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-text.cpp b/dali/internal/accessibility/tizen-wayland/atspi/bridge-text.cpp
new file mode 100644 (file)
index 0000000..5cdb744
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-text.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/input/common/input-method-context-factory.h>
+
+using namespace Dali::Accessibility;
+
+void BridgeText::RegisterInterfaces()
+{
+  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceText};
+  AddFunctionToInterface( desc, "GetText", &BridgeText::GetText );
+  AddGetPropertyToInterface( desc, "CharacterCount", &BridgeText::GetCharacterCount );
+  AddGetPropertyToInterface( desc, "CaretOffset", &BridgeText::GetCaretOffset );
+  AddFunctionToInterface( desc, "SetCaretOffset", &BridgeText::SetCaretOffset );
+  AddFunctionToInterface( desc, "GetTextAtOffset", &BridgeText::GetTextAtOffset );
+  AddFunctionToInterface( desc, "GetSelection", &BridgeText::GetSelection );
+  AddFunctionToInterface( desc, "SetSelection", &BridgeText::SetSelection );
+  AddFunctionToInterface( desc, "RemoveSelection", &BridgeText::RemoveSelection );
+  dbusServer.addInterface( "/", desc, true );
+}
+
+Text* BridgeText::FindSelf() const
+{
+  auto s = BridgeBase::FindSelf();
+  assert( s );
+  auto s2 = dynamic_cast< Text* >( s );
+  if( !s2 )
+    throw std::domain_error{"object " + s->GetAddress().ToString() + " doesn't have Text interface"};
+  return s2;
+}
+
+DBus::ValueOrError< std::string > BridgeText::GetText( int startOffset, int endOffset )
+{
+  return FindSelf()->GetText( startOffset, endOffset );
+}
+
+DBus::ValueOrError< int32_t > BridgeText::GetCharacterCount()
+{
+  return FindSelf()->GetCharacterCount();
+}
+
+DBus::ValueOrError< int32_t > BridgeText::GetCaretOffset()
+{
+  return FindSelf()->GetCaretOffset();
+}
+
+DBus::ValueOrError< bool > BridgeText::SetCaretOffset( int32_t offset )
+{
+  return FindSelf()->SetCaretOffset(offset);
+}
+
+DBus::ValueOrError< std::string, int, int > BridgeText::GetTextAtOffset( int32_t offset, uint32_t boundary )
+{
+  auto r = FindSelf()->GetTextAtOffset( offset, static_cast< TextBoundary >( boundary ) );
+  return {r.content, static_cast< int >( r.startOffset ), static_cast< int >( r.endOffset )};
+}
+
+DBus::ValueOrError< int, int > BridgeText::GetSelection( int32_t selectionNum )
+{
+  auto r = FindSelf()->GetSelection( selectionNum );
+  return {static_cast< int >( r.startOffset ), static_cast< int >( r.endOffset )};
+}
+
+DBus::ValueOrError< bool > BridgeText::RemoveSelection( int32_t selectionNum )
+{
+  return FindSelf()->RemoveSelection( selectionNum );
+}
+
+DBus::ValueOrError< bool > BridgeText::SetSelection( int32_t selectionNum, int32_t startOffset, int32_t endOffset )
+{
+  return FindSelf()->SetSelection( selectionNum, startOffset, endOffset );
+}
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-text.h b/dali/internal/accessibility/tizen-wayland/atspi/bridge-text.h
new file mode 100644 (file)
index 0000000..4fb9eec
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_TEXT_H
+#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_TEXT_H
+
+/*
+ * Copyright (c) 2019 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 <dali/internal/accessibility/tizen-wayland/atspi/bridge-base.h>
+
+class BridgeText : public virtual BridgeBase
+{
+protected:
+  BridgeText() = default;
+
+  void RegisterInterfaces();
+
+  Dali::Accessibility::Text* FindSelf() const;
+
+public:
+  DBus::ValueOrError< std::string > GetText( int startOffset, int endOffset );
+  DBus::ValueOrError< int32_t > GetCharacterCount();
+  DBus::ValueOrError< int32_t > GetCaretOffset();
+  DBus::ValueOrError< bool > SetCaretOffset( int32_t offset );
+  DBus::ValueOrError< std::string, int, int > GetTextAtOffset( int32_t offset, uint32_t boundary );
+  DBus::ValueOrError< int, int > GetSelection( int32_t selectionNum );
+  DBus::ValueOrError< bool > RemoveSelection( int32_t selectionNum );
+  DBus::ValueOrError< bool > SetSelection( int32_t selectionNum, int32_t startOffset, int32_t endOffset );
+};
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_TEXT_H
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-value.cpp b/dali/internal/accessibility/tizen-wayland/atspi/bridge-value.cpp
new file mode 100644 (file)
index 0000000..caae344
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-value.h>
+
+// EXTERNAL INCLUDES
+#include <iostream>
+
+using namespace Dali::Accessibility;
+
+BridgeValue::BridgeValue()
+{
+}
+
+void BridgeValue::RegisterInterfaces()
+{
+  DBus::DBusInterfaceDescription desc{AtspiDbusInterfaceValue};
+  AddGetSetPropertyToInterface( desc, "CurrentValue", &BridgeValue::GetCurrentValue, &BridgeValue::SetCurrentValue );
+  AddGetPropertyToInterface( desc, "MaximumValue", &BridgeValue::GetMaximumValue );
+  AddGetPropertyToInterface( desc, "MinimumIncrement", &BridgeValue::GetMinimumIncrement );
+  AddGetPropertyToInterface( desc, "MinimumValue", &BridgeValue::GetMinimumValue );
+  dbusServer.addInterface( "/", desc, true );
+}
+
+Value* BridgeValue::FindSelf() const
+{
+  auto s = BridgeBase::FindSelf();
+  assert( s );
+  auto s2 = dynamic_cast< Value* >( s );
+  if( !s2 )
+    throw std::domain_error{"object " + s->GetAddress().ToString() + " doesn't have Value interface"};
+  return s2;
+}
+double BridgeValue::GetCurrentValue()
+{
+  return FindSelf()->GetCurrent();
+}
+void BridgeValue::SetCurrentValue( double new_value )
+{
+  FindSelf()->SetCurrent( new_value );
+}
+double BridgeValue::GetMaximumValue()
+{
+  return FindSelf()->GetMaximum();
+}
+double BridgeValue::GetMinimumIncrement()
+{
+  return FindSelf()->GetMinimumIncrement();
+}
+double BridgeValue::GetMinimumValue()
+{
+  return FindSelf()->GetMinimum();
+}
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/bridge-value.h b/dali/internal/accessibility/tizen-wayland/atspi/bridge-value.h
new file mode 100644 (file)
index 0000000..daa3a95
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_VALUE_H
+#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_VALUE_H
+
+/*
+ * Copyright (c) 2019 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 <array>
+#include <string>
+#include <tuple>
+#include <unordered_map>
+#include <vector>
+
+// INTERNAL INCLUDES
+#include <dali/internal/accessibility/tizen-wayland/atspi/bridge-base.h>
+
+class BridgeValue : public virtual BridgeBase
+{
+protected:
+  BridgeValue();
+
+  void RegisterInterfaces();
+
+  Dali::Accessibility::Value* FindSelf() const;
+
+public:
+  double GetCurrentValue();
+  void SetCurrentValue( double new_value );
+  double GetMaximumValue();
+  double GetMinimumIncrement();
+  double GetMinimumValue();
+};
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_VALUE_H
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/component.cpp b/dali/internal/accessibility/tizen-wayland/atspi/component.cpp
new file mode 100644 (file)
index 0000000..2a7dfce
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019 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
+
+// EXTERNAL INCLUDES
+#include <iostream>
+
+// INTERNAL INCLUDES
+#include <dali/internal/accessibility/tizen-wayland/atspi/accessibility-common.h>
+
+using namespace Dali::Accessibility;
+
+bool Component::Contains( Point p, CoordType ctype )
+{
+  auto extents = GetExtents( ctype );
+  return p.x >= extents.x && p.y >= extents.y && p.x <= extents.x + extents.width && p.y <= extents.y + extents.height;
+}
+
+Accessible* Component::GetAccessibleAtPoint( Point p, CoordType ctype )
+{
+  auto children = GetChildren();
+  for( auto childIt = children.rbegin(); childIt != children.rend(); childIt++ )
+  {
+    auto component = dynamic_cast< Component* >( *childIt );
+    if( component && component->Contains( p, ctype ) )
+    {
+      return component;
+    }
+  }
+  return nullptr;
+}
+
+bool Component::IsScrollable()
+{
+  return false;
+}
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/dbus-locators.h b/dali/internal/accessibility/tizen-wayland/atspi/dbus-locators.h
new file mode 100644 (file)
index 0000000..1bfb8ec
--- /dev/null
@@ -0,0 +1,98 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_DBUS_LOCATORS_H
+#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_DBUS_LOCATORS_H
+
+/*
+ * Copyright 2019  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.
+ */
+
+namespace dbusLocators
+{
+namespace callmgr
+{
+static constexpr const char* BUS = "org.tizen.callmgr";
+static constexpr const char* OBJ_PATH = "/org/tizen/callmgr";
+static constexpr const char* INTERFACE = "org.tizen.callmgr";
+}
+
+namespace accessibilityEMod
+{
+static constexpr const char* BUS = "org.enlightenment.wm-screen-reader";
+static constexpr const char* OBJ_PATH = "/org/tizen/GestureNavigation";
+static constexpr const char* INTERFACE = "org.tizen.GestureNavigation";
+
+static constexpr const char* ACCESSORIES_SP_ENABLED = "AccessoriesSwitchProviderEnabled";
+static constexpr const char* KEY_DOWN_SIGNAL = "KeyDown";
+static constexpr const char* KEY_UP_SIGNAL = "KeyUp";
+
+static constexpr const char* SCREEN_SP_ENABLED = "ScreenSwitchProviderEnabled";
+static constexpr const char* MOUSE_DOWN_SIGNAL = "MouseDown";
+static constexpr const char* MOUSE_UP_SIGNAL = "MouseUp";
+
+static constexpr const char* BACK_BUTTON_INTERCEPTION_ENABLED = "BackButtonInterceptionEnabled";
+static constexpr const char* BACK_BUTTON_DOWN_SIGNAL = "BackButtonDown";
+static constexpr const char* BACK_BUTTON_UP_SIGNAL = "BackButtonUp";
+}
+
+namespace freeDesktop
+{
+static constexpr const char* BUS = "org.freedesktop.DBus";
+static constexpr const char* OBJ_PATH = "/org/freedesktop/DBus";
+static constexpr const char* INTERFACE = "org.freedesktop.DBus";
+static constexpr const char* PROPERTIES_INTERFACE = "org.freedesktop.DBus.Properties";
+static constexpr const char* GET_CONNECTION_UNIX_PROCESS_ID = "GetConnectionUnixProcessID";
+static constexpr const char* SET = "Set";
+static constexpr const char* GET = "Get";
+}
+
+namespace windowManager
+{
+static constexpr const char* BUS = "org.enlightenment.wm";
+static constexpr const char* OBJ_PATH = "/org/enlightenment/wm";
+static constexpr const char* INTERFACE = "org.enlightenment.wm.proc";
+static constexpr const char* GET_VISIBLE_WIN_INFO = "GetVisibleWinInfo";
+static constexpr const char* GET_FOCUS_PROC = "GetFocusProc";
+}
+
+namespace atspi
+{
+static constexpr const char* BUS = "org.a11y.Bus";
+static constexpr const char* OBJ_PATH = "/org/a11y/bus";
+static constexpr const char* BUS_INTERFACE = "org.a11y.Bus";
+static constexpr const char* STATUS_INTERFACE = "org.a11y.Status";
+
+static constexpr const char* GET_ADDRESS = "GetAddress";
+static constexpr const char* IS_ENABLED = "IsEnabled";
+static constexpr const char* GET_ATTRIBUTES = "GetAttributes";
+static constexpr const char* DO_ACTION_NAME = "DoActionName";
+static constexpr const char* PARENT = "Parent";
+static constexpr const char* GET_MATCHES = "GetMatches";
+static constexpr const char* GET_INDEX_IN_PARENT = "GetIndexInParent";
+static constexpr const char* SELECT_CHILD = "SelectChild";
+static constexpr const char* NAME = "Name";
+static constexpr const char* GET_ROLE = "GetRole";
+static constexpr const char* CHILD_COUNT = "ChildCount";
+static constexpr const char* GET_CHILD_AT_INDEX = "GetChildAtIndex";
+static constexpr const char* GET_STATE = "GetState";
+static constexpr const char* GET_RELATION_SET = "GetRelationSet";
+static constexpr const char* GET_EXTENTS = "GetExtents";
+static constexpr const char* CURRENT_VALUE = "CurrentValue";
+static constexpr const char* MAXIMUM_VALUE = "MaximumValue";
+static constexpr const char* MINIMUM_VALUE = "MinimumValue";
+static constexpr const char* GET_INTERFACES = "GetInterfaces";
+static constexpr const char* GET_NAVIGABLE_AT_POINT = "GetNavigableAtPoint";
+}
+}
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_DBUS_LOCATORS_H
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/dbus-tizen.cpp b/dali/internal/accessibility/tizen-wayland/atspi/dbus-tizen.cpp
new file mode 100644 (file)
index 0000000..c657284
--- /dev/null
@@ -0,0 +1,815 @@
+/*
+ * Copyright 2019  Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/tizen-wayland/atspi/dbus.h>
+#include <dali/internal/accessibility/tizen-wayland/atspi/accessibility-common.h>
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <iostream>
+#include <mutex>
+
+#include <Eldbus.h>
+#include <Ecore_Input.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+#define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties"
+
+#undef EINA_FALSE
+#undef EINA_TRUE
+#define EINA_TRUE static_cast< Eina_Bool >( 1 )
+#define EINA_FALSE static_cast< Eina_Bool >( 0 )
+
+//#define DBUS_DEBUG(...) do { DBus::debugPrint(__FILE__, __LINE__, __VA_ARGS__); } while (0)
+
+std::atomic< unsigned int > DBus::detail::CallId::LastId{0};
+static std::function< void( const char*, size_t ) > debugPrinter;
+static std::mutex debugLock;
+
+thread_local std::string DBus::DBusServer::currentObjectPath;
+thread_local DBusWrapper::ConnectionPtr DBus::DBusServer::currentConnection;
+
+void DBus::setDebugPrinter( std::function< void( const char*, size_t ) > printer )
+{
+  std::lock_guard< std::mutex > lock( debugLock );
+  debugPrinter = std::move( printer );
+}
+
+void DBus::debugPrint( const char* file, size_t line, const char* format, ... )
+{
+  std::function< void( const char*, size_t ) > debugPrintFunc;
+  {
+    std::lock_guard< std::mutex > lock( debugLock );
+    if( !debugPrinter )
+      return;
+    debugPrintFunc = debugPrinter;
+  }
+  std::vector< char > buf( 4096 );
+  int offset;
+  while( true )
+  {
+    offset = snprintf( buf.data(), buf.size(), "%s:%u: ", file, static_cast< unsigned int >( line ) );
+    if( offset < 0 )
+      return;
+    if( static_cast< size_t >( offset ) < buf.size() )
+      break;
+    buf.resize( offset + 1 );
+  }
+
+  while( true )
+  {
+    va_list args;
+    va_start( args, format );
+    int z = vsnprintf( buf.data() + offset, buf.size() - offset, format, args );
+    va_end( args );
+    if( z < 0 )
+      return;
+    bool done = static_cast< size_t >( z ) + static_cast< size_t >( offset ) < buf.size();
+    buf.resize( static_cast< size_t >( z ) + static_cast< size_t >( offset ) );
+    if( done )
+      break;
+  }
+  debugPrintFunc( buf.data(), buf.size() );
+}
+
+DBusWrapper::ConnectionPtr DBus::getDBusConnectionByName( const std::string& name )
+{
+  return DBUS_W->eldbus_address_connection_get_impl( name );
+}
+
+DBusWrapper::ConnectionPtr DBus::getDBusConnectionByType( ConnectionType connectionType )
+{
+  return DBUS_W->eldbus_connection_get_impl(connectionType);
+}
+
+DBus::DBusClient::DBusClient( std::string busName, std::string pathName, std::string interfaceName, ConnectionType tp ) : DBusClient( std::move( busName ), std::move( pathName ), std::move( interfaceName ), getDBusConnectionByType( tp ) )
+{
+}
+
+DBus::DBusClient::DBusClient( std::string busName, std::string pathName, std::string interfaceName, const DBusWrapper::ConnectionPtr &conn )
+{
+  if( !conn )
+    connectionState->connection = getDBusConnectionByType( ConnectionType::SESSION );
+  else
+    connectionState->connection = conn;
+
+  std::ostringstream o;
+  o << "bus = " << busName << " path = " << pathName << " connection = " << DBUS_W->eldbus_connection_unique_name_get_impl( connectionState->connection );
+  info = o.str();
+
+  connectionState->object = DBUS_W->eldbus_object_get_impl( connectionState->connection, busName.c_str(), pathName.c_str() );
+  if( connectionState->object )
+  {
+    connectionState->proxy = DBUS_W->eldbus_proxy_get_impl( connectionState->object, interfaceName );
+    if( interfaceName != DBUS_INTERFACE_PROPERTIES )
+    {
+      connectionState->propertiesProxy = DBUS_W->eldbus_proxy_get_impl( connectionState->object, DBUS_INTERFACE_PROPERTIES );
+    }
+    else
+    {
+      connectionState->propertiesProxy = DBUS_W->eldbus_proxy_copy_impl( connectionState->proxy );
+    }
+  }
+  connectionInfo = std::make_shared< ConnectionInfo >();
+  connectionInfo->busName = std::move( busName );
+  connectionInfo->pathName = std::move( pathName );
+  connectionInfo->interfaceName = std::move( interfaceName );
+}
+
+DBus::DBusServer::DBusServer( ConnectionType tp ) : DBus::DBusServer( DBus::getDBusConnectionByType( tp ) )
+{
+}
+
+DBus::DBusServer::DBusServer( const DBusWrapper::ConnectionPtr &conn )
+{
+  if( !conn )
+    connection = getDBusConnectionByType( ConnectionType::SESSION );
+  else
+    connection = conn;
+}
+
+DBus::DBusInterfaceDescription::DBusInterfaceDescription( std::string interfaceName ) : interfaceName( std::move( interfaceName ) )
+{
+}
+
+void DBus::DBusServer::addInterface( const std::string& pathName, DBusInterfaceDescription& dscr, bool fallback )
+{
+  DBUS_W->add_interface_impl( fallback, pathName, connection, destructorObject->destructors, dscr.interfaceName, dscr.methods, dscr.properties, dscr.signals );
+}
+
+std::string DBus::DBusServer::getBusName() const
+{
+  return getConnectionName( connection );
+}
+
+std::string DBus::getConnectionName( const DBusWrapper::ConnectionPtr &c )
+{
+  return DBUS_W->eldbus_connection_unique_name_get_impl( c );
+}
+
+bool DBus::DBusClient::getFromEinaValue(const _Eina_Value *v, void *dst)
+{
+  return eina_value_get(const_cast<Eina_Value*>(v), dst);
+}
+
+static std::unique_ptr<DBusWrapper> InstalledWrapper;
+
+struct DefaultDBusWrapper : public DBusWrapper
+{
+  constexpr static int ELDBUS_CALL_TIMEOUT = 1000;
+
+  DefaultDBusWrapper()
+  {
+  }
+
+  ~DefaultDBusWrapper()
+  {
+  }
+
+  #define DEFINE_GS(name, eldbus_name, unref_call) \
+    static eldbus_name *get(const std::shared_ptr<name> &a) { \
+      return static_cast<name ## Impl*>(a.get())->Value; \
+    } \
+    static eldbus_name *release(const std::shared_ptr<name> &a) { \
+      auto z = static_cast<name ## Impl*>(a.get())->Value; \
+      static_cast<name ## Impl*>(a.get())->Value = nullptr; \
+      return z; \
+    } \
+    template <typename ... ARGS> static std::shared_ptr<name> create(const eldbus_name *v, ARGS && ... args) { \
+      return std::make_shared<name ## Impl>(const_cast<eldbus_name*>(v), std::forward<ARGS>(args)...); \
+    }
+
+  #define DEFINE_TYPE(name, eldbus_name, unref_call) \
+  struct name ## Impl : public name { \
+    eldbus_name *Value = nullptr; \
+    bool EraseOnExit = false; \
+    name ## Impl(eldbus_name *Value, bool EraseOnExit = false) : Value(Value), EraseOnExit(EraseOnExit) { } \
+    ~name ## Impl() { \
+      if (EraseOnExit && Value) { unref_call; } \
+    } \
+  }; \
+  DEFINE_GS(name, eldbus_name, unref_call)
+
+  struct ConnectionImpl : public Connection
+  {
+    Eldbus_Connection *Value = nullptr;
+    bool EraseOnExit = false;
+    ConnectionImpl(Eldbus_Connection *Value, bool EraseOnExit = false) : Value(Value), EraseOnExit(EraseOnExit)
+    {
+      ecore_event_init();
+      eldbus_init();
+    }
+
+    ~ConnectionImpl()
+    {
+      if (EraseOnExit && Value)
+      {
+        eldbus_connection_unref( Value );
+      }
+      eldbus_shutdown();
+      ecore_event_shutdown();
+    }
+  };
+
+  struct MessageIterImpl : public MessageIter
+  {
+    Eldbus_Message_Iter *Value = nullptr, *Parent = nullptr;
+    bool EraseOnExit = false;
+    MessageIterImpl(Eldbus_Message_Iter *Value, Eldbus_Message_Iter *Parent, bool EraseOnExit = false) : Value(Value), Parent(Parent), EraseOnExit(EraseOnExit)
+    {
+    }
+
+    ~MessageIterImpl()
+    {
+      if (EraseOnExit && Value && Parent)
+      {
+        eldbus_message_iter_container_close(Parent, Value);
+      }
+    }
+  };
+
+  DEFINE_GS(Connection, Eldbus_Connection, )
+  DEFINE_GS(MessageIter, Eldbus_Message_Iter, )
+  DEFINE_TYPE(Message, Eldbus_Message, eldbus_message_unref( Value ))
+  DEFINE_TYPE(Proxy, Eldbus_Proxy, )
+  DEFINE_TYPE(Object, Eldbus_Object, eldbus_object_unref( Value ))
+  DEFINE_TYPE(Pending, Eldbus_Pending, )
+  DEFINE_TYPE(EventPropertyChanged, Eldbus_Proxy_Event_Property_Changed, )
+  #undef DEFINE_TYPE
+
+  std::shared_ptr<Connection> eldbus_address_connection_get_impl(const std::string &addr) override
+  {
+    eldbus_init();
+    auto p = eldbus_address_connection_get(addr.c_str());
+    auto w = create(p, true);
+    eldbus_shutdown();
+    return w;
+  }
+
+#define eldbus_message_iter_arguments_append_impl_basic(type, sig) \
+  void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, type src) override { \
+    eldbus_message_iter_arguments_append( get(it), #sig, src ); \
+  } \
+  bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, type &dst) override { \
+    return eldbus_message_iter_get_and_next( get(it), (#sig)[0], &dst ); \
+  }
+
+  eldbus_message_iter_arguments_append_impl_basic(uint8_t, y)
+  eldbus_message_iter_arguments_append_impl_basic(uint16_t, q)
+  eldbus_message_iter_arguments_append_impl_basic(uint32_t, u)
+  eldbus_message_iter_arguments_append_impl_basic(uint64_t, t)
+  eldbus_message_iter_arguments_append_impl_basic(int16_t, n)
+  eldbus_message_iter_arguments_append_impl_basic(int32_t, i)
+  eldbus_message_iter_arguments_append_impl_basic(int64_t, x)
+  eldbus_message_iter_arguments_append_impl_basic(double, d)
+
+#undef eldbus_message_iter_arguments_append_impl_basic
+
+  void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, bool src) override
+  {
+    eldbus_message_iter_arguments_append( get(it), "b", src ? 1 : 0 );
+  }
+
+  bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, bool &dst) override
+  {
+    unsigned char q;
+    auto z = eldbus_message_iter_get_and_next( get(it), 'b', &q );
+    dst = q != 0;
+    return z;
+  }
+
+  void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, const std::string &src) override
+  {
+    eldbus_message_iter_arguments_append( get(it), "s", src.c_str() );
+  }
+
+  bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, std::string &dst) override
+  {
+    auto iter = get(it);
+    const char* q;
+    if( !eldbus_message_iter_get_and_next( iter, 's', &q ) )
+    {
+      if( !eldbus_message_iter_get_and_next( iter, 'o', &q ) )
+      {
+        return false;
+      }
+    }
+    dst = q;
+    return true;
+  }
+
+  void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, const ObjectPath &src) override
+  {
+    eldbus_message_iter_arguments_append( get(it), "o", src.value.c_str() );
+  }
+
+  bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, ObjectPath &dst) override
+  {
+    const char* q;
+    if( !eldbus_message_iter_get_and_next( get(it), 'o', &q ) )
+    {
+      return false;
+    }
+    dst.value = q;
+    return true;
+  }
+
+  MessageIterPtr eldbus_message_iter_container_new_impl(const MessageIterPtr &it, int type, const std::string &sig) override
+  {
+    auto z = eldbus_message_iter_container_new( get(it), type, !sig.empty() ? sig.c_str() : NULL );
+    return create(z, get(it), true);
+  }
+
+  MessageIterPtr eldbus_message_iter_get_and_next_by_type_impl(const MessageIterPtr &it, int type) override
+  {
+    Eldbus_Message_Iter* entry;
+    if (!eldbus_message_iter_get_and_next( get(it), type, &entry ) )
+    {
+      return {};
+    }
+    return create(entry, get(it), false);
+  }
+
+  MessageIterPtr eldbus_message_iter_get_impl(const MessagePtr &msg, bool) override
+  {
+    return create(eldbus_message_iter_get(get(msg)), nullptr, false);
+  }
+
+  MessagePtr eldbus_proxy_method_call_new_impl(const ProxyPtr &proxy, const std::string &funcName)
+  {
+    return create(eldbus_proxy_method_call_new( get(proxy), funcName.c_str() ) );
+  }
+
+  MessagePtr eldbus_proxy_send_and_block_impl(const ProxyPtr &proxy, const MessagePtr &msg) override
+  {
+    return create(eldbus_proxy_send_and_block(get(proxy), release(msg), ELDBUS_CALL_TIMEOUT) );
+  }
+
+  bool eldbus_message_error_get_impl(const MessagePtr &msg, std::string &name, std::string &text) override
+  {
+    const char *errname, *errmsg;
+    if( eldbus_message_error_get( get(msg), &errname, &errmsg ) )
+    {
+      name = errname;
+      text = errmsg;
+      return true;
+    }
+    return false;
+  }
+
+  std::string eldbus_message_signature_get_impl(const MessagePtr &msg) override
+  {
+    return eldbus_message_signature_get(get(msg));
+  }
+
+  static void callAsyncCb( void* data, const Eldbus_Message *msg,  Eldbus_Pending *pending )
+  {
+    auto d = static_cast< SendCallback* >( data );
+    (*d)( create(msg, false) );
+  }
+
+  static void pendingFreeCb( void* data, const void* )
+  {
+    auto d = static_cast< SendCallback* >( data );
+    delete d;
+  }
+
+  static void listenerCallbackFree( void* data, const void* )
+  {
+    auto d = static_cast< std::function< void( const Eldbus_Message* msg ) >* >( data );
+    delete d;
+  }
+
+  PendingPtr eldbus_proxy_send_impl(const ProxyPtr &proxy, const MessagePtr &msg, const SendCallback &callback) override
+  {
+    auto cb = new SendCallback{ callback };
+    auto pending = eldbus_proxy_send( get(proxy), release(msg), callAsyncCb, cb, ELDBUS_CALL_TIMEOUT );
+    if( pending )
+    {
+      eldbus_pending_free_cb_add( pending, pendingFreeCb, cb );
+    }
+    else
+    {
+      delete cb;
+    }
+    return create(pending, false);
+  }
+
+  std::string eldbus_proxy_interface_get_impl(const ProxyPtr &proxy) override
+  {
+    return eldbus_proxy_interface_get( get(proxy) );
+  }
+
+  static void listenerCallback( void* data, const Eldbus_Message* msg )
+  {
+    auto p = static_cast< std::function< void( const Eldbus_Message* msg ) >* >( data );
+    ( *p )( msg );
+  }
+
+  void eldbus_proxy_signal_handler_add_impl(const ProxyPtr &proxy, const std::string &member, const std::function<void(const MessagePtr &)> &cb) override
+  {
+    auto tmp = new std::function< void( const Eldbus_Message* msg ) >
+    {
+      [cb](const Eldbus_Message* msg)
+      {
+        cb(create(msg, false));
+      }
+    };
+    auto handler = eldbus_proxy_signal_handler_add( get(proxy), member.c_str(), listenerCallback, tmp );
+    if( handler )
+    {
+      eldbus_proxy_free_cb_add( get(proxy), listenerCallbackFree, tmp );
+     }
+    else
+    {
+      delete tmp;
+     }
+  }
+
+  std::string eldbus_message_iter_signature_get_impl(const MessageIterPtr &iter) override
+  {
+    return eldbus_message_iter_signature_get( get(iter) );
+  }
+
+  MessagePtr eldbus_message_method_return_new_impl( const MessagePtr &msg) override
+  {
+    return create(eldbus_message_method_return_new( get(msg) ) );
+  }
+
+  MessagePtr eldbus_message_error_new_impl( const MessagePtr &msg, const std::string &err, const std::string &txt ) override
+  {
+    return create(eldbus_message_error_new( get(msg), err.c_str(), txt.c_str() ) );
+  }
+
+  PendingPtr eldbus_connection_send_impl(const ConnectionPtr &conn, const MessagePtr &msg) override
+  {
+    return create(eldbus_connection_send( get(conn), get(msg), NULL, NULL, -1 ) );
+  }
+
+  MessagePtr eldbus_message_signal_new_impl(const std::string &path, const std::string &iface, const std::string &name) override
+  {
+    return create(eldbus_message_signal_new( path.c_str(), iface.c_str(), name.c_str() ) );
+  }
+
+  MessagePtr eldbus_message_ref_impl(const MessagePtr &msg) override
+  {
+    return create(eldbus_message_ref( get(msg) ), true );
+  }
+
+  ConnectionPtr eldbus_connection_get_impl(ConnectionType type) override
+  {
+    Eldbus_Connection_Type eldbusType = ELDBUS_CONNECTION_TYPE_SYSTEM;
+
+    switch( type )
+    {
+      case ConnectionType::SYSTEM:
+      {
+        eldbusType = ELDBUS_CONNECTION_TYPE_SYSTEM;
+        break;
+      }
+      case ConnectionType::SESSION:
+      {
+        eldbusType = ELDBUS_CONNECTION_TYPE_SESSION;
+        break;
+      }
+    }
+
+    eldbus_init();
+    auto p = eldbus_connection_get( eldbusType );
+    auto w = create(p, true);
+    eldbus_shutdown();
+    return w;
+  }
+
+  std::string eldbus_connection_unique_name_get_impl(const ConnectionPtr &conn) override
+  {
+    return eldbus_connection_unique_name_get( get(conn) );
+  }
+
+  ObjectPtr eldbus_object_get_impl( const ConnectionPtr &conn, const std::string &bus, const std::string &path ) override
+  {
+      return create(eldbus_object_get(get(conn), bus.c_str(), path.c_str() ), true );
+  }
+
+  ProxyPtr eldbus_proxy_get_impl( const ObjectPtr &obj, const std::string &interface ) override
+  {
+    return create(eldbus_proxy_get(get(obj), interface.c_str() ), false );
+  }
+
+  ProxyPtr eldbus_proxy_copy_impl( const ProxyPtr &ptr) override
+  {
+    return create(get(ptr), false );
+  }
+
+  struct Implementation
+  {
+    Eldbus_Service_Interface_Desc dsc;
+    std::vector< std::vector< Eldbus_Arg_Info > > argsInfos;
+    std::vector< Eldbus_Method > methods;
+    std::vector< Eldbus_Signal > signals;
+    std::vector< Eldbus_Property > properties;
+
+    std::unordered_map< std::string, DBusWrapper::MethodInfo > methodsMap;
+    std::unordered_map< std::string, DBusWrapper::PropertyInfo > propertiesMap;
+    std::unordered_map< unsigned int, DBusWrapper::SignalInfo > signalsMap;
+
+    DBusWrapper::ConnectionWeakPtr connection;
+  };
+
+  static std::unordered_map< const Eldbus_Service_Interface*, std::unique_ptr< Implementation > > globalEntries;
+  static std::mutex globalEntriesMutex;
+
+#undef EINA_FALSE
+#undef EINA_TRUE
+#define EINA_FALSE static_cast<Eina_Bool>(0)
+#define EINA_TRUE static_cast<Eina_Bool>(1)
+
+  static Eina_Bool property_get_callback( const Eldbus_Service_Interface* iface, const char* propertyName, Eldbus_Message_Iter* iter,
+                                          const Eldbus_Message* message, Eldbus_Message** error )
+  {
+    Implementation* impl = nullptr;
+    {
+      std::lock_guard< std::mutex > lock( globalEntriesMutex );
+      auto it = globalEntries.find( iface );
+      if( it != globalEntries.end() )
+      {
+        impl = it->second.get();
+      }
+    }
+    if( !impl )
+    {
+      return EINA_FALSE;
+    }
+
+    auto it = impl->propertiesMap.find( propertyName );
+    if( it == impl->propertiesMap.end() || !it->second.getCallback )
+    {
+      return EINA_FALSE;
+    }
+
+    auto connection = impl->connection.lock();
+    if( !connection )
+    {
+      return EINA_FALSE;
+    }
+
+    DBus::DBusServer::CurrentObjectSetter currentObjectSetter( connection, eldbus_message_path_get( message ) );
+    auto reply = it->second.getCallback( create(message, false), create(iter, nullptr, false) );
+    if( !reply.empty() )
+    {
+      if( error )
+      {
+        *error = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", reply.c_str() );
+      }
+      return EINA_FALSE;
+    }
+
+    return EINA_TRUE;
+  }
+
+  static Eldbus_Message* property_set_callback( const Eldbus_Service_Interface* iface, const char* propertyName, Eldbus_Message_Iter* iter,
+                                                const Eldbus_Message* message )
+  {
+    Implementation* impl = nullptr;
+    {
+      std::lock_guard< std::mutex > lock( globalEntriesMutex );
+      auto it = globalEntries.find( iface );
+      if( it != globalEntries.end() )
+      {
+        impl = it->second.get();
+      }
+    }
+    if( !impl )
+    {
+      auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown interface" );
+      return ret;
+    }
+    auto it = impl->propertiesMap.find( propertyName );
+    if( it == impl->propertiesMap.end() || !it->second.setCallback )
+    {
+      auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown setter" );
+      return ret;
+    }
+    auto connection = impl->connection.lock();
+    if( !connection )
+    {
+      auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Connection lost" );
+      return ret;
+    }
+
+    DBus::DBusServer::CurrentObjectSetter currentObjectSetter( connection, eldbus_message_path_get( message ) );
+    auto reply = it->second.setCallback( create(message, false), create(iter, nullptr, false) );
+
+    Eldbus_Message* ret = nullptr;
+    if( !reply.empty() )
+    {
+      ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", reply.c_str() );
+    }
+    else
+    {
+      ret = eldbus_message_method_return_new( message );
+    }
+    return ret;
+  }
+
+  static Eldbus_Message* method_callback( const Eldbus_Service_Interface* iface, const Eldbus_Message* message )
+  {
+    Implementation* impl = nullptr;
+    {
+      std::lock_guard< std::mutex > lock( globalEntriesMutex );
+      auto it = globalEntries.find( iface );
+      if( it != globalEntries.end() )
+        impl = it->second.get();
+    }
+    if( !impl )
+    {
+      auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown interface" );
+      return ret;
+    }
+    std::string memberName = eldbus_message_member_get( message );
+    auto it = impl->methodsMap.find( memberName );
+    if( it == impl->methodsMap.end() )
+    {
+      auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Unknown method" );
+      return ret;
+    }
+    auto connection = impl->connection.lock();
+    if( !connection )
+    {
+      auto ret = eldbus_message_error_new( message, "org.freedesktop.DBus.Error.Failed", "Connection lost" );
+      return ret;
+    }
+    DBus::DBusServer::CurrentObjectSetter currentObjectSetter( connection, eldbus_message_path_get( message ) );
+    auto reply = it->second.callback( create(message) );
+    return release(reply);
+  }
+
+  void add_interface_impl( bool fallback, const std::string& pathName,
+                              const ConnectionPtr &connection,
+                              std::vector<std::function<void()>> &destructors,
+                              const std::string& interfaceName,
+                              std::vector< MethodInfo >& dscrMethods,
+                              std::vector< PropertyInfo >& dscrProperties,
+                              std::vector< SignalInfo >& dscrSignals ) override
+  {
+    std::vector< Eldbus_Method > methods;
+    std::vector< Eldbus_Signal > signals;
+    std::vector< Eldbus_Property > properties;
+    std::vector< std::vector< Eldbus_Arg_Info > > argsInfos;
+    std::unordered_map< std::string, DBus::DBusInterfaceDescription::MethodInfo > methodsMap;
+    std::unordered_map< std::string, DBus::DBusInterfaceDescription::PropertyInfo > propertiesMap;
+    std::unordered_map< unsigned int, DBus::DBusInterfaceDescription::SignalInfo > signalsMap;
+
+    DBUS_DEBUG( "interface %s path %s on bus %s", interfaceName.c_str(), pathName.c_str(), DBus::getConnectionName( connection ).c_str() );
+    auto makeArgInfo = [&](const std::vector<std::pair<std::string, std::string>> &input) {
+      argsInfos.push_back({});
+      auto &dst = argsInfos.back();
+      for(auto &s : input)
+      {
+        auto a = Strings.add(s.first);
+        auto b = Strings.add(s.second);
+        dst.push_back({ a, b });
+      }
+      dst.push_back({ nullptr, nullptr });
+      return dst.data();
+    };
+    for( auto& ee : dscrMethods )
+    {
+      auto key = ee.memberName;
+      DBUS_DEBUG( "adding method %s", ee.memberName.c_str() );
+      for( auto& r : ee.in )
+      {
+        DBUS_DEBUG( "in %s '%s'", r.first.c_str(), r.second.c_str() );
+      }
+      for( auto& r : ee.out )
+      {
+        DBUS_DEBUG( "out %s '%s'", r.first.c_str(), r.second.c_str() );
+      }
+      auto& e = ( methodsMap[key] = std::move( ee ) );
+      methods.push_back( {} );
+      auto& m = methods.back();
+      m.member = e.memberName.c_str();
+      m.in = makeArgInfo(e.in);
+      m.out = makeArgInfo(e.out);
+      m.cb = method_callback;
+      m.flags = 0;
+    }
+    for( auto& ee : dscrProperties )
+    {
+      auto key = ee.memberName;
+      DBUS_DEBUG( "adding property %s", ee.memberName.c_str() );
+      auto& e = ( propertiesMap[key] = std::move( ee ) );
+      properties.push_back( {} );
+      auto& m = properties.back();
+      m.name = e.memberName.c_str();
+      m.type = e.typeSignature.c_str();
+      m.get_func = e.getCallback ? property_get_callback : nullptr;
+      m.set_func = e.setCallback ? property_set_callback : nullptr;
+      m.flags = 0;
+    }
+    dscrMethods.clear();
+    dscrProperties.clear();
+    dscrSignals.clear();
+
+    methods.push_back( {nullptr, nullptr, nullptr, nullptr, 0} );
+    signals.push_back( {nullptr, nullptr, 0} );
+    properties.push_back( {nullptr, nullptr, nullptr, nullptr, 0} );
+
+    auto impl = std::unique_ptr< Implementation >( new Implementation{
+        {interfaceName.c_str(),
+        methods.data(),
+        signals.data(),
+        properties.data(),
+        nullptr,
+        nullptr},
+        std::move( argsInfos ),
+        std::move( methods ),
+        std::move( signals ),
+        std::move( properties ),
+        std::move( methodsMap ),
+        std::move( propertiesMap ),
+        std::move( signalsMap ),
+        connection} );
+
+    {
+      std::lock_guard< std::mutex > lock( globalEntriesMutex );
+      auto v = fallback ? eldbus_service_interface_fallback_register( get(connection), pathName.c_str(), &impl->dsc ) : eldbus_service_interface_register( get(connection), pathName.c_str(), &impl->dsc );
+      assert( v );
+      globalEntries[v] = std::move( impl );
+      DBUS_DEBUG( "registering interface %p (%d)", v, fallback ? 1 : 0 );
+      destructors.push_back([=]()
+        {
+          DBUS_DEBUG( "unregistering interface %p", v );
+          {
+            std::lock_guard< std::mutex > lock( globalEntriesMutex );
+            globalEntries.erase( v );
+          }
+          eldbus_service_interface_unregister( v );
+        }
+      );
+    }
+  }
+
+  static void listenerEventChangedCallback( void* data, Eldbus_Proxy* proxy EINA_UNUSED, void* event )
+  {
+    auto p = static_cast< std::function< void( Eldbus_Proxy_Event_Property_Changed* ) >* >( data );
+    ( *p )( static_cast< Eldbus_Proxy_Event_Property_Changed* >( event ) );
+  }
+
+  static void ProxyEventCallbackDelCb( void* data, const void *obj )
+  {
+    auto d = static_cast< std::function< void( Eldbus_Proxy_Event_Property_Changed* ) >* >( data );
+    delete d;
+  }
+
+  void add_property_changed_event_listener_impl( const ProxyPtr &proxy, const std::string &interface, const std::string &name, std::function< void( const Eina_Value * ) > cb) override
+  {
+    auto callbackLambdaPtr = new std::function< void( Eldbus_Proxy_Event_Property_Changed *epc ) >
+    {
+      [cb, name, interface]( Eldbus_Proxy_Event_Property_Changed *ev )
+      {
+        const char* ifc = eldbus_proxy_interface_get( ev->proxy );
+        if( ev->name && ev->name == name && ifc && interface == ifc )
+        {
+          cb(ev->value);
+        }
+      }
+    };
+    auto p = get(proxy);
+    eldbus_proxy_event_callback_add( p, ELDBUS_PROXY_EVENT_PROPERTY_CHANGED, listenerEventChangedCallback, callbackLambdaPtr );
+    eldbus_proxy_free_cb_add( p, ProxyEventCallbackDelCb, callbackLambdaPtr );
+  }
+};
+
+std::unordered_map< const Eldbus_Service_Interface*, std::unique_ptr< DefaultDBusWrapper::Implementation > > DefaultDBusWrapper::globalEntries;
+std::mutex DefaultDBusWrapper::globalEntriesMutex;
+
+DBusWrapper *DBusWrapper::Installed()
+{
+  if (!InstalledWrapper)
+  {
+    InstalledWrapper.reset(new DefaultDBusWrapper);
+  }
+  return InstalledWrapper.get();
+}
+
+void DBusWrapper::Install(std::unique_ptr<DBusWrapper> w)
+{
+  InstalledWrapper = std::move(w);
+}
diff --git a/dali/internal/accessibility/tizen-wayland/atspi/dbus.h b/dali/internal/accessibility/tizen-wayland/atspi/dbus.h
new file mode 100644 (file)
index 0000000..e3176a3
--- /dev/null
@@ -0,0 +1,2935 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_BRIDGE_DBUS_H
+#define DALI_INTERNAL_ACCESSIBILITY_BRIDGE_DBUS_H
+
+/*
+ * Copyright 2019  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 <memory>
+#include <array>
+#include <atomic>
+#include <cstdint>
+#include <map>
+#include <sstream>
+#include <string>
+#include <thread>
+#include <tuple>
+#include <type_traits>
+#include <unordered_map>
+#include <vector>
+#include <functional>
+#include <string.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/atspi-accessibility.h>
+#include <dali/internal/accessibility/tizen-wayland/atspi/accessibility-optional.h>
+
+#define ATSPI_PREFIX_PATH "/org/a11y/atspi/accessible/"
+#define ATSPI_NULL_PATH "/org/a11y/atspi/null"
+
+struct _Eina_Value;
+
+struct ObjectPath
+{
+  std::string value;
+};
+
+struct DALI_ADAPTOR_API DBusWrapper
+{
+  virtual ~DBusWrapper() = default;
+
+  enum class ConnectionType
+  {
+    SYSTEM,
+    SESSION
+  };
+
+#define DEFINE_TYPE(name, eldbus_name, unref_call) \
+    struct name { virtual ~name() = default; }; \
+    using name ## Ptr = std::shared_ptr<name>; \
+    using name ## WeakPtr = std::weak_ptr<name>; \
+
+  DEFINE_TYPE(Connection, Eldbus_Connection, )
+    DEFINE_TYPE(MessageIter, Eldbus_Message_Iter, eldbus_message_iter_container_close(Value))
+    DEFINE_TYPE(Message, Eldbus_Message, eldbus_message_unref(Value))
+    DEFINE_TYPE(Proxy, Eldbus_Proxy, eldbus_proxy_unref(Value))
+    DEFINE_TYPE(Object, Eldbus_Object, eldbus_object_unref(Value))
+    DEFINE_TYPE(Pending, Eldbus_Pending, )
+    DEFINE_TYPE(EventPropertyChanged, Eldbus_Proxy_Event_Property_Changed, )
+
+#undef DEFINE_TYPE
+    virtual ConnectionPtr eldbus_address_connection_get_impl(const std::string& addr) = 0;
+
+#define eldbus_message_iter_arguments_append_impl_basic_impl(type_set, type_get, sig) \
+  virtual void eldbus_message_iter_arguments_append_impl(const MessageIterPtr &it, type_set src) = 0; \
+  virtual bool eldbus_message_iter_get_and_next_impl(const MessageIterPtr &it, type_get &dst) = 0;
+#define eldbus_message_iter_arguments_append_impl_basic(type, sig) \
+  eldbus_message_iter_arguments_append_impl_basic_impl(type, type, sig)
+
+  eldbus_message_iter_arguments_append_impl_basic(uint8_t, y)
+    eldbus_message_iter_arguments_append_impl_basic(uint16_t, q)
+    eldbus_message_iter_arguments_append_impl_basic(uint32_t, u)
+    eldbus_message_iter_arguments_append_impl_basic(uint64_t, t)
+    eldbus_message_iter_arguments_append_impl_basic(int16_t, n)
+    eldbus_message_iter_arguments_append_impl_basic(int32_t, i)
+    eldbus_message_iter_arguments_append_impl_basic(int64_t, x)
+    eldbus_message_iter_arguments_append_impl_basic(double, d)
+    eldbus_message_iter_arguments_append_impl_basic(bool, b)
+    eldbus_message_iter_arguments_append_impl_basic_impl(const std::string&, std::string, s)
+    eldbus_message_iter_arguments_append_impl_basic_impl(const ObjectPath&, ObjectPath, o)
+
+#undef eldbus_message_iter_arguments_append_impl_basic
+#undef eldbus_message_iter_arguments_append_impl_basic_impl
+
+    virtual MessageIterPtr eldbus_message_iter_container_new_impl(const MessageIterPtr& it, int type, const std::string& sig) = 0;
+  virtual MessageIterPtr eldbus_message_iter_get_and_next_by_type_impl(const MessageIterPtr& it, int type) = 0;
+  virtual MessageIterPtr eldbus_message_iter_get_impl(const MessagePtr& it, bool write) = 0;
+  virtual MessagePtr eldbus_proxy_method_call_new_impl(const ProxyPtr& proxy, const std::string& funcName) = 0;
+  virtual MessagePtr eldbus_proxy_send_and_block_impl(const ProxyPtr& proxy, const MessagePtr& msg) = 0;
+  virtual bool eldbus_message_error_get_impl(const MessagePtr& msg, std::string& name, std::string& text) = 0;
+  virtual std::string eldbus_message_signature_get_impl(const MessagePtr& msg) = 0;
+
+  using SendCallback = std::function<void(const MessagePtr & msg)>;
+  virtual PendingPtr eldbus_proxy_send_impl(const ProxyPtr& proxy, const MessagePtr& msg, const SendCallback& callback) = 0;
+  virtual std::string eldbus_proxy_interface_get_impl(const ProxyPtr&) = 0;
+  virtual void eldbus_proxy_signal_handler_add_impl(const ProxyPtr& proxy, const std::string& member, const std::function<void(const MessagePtr&)>& cb) = 0;
+  virtual std::string eldbus_message_iter_signature_get_impl(const MessageIterPtr& iter) = 0;
+  virtual MessagePtr eldbus_message_method_return_new_impl(const MessagePtr& msg) = 0;
+  virtual MessagePtr eldbus_message_error_new_impl(const MessagePtr& msg, const std::string& err, const std::string& txt) = 0;
+  virtual PendingPtr eldbus_connection_send_impl(const ConnectionPtr& conn, const MessagePtr& msg) = 0;
+  virtual MessagePtr eldbus_message_signal_new_impl(const std::string& path, const std::string& iface, const std::string& name) = 0;
+  virtual MessagePtr eldbus_message_ref_impl(const MessagePtr& msg) = 0;
+  virtual ConnectionPtr eldbus_connection_get_impl(ConnectionType type) = 0;
+  virtual std::string eldbus_connection_unique_name_get_impl(const ConnectionPtr& conn) = 0;
+  virtual ObjectPtr eldbus_object_get_impl(const ConnectionPtr& conn, const std::string& bus, const std::string& path) = 0;
+  virtual ProxyPtr eldbus_proxy_get_impl(const ObjectPtr& obj, const std::string& interface) = 0;
+  virtual ProxyPtr eldbus_proxy_copy_impl(const ProxyPtr& ptr) = 0;
+
+  class StringStorage
+  {
+  public:
+    struct char_ptr_deleter
+    {
+      void operator()(char* p)
+      {
+        free(p);
+      }
+    };
+    std::vector< std::unique_ptr< char, char_ptr_deleter > > storage;
+
+    const char* add(const char* txt)
+    {
+      auto ptr = strdup(txt);
+      storage.push_back(std::unique_ptr< char, char_ptr_deleter >(ptr));
+      return storage.back().get();
+    }
+    const char* add(const std::string& txt)
+    {
+      return add(txt.c_str());
+    }
+  };
+
+  struct CallId
+  {
+    static std::atomic< unsigned int > LastId;
+    unsigned int id = ++LastId;
+  };
+  struct MethodInfo
+  {
+    CallId id;
+    std::string memberName;
+    std::vector< std::pair<std::string, std::string> > in, out; // _Eldbus_Arg_Info
+    std::function< DBusWrapper::MessagePtr(const DBusWrapper::MessagePtr & msg) > callback;
+  };
+  struct SignalInfo
+  {
+    CallId id;
+    std::string memberName;
+    std::vector< std::pair<std::string, std::string> > args;
+    unsigned int uniqueId;
+  };
+  struct PropertyInfo
+  {
+    CallId setterId, getterId;
+    std::string memberName, typeSignature;
+    std::function< std::string(const DBusWrapper::MessagePtr & src, const DBusWrapper::MessageIterPtr & dst) > getCallback, setCallback;
+  };
+  struct SignalId
+  {
+    CallId id;
+
+    SignalId() = default;
+    SignalId(CallId id) : id(id) {}
+  };
+  virtual void add_interface_impl(bool fallback, const std::string& pathName,
+    const ConnectionPtr& connection,
+    std::vector<std::function<void()>>& destructors,
+    const std::string& interfaceName,
+    std::vector< MethodInfo >& dscrMethods,
+    std::vector< PropertyInfo >& dscrProperties,
+    std::vector< SignalInfo >& dscrSignals) = 0;
+  virtual void add_property_changed_event_listener_impl(const ProxyPtr& proxy, const std::string& interface, const std::string& name, std::function< void(const _Eina_Value*) > cb) = 0;
+  static DBusWrapper* Installed();
+  static void Install(std::unique_ptr<DBusWrapper>);
+
+  StringStorage Strings;
+};
+
+namespace detail {
+  enum class MethodType {
+    Method, Getter, Setter
+  };
+}
+
+namespace std {
+  template <> struct hash<std::tuple<std::string, std::string, std::string>> {
+    size_t operator () (const std::tuple<std::string, std::string, std::string>& a) const {
+      auto a1 = std::hash<std::string>()(std::get<0>(a));
+      auto a2 = std::hash<std::string>()(std::get<1>(a));
+      auto a3 = std::hash<std::string>()(std::get<2>(a));
+      size_t v = a1;
+      v = (v * 11400714819323198485llu) + a2;
+      v = (v * 11400714819323198485llu) + a3;
+      return v;
+    }
+  };
+  template <> struct hash<std::tuple<std::string, std::string, std::string, detail::MethodType>> {
+    size_t operator () (const std::tuple<std::string, std::string, std::string, detail::MethodType>& a) const {
+      auto a1 = std::hash<std::string>()(std::get<0>(a));
+      auto a2 = std::hash<std::string>()(std::get<1>(a));
+      auto a3 = std::hash<std::string>()(std::get<2>(a));
+      auto a4 = static_cast<size_t>(std::get<3>(a));
+      size_t v = a1;
+      v = (v * 11400714819323198485llu) + a2;
+      v = (v * 11400714819323198485llu) + a3;
+      v = (v * 11400714819323198485llu) + a4;
+      return v;
+    }
+  };
+  template <> struct hash<std::tuple<std::string, std::string, unsigned int>> {
+    size_t operator () (const std::tuple<std::string, std::string, unsigned int>& a) const {
+      auto a1 = std::hash<std::string>()(std::get<0>(a));
+      auto a2 = std::hash<std::string>()(std::get<1>(a));
+      auto a3 = std::get<2>(a);
+      size_t v = a1;
+      v = (v * 11400714819323198485llu) + a2;
+      v = (v * 11400714819323198485llu) + a3;
+      return v;
+    }
+  };
+}
+
+namespace detail {
+  template <typename T> struct DBusSigImpl { enum { value = 0, end = 0 }; };
+  template <typename T> struct DBusSig { enum { value = DBusSigImpl<typename std::decay<T>::type>::value, end = DBusSigImpl<typename std::decay<T>::type>::end }; };
+  template <typename T, typename Q, size_t I, size_t S> struct IndexFromTypeTupleImpl {
+    enum { value = std::is_same<typename std::decay<typename std::tuple_element<I, T>::type>::type, Q>::value ? I : IndexFromTypeTupleImpl<T, Q, I + 1, S>::value };
+  };
+  template <typename T, typename Q, size_t S> struct IndexFromTypeTupleImpl<T, Q, S, S> { enum { value = S }; };
+  template <typename T, typename Q> struct IndexFromTypeTuple {
+    enum { value = IndexFromTypeTupleImpl<T, typename std::decay<Q>::type, 0, std::tuple_size<T>::value>::value };
+  };
+  template <typename T, typename = void> struct Encoder;
+  template <size_t I, size_t S, typename ... ARGS> struct EncoderTuple;
+}
+
+namespace detail {
+  template <> struct DBusSigImpl<uint8_t> { enum { value = 'y', end = 0 }; };
+  template <> struct DBusSigImpl<uint16_t> { enum { value = 'q', end = 0 }; };
+  template <> struct DBusSigImpl<uint32_t> { enum { value = 'u', end = 0 }; };
+  template <> struct DBusSigImpl<uint64_t> { enum { value = 't', end = 0 }; };
+  template <> struct DBusSigImpl<int16_t> { enum { value = 'n', end = 0 }; };
+  template <> struct DBusSigImpl<int32_t> { enum { value = 'i', end = 0 }; };
+  template <> struct DBusSigImpl<int64_t> { enum { value = 'x', end = 0 }; };
+  template <> struct DBusSigImpl<double> { enum { value = 'd', end = 0 }; };
+  template <> struct DBusSigImpl<bool> { enum { value = 'b', end = 0 }; };
+  template <> struct DBusSigImpl<std::string> { enum { value = 's', end = 0 }; };
+  template <> struct DBusSigImpl<ObjectPath> { enum { value = 'o', end = 0 }; };
+}
+
+
+#define DBUS_DEBUG( ... )                                \
+  do                                                     \
+  {                                                      \
+    DBus::debugPrint( __FILE__, __LINE__, __VA_ARGS__ ); \
+  } while( 0 )
+
+#define DBUS_W DBusWrapper::Installed()
+
+/**
+ * @brief Template based, single file, wrapper library around eldbus for DBUS based communication.
+ *
+ * Main motivation was missing asynchronous calls in AT-SPI library and difficulties,
+ * when using eldbus from C++.
+ *
+ * The library:
+ * - takes care of marshalling arguments to and from DBUS calls.
+ * - allows synchronous and asynchronous calls.
+ * - allows synchronous and asynchronous listeners on signals.
+ * - manages all involved objects' lifetimes.
+ * - errors are passed as optional-alike objects, no exceptions are used.
+ * - allows setting additional debug-print function for more details about
+ *   what's going on
+ *
+ * DBUS's method signatures (and expected return values) are specified as template argument,
+ * using functor syntax. For example:
+ * \code{.cpp}
+ * auto dbus = DBusClient{ ... };
+ * auto v = dbus.method<std::tuple<int, float>(float, float, std::string)>("foo").call(1.0f, 2.0f, "qwe");
+ * \endcode
+ * means (synchronous) call on dbus object, which takes three arguments (thus making call signature \b dds)
+ * of types float, float and string (float will be automatically converted to double).
+ * Expected return value is std::tuple<int, float>, which gives signature <B>(id)</B> - std::tuple acts
+ * as struct container. Returned value v will be of type ValueOrError<std::tuple<int, float>>.\n
+ * Slightly different (asynchronous) example:
+ * \code{.cpp}
+ * auto dbus = DBusClient{ ... };
+ * std::function<void(ValueOrError<int, float>)> callback;
+ * dbus.method<ValueOrError<int, float>(float, float, std::string)>("foo").asyncCall(callback, 1.0f, 2.0f, "qwe");
+ * \endcode
+ * Now the call takes the same arguments and has the same signature. But expected values are different -
+ * now the signature is simply \b id. ValueOrError acts in this case as placeholder for list of values,
+ * which DBUS allows as return data. The call itself is asynchronous - instead of expecting reply
+ * you need to pass a callback, which will be called either with received data and error message.
+ *
+ * Library is not thread-safe, the same object shouldn't be called from different threads without
+ * synchronization. There's no guarantee, that callbacks will be executed on the same thread.
+ */
+namespace DBus
+{
+
+  class DBusServer;
+  class DBusClient;
+  class DBusInterfaceDescription;
+
+  /**
+   * @brief Formats debug message and calls debug printer (if any) with it
+   */
+  void debugPrint(const char* file, size_t line, const char* format, ...);
+
+  /**
+   * @brief Sets debug printer callback, which will be called with debug messages
+   *
+   * Callback will be called in various moments of DBus activity. First value passed to callback
+   * is pointer to text, second it's length. Text is ended with 0 (not counted towards it's size),
+   * user can safely printf it.
+   */
+  void setDebugPrinter(std::function< void(const char*, size_t) >);
+
+  struct Error
+  {
+    std::string message;
+
+    Error() = default;
+    Error(std::string msg) : message(std::move(msg))
+    {
+      assert(!message.empty());
+    }
+  };
+
+  struct Success
+  {
+  };
+
+
+  /**
+   * @brief Value representing data, that came from DBUS or error message
+   *
+   * Object of this class either helds series of values (of types ARGS...)
+   * or error message. This object will be true in boolean context, if has data
+   * and false, if an error occured.
+   * It's valid to create ValueOrError object with empty argument list or void:
+   * \code{.cpp}
+   * ValueOrError<> v1;
+   * ValueOrError<void> v2;
+   * \endcode
+   * Both mean the same - ValueOrError containing no real data and being a marker,
+   * wherever operation successed or failed and containing possible error message.
+   */
+  template < typename... ARGS >
+  class ValueOrError
+  {
+  public:
+    /**
+     * @brief Empty constructor. Valid only, if all ARGS types are default constructible.
+     */
+    ValueOrError() = default;
+
+    /**
+     * @brief Value constructor.
+     *
+     * This will be initialized as success with passed in values.
+     */
+    ValueOrError(ARGS... t) : value(std::move(t)...) {}
+
+    /**
+     * @brief Alternative Value constructor.
+     *
+     * This will be initialized as success with passed in values.
+     */
+    ValueOrError(std::tuple< ARGS... > t) : value(std::move(t)) {}
+
+    /**
+     * @brief Error constructor. This will be initialized as failure with given error message.
+     */
+    ValueOrError(Error e) : error(std::move(e))
+    {
+      assert(!error.message.empty());
+    }
+
+    /**
+     * @brief bool operator.
+     *
+     * Returns true, if operation was successful (getValues member is callable), or false
+     * when operation failed (getError is callable).
+     */
+    explicit operator bool() const
+    {
+      return error.message.empty();
+    }
+
+    /**
+     * @brief Returns error message object.
+     *
+     * Returns object containing error message associated with the failed operation.
+     * Only callable, if operation actually failed, otherwise will assert.
+     */
+    const Error& getError() const
+    {
+      return error;
+    }
+
+    /**
+     * @brief Returns modifiable tuple of held data.
+     *
+     * Returns reference to the internal tuple containing held data.
+     * User can modify (or move) data safely.
+     * Only callable, if operation actually successed, otherwise will assert.
+     */
+    std::tuple< ARGS... >& getValues()
+    {
+      assert(*this);
+      return value;
+    }
+
+    /**
+     * @brief Returns const tuple of held data.
+     *
+     * Returns const reference to the internal tuple containing held data.
+     * Only callable, if operation actually successed, otherwise will assert.
+     */
+    const std::tuple< ARGS... >& getValues() const
+    {
+      assert(*this);
+      return value;
+    }
+
+  protected:
+    std::tuple< ARGS... > value;
+    Error error;
+
+  };
+
+
+  template <>
+  class ValueOrError<>
+  {
+  public:
+    ValueOrError() = default;
+    ValueOrError(std::tuple<> t) {}
+    ValueOrError(Error e) : error(std::move(e))
+    {
+      assert(!error.message.empty());
+    }
+
+    explicit operator bool() const
+    {
+      return error.message.empty();
+    }
+    const Error& getError() const
+    {
+      return error;
+    }
+    std::tuple<>& getValues()
+    {
+      assert(*this);
+      static std::tuple<> t;
+      return t;
+    }
+    std::tuple<> getValues() const
+    {
+      assert(*this);
+      return {};
+    }
+
+  protected:
+    Error error;
+  };
+
+  template <>
+  class ValueOrError< void >
+  {
+  public:
+    ValueOrError() = default;
+    ValueOrError(Success) {}
+    ValueOrError(Error e) : error(std::move(e))
+    {
+      assert(!error.message.empty());
+    }
+
+    explicit operator bool() const
+    {
+      return error.message.empty();
+    }
+    const Error& getError() const
+    {
+      return error;
+    }
+    std::tuple<>& getValues()
+    {
+      assert(*this);
+      static std::tuple<> t;
+      return t;
+    }
+    std::tuple<> getValues() const
+    {
+      assert(*this);
+      return {};
+    }
+
+  protected:
+    Error error;
+  };
+
+  using ObjectPath = ObjectPath;
+
+
+  /**
+   * @brief Class used to marshall DBUS's variant type
+   *
+   * Minimalistic class, that allows user to specify DBUS variant type
+   * as argument or return value. You need to pass real type hidden under variant as
+   * template type \b A. At this point library doesn't allow to expected one of few classes
+   * as return data in variant. So for example user can't specify method call, which on return
+   * expects DBUS variant holding either string or int.
+   */
+  template < typename A >
+  struct EldbusVariant
+  {
+    A value;
+  };
+
+  /**
+   * @brief Namespace for private, internal functions and classes
+   */
+  namespace detail
+  {
+    template < typename T, typename = void >
+    struct signature;
+    template < typename... ARGS >
+    struct signature< std::tuple< ARGS... > >;
+    template < typename A, typename B >
+    struct signature< std::pair< A, B > >;
+    template < typename A >
+    struct signature< std::vector< A > >;
+    template < typename A, size_t N >
+    struct signature< std::array< A, N > >;
+    template < typename A, typename B >
+    struct signature< std::unordered_map< A, B > >;
+    template < typename A, typename B >
+    struct signature< std::map< A, B > >;
+
+    /**
+     * @brief Signature class for marshalling uint8 type.
+     */
+    template <>
+    struct signature< uint8_t >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "uint8_t";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "y";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, uint8_t v)
+      {
+        DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, uint8_t& v)
+      {
+        return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v);
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling uint16 type.
+     */
+    template <>
+    struct signature< uint16_t >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "uint16_t";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "q";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, uint16_t v)
+      {
+        DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, uint16_t& v)
+      {
+        return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v);
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling uint32 type.
+     */
+    template <>
+    struct signature< uint32_t >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "uint32_t";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "u";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, uint32_t v)
+      {
+        DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, uint32_t& v)
+      {
+        return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v);
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling uint64 type.
+     */
+    template <>
+    struct signature< uint64_t >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "uint64_t";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "t";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, uint64_t v)
+      {
+        DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, uint64_t& v)
+      {
+        return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v);
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling int16 type.
+     */
+    template <>
+    struct signature< int16_t >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "int16_t";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "n";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, int16_t v)
+      {
+        DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, int16_t& v)
+      {
+        return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v);
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling int32 type.
+     */
+    template <>
+    struct signature< int32_t >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "int32_t";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "i";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, int32_t v)
+      {
+        DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, int32_t& v)
+      {
+        return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v);
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling int64 type.
+     */
+    template <>
+    struct signature< int64_t >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "int64_t";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "x";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, int64_t v)
+      {
+        DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, int64_t& v)
+      {
+        return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v);
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling double type.
+     */
+    template <>
+    struct signature< double >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "double";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "d";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, double v)
+      {
+        DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, double& v)
+      {
+        return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, float& v2)
+      {
+        double v = 0;
+        auto r = DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v);
+        v2 = static_cast<float>(v);
+        return r;
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling float type.
+     */
+    template <>
+    struct signature< float >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "float";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "d";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, float v)
+      {
+        DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, double& v)
+      {
+        return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, float& v2)
+      {
+        double v = 0;
+        auto r = DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v);
+        v2 = static_cast<float>(v);
+        return r;
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling boolean type.
+     */
+    template <>
+    struct signature< bool >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "bool";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "b";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, bool v)
+      {
+        DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, bool& v)
+      {
+        return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v);
+      }
+    };
+
+    template < typename T >
+    struct signature< T, typename std::enable_if< std::is_enum< T >::value, void >::type >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "enum";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return signature<typename std::underlying_type<T>::type>::sig();
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, T v)
+      {
+        signature<typename std::underlying_type<T>::type>::set(iter, static_cast<int64_t>(v));
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, T& v)
+      {
+        typename std::underlying_type<T>::type q = 0;
+        if (!signature<typename std::underlying_type<T>::type>::get(iter, q))
+          return false;
+
+        v = static_cast<T>(q);
+        return true;
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling string type.
+     *
+     * Both (const) char * and std::string types are accepted as value to send.
+     * Only std::string is accepted as value to receive.
+     */
+    template <>
+    struct signature< std::string >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "string";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "s";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const std::string& v)
+      {
+        DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, std::string& v)
+      {
+        return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v);
+      }
+    };
+
+    template <>
+    struct signature< ObjectPath >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "path";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "o";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const std::string& v)
+      {
+        DBUS_W->eldbus_message_iter_arguments_append_impl(iter, ObjectPath{ v });
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const ObjectPath& v)
+      {
+        DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v);
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const char* v)
+      {
+        DBUS_W->eldbus_message_iter_arguments_append_impl(iter, ObjectPath{ v });
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, ObjectPath& v)
+      {
+        return DBUS_W->eldbus_message_iter_get_and_next_impl(iter, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, std::string& v)
+      {
+        ObjectPath q;
+        if (!DBUS_W->eldbus_message_iter_get_and_next_impl(iter, q)) return false;
+        v = std::move(q.value);
+        return true;
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling (const) char * type.
+     *
+     * Both (const) char * and std::string types are accepted as value to send.
+     * You can't use (const) char * variable type to receive value.
+     */
+    template <>
+    struct signature< char* >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "string";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "s";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const std::string& v)
+      {
+        DBUS_W->eldbus_message_iter_arguments_append_impl(iter, v);
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const char* v)
+      {
+        DBUS_W->eldbus_message_iter_arguments_append_impl(iter, std::string{ v });
+      }
+    };
+
+    template < size_t INDEX, typename A, typename... ARGS >
+    struct signature_tuple_element_type_helper
+    {
+      using type = typename signature_tuple_element_type_helper< INDEX - 1, ARGS... >::type;
+    };
+
+    template < typename A, typename... ARGS >
+    struct signature_tuple_element_type_helper< 0, A, ARGS... >
+    {
+      using type = A;
+    };
+
+    /**
+     * @brief Helper class to marshall tuples
+     *
+     * This class marshals all elements of the tuple value starting at the index INDEX
+     * and incrementing. This class recursively calls itself with increasing INDEX value
+     * until INDEX is equal to SIZE, where recursive calling ends.
+     */
+    template < size_t INDEX, size_t SIZE, typename... ARGS >
+    struct signature_tuple_helper
+    {
+      using current_type = typename signature_tuple_element_type_helper< INDEX, ARGS... >::type;
+
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        if (INDEX + 1 >= SIZE)
+          return signature< current_type >::name();
+        return signature< current_type >::name() + ", " + signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::name();
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return signature< current_type >::sig() + signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::sig();
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const std::tuple< ARGS... >& args)
+      {
+        signature< current_type >::set(iter, std::get< INDEX >(args));
+        signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::set(iter, args);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, std::tuple< ARGS... >& args)
+      {
+        return signature< current_type >::get(iter, std::get< INDEX >(args)) &&
+          signature_tuple_helper< INDEX + 1, SIZE, ARGS... >::get(iter, args);
+      }
+    };
+
+    /**
+     * @brief Helper class to marshall tuples
+     *
+     * This class marks end of the tuple marshalling. Members of this class are called
+     * when INDEX value is equal to SIZE.
+     */
+    template < size_t SIZE, typename... ARGS >
+    struct signature_tuple_helper< SIZE, SIZE, ARGS... >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const std::tuple< ARGS... >& args)
+      {
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, std::tuple< ARGS... >& args)
+      {
+        return true;
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling tuple of values
+     *
+     * This class marshalls tuple of values. This represents
+     * DBUS struct typle, encoded with character 'r'
+     */
+    template < typename... ARGS >
+    struct signature< std::tuple< ARGS... > >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "tuple<" + signature_tuple_helper< 0, sizeof...(ARGS), ARGS... >::name() + ">";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "(" + signature_tuple_helper< 0, sizeof...(ARGS), ARGS... >::sig() + ")";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const std::tuple< ARGS... >& args)
+      {
+        auto entry = DBUS_W->eldbus_message_iter_container_new_impl(iter, 'r', "");
+        signature_tuple_helper< 0, sizeof...(ARGS), ARGS... >::set(entry, args);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, std::tuple< ARGS... >& args)
+      {
+        auto entry = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl(iter, 'r');
+        if (!entry) return false;
+        return signature_tuple_helper< 0, sizeof...(ARGS), ARGS... >::get(entry, args);
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling ValueOrError template type
+     *
+     * ValueOrError template type is used to marshall list of values passed to
+     * DBUS (or received from) at the "top" level. For example ss(s) is represented as
+     * \code{.cpp} ValueOrError<std::string, std::string, std::tuple<std::string>> \endcode
+     * While (ss(s)) is represented as
+     * \code{.cpp} std::tuple<std::string, std::string, std::tuple<std::string>> \endcode
+     * or
+     * \code{.cpp} ValueOrError<std::tuple<std::string, std::string, std::tuple<std::string>>> \endcode
+     */
+    template < typename... ARGS >
+    struct signature< ValueOrError< ARGS... > >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "ValueOrError<" + signature_tuple_helper< 0, sizeof...(ARGS), ARGS... >::name() + ">";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return signature_tuple_helper< 0, sizeof...(ARGS), ARGS... >::sig();
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const ValueOrError< ARGS... >& args)
+      {
+        signature_tuple_helper< 0, sizeof...(ARGS), ARGS... >::set(iter, args.getValues());
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, ValueOrError< ARGS... >& args)
+      {
+        return signature_tuple_helper< 0, sizeof...(ARGS), ARGS... >::get(iter, args.getValues());
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling ValueOrError<void> type
+     */
+    template <>
+    struct signature< ValueOrError< void > >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "ValueOrError<void>";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const ValueOrError< void >& args)
+      {
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, ValueOrError< void >& args)
+      {
+        return true;
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling ValueOrError<> type
+     */
+    template <>
+    struct signature< ValueOrError<> >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "ValueOrError<>";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const ValueOrError<>& args)
+      {
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, ValueOrError<>& args)
+      {
+        return true;
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling pair of types
+     */
+    template < typename A, typename B >
+    struct signature< std::pair< A, B > >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "pair<" + signature_tuple_helper< 0, 2, A, B >::name() + ">";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "(" + signature_tuple_helper< 0, 2, A, B >::sig() + ")";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const std::pair< A, B >& ab, bool dictionary = false)
+      {
+        auto entry = DBUS_W->eldbus_message_iter_container_new_impl(iter, dictionary ? 'e' : 'r', "");
+        signature_tuple_helper< 0, 2, A, B >::set(entry, ab);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, std::pair< A, B >& ab)
+      {
+        auto entry = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl(iter, 'r');
+        if (!entry) {
+          entry = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl(iter, '{');
+          if (!entry) return false;
+        }
+
+        std::tuple< A, B > ab_tmp;
+        auto z = signature_tuple_helper< 0, 2, A, B >::get(entry, ab_tmp);
+        if (z)
+        {
+          ab.first = std::move(std::get< 0 >(ab_tmp));
+          ab.second = std::move(std::get< 1 >(ab_tmp));
+        }
+        return z;
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling std::vector template type
+     *
+     * This marshals container's content as DBUS a ascii character type code.
+     */
+    template < typename A >
+    struct signature< std::vector< A > >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "vector<" + signature< A >::name() + ">";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "a" + signature< A >::sig();
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const std::vector< A >& v)
+      {
+        auto lst = DBUS_W->eldbus_message_iter_container_new_impl(iter, 'a', signature< A >::sig());
+        assert(lst);
+        for (auto& a : v)
+        {
+          signature< A >::set(lst, a);
+        }
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, std::vector< A >& v)
+      {
+        auto s = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl(iter, 'a');
+        if (!s) return false;
+        v.clear();
+        A a;
+        while (signature< A >::get(s, a))
+          v.push_back(std::move(a));
+
+        return true;
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling std::array template type
+     *
+     * This marshals container's content as DBUS a ascii character type code.
+     */
+    template < typename A, size_t N >
+    struct signature< std::array< A, N > >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "array<" + signature< A >::name() + ", " + std::to_string(N) + ">";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "a" + signature< A >::sig();
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const std::array< A, N >& v)
+      {
+        auto lst = DBUS_W->eldbus_message_iter_container_new_impl(iter, 'a', signature< A >::sig());
+        assert(lst);
+        for (auto& a : v)
+        {
+          signature< A >::set(lst, a);
+        }
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, std::array< A, N >& v)
+      {
+        auto s = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl(iter, 'a');
+        if (!s)
+          return false;
+        for (auto& a : v)
+        {
+          if (!signature< A >::get(s, a))
+            return false;
+        }
+        return true;
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling EldbusVariant type
+     *
+     * This marshals variant's content as DBUS v ascii character type code.
+     */
+    template < typename A >
+    struct signature< EldbusVariant< A > >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "variant<" + signature< A >::name() + ">";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "v";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const EldbusVariant< A >& v)
+      {
+        set(iter, v.value);
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const A& v)
+      {
+        auto var = DBUS_W->eldbus_message_iter_container_new_impl(iter, 'v', signature< A >::sig());
+        signature< A >::set(var, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, EldbusVariant< A >& v)
+      {
+        auto s = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl(iter, 'v');
+        if (!s)
+          return false;
+        return signature< A >::get(s, v.value);
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling std::unordered_map template type
+     *
+     * This marshals container's content as DBUS {} ascii character type code.
+     * Note, that library doesnt check, if the key is basic type, as DBUS
+     * specification mandates.
+     * User can always exchange std::unordered_map for std::map and the reverse.
+     * User can receive such values as std::vector of std::pair<key, value> values.
+     * Order of such values is unspecified.
+     */
+    template < typename A, typename B >
+    struct signature< std::unordered_map< A, B > >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "unordered_map<" + signature< A >::name() + ", " + signature< B >::name() + ">";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "a{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const std::unordered_map< A, B >& v)
+      {
+        auto sig = "{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}";
+        auto lst = DBUS_W->eldbus_message_iter_container_new_impl(iter, 'a', sig);
+        assert(lst);
+        for (auto& a : v)
+        {
+          signature< std::pair< A, B > >::set(lst, a, true);
+        }
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, std::unordered_map< A, B >& v)
+      {
+        auto s = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl(iter, 'a');
+        v.clear();
+        if (!s)
+          return false;
+        std::pair< A, B > a;
+        while (signature< std::pair< A, B > >::get(s, a))
+          v.insert(std::move(a));
+        return true;
+      }
+    };
+
+    /**
+     * @brief Signature class for marshalling std::unordered_map template type
+     *
+     * This marshals container's content as DBUS {} ascii character type code.
+     * Note, that library doesnt check, if the key is basic type, as DBUS
+     * specification mandates.
+     * User can always exchange std::unordered_map for std::map and the reverse.
+     * User can receive such values as std::vector of std::pair<key, value> values.
+     * Order of such values is unspecified.
+     */
+    template < typename A, typename B >
+    struct signature< std::map< A, B > >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "map<" + signature< A >::name() + ", " + signature< B >::name() + ">";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return "a{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}";
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const std::map< A, B >& v)
+      {
+        auto sig = "{" + signature_tuple_helper< 0, 2, A, B >::sig() + "}";
+        auto lst = DBUS_W->eldbus_message_iter_container_new_impl(iter, 'a', sig);
+        assert(lst);
+        for (auto& a : v)
+        {
+          signature< std::pair< A, B > >::set(lst, a, true);
+        }
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static bool get(const DBusWrapper::MessageIterPtr& iter, std::map< A, B >& v)
+      {
+        auto s = DBUS_W->eldbus_message_iter_get_and_next_by_type_impl(iter, 'a');
+        if (!s)
+          return false;
+        std::pair< A, B > a;
+        while (signature< std::pair< A, B > >::get(s, a))
+          v.insert(std::move(a));
+        return true;
+      }
+    };
+
+    /**
+     * @brief Signature helper class for marshalling const reference types
+     */
+    template < typename A >
+    struct signature< const A& >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "const " + signature< A >::name() + "&";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return signature< A >::sig();
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const A& v)
+      {
+        signature< A >::set(iter, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static void get(const DBusWrapper::MessageIterPtr& iter, A& v)
+      {
+        signature< A >::get(iter, v);
+      }
+    };
+
+    /**
+     * @brief Signature helper class for marshalling reference types
+     */
+    template < typename A >
+    struct signature< A& >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return signature< A >::name() + "&";
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return signature< A >::sig();
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const A& v)
+      {
+        signature< A >::set(iter, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static void get(const DBusWrapper::MessageIterPtr& iter, A& v)
+      {
+        signature< A >::get(iter, v);
+      }
+    };
+
+    /**
+     * @brief Signature helper class for marshalling const types
+     */
+    template < typename A >
+    struct signature< const A >
+    {
+      /**
+       * @brief Returns name of type marshalled, for informative purposes
+       */
+      static std::string name()
+      {
+        return "const " + signature< A >::name();
+      }
+
+      /**
+       * @brief Returns DBUS' signature of type marshalled
+       */
+      static std::string sig()
+      {
+        return signature< A >::sig();
+      }
+
+      /**
+       * @brief Marshals value v as marshalled type into message
+       */
+      static void set(const DBusWrapper::MessageIterPtr& iter, const A& v)
+      {
+        signature< A >::set(iter, v);
+      }
+
+      /**
+       * @brief Marshals value from marshalled type into variable v
+       */
+      static void get(const DBusWrapper::MessageIterPtr& iter, A& v)
+      {
+        signature< A >::get(iter, v);
+      }
+    };
+
+    using CallId = DBusWrapper::CallId;
+
+    template < typename ValueType >
+    ValueType unpackValues(CallId callId, const DBusWrapper::MessagePtr& msg)
+    {
+      auto iter = DBUS_W->eldbus_message_iter_get_impl(msg, false);
+      ValueType r;
+
+      if (iter)
+      {
+        if (!signature< ValueType >::get(iter, r))
+        {
+          DBUS_DEBUG("ValueType is %s", signature< ValueType >::name().c_str());
+          r = Error{ "call " + std::to_string(callId.id) + ": failed to unpack values, got signature '" +
+                DBUS_W->eldbus_message_signature_get_impl(msg) + "', expected '" + signature< ValueType >::sig() + "'" };
+        }
+      }
+      else
+      {
+        r = Error{ "call " + std::to_string(callId.id) + ": failed to get iterator" };
+      }
+      return r;
+    }
+
+    inline void packValues_helper(const DBusWrapper::MessageIterPtr&) {}
+
+    template < typename A, typename... ARGS >
+    void packValues_helper(const DBusWrapper::MessageIterPtr& iter, A&& a, ARGS&&... r)
+    {
+      signature< A >::set(iter, std::forward< A >(a));
+      packValues_helper(iter, std::forward< ARGS >(r)...);
+    }
+
+    template < typename... ARGS >
+    void packValues(CallId callId, const DBusWrapper::MessagePtr& msg, ARGS&&... r)
+    {
+      auto iter = DBUS_W->eldbus_message_iter_get_impl(msg, true);
+      packValues_helper(iter, std::forward< ARGS >(r)...);
+    }
+
+    template < typename >
+    struct ReturnType;
+    template < typename R, typename... ARGS >
+    struct ReturnType< R(ARGS...) >
+    {
+      using type = R;
+    };
+
+    template < typename R, typename... ARGS >
+    struct ReturnType< std::function< R(ARGS...) > >
+    {
+      using type = R;
+    };
+
+    template < int... >
+    struct sequence
+    {
+    };
+
+    template < int N, int... S >
+    struct sequence_gen : sequence_gen< N - 1, N - 1, S... >
+    {
+    };
+
+    template < int... S >
+    struct sequence_gen< 0, S... >
+    {
+      typedef sequence< S... > type;
+    };
+
+    template < typename C, typename... ARGS >
+    struct apply_helper
+    {
+      const std::function< C >& c;
+      const std::tuple< ARGS... >& args;
+
+      template < int... S >
+      auto apply_2(sequence< S... >) const -> decltype(c(std::get< S >(args)...))
+      {
+        return c(std::get< S >(args)...);
+      }
+      auto apply_1() const -> decltype(apply_2(typename sequence_gen< sizeof...(ARGS) >::type()))
+      {
+        return apply_2(typename sequence_gen< sizeof...(ARGS) >::type());
+      }
+    };
+
+    template < typename C, typename A, typename... ARGS >
+    struct apply_helper_2
+    {
+      const std::function< C >& c;
+      const A& a;
+      const std::tuple< ARGS... >& args;
+
+      template < int... S >
+      auto apply_2(sequence< S... >) const -> decltype(c(a, std::get< S >(args)...))
+      {
+        return c(a, std::get< S >(args)...);
+      }
+      auto apply_1() const -> decltype(apply_2(typename sequence_gen< sizeof...(ARGS) >::type()))
+      {
+        return apply_2(typename sequence_gen< sizeof...(ARGS) >::type());
+      }
+    };
+
+    template < typename C, typename... ARGS >
+    auto apply(const std::function< C >& c, const std::tuple< ARGS... >& args) -> typename ReturnType< C >::type
+    {
+      apply_helper< C, ARGS... > ah{ c, args };
+      return ah.apply_1();
+    }
+
+    template < typename C, typename D, typename... ARGS >
+    auto apply(const std::function< C >& c, const D& d, const std::tuple< ARGS... >& args) -> typename ReturnType< C >::type
+    {
+      apply_helper_2< C, D, ARGS... > ah{ c, d, args };
+      return ah.apply_1();
+    }
+
+    struct ConnectionState
+    {
+      DBusWrapper::ConnectionPtr connection;
+      DBusWrapper::ObjectPtr object;
+      DBusWrapper::ProxyPtr proxy, propertiesProxy;
+    };
+
+    template < typename RETTYPE, typename... ARGS >
+    RETTYPE call(CallId callId, const ConnectionState& connectionState, bool property, const std::string& funcName, const ARGS&... args)
+    {
+      const auto& proxy = property ? connectionState.propertiesProxy : connectionState.proxy;
+      if (!proxy)
+      {
+        DBUS_DEBUG("call %d: not initialized", callId.id);
+        return Error{ "not initialized" };
+      }
+
+      DBUS_DEBUG("call %d: calling '%s'", callId.id, funcName.c_str());
+      auto msg = DBUS_W->eldbus_proxy_method_call_new_impl(proxy, funcName);
+      if (!msg)
+      {
+        DBUS_DEBUG("call %d: failed", callId.id);
+        return Error{ "failed to create message" };
+      }
+
+      detail::packValues(callId, msg, args...);
+      auto reply = DBUS_W->eldbus_proxy_send_and_block_impl(proxy, msg);
+      DBUS_DEBUG("call %d: calling '%s' done", callId.id, funcName.c_str());
+      if (!reply)
+      {
+        DBUS_DEBUG("call %d: failed", callId.id);
+        return Error{ "eldbus returned null as reply" };
+      }
+      std::string errname, errmsg;
+      if (DBUS_W->eldbus_message_error_get_impl(reply, errname, errmsg))
+      {
+        DBUS_DEBUG("call %d: %s: %s", callId.id, errname.c_str(), errmsg.c_str());
+        return Error{ errname + ": " + errmsg };
+      }
+      DBUS_DEBUG("call %d: got reply with signature '%s'", callId.id,
+        DBUS_W->eldbus_message_signature_get_impl(reply).c_str());
+      return detail::unpackValues< RETTYPE >(callId, reply);
+    }
+
+    template < typename RETTYPE, typename... ARGS >
+    void asyncCall(CallId callId, const ConnectionState& connectionState,
+      bool property, const std::string& funcName,
+      std::function< void(RETTYPE) > callback, const ARGS&... args)
+    {
+      const auto& proxy = property ? connectionState.propertiesProxy : connectionState.proxy;
+      if (!proxy)
+      {
+        DBUS_DEBUG("call %d: not initialized", callId.id);
+        callback(Error{ "not initialized" });
+        return;
+      }
+
+      auto msg = DBUS_W->eldbus_proxy_method_call_new_impl(proxy, funcName);
+      if (!msg)
+      {
+        DBUS_DEBUG("call %d: failed", callId.id);
+        callback(Error{ "failed to create message" });
+        return;
+      }
+
+      detail::packValues(callId, msg, args...);
+      auto pending = DBUS_W->eldbus_proxy_send_impl(proxy, msg, [callback, callId, proxy](const DBusWrapper::MessagePtr& reply) {
+        DBUS_DEBUG("call %d: calling done", callId.id);
+        if (!reply)
+        {
+          DBUS_DEBUG("call %d: failed", callId.id);
+          callback(Error{ "eldbus returned null as reply" });
+        }
+        else
+        {
+          std::string errname, errmsg;
+          if (DBUS_W->eldbus_message_error_get_impl(reply, errname, errmsg))
+          {
+            DBUS_DEBUG("call %d: %s: %s", callId.id, errname.c_str(), errmsg.c_str());
+            callback(Error{ errname + ": " + errmsg });
+          }
+          else
+          {
+            DBUS_DEBUG("call %d: got reply with signature '%s'", callId.id,
+              DBUS_W->eldbus_message_signature_get_impl(reply).c_str());
+            callback(detail::unpackValues< RETTYPE >(callId, reply));
+          }
+        }
+        }
+      );
+      if (pending)
+      {
+        DBUS_DEBUG("call %d: call sent", callId.id);
+      }
+      else
+      {
+        DBUS_DEBUG("call %d: failed to send call", callId.id);
+        callback(Error{ "failed to send call" });
+      }
+    }
+
+    inline void displayDebugCallInfo(CallId callId, const std::string& funcName, const std::string& info, const std::string& interfaceName)
+    {
+      DBUS_DEBUG("call %d: %s iname = %s fname = %s", callId.id, info.c_str(), interfaceName.c_str(), funcName.c_str());
+    }
+
+    inline void displayDebugCallInfoSignal(CallId callId, const std::string& funcName, const std::string& info, const std::string& interfaceName)
+    {
+      DBUS_DEBUG("call %d: %s signal iname = %s fname = %s", callId.id, info.c_str(), interfaceName.c_str(), funcName.c_str());
+    }
+
+    inline void displayDebugCallInfoProperty(CallId callId, const std::string& funcName, std::string info, const std::string& interfaceName,
+      const std::string& propertyName)
+    {
+      DBUS_DEBUG("call %d: %s iname = %s pname = %s", callId.id, info.c_str(), interfaceName.c_str(), propertyName.c_str());
+    }
+
+    using StringStorage = DBusWrapper::StringStorage;
+
+    template < typename A, typename... ARGS >
+    struct EldbusArgGenerator_Helper
+    {
+      static void add(std::vector< std::pair<std::string, std::string> >& r)
+      {
+        auto s = r.size();
+        auto sig = signature< A >::sig();
+        assert(!sig.empty());
+        auto name = "p" + std::to_string(s + 1);
+        r.push_back({ std::move(sig), std::move(name) });
+        EldbusArgGenerator_Helper<ARGS...>::add(r);
+      }
+    };
+
+    template <>
+    struct EldbusArgGenerator_Helper< void >
+    {
+      static void add(std::vector< std::pair<std::string, std::string> >&)
+      {
+      }
+    };
+
+    template <>
+    struct EldbusArgGenerator_Helper< ValueOrError< void >, void >
+    {
+      static void add(std::vector< std::pair<std::string, std::string> >&)
+      {
+      }
+    };
+    template <>
+    struct EldbusArgGenerator_Helper< ValueOrError<>, void >
+    {
+      static void add(std::vector< std::pair<std::string, std::string> >&)
+      {
+      }
+    };
+
+    template < typename... ARGS >
+    struct EldbusArgGenerator_Helper< std::tuple< ARGS... > >
+    {
+      static void add(std::vector< std::pair<std::string, std::string> >& r)
+      {
+        EldbusArgGenerator_Helper< ARGS..., void >::add(r);
+      }
+    };
+
+    template < typename RetType >
+    struct dbus_interface_return_type_traits
+    {
+      using type = ValueOrError< RetType >;
+    };
+
+    template < typename... ARGS >
+    struct dbus_interface_return_type_traits< ValueOrError< ARGS... > >
+    {
+      using type = ValueOrError< ARGS... >;
+    };
+
+    template < typename T >
+    struct dbus_interface_traits;
+    template < typename RetType, typename... ARGS >
+    struct dbus_interface_traits< RetType(ARGS...) >
+    {
+      using Ret = typename dbus_interface_return_type_traits< RetType >::type;
+      using SyncCB = std::function< Ret(ARGS...) >;
+      using AsyncCB = std::function< void(std::function< void(Ret) >, ARGS...) >;
+      using VEArgs = ValueOrError< ARGS... >;
+    };
+
+    template < typename T >
+    struct EldbusArgGenerator_Args;
+    template < typename RetType, typename... ARGS >
+    struct EldbusArgGenerator_Args< RetType(ARGS...) >
+    {
+      static std::string name()
+      {
+        return signature_tuple_helper< 0, sizeof...(ARGS), ARGS... >::name();
+      }
+      static std::vector< std::pair<std::string, std::string> > get()
+      {
+        std::vector< std::pair<std::string, std::string> > tmp;
+        EldbusArgGenerator_Helper< ARGS..., void >::add(tmp);
+        return tmp;
+      }
+    };
+
+    template < typename T >
+    struct EldbusArgGenerator_ReturnType;
+    template < typename RetType, typename... ARGS >
+    struct EldbusArgGenerator_ReturnType< RetType(ARGS...) >
+    {
+      static std::string name()
+      {
+        return signature< RetType >::name();
+      }
+      static std::vector< std::pair<std::string, std::string> > get()
+      {
+        std::vector< std::pair<std::string, std::string> > tmp;
+        EldbusArgGenerator_Helper< RetType, void >::add(tmp);
+        return tmp;
+      }
+    };
+
+    template < typename T >
+    struct EldbusArgGenerator_ReturnType;
+    template < typename... ARGS >
+    struct EldbusArgGenerator_ReturnType< void(ARGS...) >
+    {
+      static std::string name()
+      {
+        return "";
+      }
+      static std::vector< std::pair<std::string, std::string> > get()
+      {
+        return {};
+      }
+    };
+
+  }
+
+  using ConnectionType = DBusWrapper::ConnectionType;
+
+  /**
+   * @brief Class representing client's end of DBUS connection
+   *
+   * Allows calling (synchronous and asynchronos) methods on selected interface
+   * Allows (synchronous and asynchronos) setting / getting properties.
+   * Allows registering signals.
+   */
+  class DBusClient
+  {
+    struct ConnectionInfo
+    {
+      std::string interfaceName, busName, pathName;
+    };
+  public:
+    /**
+     * @brief Default constructor, creates non-connected object.
+     */
+    DBusClient() = default;
+
+    /**
+     * @brief Connects to dbus choosen by tp, using given arguments
+     *
+     * @param bus_name name of the bus to connect to
+     * @param path_name object's path
+     * @param interface_name interface name
+     */
+    DBusClient(std::string busName_, std::string pathName_, std::string interfaceName_,
+      ConnectionType tp);
+
+    /**
+     * @brief Connects to dbus using connection conn
+     *
+     * @param bus_name name of the bus to connect to
+     * @param path_name object's path
+     * @param interface_name interface name
+     * @param conn connection object from getDBusConnectionByType call
+     */
+    DBusClient(std::string busName_, std::string pathName_, std::string interfaceName_,
+      const DBusWrapper::ConnectionPtr& conn = {});
+
+    /**
+     * @brief Destructor object.
+     *
+     * All signals added will be disconnected.
+     * All asynchronous calls will be cancelled, their callback's will be called
+     * with failure message.
+     */
+    ~DBusClient() = default;
+    DBusClient(const DBusClient&) = delete;
+    DBusClient(DBusClient&&) = default;
+
+    DBusClient& operator=(DBusClient&&) = default;
+    DBusClient& operator=(const DBusClient&) = delete;
+
+    /**
+     * @brief bool operator
+     *
+     * Returns true, if object is connected to DBUS
+     */
+    explicit operator bool() const
+    {
+      return bool(connectionState->proxy);
+    }
+
+    /**
+     * @brief Helper class for calling a method
+     *
+     * Template type T defines both arguments sent to the method
+     * and expected values. Receiving different values will be reported as
+     * error. For example:
+     * \code{.cpp} Method<int(float, float)> \endcode
+     * defines method, which takes two arguments (two floats) and return
+     * single value of type int.
+     */
+    template < typename T >
+    struct Method
+    {
+      using RetType = typename detail::dbus_interface_traits< T >::Ret;
+      const detail::ConnectionState& connectionState;
+      std::string funcName;
+      std::string info;
+      std::shared_ptr< ConnectionInfo > connectionInfo;
+
+      /**
+       * @brief Executes synchronous call on DBUS's method
+       *
+       * The function returns ValueOrError<...> object, which
+       * contains either received values or error message.
+       *
+       * @param args arguments to pass to the method
+       */
+      template < typename... ARGS >
+      RetType call(const ARGS&... args)
+      {
+        detail::CallId callId;
+        detail::displayDebugCallInfo(callId, funcName, info, connectionInfo->interfaceName);
+        return detail::call< RetType >(callId, connectionState, false, funcName, args...);
+      }
+
+      /**
+       * @brief Executes asynchronous call on DBUS's method
+       *
+       * The function calls callback with either received values or error message.
+       *
+       * @param callback callback functor, which will be called with return value(s) or error message
+       * @param args arguments to pass to the method
+       */
+      template < typename... ARGS >
+      void asyncCall(std::function< void(RetType) > callback, const ARGS&... args)
+      {
+        detail::CallId callId;
+        detail::displayDebugCallInfo(callId, funcName, info, connectionInfo->interfaceName);
+        detail::asyncCall< RetType >(callId, connectionState, false, funcName, std::move(callback), args...);
+      }
+    };
+
+    /**
+     * @brief Helper class for calling a property
+     *
+     * Template type T defines type of the value hidden under property.
+     * Note, that library automatically wraps both sent and received value into
+     * DBUS's wrapper type.
+     */
+    template < typename T >
+    struct Property
+    {
+      using RetType = typename detail::dbus_interface_return_type_traits< T >::type;
+      using VariantRetType = typename detail::dbus_interface_return_type_traits< EldbusVariant< T > >::type;
+      const detail::ConnectionState& connectionState;
+      std::string propName;
+      std::string info;
+      std::shared_ptr< ConnectionInfo > connectionInfo;
+
+      /**
+       * @brief executes synchronous get on property
+       *
+       * The function returns ValueOrError<...> object, which
+       * contains either received values or error message.
+       */
+      RetType get()
+      {
+        detail::CallId callId;
+        detail::displayDebugCallInfoProperty(callId, "Get", info, connectionInfo->interfaceName, propName);
+        auto z = detail::call< VariantRetType >(callId, connectionState, true, "Get", connectionInfo->interfaceName, propName);
+        if (!z)
+          return z.getError();
+        return { std::get< 0 >(z.getValues()).value };
+      }
+
+      /**
+       * @brief executes asynchronous get on property
+       *
+       * The function calls callback with either received values or error message.
+       *
+       * @param callback callback functor, which will be called with return value(s) or error message
+       */
+      void asyncGet(std::function< void(RetType) > callback)
+      {
+        detail::CallId callId;
+        detail::displayDebugCallInfoProperty(callId, "Get", info, connectionInfo->interfaceName, propName);
+        auto cc = [callback](VariantRetType reply) {
+          if (reply)
+            callback(std::move(std::get< 0 >(reply.getValues()).value));
+          else
+            callback(reply.getError());
+        };
+        detail::asyncCall< VariantRetType >(callId, connectionState, true, "Get", std::move(cc), connectionInfo->interfaceName, propName);
+      }
+
+      /**
+       * @brief executes synchronous set on property
+       *
+       * The function returns ValueOrError<void> object, with
+       * possible error message.
+       */
+      ValueOrError< void > set(const T& r)
+      {
+        detail::CallId callId;
+        detail::displayDebugCallInfoProperty(callId, "Set", info, connectionInfo->interfaceName, propName);
+        EldbusVariant< T > variantValue{ std::move(r) };
+        return detail::call< ValueOrError< void > >(callId, connectionState, true, "Set", connectionInfo->interfaceName, propName, variantValue);
+      }
+
+      /**
+       * @brief executes asynchronous get on property
+       *
+       * The function calls callback with either received values or error message.
+       *
+       * @param callback callback functor, which will be called with return value(s) or error message
+       */
+      void asyncSet(std::function< void(ValueOrError< void >) > callback, const T& r)
+      {
+        detail::CallId callId;
+        detail::displayDebugCallInfoProperty(callId, "Set", info, connectionInfo->interfaceName, propName);
+        EldbusVariant< T > variantValue{ std::move(r) };
+        detail::asyncCall< ValueOrError< void > >(callId, connectionState, true, "Set", std::move(callback), connectionInfo->interfaceName, propName, variantValue);
+      }
+    };
+
+    /**
+     * @brief Constructs Property<...> object for calling properties
+     *
+     * The function constructs and returns proxy object for calling property.
+     *
+     * @param propName property name to set and / or query
+     */
+    template < typename PropertyType >
+    Property< PropertyType > property(std::string propName)
+    {
+      return Property< PropertyType >{*connectionState, std::move(propName), info, connectionInfo};
+    }
+
+    /**
+     * @brief Constructs Method<...> object for calling methods
+     *
+     * The function constructs and returns proxy object for calling method.
+     *
+     * @param funcName function name to call
+     */
+    template < typename MethodType >
+    Method< MethodType > method(std::string funcName)
+    {
+      return Method< MethodType >{*connectionState, std::move(funcName), info, connectionInfo};
+    }
+
+    /**
+     * @brief Registers notification callback, when property has changed
+     *
+     * The callback will be called with new value, when property's value has changed.
+     * Note, that template type V must match expected type, otherwise undefined behavior will occur,
+     * there's no check for this.
+     */
+    template < typename V >
+    void addPropertyChangedEvent(std::string propertyName, std::function< void(V) > callback)
+    {
+      detail::CallId callId;
+      detail::displayDebugCallInfoSignal(callId, propertyName, info, connectionInfo->interfaceName);
+      DBUS_DEBUG("call %d: adding property", callId.id);
+      auto& cI = this->connectionInfo;
+      DBUS_W->add_property_changed_event_listener_impl(connectionState->proxy, cI->interfaceName, propertyName,
+        [callback](const _Eina_Value* newValue) {
+          V val = 0;
+          if (!getFromEinaValue(newValue, &val))
+          {
+            DBUS_DEBUG("unable to get property's value");
+            return;
+          }
+          callback(val);
+        });
+    }
+
+    /**
+     * @brief Registers callback on the DBUS' signal
+     *
+     * The function registers callback signalName. When signal comes, callback will be called.
+     * Callback object will exists as long as signal is registered. You can unregister signal
+     * by destroying DBusClient object.
+     *
+     * @param signalName name of the signal to register
+     * @param callback callback to call
+     */
+    template < typename SignalType >
+    void addSignal(std::string signalName, std::function< SignalType > callback)
+    {
+      detail::CallId callId;
+      detail::displayDebugCallInfoSignal(callId, signalName, info, connectionInfo->interfaceName);
+      DBUS_W->eldbus_proxy_signal_handler_add_impl(connectionState->proxy, signalName,
+        [callId, callback, signalName](const DBusWrapper::MessagePtr& msg) -> void {
+          std::string errname, aux;
+          if (DBUS_W->eldbus_message_error_get_impl(msg, errname, aux))
+          {
+            DBUS_DEBUG("call %d: Eldbus error: %s %s", callId.id, errname.c_str(), aux.c_str());
+            return;
+          }
+          DBUS_DEBUG("call %d: received signal with signature '%s'", callId.id, DBUS_W->eldbus_message_signature_get_impl(msg).c_str());
+          using ParamsType = typename detail::dbus_interface_traits< SignalType >::VEArgs;
+          auto params = detail::unpackValues< ParamsType >(callId, msg);
+          if (!params)
+          {
+            DBUS_DEBUG("call %d: failed: %s", callId.id, params.getError().message.c_str());
+            return;
+          }
+          try
+          {
+            detail::apply(callback, params.getValues());
+          }
+          catch (...)
+          {
+            DBUS_DEBUG("unhandled exception");
+            assert(0);
+          }
+        });
+    }
+
+  private:
+    std::unique_ptr<detail::ConnectionState> connectionState{ new detail::ConnectionState };
+    std::string info;
+    std::shared_ptr< ConnectionInfo > connectionInfo;
+
+    static bool getFromEinaValue(const _Eina_Value* v, void* dst);
+  };
+
+  /**
+   * @brief Helper class describing DBUS's server interface
+   *
+   */
+  class DBusInterfaceDescription
+  {
+    friend class DBusServer;
+
+  public:
+    using MethodInfo = DBusWrapper::MethodInfo;
+    using SignalInfo = DBusWrapper::SignalInfo;
+    using PropertyInfo = DBusWrapper::PropertyInfo;
+    using SignalId = DBusWrapper::SignalId;
+
+    /**
+     * @brief Creates empty interface description with given name
+     *
+     * @param interfaceName name of the interface
+     */
+    DBusInterfaceDescription(std::string interfaceName);
+
+    /**
+     * @brief adds new, synchronous method to the interface
+     *
+     * When method memberName is called on DBUS, callback functor will be called
+     * with values received from DBUS. callback won't be called, if method was
+     * called with invalid signature. Value returned from functor (or error message)
+     * will be marshalled back to the caller.
+     *
+     * Template type T defines both arguments sent to the method
+     * and expected values. Receiving different values will be reported as
+     * error. For example:
+     * \code{.cpp} Method<int(float, float)> \endcode
+     * defines method, which takes two arguments (two floats) and return
+     * single value of type int.
+     *
+     * @param memberName name of the method
+     * @param callback functor, which will be called
+     */
+    template < typename T >
+    void addMethod(const std::string& memberName, typename detail::dbus_interface_traits< T >::SyncCB callback)
+    {
+      detail::CallId callId;
+      MethodInfo mi;
+      methods.push_back(std::move(mi));
+      auto& z = methods.back();
+      z.in = detail::EldbusArgGenerator_Args< T >::get();
+      z.out = detail::EldbusArgGenerator_ReturnType< T >::get();
+      z.memberName = memberName;
+      DBUS_DEBUG("call %d: method %s, in %s, out %s", callId.id, memberName.c_str(),
+        detail::EldbusArgGenerator_Args< T >::name().c_str(),
+        detail::EldbusArgGenerator_ReturnType< T >::name().c_str());
+      z.callback = construct< T >(callId, callback);
+      z.id = callId;
+    }
+
+    /**
+     * @brief adds new, synchronous property to the interface
+     *
+     * When property memberName is called on DBUS, respective callback functor will be called
+     * with values received from DBUS. callback won't be called, if method was
+     * called with invalid signature. Value returned from functor (or error message)
+     * will be marshalled back to the caller.
+     *
+     * Template type T defines type of the value hidden under property.
+     * Note, that library automatically wraps both sent and received value into
+     * DBUS's wrapper type.
+     *
+     * @param memberName name of the method
+     * @param getter functor, which will be called when property is being read
+     * @param setter functor, which will be called when property is being set
+     */
+    template < typename T >
+    void addProperty(const std::string& memberName, std::function< ValueOrError< T >() > getter, std::function< ValueOrError< void >(T) > setter)
+    {
+      properties.push_back({});
+      auto& z = properties.back();
+      z.memberName = memberName;
+      z.typeSignature = detail::signature< T >::sig();
+      if (getter)
+      {
+        detail::CallId getterId;
+        z.getterId = getterId;
+        DBUS_DEBUG("call %d: property %s (get) type %s", getterId.id, memberName.c_str(), detail::signature< T >::name().c_str());
+        z.getCallback = [=](const DBusWrapper::MessagePtr& src, const DBusWrapper::MessageIterPtr& dst) -> std::string {
+          try
+          {
+            auto v = detail::apply(getter, std::tuple<>{});
+            if (v)
+            {
+              detail::signature< T >::set(dst, std::get< 0 >(v.getValues()));
+              DBUS_DEBUG("call %d: success", getterId.id);
+              return "";
+            }
+            DBUS_DEBUG("call %d: failed: %s", getterId.id, v.getError().message.c_str());
+            return v.getError().message;
+          }
+          catch (std::exception & e)
+          {
+            return std::string("unhandled exception (") + e.what() + ")";
+          }
+          catch (...)
+          {
+            return "unhandled exception";
+          }
+        };
+      }
+      if (setter)
+      {
+        detail::CallId setterId;
+        z.setterId = setterId;
+        DBUS_DEBUG("call %d: property %s (set) type %s", setterId.id, memberName.c_str(), detail::signature< T >::name().c_str());
+        z.setCallback = [=](const DBusWrapper::MessagePtr& src, const DBusWrapper::MessageIterPtr& src_iter) -> std::string {
+          std::tuple< T > value;
+          auto src_signature = DBUS_W->eldbus_message_iter_signature_get_impl(src_iter);
+          if (detail::signature< T >::get(src_iter, std::get< 0 >(value)))
+          {
+            try
+            {
+              auto v = detail::apply(setter, std::move(value));
+              if (v)
+              {
+                DBUS_DEBUG("call %d: success", setterId.id);
+                return "";
+              }
+              DBUS_DEBUG("call %d: failed: %s", setterId.id, v.getError().message.c_str());
+              return v.getError().message;
+            }
+            catch (std::exception & e)
+            {
+              return std::string("unhandled exception (") + e.what() + ")";
+            }
+            catch (...)
+            {
+              return "unhandled exception";
+            }
+          }
+          DBUS_DEBUG("call %d: failed to unpack values, got signature '%s', expected '%s'", setterId.id,
+            src_signature.c_str(), detail::signature< T >::sig().c_str());
+          return "call " + std::to_string(setterId.id) + ": failed to unpack values, got signature '" +
+            src_signature + "', expected '" + detail::signature< T >::sig() + "'";
+        };
+      }
+    }
+
+    /**
+     * @brief adds new signal to the interface
+     *
+     * Template types ARGS defines values, which will be emited with the signal
+     *
+     * @param memberName name of the method
+     */
+    template < typename... ARGS >
+    SignalId addSignal(const std::string& memberName)
+    {
+      detail::CallId callId;
+      signals.push_back({});
+      auto& z = signals.back();
+      z.memberName = memberName;
+      z.args = detail::EldbusArgGenerator_Args< void(ARGS...) >::get(DBUS_W->Strings);
+      z.id = callId;
+      DBUS_DEBUG("call %d: signal %s", callId.id, memberName.c_str());
+      return SignalId{ callId };
+    }
+
+  private:
+    std::vector< MethodInfo > methods;
+    std::vector< PropertyInfo > properties;
+    std::vector< SignalInfo > signals;
+    std::string interfaceName;
+
+    template < typename T >
+    std::function< DBusWrapper::MessagePtr(const DBusWrapper::MessagePtr & msg) > construct(detail::CallId callId,
+      typename detail::dbus_interface_traits< T >::SyncCB callback)
+    {
+      using VEArgs = typename detail::dbus_interface_traits< T >::VEArgs;
+      return [=](const DBusWrapper::MessagePtr& msg) -> DBusWrapper::MessagePtr {
+        DBUS_DEBUG("call %d: entering", callId.id);
+        DBusWrapper::MessagePtr ret = {};
+        auto args = detail::unpackValues< VEArgs >(callId, msg);
+        if (args)
+        {
+          try
+          {
+            auto v = detail::apply(callback, std::move(args.getValues()));
+            if (v)
+            {
+              DBUS_DEBUG("call %d: success", callId.id);
+              ret = DBUS_W->eldbus_message_method_return_new_impl(msg);
+              detail::packValues(callId, ret, v);
+            }
+            else
+            {
+              DBUS_DEBUG("call %d: failed: %s", callId.id, v.getError().message.c_str());
+              ret = DBUS_W->eldbus_message_error_new_impl(msg, "org.freedesktop.DBus.Error.Failed", v.getError().message);
+            }
+          }
+          catch (std::exception & e)
+          {
+            auto txt = std::string("unhandled exception (") + e.what() + ")";
+            DBUS_DEBUG("call %d: failed: %s", callId.id, txt.c_str());
+            ret = DBUS_W->eldbus_message_error_new_impl(msg, "org.freedesktop.DBus.Error.Failed", txt);
+          }
+          catch (...)
+          {
+            DBUS_DEBUG("call %d: failed: %s", callId.id, "unhandled exception");
+            ret = DBUS_W->eldbus_message_error_new_impl(msg, "org.freedesktop.DBus.Error.Failed", "unhandled exception");
+          }
+        }
+        else
+        {
+          std::ostringstream err;
+          err << "expected signature '" << detail::signature< VEArgs >::sig() << "', got '" << DBUS_W->eldbus_message_signature_get_impl(msg) << "'";
+          auto str = err.str();
+          DBUS_DEBUG("call %d: failed: %s", callId.id, str.c_str());
+          ret = DBUS_W->eldbus_message_error_new_impl(msg, "org.freedesktop.DBus.Error.InvalidArgs", str);
+        }
+        return ret;
+      };
+    }
+  };
+
+  /**
+   * @brief Class representing server's end of DBUS connection
+   *
+   * Allows listening (synchronously and asynchronosly) on methods on selected interface
+   * Allows listening (synchronously and asynchronosly) on setting / getting properties.
+   * Allows emiting signals.
+   */
+  class DBusServer
+  {
+  public:
+    /**
+     * @brief Constructs non-connected dbus server.
+     */
+    DBusServer() = default;
+
+    /**
+     * @brief Constructs dbus server on either system or user dbus connection.
+     */
+    DBusServer(ConnectionType tp);
+
+    /**
+     * @brief Constructs dbus server on connection from getDBusConnectionByType
+     */
+    DBusServer(const DBusWrapper::ConnectionPtr& conn);
+
+    /**
+     * @brief Destructor
+     *
+     * Destructor will properly destroy everything. Destructor will cancel
+     * pending replies.
+     */
+    ~DBusServer() = default;
+
+    DBusServer(const DBusServer&) = delete;
+    DBusServer(DBusServer&&) = default;
+
+    DBusServer& operator=(DBusServer&&) = default;
+    DBusServer& operator=(const DBusServer&) = delete;
+
+    /**
+     * @brief Registers interface on given path name
+     *
+     * @param pathName path object to register interface on.
+     * @param dscr
+     * @param fallback
+     */
+    void addInterface(const std::string& pathName, DBusInterfaceDescription& dscr, bool fallback = false);
+
+    /**
+     * @brief Gets bus name of the current connection (must be connected)
+     */
+    std::string getBusName() const;
+
+    /**
+     * @brief Returns connection object for this dbus server object
+     *
+     * @return connection object
+     */
+    DBusWrapper::ConnectionPtr getConnection();
+
+    /**
+     * @brief Emits signal
+     *
+     * Emits signal based only on data passed to the function
+     *
+     * @param signal identifier of the signal
+     * @param args values to emit
+     */
+    template < typename... ARGS >
+    void emit2(const std::string& path, const std::string& interfaceName,
+      const std::string& signalName, const ARGS&... args)
+    {
+      auto msg = DBUS_W->eldbus_message_signal_new_impl(path, interfaceName, signalName);
+      detail::CallId id;
+      detail::packValues(id, msg, args...);
+      DBUS_W->eldbus_connection_send_impl(connection, msg);
+    }
+
+    /**
+     * @brief Returns current object path, when handling call to property / method
+     *
+     * User can call this function from inside callback used to handle property / method calls.
+     * It will retrieve object's path used in the call. Note, that in asynchronous handling
+     * of those calls user need to retrieve and store the current object / current connection
+     * as the value will change at the moment user's callback handling will exit. For example:
+     * \code{.cpp}
+     * DBusInterfaceDescription interface{"name"};
+     * auto handler_later = [](std::function<void(void)> done_cb) {
+     *   // process something later on
+     *   DBusServer::getCurrentObjectPath(); // this will return empty string
+     * };
+     * interface.addAsyncMethod<void()>("m", [=](std::function<void(void)> done_cb) {
+     *   DBusServer::getCurrentObjectPath(); // this will current object's path
+     *
+     *   // do some processing later on and call done_cb, when it's done
+     *   register_to_call_sometime_later_on(std::move(done_cb));
+     * };
+     * \endcode
+     */
+    static std::string getCurrentObjectPath() { return currentObjectPath; }
+
+    /**
+     * @brief Returns current connection object, when handling call to property / method
+     *
+     * User can call this function from inside callback used to handle property / method calls.
+     * It will retrieve object's path used in the call. Note, that in asynchronous handling
+     * of those calls user need to retrieve and store the current object / current connection
+     * as the value will change at the moment user's callback handling will exit. For example:
+     * \code{.cpp}
+     * DBusInterfaceDescription interface{"name"};
+     * auto handler_later = [](std::function<void(void)> done_cb) {
+     *   // process something later on
+     *   DBusServer::getCurrentObjectPath(); // this will return empty string
+     * };
+     * interface.addAsyncMethod<void()>("m", [=](std::function<void(void)> done_cb) {
+     *   DBusServer::getCurrentObjectPath(); // this will current object's path
+     *
+     *   // do some processing later on and call done_cb, when it's done
+     *   register_to_call_sometime_later_on(std::move(done_cb));
+     * };
+     * \endcode
+     */
+    static const DBusWrapper::ConnectionPtr& getCurrentConnection() { return currentConnection; }
+
+    /// \cond
+    class CurrentObjectSetter
+    {
+    public:
+      CurrentObjectSetter(DBusWrapper::ConnectionPtr con, std::string path)
+      {
+        currentObjectPath = std::move(path);
+        currentConnection = std::move(con);
+      }
+      ~CurrentObjectSetter()
+      {
+        currentObjectPath = "";
+        currentConnection = {};
+      }
+      CurrentObjectSetter(const CurrentObjectSetter&) = delete;
+      CurrentObjectSetter(CurrentObjectSetter&&) = delete;
+      void operator=(const CurrentObjectSetter&) = delete;
+      void operator=(CurrentObjectSetter&&) = delete;
+    };
+
+  private:
+    DBusWrapper::ConnectionPtr connection;
+    struct DestructorObject {
+      std::vector<std::function<void()>> destructors;
+      ~DestructorObject() {
+        for (auto& a : destructors) a();
+      }
+    };
+
+    std::unique_ptr<DestructorObject> destructorObject{ new DestructorObject() };
+    static thread_local std::string currentObjectPath;
+    static thread_local DBusWrapper::ConnectionPtr currentConnection;
+
+  };
+
+  DBusWrapper::ConnectionPtr getDBusConnectionByType(ConnectionType tp);
+  DBusWrapper::ConnectionPtr getDBusConnectionByName(const std::string& name);
+  std::string getConnectionName(const DBusWrapper::ConnectionPtr&);
+}
+
+namespace std
+{
+  template < size_t INDEX, typename... ARGS >
+  inline auto get(DBus::ValueOrError< ARGS... >& v) -> decltype(std::get< INDEX >(v.getValues()))&
+  {
+    return std::get< INDEX >(v.getValues());
+  }
+
+  template < size_t INDEX, typename... ARGS >
+  inline auto get(const DBus::ValueOrError< ARGS... >& v) -> decltype(std::get< INDEX >(v.getValues()))
+  {
+    return std::get< INDEX >(v.getValues());
+  }
+}
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_BRIDGE_DBUS_H
diff --git a/dali/internal/accessibility/tizen-wayland/tizen-common/accessibility-adaptor-impl-tizen.cpp b/dali/internal/accessibility/tizen-wayland/tizen-common/accessibility-adaptor-impl-tizen.cpp
new file mode 100644 (file)
index 0000000..b2418f8
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/common/accessibility-adaptor-impl.h>
+
+// EXTERNAL INCLUDES
+#include <vconf.h>
+
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/system-settings.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+const char * DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS = "db/setting/accessibility/atspi";
+
+// Disabled Accessibility temporarily in Tizen platform
+bool GetEnabledVConf()
+{
+  int isEnabled = 0;
+  //vconf_get_bool( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, &isEnabled );
+
+  if( isEnabled == 0 )
+  {
+    //vconf_get_bool( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, &isEnabled );
+  }
+
+  return static_cast<bool>(isEnabled);
+}
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gAccessibilityAdaptorLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_ACCESSIBILITY_ADAPTOR" );
+#endif
+
+void AccessibilityOnOffNotification(keynode_t* node, void* data)
+{
+  AccessibilityAdaptor* adaptor = static_cast<AccessibilityAdaptor*>( data );
+
+  bool isEnabled = GetEnabledVConf();
+
+  DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" );
+
+  if( isEnabled )
+  {
+    adaptor->EnableAccessibility();
+  }
+  else
+  {
+    adaptor->DisableAccessibility();
+  }
+}
+
+} // unnamed namespace
+
+Dali::AccessibilityAdaptor AccessibilityAdaptor::Get()
+{
+  Dali::AccessibilityAdaptor adaptor;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::AccessibilityAdaptor ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      adaptor = Dali::AccessibilityAdaptor( dynamic_cast< AccessibilityAdaptor* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      adaptor = Dali::AccessibilityAdaptor( new AccessibilityAdaptor() );
+      AccessibilityAdaptor& adaptorImpl = AccessibilityAdaptor::GetImplementation( adaptor );
+
+      bool isEnabled = GetEnabledVConf();
+
+      if( isEnabled )
+      {
+        adaptorImpl.EnableAccessibility();
+      }
+      DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" );
+
+      vconf_notify_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification, &adaptorImpl );
+      vconf_notify_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification, &adaptorImpl );
+
+      service.Register( typeid( adaptor ), adaptor );
+    }
+  }
+
+  return adaptor;
+}
+
+void AccessibilityAdaptor::OnDestroy()
+{
+  vconf_ignore_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification );
+  vconf_ignore_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification );
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/accessibility/tizen-wayland/tizen-ivi/accessibility-adaptor-impl-ivi.cpp b/dali/internal/accessibility/tizen-wayland/tizen-ivi/accessibility-adaptor-impl-ivi.cpp
new file mode 100644 (file)
index 0000000..95f8809
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/tizen-wayland/tizen-mobile/accessibility-adaptor-impl-mobile.h>
+
+// EXTERNAL INCLUDES
+#include <vconf.h>
+
+#ifndef WAYLAND
+#include <dali/internal/system/linux/dali-ecore-x.h>
+#include <dali/internal/system/linux/dali-elementary.h>
+#endif
+
+#include <vconf.h>
+
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/system-settings.h>
+
+#ifndef WAYLAND
+#define MSG_DOMAIN_CONTROL_ACCESS static_cast< int >( ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL )
+#endif
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // unnamed namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gAccessibilityAdaptorLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ACCESSIBILITY_ADAPTOR");
+#endif
+
+const char * DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS = "db/setting/accessibility/atspi";
+
+bool GetEnabledVConf()
+{
+  int isEnabled = 0;
+  vconf_get_bool( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, &isEnabled );
+
+  if( isEnabled == 0 )
+  {
+    vconf_get_bool( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, &isEnabled );
+  }
+
+  return bool( isEnabled );
+}
+
+
+void AccessibilityOnOffNotification(keynode_t* node, void* data)
+{
+  AccessibilityAdaptor* adaptor = static_cast<AccessibilityAdaptor*>( data );
+
+  bool isEnabled = GetEnabledVConf();
+
+  DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" );
+
+  if( isEnabled )
+  {
+    adaptor->EnableAccessibility();
+  }
+  else
+  {
+    adaptor->DisableAccessibility();
+  }
+}
+
+} // unnamed namespace
+
+Dali::AccessibilityAdaptor AccessibilityAdaptor::Get()
+{
+  Dali::AccessibilityAdaptor adaptor;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::AccessibilityAdaptor ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      adaptor = Dali::AccessibilityAdaptor( dynamic_cast< AccessibilityAdaptor* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      adaptor = Dali::AccessibilityAdaptor( new AccessibilityAdaptorMobile() );
+      AccessibilityAdaptorMobile& adaptorImpl = AccessibilityAdaptorMobile::GetImplementation( adaptor );
+
+      bool isEnabled = GetEnabledVConf();
+
+      if( isEnabled )
+      {
+        adaptorImpl.EnableAccessibility();
+      }
+      DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" );
+
+      vconf_notify_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification, &adaptorImpl );
+      vconf_notify_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification, &adaptorImpl );
+
+      service.Register( typeid( adaptor ), adaptor );
+    }
+  }
+
+  return adaptor;
+}
+
+void AccessibilityAdaptor::OnDestroy()
+{
+  vconf_ignore_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification );
+  vconf_ignore_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification );
+}
+
+AccessibilityAdaptorMobile::AccessibilityAdaptorMobile()
+{
+}
+
+bool AccessibilityAdaptorMobile::HandleActionNextEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionNext(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionPreviousEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPrevious(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionActivateEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionActivate();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain)
+{
+  bool ret = false;
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %d , %d\n", __FUNCTION__, __LINE__, x, y);
+
+  mReadPosition.x = x;
+  mReadPosition.y = y;
+
+  if( mActionHandler )
+  {
+    // The accessibility actions should be handled by the registered accessibility action handler (e.g. focus manager)
+    ret = mActionHandler->AccessibilityActionRead(allowReadAgain);
+    DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+  }
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionReadNextEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadNext(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionReadPreviousEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadPrevious(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionUpEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionUp();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionDownEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionDown();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+AccessibilityAdaptorMobile::~AccessibilityAdaptorMobile()
+{
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/accessibility/tizen-wayland/tizen-mobile/accessibility-adaptor-impl-mobile.cpp b/dali/internal/accessibility/tizen-wayland/tizen-mobile/accessibility-adaptor-impl-mobile.cpp
new file mode 100644 (file)
index 0000000..95f8809
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/tizen-wayland/tizen-mobile/accessibility-adaptor-impl-mobile.h>
+
+// EXTERNAL INCLUDES
+#include <vconf.h>
+
+#ifndef WAYLAND
+#include <dali/internal/system/linux/dali-ecore-x.h>
+#include <dali/internal/system/linux/dali-elementary.h>
+#endif
+
+#include <vconf.h>
+
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/system-settings.h>
+
+#ifndef WAYLAND
+#define MSG_DOMAIN_CONTROL_ACCESS static_cast< int >( ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL )
+#endif
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // unnamed namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gAccessibilityAdaptorLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ACCESSIBILITY_ADAPTOR");
+#endif
+
+const char * DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS = "db/setting/accessibility/atspi";
+
+bool GetEnabledVConf()
+{
+  int isEnabled = 0;
+  vconf_get_bool( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, &isEnabled );
+
+  if( isEnabled == 0 )
+  {
+    vconf_get_bool( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, &isEnabled );
+  }
+
+  return bool( isEnabled );
+}
+
+
+void AccessibilityOnOffNotification(keynode_t* node, void* data)
+{
+  AccessibilityAdaptor* adaptor = static_cast<AccessibilityAdaptor*>( data );
+
+  bool isEnabled = GetEnabledVConf();
+
+  DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" );
+
+  if( isEnabled )
+  {
+    adaptor->EnableAccessibility();
+  }
+  else
+  {
+    adaptor->DisableAccessibility();
+  }
+}
+
+} // unnamed namespace
+
+Dali::AccessibilityAdaptor AccessibilityAdaptor::Get()
+{
+  Dali::AccessibilityAdaptor adaptor;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::AccessibilityAdaptor ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      adaptor = Dali::AccessibilityAdaptor( dynamic_cast< AccessibilityAdaptor* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      adaptor = Dali::AccessibilityAdaptor( new AccessibilityAdaptorMobile() );
+      AccessibilityAdaptorMobile& adaptorImpl = AccessibilityAdaptorMobile::GetImplementation( adaptor );
+
+      bool isEnabled = GetEnabledVConf();
+
+      if( isEnabled )
+      {
+        adaptorImpl.EnableAccessibility();
+      }
+      DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" );
+
+      vconf_notify_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification, &adaptorImpl );
+      vconf_notify_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification, &adaptorImpl );
+
+      service.Register( typeid( adaptor ), adaptor );
+    }
+  }
+
+  return adaptor;
+}
+
+void AccessibilityAdaptor::OnDestroy()
+{
+  vconf_ignore_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification );
+  vconf_ignore_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification );
+}
+
+AccessibilityAdaptorMobile::AccessibilityAdaptorMobile()
+{
+}
+
+bool AccessibilityAdaptorMobile::HandleActionNextEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionNext(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionPreviousEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPrevious(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionActivateEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionActivate();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain)
+{
+  bool ret = false;
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %d , %d\n", __FUNCTION__, __LINE__, x, y);
+
+  mReadPosition.x = x;
+  mReadPosition.y = y;
+
+  if( mActionHandler )
+  {
+    // The accessibility actions should be handled by the registered accessibility action handler (e.g. focus manager)
+    ret = mActionHandler->AccessibilityActionRead(allowReadAgain);
+    DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+  }
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionReadNextEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadNext(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionReadPreviousEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadPrevious(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionUpEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionUp();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionDownEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionDown();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+AccessibilityAdaptorMobile::~AccessibilityAdaptorMobile()
+{
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/accessibility/tizen-wayland/tizen-mobile/accessibility-adaptor-impl-mobile.h b/dali/internal/accessibility/tizen-wayland/tizen-mobile/accessibility-adaptor-impl-mobile.h
new file mode 100644 (file)
index 0000000..fd2939e
--- /dev/null
@@ -0,0 +1,132 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_MOBILE_H
+#define DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_MOBILE_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/adaptor-framework/accessibility-adaptor.h>
+#include <dali/devel-api/adaptor-framework/accessibility-action-handler.h>
+#include <dali/devel-api/adaptor-framework/accessibility-gesture-handler.h>
+#include <dali/internal/accessibility/common/accessibility-gesture-detector.h>
+#include <dali/internal/accessibility/common/accessibility-adaptor-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * This mobile version is different since it forwards events to the indicator.
+ */
+class AccessibilityAdaptorMobile : public AccessibilityAdaptor
+{
+public:
+
+  /**
+   * Constructor.
+   */
+  AccessibilityAdaptorMobile();
+
+  // From AccessibilityAdaptor base class
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionNextEvent()
+   */
+  virtual bool HandleActionNextEvent( bool allowEndFeedback );
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionPreviousEvent()
+   */
+  virtual bool HandleActionPreviousEvent( bool allowEndFeedback );
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionActivateEvent()
+   */
+  virtual bool HandleActionActivateEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadEvent()
+   */
+  virtual bool HandleActionReadEvent( unsigned int x, unsigned int y, bool allowReadAgain );
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadNextEvent()
+   */
+  virtual bool HandleActionReadNextEvent( bool allowEndFeedback );
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionReadPreviousEvent()
+   */
+  virtual bool HandleActionReadPreviousEvent( bool allowEndFeedback );
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionUpEvent()
+   */
+  virtual bool HandleActionUpEvent();
+
+  /**
+   * @copydoc Dali::AccessibilityAdaptor::HandleActionDownEvent()
+   */
+  virtual bool HandleActionDownEvent();
+
+private:
+
+  /**
+   * Destructor.
+   */
+  virtual ~AccessibilityAdaptorMobile();
+
+  // Undefined
+  AccessibilityAdaptorMobile( const AccessibilityAdaptorMobile& );
+  AccessibilityAdaptorMobile& operator=( AccessibilityAdaptorMobile& );
+
+public:
+
+  // Helpers for public-api forwarding methods
+
+  inline static Internal::Adaptor::AccessibilityAdaptorMobile& GetImplementation(Dali::AccessibilityAdaptor& adaptor)
+  {
+    DALI_ASSERT_ALWAYS( adaptor && "AccessibilityAdaptorMobile handle is empty" );
+
+    BaseObject& handle = adaptor.GetBaseObject();
+
+    return static_cast<Internal::Adaptor::AccessibilityAdaptorMobile&>(handle);
+  }
+
+  inline static const Internal::Adaptor::AccessibilityAdaptorMobile& GetImplementation(const Dali::AccessibilityAdaptor& adaptor)
+  {
+    DALI_ASSERT_ALWAYS( adaptor && "AccessibilityAdaptorMobile handle is empty" );
+
+    const BaseObject& handle = adaptor.GetBaseObject();
+
+    return static_cast<const Internal::Adaptor::AccessibilityAdaptorMobile&>(handle);
+  }
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_ADAPTOR_MOBILE_H
diff --git a/dali/internal/accessibility/tizen-wayland/tizen-tv/accessibility-adaptor-impl-tv.cpp b/dali/internal/accessibility/tizen-wayland/tizen-tv/accessibility-adaptor-impl-tv.cpp
new file mode 100644 (file)
index 0000000..b2418f8
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/common/accessibility-adaptor-impl.h>
+
+// EXTERNAL INCLUDES
+#include <vconf.h>
+
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/system-settings.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+const char * DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS = "db/setting/accessibility/atspi";
+
+// Disabled Accessibility temporarily in Tizen platform
+bool GetEnabledVConf()
+{
+  int isEnabled = 0;
+  //vconf_get_bool( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, &isEnabled );
+
+  if( isEnabled == 0 )
+  {
+    //vconf_get_bool( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, &isEnabled );
+  }
+
+  return static_cast<bool>(isEnabled);
+}
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gAccessibilityAdaptorLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_ACCESSIBILITY_ADAPTOR" );
+#endif
+
+void AccessibilityOnOffNotification(keynode_t* node, void* data)
+{
+  AccessibilityAdaptor* adaptor = static_cast<AccessibilityAdaptor*>( data );
+
+  bool isEnabled = GetEnabledVConf();
+
+  DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" );
+
+  if( isEnabled )
+  {
+    adaptor->EnableAccessibility();
+  }
+  else
+  {
+    adaptor->DisableAccessibility();
+  }
+}
+
+} // unnamed namespace
+
+Dali::AccessibilityAdaptor AccessibilityAdaptor::Get()
+{
+  Dali::AccessibilityAdaptor adaptor;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::AccessibilityAdaptor ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      adaptor = Dali::AccessibilityAdaptor( dynamic_cast< AccessibilityAdaptor* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      adaptor = Dali::AccessibilityAdaptor( new AccessibilityAdaptor() );
+      AccessibilityAdaptor& adaptorImpl = AccessibilityAdaptor::GetImplementation( adaptor );
+
+      bool isEnabled = GetEnabledVConf();
+
+      if( isEnabled )
+      {
+        adaptorImpl.EnableAccessibility();
+      }
+      DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" );
+
+      vconf_notify_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification, &adaptorImpl );
+      vconf_notify_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification, &adaptorImpl );
+
+      service.Register( typeid( adaptor ), adaptor );
+    }
+  }
+
+  return adaptor;
+}
+
+void AccessibilityAdaptor::OnDestroy()
+{
+  vconf_ignore_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification );
+  vconf_ignore_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification );
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/accessibility/tizen-wayland/tizen-wearable/accessibility-adaptor-impl-wearable.cpp b/dali/internal/accessibility/tizen-wayland/tizen-wearable/accessibility-adaptor-impl-wearable.cpp
new file mode 100644 (file)
index 0000000..525faaf
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/tizen-wayland/tizen-mobile/accessibility-adaptor-impl-mobile.h>
+
+// EXTERNAL INCLUDES
+#include <vconf.h>
+
+#ifndef WAYLAND
+#include <dali/internal/system/linux/dali-ecore-x.h>
+#include <dali/internal/system/linux/dali-elementary.h>
+#endif
+
+#include <vconf.h>
+
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/system-settings.h>
+
+#ifndef WAYLAND
+#define MSG_DOMAIN_CONTROL_ACCESS static_cast< int >( ECORE_X_ATOM_E_ILLUME_ACCESS_CONTROL )
+#endif
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // unnamed namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gAccessibilityAdaptorLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_ACCESSIBILITY_ADAPTOR");
+#endif
+
+const char * DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS = "db/setting/accessibility/atspi";
+
+bool GetEnabledVConf()
+{
+  int isEnabled = 0;
+  vconf_get_bool( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, &isEnabled );
+
+  if( isEnabled == 0 )
+  {
+    vconf_get_bool( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, &isEnabled );
+  }
+
+  return bool( isEnabled );
+}
+
+
+void AccessibilityOnOffNotification(keynode_t* node, void* data)
+{
+  AccessibilityAdaptor* adaptor = static_cast<AccessibilityAdaptor*>( data );
+
+  bool isEnabled = GetEnabledVConf();
+
+  DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" );
+
+  if( isEnabled )
+  {
+    adaptor->EnableAccessibility();
+  }
+  else
+  {
+    adaptor->DisableAccessibility();
+  }
+}
+
+} // unnamed namespace
+
+Dali::AccessibilityAdaptor AccessibilityAdaptor::Get()
+{
+  Dali::AccessibilityAdaptor adaptor;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::AccessibilityAdaptor ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      adaptor = Dali::AccessibilityAdaptor( dynamic_cast< AccessibilityAdaptor* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      adaptor = Dali::AccessibilityAdaptor( new AccessibilityAdaptorMobile() );
+      AccessibilityAdaptorMobile& adaptorImpl = AccessibilityAdaptorMobile::GetImplementation( adaptor );
+
+      bool isEnabled = GetEnabledVConf();
+
+      if( isEnabled )
+      {
+        adaptorImpl.EnableAccessibility();
+      }
+      DALI_LOG_INFO( gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, isEnabled ? "ENABLED" : "DISABLED" );
+
+      vconf_notify_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification, &adaptorImpl );
+      vconf_notify_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification, &adaptorImpl );
+
+      service.Register( typeid( adaptor ), adaptor );
+    }
+  }
+
+  return adaptor;
+}
+
+void AccessibilityAdaptor::OnDestroy()
+{
+  vconf_ignore_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_TTS, AccessibilityOnOffNotification );
+  vconf_ignore_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_DBUS_TTS, AccessibilityOnOffNotification );
+}
+
+AccessibilityAdaptorMobile::AccessibilityAdaptorMobile()
+{
+}
+
+bool AccessibilityAdaptorMobile::HandleActionNextEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionNext(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionPreviousEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionPrevious(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionActivateEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionActivate();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionReadEvent(unsigned int x, unsigned int y, bool allowReadAgain)
+{
+  bool ret = false;
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %d , %d\n", __FUNCTION__, __LINE__, x, y);
+
+  mReadPosition.x = x;
+  mReadPosition.y = y;
+
+  if( mActionHandler)
+  {
+    // The accessibility actions should be handled by the registered accessibility action handler (e.g. focus manager)
+    ret = mActionHandler->AccessibilityActionRead(allowReadAgain);
+    DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+  }
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionReadNextEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadNext(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionReadPreviousEvent(bool allowEndFeedback)
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionReadPrevious(allowEndFeedback);
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionUpEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionUp();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+bool AccessibilityAdaptorMobile::HandleActionDownEvent()
+{
+  bool ret = false;
+
+  if( mActionHandler )
+  {
+    ret = mActionHandler->AccessibilityActionDown();
+  }
+
+  DALI_LOG_INFO(gAccessibilityAdaptorLogFilter, Debug::General, "[%s:%d] %s\n", __FUNCTION__, __LINE__, ret?"TRUE":"FALSE");
+
+  return ret;
+}
+
+AccessibilityAdaptorMobile::~AccessibilityAdaptorMobile()
+{
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/accessibility/tizen-wayland/tts-player-factory-tizen.cpp b/dali/internal/accessibility/tizen-wayland/tts-player-factory-tizen.cpp
new file mode 100644 (file)
index 0000000..6287f4d
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 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/internal/accessibility/common/tts-player-factory.h>
+#include <dali/internal/accessibility/tizen-wayland/tts-player-impl-tizen.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class TtsPlayer;
+namespace TtsPlayerFactory
+{
+
+std::unique_ptr<TtsPlayer> New(Dali::TtsPlayer::Mode mode)
+{
+  return TtsPlayerTizen::New(mode);
+}
+
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/dali/internal/accessibility/tizen-wayland/tts-player-impl-tizen.cpp b/dali/internal/accessibility/tizen-wayland/tts-player-impl-tizen.cpp
new file mode 100644 (file)
index 0000000..b18a74e
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/accessibility/tizen-wayland/tts-player-impl-tizen.h>
+
+// EXTERNAL INCLUDES
+#include <tts.h>
+
+#include <dali/public-api/object/type-registry.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // unnamed namespace
+{
+
+/**
+ * Helper function to convert Tizen-specific TTS state to external state.
+ * @param state The Tizen TTS state.
+ * @return The external TTS state.
+ */
+Dali::TtsPlayer::State InternalToExternalState( tts_state_e state )
+{
+  switch( state )
+  {
+    case TTS_STATE_CREATED:
+    {
+      return Dali::TtsPlayer::UNAVAILABLE;
+    }
+    case TTS_STATE_READY:
+    {
+      return Dali::TtsPlayer::READY;
+    }
+    case TTS_STATE_PLAYING:
+    {
+      return Dali::TtsPlayer::PLAYING;
+    }
+    case TTS_STATE_PAUSED:
+    {
+      return Dali::TtsPlayer::PAUSED;
+    }
+  }
+
+  return Dali::TtsPlayer::UNAVAILABLE;
+}
+
+} // unnamed namespace
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* TtsPlayerTizen::gLogFilter = Debug::Filter::New(Debug::Concise, false, "LOG_TTS_PLAYER");
+#endif
+
+std::unique_ptr<TtsPlayerTizen> TtsPlayerTizen::New(Dali::TtsPlayer::Mode mode)
+{
+  return std::unique_ptr<TtsPlayerTizen>(new TtsPlayerTizen(mode));
+}
+
+TtsPlayerTizen::TtsPlayerTizen(Dali::TtsPlayer::Mode mode)
+: mInitialized(false),
+  mUnplayedString(""),
+  mTtsHandle(),
+  mUtteranceId(0),
+  mTtsMode(mode)
+{
+  Initialize();
+}
+
+TtsPlayerTizen::~TtsPlayerTizen()
+{
+  // If it is playing, stop it
+  Stop();
+
+  // Unset the callback funtion for TTS state change
+  int retVal = tts_unset_state_changed_cb(mTtsHandle);
+  if( retVal != TTS_ERROR_NONE )
+  {
+    LogErrorCode(static_cast<tts_error_e>(retVal));
+  }
+
+  // Destroy the TTS handle and disconnects the daemon
+  retVal = tts_destroy(mTtsHandle);
+  if( retVal != TTS_ERROR_NONE )
+  {
+    LogErrorCode(static_cast<tts_error_e>(retVal));
+  }
+}
+
+void TtsPlayerTizen::Initialize()
+{
+  // Create the TTS handle
+  int retVal = tts_create(&mTtsHandle);
+
+  if( retVal != TTS_ERROR_NONE )
+  {
+    LogErrorCode(static_cast<tts_error_e>(retVal));
+  }
+  else
+  {
+    // Set the callback funtion for TTS state change
+    retVal = tts_set_state_changed_cb(mTtsHandle, &StateChangedCallback, this);
+    if( retVal != TTS_ERROR_NONE )
+    {
+      LogErrorCode(static_cast<tts_error_e>(retVal));
+    }
+
+    // Check tts mode
+    tts_mode_e ttsMode = TTS_MODE_DEFAULT;
+    switch (mTtsMode)
+    {
+      case Dali::TtsPlayer::DEFAULT:
+        ttsMode = TTS_MODE_DEFAULT;
+      break;
+      case Dali::TtsPlayer::NOTIFICATION:
+        ttsMode = TTS_MODE_NOTIFICATION;
+      break;
+      case Dali::TtsPlayer::SCREEN_READER:
+        ttsMode = TTS_MODE_SCREEN_READER;
+      break;
+      default:
+      break;
+    }
+
+    // Set mode
+    retVal = tts_set_mode(mTtsHandle, ttsMode);
+    if(retVal != TTS_ERROR_NONE)
+    {
+      LogErrorCode(static_cast<tts_error_e>(retVal));
+    }
+
+    // Connect the TTS daemon asynchronously
+    retVal = tts_prepare(mTtsHandle);
+    if(retVal != TTS_ERROR_NONE)
+    {
+      LogErrorCode(static_cast<tts_error_e>(retVal));
+    }
+  }
+}
+
+void TtsPlayerTizen::Play(const std::string& text)
+{
+  if(mInitialized)
+  {
+    Stop();
+
+    // Add text to the queue, and use normal speed, default language and default voice set by the user
+    int retVal = tts_add_text(mTtsHandle, text.c_str(), NULL, TTS_VOICE_TYPE_AUTO, TTS_SPEED_AUTO, &mUtteranceId);
+    if(retVal != TTS_ERROR_NONE)
+    {
+      LogErrorCode(static_cast<tts_error_e>(retVal));
+    }
+    else
+    {
+      // Start synthesizing voice from text in the queue and play synthesized audio data
+      retVal = tts_play(mTtsHandle);
+      if(retVal != TTS_ERROR_NONE)
+      {
+        LogErrorCode(static_cast<tts_error_e>(retVal));
+      }
+    }
+  }
+  else
+  {
+    mUnplayedString = text;
+  }
+}
+
+void TtsPlayerTizen::Stop()
+{
+  if(mInitialized)
+  {
+    // Check the current TTS state
+    tts_state_e state;
+    int retVal = tts_get_state(mTtsHandle, &state);
+    if(retVal != TTS_ERROR_NONE)
+    {
+      LogErrorCode(static_cast<tts_error_e>(retVal));
+    }
+    else if(state == TTS_STATE_PLAYING || state == TTS_STATE_PAUSED)
+    {
+      // If it is playing or paused, stop playing and clear the queue
+      retVal = tts_stop(mTtsHandle);
+      if( retVal != TTS_ERROR_NONE )
+      {
+        LogErrorCode(static_cast<tts_error_e>(retVal));
+      }
+    }
+  }
+}
+
+void TtsPlayerTizen::Pause()
+{
+  if(mInitialized)
+  {
+    // Check the current TTS state
+    tts_state_e state;
+    int retVal = tts_get_state(mTtsHandle, &state);
+    if(retVal != TTS_ERROR_NONE)
+    {
+      LogErrorCode(static_cast<tts_error_e>(retVal));
+    }
+    else if(state == TTS_STATE_PLAYING)
+    {
+      // If the player is playing, pause it.
+      retVal = tts_pause(mTtsHandle);
+      if( retVal != TTS_ERROR_NONE )
+      {
+        LogErrorCode(static_cast<tts_error_e>(retVal));
+      }
+    }
+  }
+}
+
+void TtsPlayerTizen::Resume()
+{
+  if(mInitialized)
+  {
+    // Check the current TTS state
+    tts_state_e state;
+    int retVal = tts_get_state(mTtsHandle, &state);
+    if(retVal != TTS_ERROR_NONE)
+    {
+      LogErrorCode(static_cast<tts_error_e>(retVal));
+    }
+    else if(state == TTS_STATE_PAUSED)
+    {
+      // If the player is paused, resume it.
+      retVal = tts_play(mTtsHandle);
+      if( retVal != TTS_ERROR_NONE )
+      {
+        LogErrorCode(static_cast<tts_error_e>(retVal));
+      }
+    }
+  }
+}
+
+Dali::TtsPlayer::State TtsPlayerTizen::GetState()
+{
+  Dali::TtsPlayer::State ttsState = Dali::TtsPlayer::UNAVAILABLE;
+
+  if(mInitialized)
+  {
+    // Check the current TTS state
+    tts_state_e state;
+    int retVal = tts_get_state(mTtsHandle, &state);
+    if(retVal != TTS_ERROR_NONE)
+    {
+      LogErrorCode(static_cast<tts_error_e>(retVal));
+    }
+    else
+    {
+      ttsState = InternalToExternalState( state );
+    }
+  }
+
+  return ttsState;
+}
+
+Dali::TtsPlayer::StateChangedSignalType& TtsPlayerTizen::StateChangedSignal()
+{
+  return mStateChangedSignal;
+}
+
+void TtsPlayerTizen::EmitStateChangedSignal( tts_state_e previous, tts_state_e current )
+{
+  // Convert the previous and current states to external states and emit them as a signal.
+  if( !mStateChangedSignal.Empty() )
+  {
+    mStateChangedSignal.Emit( InternalToExternalState( previous ), InternalToExternalState( current ) );
+  }
+}
+
+void TtsPlayerTizen::StateChangedCallback(tts_h tts, tts_state_e previous, tts_state_e current, void *userData)
+{
+  // Get the implementation (this is a static function).
+  TtsPlayerTizen* obj = static_cast<TtsPlayerTizen*>(userData);
+
+  // Emit the signal.
+  obj->EmitStateChangedSignal( previous, current );
+
+  if(!obj->mInitialized && current == TTS_STATE_READY)
+  {
+    obj->mInitialized = true;
+
+    // if there is queued text before initialization, play it
+    if(obj->mUnplayedString != "")
+    {
+      obj->Play(obj->mUnplayedString);
+      obj->mUnplayedString = "";
+    }
+  }
+}
+
+void TtsPlayerTizen::LogErrorCode(tts_error_e reason)
+{
+  std::string error_string;
+
+  switch (reason)
+  {
+    case TTS_ERROR_NONE:
+    {
+      break;
+    }
+    case TTS_ERROR_OUT_OF_MEMORY:
+    {
+      error_string = "TTS: Out of Memory\n";
+      break;
+    }
+    case TTS_ERROR_IO_ERROR:
+    {
+      error_string = "TTS: I/O error\n";
+      break;
+    }
+    case TTS_ERROR_INVALID_PARAMETER:
+    {
+      error_string = "TTS: Invalid parameter\n";
+      break;
+    }
+    case TTS_ERROR_OUT_OF_NETWORK:
+    {
+      error_string = "TTS: Out of network\n";
+      break;
+    }
+    case TTS_ERROR_INVALID_STATE:
+    {
+      error_string = "TTS: Invalid state\n";
+      break;
+    }
+    case TTS_ERROR_INVALID_VOICE:
+    {
+      error_string = "TTS: Invalid voice\n";
+      break;
+    }
+    case TTS_ERROR_ENGINE_NOT_FOUND:
+    {
+      error_string = "TTS: No available engine\n";
+      break;
+    }
+    case TTS_ERROR_TIMED_OUT:
+    {
+      error_string = "TTS: No answer from the daemon\n";
+      break;
+    }
+    case TTS_ERROR_OPERATION_FAILED:
+    {
+      error_string = "TTS: Operation failed\n";
+      break;
+    }
+    default:
+    {
+      error_string = "Invalid TTS error code\n";
+      break;
+    }
+  }
+
+  if(reason != TTS_ERROR_NONE)
+  {
+    DALI_LOG_WARNING("[%s:%d] tts error : %s\n", __FUNCTION__, __LINE__, error_string.c_str());
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/accessibility/tizen-wayland/tts-player-impl-tizen.h b/dali/internal/accessibility/tizen-wayland/tts-player-impl-tizen.h
new file mode 100644 (file)
index 0000000..7ae8d18
--- /dev/null
@@ -0,0 +1,157 @@
+#ifndef DALI_INTERNAL_ACCESSIBILITY_TIZEN_TTS_PLAYER_IMPL_TIZEN_H
+#define DALI_INTERNAL_ACCESSIBILITY_TIZEN_TTS_PLAYER_IMPL_TIZEN_H
+
+/*
+ * Copyright (c) 2018 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 <tts.h>
+#include <string>
+#include <memory>
+
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/tts-player.h>
+#include <dali/internal/accessibility/common/tts-player-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Text-to-speech player
+ */
+class TtsPlayerTizen : public Dali::Internal::Adaptor::TtsPlayer
+{
+
+public:
+
+  /**
+   * Create a TtsPlayer with the given mode.
+   * This should only be called once by the Adaptor class for each given mode.
+   * @param mode the mode of tts-player
+   * @return A newly created TtsPlayer.
+   */
+  static std::unique_ptr<TtsPlayerTizen> New(Dali::TtsPlayer::Mode mode);
+
+  /**
+   * @copydoc TtsPlayer::Play()
+   */
+  void Play(const std::string& text) override;
+
+  /**
+   * @copydoc TtsPlayer::Stop()
+   */
+  void Stop() override;
+
+  /**
+   * @copydoc TtsPlayer::Pause()
+   */
+  void Pause() override;
+
+  /**
+   * @copydoc TtsPlayer::Resume()
+   */
+  void Resume() override;
+
+  /**
+   * @copydoc TtsPlayer::GetState()
+   */
+  Dali::TtsPlayer::State GetState() override;
+
+  /**
+   * @copydoc TtsPlayer::StateChangedSignal()
+   */
+  Dali::TtsPlayer::StateChangedSignalType& StateChangedSignal() override;
+
+  /**
+   * Destructor
+   */
+  ~TtsPlayerTizen() override;
+
+private:
+
+  /**
+   * Private Constructor; see also TtsPlayer::New()
+   * @param mode the mode of tts-player
+   */
+  TtsPlayerTizen(Dali::TtsPlayer::Mode mode);
+
+  /**
+   * Initializes the player.
+   */
+  void Initialize();
+
+  /**
+   * Logs the error code.
+   * @param[in] reason The error code
+   */
+  void LogErrorCode(tts_error_e reason);
+
+  /**
+   * Used to emit the state changed signal from outside the object (EG. A static function).
+   * @param[in] previous The previous state
+   * @param[in] current The current state
+   */
+  void EmitStateChangedSignal( tts_state_e previous, tts_state_e current );
+
+  /**
+   * Called when the state of TTS is changed.
+   *
+   * @param[in] tts The handle for TTS
+   * @param[in] previous A previous state
+   * @param[in] current A current state
+   * @param[in] userData The user data passed from the callback registration function.
+   */
+  static void StateChangedCallback(tts_h tts, tts_state_e previous, tts_state_e current, void *userData);
+
+  // Undefined
+  TtsPlayerTizen(const TtsPlayerTizen&);
+
+  // Undefined
+  TtsPlayerTizen& operator=(TtsPlayerTizen&);
+
+private:
+
+  Dali::TtsPlayer::StateChangedSignalType mStateChangedSignal; ///< Signal emitted when the TTS state changes
+  bool mInitialized; ///< Whether the TTS player is initialised successfully or not
+  std::string mUnplayedString; ///< The text that can not be played because tts engine is not yet initialized
+  tts_h mTtsHandle;  ///< The handle of TTS
+  int mUtteranceId;  ///< The utterance ID
+
+  Dali::TtsPlayer::Mode mTtsMode; ///< The current mode of tts engine
+
+#if defined(DEBUG_ENABLED)
+public:
+  static Debug::Filter* gLogFilter;
+#endif
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ACCESSIBILITY_TIZEN_TTS_PLAYER_IMPL_TIZEN_H
diff --git a/dali/internal/adaptor-framework/android/file-loader-impl-android.cpp b/dali/internal/adaptor-framework/android/file-loader-impl-android.cpp
new file mode 100644 (file)
index 0000000..c35e70f
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor-framework/common/file-loader-impl.h>
+
+// EXTERNAL INCLUDES
+#include <cstdio>
+#include <string>
+#include <fstream>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/android/android-framework.h>
+#include <dali/internal/adaptor/common/framework.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+int ReadFile(const std::string& filename, Dali::Vector<char>& memblock, Dali::FileLoader::FileType fileType)
+{
+  std::streampos size;
+
+  return Dali::Internal::Adaptor::ReadFile( filename, size, memblock, fileType);
+}
+
+inline bool hasPrefix(const std::string& prefix, const std::string& path)
+{
+  return std::mismatch(prefix.begin(), prefix.end(), path.begin()).first == prefix.end();
+}
+
+inline std::string ConvertToAssetsInternalPath(const std::string& path, int offset)
+{
+  std::string internalPath = std::string(path.c_str() + offset);
+
+  int i = 0;
+  while ((i = internalPath.find("//", i)) != std::string::npos)
+  {
+    internalPath.replace(i, 2, "/");
+  }
+
+  return internalPath;
+}
+
+int ReadFile(const std::string& filename, std::streampos& fileSize, Dali::Vector<char>& memblock, Dali::FileLoader::FileType fileType)
+{
+  int errorCode = 0;
+  int length = 0;
+  char mode[3] = { 'r', 0, 0 };
+
+  if( fileType == Dali::FileLoader::BINARY )
+  {
+    mode[1] = 'b';
+  }
+  else if( fileType != Dali::FileLoader::TEXT )
+  {
+    return errorCode;
+  }
+
+  const std::string assetsPrefix = "assets/";
+  if( hasPrefix( assetsPrefix, filename ) )
+  {
+    std::string internalPath = ConvertToAssetsInternalPath( filename, assetsPrefix.length() );
+    AAssetManager* assetManager = Dali::Integration::AndroidFramework::Get().GetApplicationAssets();
+    AAsset* asset = AAssetManager_open( assetManager, internalPath.c_str(), AASSET_MODE_BUFFER );
+    if( asset )
+    {
+      length = AAsset_getLength( asset );
+      memblock.Resize( length + 1 ); // 1 for extra zero at the end
+
+      char* buffer = &memblock[0];
+      errorCode = ( AAsset_read( asset, buffer, length ) != length ) ? 0 : 1;
+      fileSize = length;
+
+      AAsset_close( asset );
+    }
+    else
+    {
+      DALI_LOG_ERROR( "Asset not found %s\n", internalPath.c_str() );
+    }
+  }
+  else
+  {
+    FILE* file = fopen( filename.c_str(),  mode );
+    if( file )
+    {
+      fseek( file, 0, SEEK_END );
+      length = ftell( file );
+      memblock.Resize( length + 1 ); // 1 for extra zero at the end
+
+      char* buffer = &memblock[0];
+      fseek( file, 0, SEEK_SET );
+      errorCode = ( fread( buffer, 1, length, file ) != length ) ? 0 : 1;
+      fileSize = length;
+
+      fclose( file );
+    }
+    else
+    {
+      DALI_LOG_ERROR( "File not found %s\n", filename.c_str() );
+    }
+  }
+
+  return errorCode;
+}
+
+std::streampos GetFileSize(const std::string& filename)
+{
+  std::streampos size = 0;
+
+  const std::string assetsPrefix = "assets/";
+  if( hasPrefix( assetsPrefix, filename ) )
+  {
+    std::string internalPath = ConvertToAssetsInternalPath( filename, assetsPrefix.length() );
+    AAssetManager* assetManager = Dali::Integration::AndroidFramework::Get().GetApplicationAssets();
+    AAsset* asset = AAssetManager_open( assetManager, internalPath.c_str(), AASSET_MODE_BUFFER );
+    if( asset )
+    {
+      size = AAsset_getLength( asset );
+      AAsset_close( asset );
+    }
+    else
+    {
+      DALI_LOG_ERROR( "Asset not found %s\n", internalPath.c_str() );
+    }
+  }
+  else
+  {
+    FILE* file = fopen( filename.c_str(), "r" );
+    if( file )
+    {
+      fseek( file, 0, SEEK_END );
+      size = ftell( file );
+      fclose( file );
+    }
+    else
+    {
+      DALI_LOG_ERROR( "File not found %s\n", filename.c_str() );
+    }
+  }
+
+  return size;
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/dali/internal/adaptor-framework/android/file-stream-impl-android.cpp b/dali/internal/adaptor-framework/android/file-stream-impl-android.cpp
new file mode 100644 (file)
index 0000000..3c85454
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor-framework/common/file-stream-impl.h>
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <fstream>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/android/android-framework.h>
+#include <dali/internal/adaptor-framework/common/file-loader-impl.h>
+
+namespace Dali
+{
+
+FileStream::Impl::Impl(const std::string& filename, uint8_t mode)
+: mFileName( filename ),
+  mMode( mode ),
+  mBuffer( nullptr ),
+  mDataSize( 0 ),
+  mFile( nullptr )
+{
+  DALI_ASSERT_DEBUG( !filename.empty() && "Can't open a empty filename." );
+  DALI_ASSERT_DEBUG( mode != 0 && "No mode is undefined behaviour" );
+}
+
+FileStream::Impl::Impl(uint8_t* buffer, size_t dataSize, uint8_t mode)
+: mMode( mode ),
+  mBuffer( buffer ),
+  mDataSize( dataSize ),
+  mFile( nullptr )
+{
+  DALI_ASSERT_DEBUG( buffer != 0 && "Can't open file on null buffer." );
+  DALI_ASSERT_DEBUG( dataSize > 0 && "Pointless to open file on empty buffer." );
+  DALI_ASSERT_DEBUG( mode != 0 && "No mode is undefined behaviour." );
+}
+
+FileStream::Impl::Impl(Dali::Vector<uint8_t>& buffer, size_t dataSize, uint8_t mode)
+: mMode( mode ),
+  mBuffer( nullptr ),
+  mDataSize( dataSize ),
+  mFile( nullptr )
+{
+  // Resize the buffer to ensure any null that gets written by
+  // fmemopen is written past the end of any data that is written to the buffer.
+  // (Workaround for a bug in Ubuntu that overwrites null to the last byte of the
+  // data block regardless of whether binary mode was specified. Tizen doesn't write
+  // null if binary mode is specified).
+
+  ++mDataSize;
+  buffer.Resize( mDataSize );
+  mBuffer = &buffer[0];
+
+  DALI_ASSERT_DEBUG( mBuffer != nullptr && "Can't open file on null buffer." );
+  DALI_ASSERT_DEBUG( dataSize > 0 && "Pointless to open file on empty buffer." );
+  DALI_ASSERT_DEBUG( mode != 0 && "No mode is undefined behaviour." );
+}
+
+FileStream::Impl::~Impl()
+{
+  if( mFile )
+  {
+    const int closeFailed = fclose( mFile );
+    if( closeFailed )
+    {
+      DALI_LOG_WARNING( "File close failed for FILE: \"%p\".\n", static_cast<void*>( mFile ) );
+    }
+
+    mFile = nullptr;
+  }
+
+  if( mFileStream.is_open() )
+  {
+    mFileStream.close();
+  }
+}
+
+std::iostream& FileStream::Impl::GetStream()
+{
+  if( mFile )
+  {
+    // return empty stream if FILE stream is open to avoid simultaneous access to the same file
+    return mFileStream;
+  }
+
+  if( mFileStream.is_open() )
+  {
+    return mFileStream;
+  }
+
+  if( mBufferStream.rdbuf()->in_avail() )
+  {
+    return mBufferStream;
+  }
+
+  int openMode = 0;
+
+  if( mMode & Dali::FileStream::APPEND )
+  {
+    openMode |= ( std::ios::out | std::ios::app );
+  }
+  else if( mMode & Dali::FileStream::WRITE )
+  {
+    openMode |= ( std::ios::out | std::ios::ate );
+  }
+
+  if( mMode & Dali::FileStream::READ )
+  {
+    openMode |= std::ios::in;
+  }
+
+  if( mMode & Dali::FileStream::BINARY )
+  {
+    openMode |= std::ios::binary;
+  }
+
+  if( !mFileName.empty() )
+  {
+    // TODO: it works only with text files, we need custom stream buffer implementation for binary and to avoid buffer copy
+    if( !( mMode & Dali::FileStream::WRITE ) && !( mMode & Dali::FileStream::APPEND ) && !( mMode & Dali::FileStream::BINARY ) )
+    {
+      std::streampos fileSize;
+      if( ReadFile( mFileName, fileSize, mFileBuffer, Dali::FileLoader::TEXT ) )
+      {
+        mBuffer = reinterpret_cast<uint8_t*>( &mFileBuffer[0] );
+        mDataSize = fileSize;
+        mBufferStream.str( std::string ( &mFileBuffer[0], fileSize ) );
+        if( !mBufferStream.rdbuf()->in_avail() )
+        {
+          DALI_LOG_ERROR( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%d\".\n",
+              static_cast<void*>( mBuffer ), static_cast<unsigned>( mDataSize ), static_cast<int>( openMode ) );
+        }
+        return mBufferStream;
+      }
+      else
+      {
+        DALI_LOG_ERROR( "stream open failed for: \"%s\", in mode: \"%d\".\n", mFileName.c_str(), static_cast<int>( openMode ) );
+      }
+    }
+    else
+    {
+      mFileStream.open( mFileName, static_cast<std::ios_base::openmode>( openMode ) );
+      if( !mFileStream.is_open() )
+      {
+        DALI_LOG_ERROR( "stream open failed for: \"%s\", in mode: \"%d\".\n", mFileName.c_str(), static_cast<int>( openMode ) );
+      }
+    }
+    return mFileStream;
+  }
+  else if( mBuffer )
+  {
+    mBufferStream.rdbuf()->pubsetbuf( reinterpret_cast<char*>( mBuffer ), mDataSize );
+    if( !mBufferStream.rdbuf()->in_avail() )
+    {
+      DALI_LOG_ERROR( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%d\".\n",
+          static_cast<void*>( mBuffer ), static_cast<unsigned>( mDataSize ), static_cast<int>( openMode ) );
+    }
+  }
+
+  return mBufferStream;
+}
+
+FILE* FileStream::Impl::GetFile()
+{
+  if( mFileStream.is_open() || mBufferStream.rdbuf()->in_avail() )
+  {
+    // return empty FILE stream if the stream is open to avoid simultaneous access to the same file
+    return nullptr;
+  }
+
+  if( mFile )
+  {
+    return mFile;
+  }
+
+  char openMode[16] = { 0 };
+  int i = 0;
+
+  if( mMode & Dali::FileStream::APPEND )
+  {
+    openMode[i++] = 'a';
+  }
+  else if( mMode & Dali::FileStream::WRITE )
+  {
+    openMode[i++] = 'w';
+  }
+  else
+  {
+    openMode[i++] = 'r';
+  }
+
+  if( mMode & Dali::FileStream::BINARY )
+  {
+    openMode[i++] = 'b';
+  }
+
+  openMode[i++] = 0;
+
+  if( !mFileName.empty() )
+  {
+    if ( !( mMode & Dali::FileStream::WRITE ) && !( mMode & Dali::FileStream::APPEND ) )
+    {
+      std::streampos fileSize;
+      if ( ReadFile( mFileName, fileSize, mFileBuffer, ( mMode & Dali::FileStream::BINARY ) ? Dali::FileLoader::BINARY : Dali::FileLoader::TEXT ) )
+      {
+        mBuffer = reinterpret_cast<uint8_t*>( &mFileBuffer[0] );
+        mDataSize = fileSize;
+        mFile = fmemopen( mBuffer, mDataSize, openMode );
+        if( !mFile )
+        {
+          DALI_LOG_ERROR( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%s\".\n",
+              static_cast<void*>( mBuffer ), static_cast<unsigned>( mDataSize ), openMode );
+        }
+      }
+      else
+      {
+        DALI_LOG_ERROR( "read file failed for: \"%s\", in mode: \"%s\".\n", mFileName.c_str(), openMode );
+      }
+    }
+    else
+    {
+      mFile = fopen( mFileName.c_str(), openMode );
+      if( !mFile )
+      {
+        DALI_LOG_ERROR( "file open failed for: \"%s\", in mode: \"%s\".\n", mFileName.c_str(), openMode );
+      }
+    }
+  }
+  else if( mBuffer )
+  {
+    mFile = fmemopen( mBuffer, mDataSize, openMode );
+    if( !mFile )
+    {
+      DALI_LOG_ERROR( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%s\".\n",
+          static_cast<void*>( mBuffer ), static_cast<unsigned>( mDataSize ), openMode );
+    }
+  }
+
+  return mFile;
+}
+
+} // Dali
diff --git a/dali/internal/adaptor-framework/common/file-loader-impl.h b/dali/internal/adaptor-framework/common/file-loader-impl.h
new file mode 100644 (file)
index 0000000..8319716
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef DALI_FILE_LOADER_IMPL_GENERIC_H
+#define DALI_FILE_LOADER_IMPL_GENERIC_H
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/file-loader.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+int ReadFile(const std::string& filename, Dali::Vector<char>& memblock, Dali::FileLoader::FileType fileType = Dali::FileLoader::BINARY);
+
+int ReadFile(const std::string& filename, std::streampos& fileSize, Dali::Vector<char>& memblock, Dali::FileLoader::FileType fileType = Dali::FileLoader::BINARY);
+
+std::streampos GetFileSize(const std::string& filename);
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
+#endif // DALI_FILE_LOADER_IMPL_GENERIC_H
diff --git a/dali/internal/adaptor-framework/common/file-stream-impl.h b/dali/internal/adaptor-framework/common/file-stream-impl.h
new file mode 100644 (file)
index 0000000..8b4e3ae
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef DALI_FILE_STREAM_IMPL_GENERIC_H
+#define DALI_FILE_STREAM_IMPL_GENERIC_H
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/file-stream.h>
+#include <fstream>
+#include <sstream>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+class FileStream::Impl
+{
+public:
+  Impl(const std::string& filename, uint8_t mode);
+
+  Impl(uint8_t* buffer, size_t dataSize, uint8_t mode);
+
+  Impl(Dali::Vector<uint8_t>& buffer, size_t dataSize, uint8_t mode);
+
+  ~Impl();
+
+  std::iostream& GetStream();
+
+  FILE* GetFile();
+
+private:
+  std::string mFileName;
+  uint8_t mMode;
+  uint8_t* mBuffer; // external buffer, not owned
+  size_t mDataSize;
+
+  Dali::Vector<char> mFileBuffer; // for internal usage only
+  FILE* mFile;
+  std::fstream mFileStream;
+  std::stringstream mBufferStream;
+};
+
+} // Dali
+
+#endif // DALI_FILE_STREAM_IMPL_GENERIC_H
diff --git a/dali/internal/adaptor-framework/file.list b/dali/internal/adaptor-framework/file.list
new file mode 100644 (file)
index 0000000..dc909f6
--- /dev/null
@@ -0,0 +1,12 @@
+
+# module: adaptor-framework, backend: generic
+SET( adaptor_framework_generic_src_files 
+    ${adaptor_framework_dir}/generic/file-loader-impl-generic.cpp 
+    ${adaptor_framework_dir}/generic/file-stream-impl-generic.cpp
+)
+
+# module: adaptor-framework, backend: android
+SET( adaptor_framework_android_src_files
+    ${adaptor_framework_dir}/android/file-loader-impl-android.cpp
+    ${adaptor_framework_dir}/android/file-stream-impl-android.cpp
+)
diff --git a/dali/internal/adaptor-framework/generic/file-loader-impl-generic.cpp b/dali/internal/adaptor-framework/generic/file-loader-impl-generic.cpp
new file mode 100644 (file)
index 0000000..31302ef
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor-framework/common/file-loader-impl.h>
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <fstream>
+
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+int ReadFile(const std::string& filename, Dali::Vector<char> & memblock, Dali::FileLoader::FileType fileType)
+{
+  std::streampos size;
+
+  return Dali::Internal::Adaptor::ReadFile( filename, size, memblock, fileType);
+}
+
+int ReadFile(const std::string& filename, std::streampos& fileSize, Dali::Vector<char> & memblock, Dali::FileLoader::FileType fileType)
+{
+  int errorCode = 0;
+  std::ifstream * file;
+
+  if( fileType == Dali::FileLoader::BINARY )
+  {
+    file = new std::ifstream (filename.c_str(), std::ios::in|std::ios::binary|std::ios::ate);
+  }
+  else if( fileType == Dali::FileLoader::TEXT )
+  {
+    file = new std::ifstream (filename.c_str(), std::ios::in|std::ios::ate);
+  }
+  else
+  {
+    return errorCode;
+  }
+
+  if( file->is_open() )
+  {
+    fileSize = file->tellg();
+
+    memblock.Resize( fileSize );
+
+    file->seekg (0, std::ios::beg);
+    file->read( memblock.Begin(), fileSize );
+    file->close();
+
+    delete file;
+
+    errorCode = 1;
+  }
+  else
+  {
+    DALI_LOG_ERROR( "file open failed for: \"%s\"\n", filename.c_str() );
+  }
+
+  return errorCode;
+}
+
+std::streampos GetFileSize(const std::string& filename)
+{
+  std::streampos size = 0;
+
+  std::ifstream file( filename.c_str(), std::ios::in|std::ios::binary|std::ios::ate );
+  if( file.is_open() )
+  {
+    size = file.tellg();
+    file.close();
+  }
+
+  return size;
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/dali/internal/adaptor-framework/generic/file-stream-impl-generic.cpp b/dali/internal/adaptor-framework/generic/file-stream-impl-generic.cpp
new file mode 100644 (file)
index 0000000..3f40285
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor-framework/common/file-stream-impl.h>
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <fstream>
+
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+FileStream::Impl::Impl(const std::string& filename, uint8_t mode)
+: mFileName( filename ),
+  mMode( mode ),
+  mBuffer( nullptr ),
+  mDataSize( 0 ),
+  mFile( nullptr )
+{
+  DALI_ASSERT_DEBUG( !filename.empty() && "Can't open a empty filename." );
+  DALI_ASSERT_DEBUG( mode != 0 && "No mode is undefined behaviour" );
+}
+
+FileStream::Impl::Impl(uint8_t* buffer, size_t dataSize, uint8_t mode)
+: mMode( mode ),
+  mBuffer( buffer ),
+  mDataSize( dataSize ),
+  mFile( nullptr )
+{
+  DALI_ASSERT_DEBUG( buffer != 0 && "Can't open file on null buffer." );
+  DALI_ASSERT_DEBUG( dataSize > 0 && "Pointless to open file on empty buffer." );
+  DALI_ASSERT_DEBUG( mode != 0 && "No mode is undefined behaviour." );
+}
+
+FileStream::Impl::Impl(Dali::Vector<uint8_t>& vector, size_t dataSize, uint8_t mode)
+: mMode( mode ),
+  mBuffer( nullptr ),
+  mDataSize( dataSize ),
+  mFile( nullptr )
+{
+  // Resize the buffer to ensure any null that gets written by
+  // fmemopen is written past the end of any data that is written to the buffer.
+  // (Workaround for a bug in Ubuntu that overwrites null to the last byte of the
+  // data block regardless of whether binary mode was specified. Tizen doesn't write
+  // null if binary mode is specified).
+
+  ++mDataSize;
+  vector.Resize( mDataSize );
+  mBuffer = &vector[0];
+
+  DALI_ASSERT_DEBUG( mBuffer != nullptr && "Can't open file on null buffer." );
+  DALI_ASSERT_DEBUG( dataSize > 0 && "Pointless to open file on empty buffer." );
+  DALI_ASSERT_DEBUG( mode != 0 && "No mode is undefined behaviour." );
+}
+
+FileStream::Impl::~Impl()
+{
+  if( mFile )
+  {
+    const int closeFailed = fclose( mFile );
+    if( closeFailed )
+    {
+      DALI_LOG_WARNING( "File close failed for FILE: \"%p\".\n", static_cast<void*>( mFile ) );
+    }
+
+    mFile = nullptr;
+  }
+
+  if( mFileStream.is_open() )
+  {
+    mFileStream.close();
+  }
+}
+
+std::iostream& FileStream::Impl::GetStream()
+{
+  if( mFile )
+  {
+    // return empty stream if FILE stream is open to avoid simultaneous access to the same file
+    return mFileStream;
+  }
+
+  if( mFileStream.is_open() )
+  {
+    return mFileStream;
+  }
+
+  if( mBufferStream.rdbuf()->in_avail() )
+  {
+    return mBufferStream;
+  }
+
+  int openMode = 0;
+
+  if( mMode & Dali::FileStream::APPEND )
+  {
+    openMode |= ( std::ios::out | std::ios::app );
+  }
+  else if( mMode & Dali::FileStream::WRITE )
+  {
+    openMode |= ( std::ios::out | std::ios::ate );
+  }
+
+  if( mMode & Dali::FileStream::READ )
+  {
+    openMode |= std::ios::in;
+  }
+
+  if( mMode & Dali::FileStream::BINARY )
+  {
+    openMode |= std::ios::binary;
+  }
+
+  if( !mFileName.empty() )
+  {
+    mFileStream.open( mFileName, static_cast<std::ios_base::openmode>( openMode ) );
+    if( !mFileStream.is_open() )
+    {
+      DALI_LOG_WARNING( "stream open failed for: \"%s\", in mode: \"%d\".\n", mFileName.c_str(), openMode );
+    }
+    return mFileStream;
+  }
+  else if( mBuffer )
+  {
+    mBufferStream.rdbuf()->pubsetbuf( reinterpret_cast<char*>( mBuffer ), mDataSize );
+    if( !mBufferStream.rdbuf()->in_avail() )
+    {
+      DALI_LOG_WARNING( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%d\".\n",
+          static_cast<void*>( mBuffer ), static_cast<unsigned>( mDataSize ), openMode );
+    }
+  }
+
+  return mBufferStream;
+}
+
+FILE* FileStream::Impl::GetFile()
+{
+  if( mFileStream.is_open() || mBufferStream.rdbuf()->in_avail() )
+  {
+    // return empty FILE stream if the stream is open to avoid simultaneous access to the same file
+    return nullptr;
+  }
+
+  if( mFile )
+  {
+    return mFile;
+  }
+
+  char openMode[16] = { 0 };
+  int i = 0;
+
+  if( mMode & Dali::FileStream::APPEND )
+  {
+    openMode[i++] = 'a';
+  }
+  else if( mMode & Dali::FileStream::WRITE )
+  {
+    openMode[i++] = 'w';
+  }
+  else
+  {
+    openMode[i++] = 'r';
+  }
+
+  if( mMode & Dali::FileStream::BINARY )
+  {
+    openMode[i++] = 'b';
+  }
+
+  openMode[i++] = 0;
+
+  if( !mFileName.empty() )
+  {
+    mFile = fopen( mFileName.c_str(), openMode );
+    if( !mFile )
+    {
+      DALI_LOG_ERROR( "file open failed for: \"%s\", in mode: \"%s\".\n", mFileName.c_str(), openMode );
+    }
+  }
+  else if( mBuffer )
+  {
+    mFile = fmemopen( mBuffer, mDataSize, openMode );
+    if( !mFile )
+    {
+      DALI_LOG_ERROR( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%s\".\n",
+          static_cast<void*>( mBuffer ), static_cast<unsigned>( mDataSize ), openMode );
+    }
+  }
+
+  return mFile;
+}
+
+} // Dali
diff --git a/dali/internal/adaptor/android/android-framework-impl.cpp b/dali/internal/adaptor/android/android-framework-impl.cpp
new file mode 100644 (file)
index 0000000..c83265e
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor/android/android-framework-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+AndroidFramework* gAndroidFramework = nullptr; // raw specific pointer to allow AndroidFramework::Get
+}
+
+Dali::Integration::AndroidFramework& AndroidFramework::New()
+{
+  Dali::Integration::AndroidFramework* androidFramework = new Dali::Integration::AndroidFramework;
+  AndroidFramework* impl = new AndroidFramework( androidFramework );
+  androidFramework->mImpl = impl;
+  return *androidFramework;
+}
+
+void AndroidFramework::Delete()
+{
+  DALI_ASSERT_ALWAYS( gAndroidFramework != nullptr && "Cannot delete already deleted AndroidFramework." );
+
+  delete gAndroidFramework->mAndroidFramework;
+  gAndroidFramework = nullptr;
+}
+
+void AndroidFramework::SetNativeApplication( android_app* application )
+{
+  mNativeApplication = application;
+}
+
+android_app* AndroidFramework::GetNativeApplication() const
+{
+  return mNativeApplication;
+}
+
+void AndroidFramework::SetJVM( JavaVM* jvm )
+{
+  mJVM = jvm;
+}
+
+JavaVM* AndroidFramework::GetJVM() const
+{
+  return mJVM;
+}
+
+void AndroidFramework::SetApplicationAssets( AAssetManager* assets )
+{
+  mAssets = assets;
+}
+
+AAssetManager* AndroidFramework::GetApplicationAssets() const
+{
+  return mAssets;
+}
+
+void AndroidFramework::SetInternalDataPath( const std::string& path )
+{
+  mInternalDataPath = path;
+}
+
+std::string AndroidFramework::GetInternalDataPath() const
+{
+  return mInternalDataPath;
+}
+
+void AndroidFramework::SetApplicationConfiguration( AConfiguration* configuration )
+{
+  mConfiguration = configuration;
+}
+
+AConfiguration* AndroidFramework::GetApplicationConfiguration() const
+{
+  return mConfiguration;
+}
+
+void AndroidFramework::SetApplicationWindow( ANativeWindow* window )
+{
+  mWindow = window;
+}
+
+ANativeWindow* AndroidFramework::GetApplicationWindow() const
+{
+  return mWindow;
+}
+
+void AndroidFramework::OnTerminate()
+{
+  mFramework->AppStatusHandler( APP_DESTROYED, nullptr );
+}
+
+void AndroidFramework::OnPause()
+{
+  mFramework->AppStatusHandler( APP_PAUSE, nullptr );
+}
+
+void AndroidFramework::OnResume()
+{
+  mFramework->AppStatusHandler( APP_RESUME, nullptr );
+}
+
+void AndroidFramework::OnWindowCreated( ANativeWindow* window )
+{
+  mFramework->AppStatusHandler( APP_WINDOW_CREATED, window );
+}
+
+void AndroidFramework::OnWindowDestroyed( ANativeWindow* window )
+{
+  mFramework->AppStatusHandler( APP_WINDOW_DESTROYED, window );
+}
+
+Dali::Integration::AndroidFramework& AndroidFramework::Get()
+{
+  DALI_ASSERT_ALWAYS( gAndroidFramework != nullptr && "AndroidFramework not instantiated" );
+
+  return *gAndroidFramework->mAndroidFramework;
+}
+
+AndroidFramework::AndroidFramework( Dali::Integration::AndroidFramework* androidFramework )
+ : mAndroidFramework( androidFramework ),
+   mFramework( nullptr ),
+   mNativeApplication( nullptr ),
+   mWindow( nullptr ),
+   mAssets( nullptr ),
+   mConfiguration( nullptr ),
+   mJVM( nullptr )
+{
+  DALI_ASSERT_ALWAYS( gAndroidFramework == nullptr && "Cannot create more than one AndroidFramework." );
+
+  gAndroidFramework = this;
+}
+
+AndroidFramework::~AndroidFramework()
+{
+  gAndroidFramework = nullptr;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/adaptor/android/android-framework-impl.h b/dali/internal/adaptor/android/android-framework-impl.h
new file mode 100644 (file)
index 0000000..9bec4ce
--- /dev/null
@@ -0,0 +1,204 @@
+#ifndef DALI_INTEGRATION_ANDROID_FRAMEWORK_IMPL_H
+#define DALI_INTEGRATION_ANDROID_FRAMEWORK_IMPL_H
+
+/*
+ * Copyright (c) 2019 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/adaptor-framework/android/android-framework.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/framework.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/// Android application events
+enum
+{
+  APP_WINDOW_CREATED = 0,
+  APP_WINDOW_DESTROYED,
+  APP_PAUSE,
+  APP_RESUME,
+  APP_RESET,
+  APP_LANGUAGE_CHANGE,
+  APP_DESTROYED,
+};
+
+/**
+ * AndroidFramework implementation to set/get Android native interfaces for Android Adaptor.
+ * Also passes Android application events to Android Adaptor internal framework.
+ */
+class AndroidFramework
+{
+public:
+  /**
+   * @brief Create a new Android framework.
+   *
+   * @return a reference to the Android framework
+   */
+  static Dali::Integration::AndroidFramework& New();
+
+  /**
+   * @brief Delete an Android framework.
+   */
+  static void Delete();
+
+  /**
+   * @copydoc Dali::Integration::AndroidFramework::SetNativeApplication()
+   */
+  void SetNativeApplication( android_app* application );
+
+  /**
+   * @copydoc Dali::Integration::AndroidFramework::GetNativeApplication()
+   */
+  android_app* GetNativeApplication() const;
+
+  /**
+   * @copydoc Dali::Integration::AndroidFramework::SetJVM()
+   */
+  void SetJVM( JavaVM* jvm );
+
+  /**
+   * @copydoc Dali::Integration::AndroidFramework::GetJVM()
+   */
+  JavaVM* GetJVM() const;
+
+  /**
+   * @copydoc Dali::Integration::AndroidFramework::SetApplicationAssets()
+   */
+  void SetApplicationAssets( AAssetManager* assets );
+
+  /**
+   * @copydoc Dali::Integration::AndroidFramework::GetApplicationAssets()
+   */
+  AAssetManager* GetApplicationAssets() const;
+
+  /**
+   *  copydoc Dali::Integration::AndroidFramework::SetInternalDataPath()
+   */
+  void SetInternalDataPath( const std::string& path );
+
+  /**
+   *  copydoc Dali::Integration::AndroidFramework::GetInternalDataPath()
+   */
+  std::string GetInternalDataPath() const;
+
+  /**
+   * @copydoc Dali::Integration::AndroidFramework::SetApplicationConfiguration()
+   */
+  void SetApplicationConfiguration( AConfiguration* configuration );
+
+  /**
+   * @copydoc Dali::Integration::AndroidFramework::GetApplicationConfiguration()
+   */
+  AConfiguration* GetApplicationConfiguration() const;
+
+  /**
+   * @copydoc Dali::Integration::AndroidFramework::SetApplicationWindow()
+   */
+  void SetApplicationWindow( ANativeWindow* window );
+
+  /**
+   * @copydoc Dali::Integration::AndroidFramework::GetApplicationWindow()
+   */
+  ANativeWindow* GetApplicationWindow() const;
+
+  /**
+   * @copydoc Dali::Integration::AndroidFramework::OnTerminate()
+   */
+  void OnTerminate();
+
+  /**
+   * @copydoc Dali::Integration::AndroidFramework::OnPause()
+   */
+  void OnPause();
+
+  /**
+   * @copydoc Dali::Integration::AndroidFramework::OnResume()
+   */
+  void OnResume();
+
+  /**
+   * @copydoc Dali::Integration::AndroidFramework::OnWindowCreated()
+   */
+  void OnWindowCreated( ANativeWindow* window );
+
+  /**
+   * @copydoc Dali::Integration::AndroidFramework::OnWindowDestroyed()
+   */
+  void OnWindowDestroyed( ANativeWindow* window );
+
+  /**
+   * @copydoc Dali::Integration::AndroidFramework::Get()
+   */
+  static Dali::Integration::AndroidFramework& Get();
+
+  /**
+   * @brief Sets an internal framework.
+   */
+  void SetFramework( Framework* framework ) { mFramework = framework; }
+
+  /**
+   * @brief Gets an internal framework.
+   *
+   * @return a pointer to the internal framework
+   */
+  Framework* GetFramework() { return mFramework; }
+
+  /**
+   * Virtual destructor.
+   */
+  virtual ~AndroidFramework();
+
+  // Not copyable or movable
+  AndroidFramework( const AndroidFramework& ) = delete; ///< Deleted copy constructor
+  AndroidFramework( AndroidFramework&& ) = delete; ///< Deleted move constructor
+  AndroidFramework& operator=( const AndroidFramework& ) = delete; ///< Deleted copy assignment operator
+  AndroidFramework& operator=( AndroidFramework&& ) = delete; ///< Deleted move assignment operator
+
+private:
+  AndroidFramework( Dali::Integration::AndroidFramework* androidFramework );
+  Dali::Integration::AndroidFramework* mAndroidFramework;
+  Framework* mFramework;
+
+  android_app* mNativeApplication;
+  ANativeWindow* mWindow;
+  AAssetManager* mAssets;
+  std::string mInternalDataPath;
+  AConfiguration* mConfiguration;
+  JavaVM* mJVM;
+
+public:
+  static AndroidFramework& GetImplementation( Dali::Integration::AndroidFramework& androidFramework ) { return *androidFramework.mImpl; }
+  static Framework& GetFramework( Dali::Integration::AndroidFramework& androidFramework ) { return *androidFramework.mImpl->mFramework; }
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // DALI_INTEGRATION_ANDROID_FRAMEWORK_IMPL_H
+
diff --git a/dali/internal/adaptor/android/framework-android.cpp b/dali/internal/adaptor/android/framework-android.cpp
new file mode 100644 (file)
index 0000000..741f76c
--- /dev/null
@@ -0,0 +1,718 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor/common/framework.h>
+
+// EXTERNAL INCLUDES
+#include <unistd.h>
+#include <queue>
+#include <unordered_set>
+#include <android_native_app_glue.h>
+
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/integration-api/adaptor-framework/android/android-framework.h>
+#include <dali/public-api/events/touch-point.h>
+#include <dali/public-api/events/key-event.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/callback-manager.h>
+#include <dali/internal/adaptor/android/android-framework-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+// Copied from x server
+static unsigned int GetCurrentMilliSeconds(void)
+{
+  struct timeval tv;
+
+  struct timespec tp;
+  static clockid_t clockid;
+
+  if (!clockid)
+  {
+#ifdef CLOCK_MONOTONIC_COARSE
+    if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
+      (tp.tv_nsec / 1000) <= 1000 && clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
+    {
+      clockid = CLOCK_MONOTONIC_COARSE;
+    }
+    else
+#endif
+    if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
+    {
+      clockid = CLOCK_MONOTONIC;
+    }
+    else
+    {
+      clockid = ~0L;
+    }
+  }
+  if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
+  {
+    return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
+  }
+
+  gettimeofday(&tv, NULL);
+  return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+}
+
+} // Unnamed namespace
+
+/**
+ * Impl to hide android data members
+ */
+struct Framework::Impl
+{
+
+  struct IdleCallback
+  {
+    int timestamp;
+    int timeout;
+    int id;
+    void* data;
+    bool ( *callback )( void *data );
+
+    IdleCallback( int timeout, int id, void* data, bool ( *callback )( void *data ) )
+    : timestamp( GetCurrentMilliSeconds() + timeout ),
+      timeout( timeout ),
+      id ( id ),
+      data( data ),
+      callback( callback )
+    {
+    }
+
+    bool operator()()
+    {
+      return callback( data );
+    }
+
+    bool operator<( const IdleCallback& rhs ) const
+    {
+      return timestamp > rhs.timestamp;
+    }
+  };
+
+  // Constructor
+
+  Impl( Framework* framework )
+  : mAbortCallBack( nullptr ),
+    mCallbackManager( CallbackManager::New() ),
+    mLanguage( "NOT_SUPPORTED" ),
+    mRegion( "NOT_SUPPORTED" ),
+    mFinishRequested( false ),
+    mIdleId( 0 ),
+    mIdleReadPipe( -1 ),
+    mIdleWritePipe( -1 )
+
+
+  {
+    AndroidFramework::GetImplementation( AndroidFramework::Get() ).SetFramework( framework );
+  }
+
+  ~Impl()
+  {
+    AndroidFramework::GetImplementation( AndroidFramework::Get() ).SetFramework( nullptr );
+
+    delete mAbortCallBack;
+    mAbortCallBack = nullptr;
+
+    // we're quiting the main loop so
+    // mCallbackManager->RemoveAllCallBacks() does not need to be called
+    // to delete our abort handler
+    delete mCallbackManager;
+    mCallbackManager = nullptr;
+  }
+
+  std::string GetLanguage() const
+  {
+    return mLanguage;
+  }
+
+  std::string GetRegion() const
+  {
+    return mRegion;
+  }
+
+  void OnIdle()
+  {
+    // Dequeue the pipe
+    int8_t msg = -1;
+    read( mIdleReadPipe, &msg, sizeof( msg ) );
+
+    unsigned int ts = GetCurrentMilliSeconds();
+
+    if ( !mIdleCallbacks.empty() )
+    {
+      IdleCallback callback = mIdleCallbacks.top();
+      if( callback.timestamp <= ts )
+      {
+        mIdleCallbacks.pop();
+
+        // Callback wasn't removed
+        if( mRemovedIdleCallbacks.find( callback.id ) == mRemovedIdleCallbacks.end() )
+        {
+          if ( callback() ) // keep the callback
+          {
+            AddIdle( callback.timeout, callback.data, callback.callback );
+          }
+        }
+
+        // Callback cane be also removed during the callback call
+        auto i = mRemovedIdleCallbacks.find( callback.id );
+        if( i != mRemovedIdleCallbacks.end() )
+        {
+          mRemovedIdleCallbacks.erase( i );
+        }
+      }
+    }
+
+    if( mIdleCallbacks.empty() )
+    {
+      mRemovedIdleCallbacks.clear();
+    }
+  }
+
+  unsigned int AddIdle( int timeout, void* data, bool ( *callback )( void *data ) )
+  {
+    ++mIdleId;
+    if( mIdleId == 0 )
+    {
+      ++mIdleId;
+    }
+
+    mIdleCallbacks.push( IdleCallback( timeout, mIdleId, data, callback ) );
+
+    // To wake up the idle pipe and to trigger OnIdle
+    int8_t msg = 1;
+    write( mIdleWritePipe, &msg, sizeof( msg ) );
+
+    return mIdleId;
+  }
+
+  void RemoveIdle( unsigned int id )
+  {
+    if( id != 0 )
+    {
+      mRemovedIdleCallbacks.insert( id );
+    }
+  }
+
+  int GetIdleTimeout()
+  {
+    int timeout = -1;
+
+    if( !mIdleCallbacks.empty() )
+    {
+      IdleCallback idleTimeout = mIdleCallbacks.top();
+      timeout = idleTimeout.timestamp - GetCurrentMilliSeconds();
+      if( timeout < 0 )
+      {
+         timeout = 0;
+      }
+    }
+
+    return timeout;
+  }
+
+  // Data
+  CallbackBase* mAbortCallBack;
+  CallbackManager* mCallbackManager;
+  std::string mLanguage;
+  std::string mRegion;
+  bool mFinishRequested;
+
+  int mIdleReadPipe;
+  int mIdleWritePipe;
+  unsigned int mIdleId;
+  std::priority_queue<IdleCallback> mIdleCallbacks;
+  std::unordered_set<int> mRemovedIdleCallbacks;
+
+  // Static methods
+
+  /**
+   * Called by the native activity loop when the application APP_CMD_INIT_WINDOW event is processed.
+   */
+  static void NativeWindowCreated( Framework* framework, ANativeWindow* window )
+  {
+    if( framework )
+    {
+      framework->AppStatusHandler( APP_WINDOW_CREATED, window );
+    }
+  }
+
+  /**
+   * Called by the native activity loop when the application APP_CMD_DESTROY event is processed.
+   */
+  static void NativeWindowDestroyed( Framework* framework, ANativeWindow* window )
+  {
+    if( framework )
+    {
+      framework->AppStatusHandler( APP_WINDOW_DESTROYED, window );
+    }
+  }
+
+  /**
+   * Called by the native activity loop when the application APP_CMD_INIT_WINDOW event is processed.
+   */
+  static void NativeAppPaused( Framework* framework )
+  {
+    if( framework )
+    {
+      framework->AppStatusHandler( APP_PAUSE, nullptr );
+    }
+  }
+
+  /**
+   * Called by the native activity loop when the application APP_CMD_TERM_WINDOW event is processed.
+   */
+  static void NativeAppResumed( Framework* framework )
+  {
+    if( framework )
+    {
+      framework->AppStatusHandler( APP_RESUME, nullptr );
+    }
+  }
+
+  /**
+   * Called by the native activity loop when the application input touch event is processed.
+   */
+  static void NativeAppTouchEvent( Framework* framework, Dali::TouchPoint& touchPoint, int64_t timeStamp )
+  {
+    Dali::Adaptor::Get().FeedTouchPoint( touchPoint, timeStamp );
+  }
+
+  /**
+   * Called by the native activity loop when the application input key event is processed.
+   */
+  static void NativeAppKeyEvent( Framework* framework, Dali::KeyEvent& keyEvent )
+  {
+    Dali::Adaptor::Get().FeedKeyEvent( keyEvent );
+  }
+
+  /**
+   * Called by the native activity loop when the application APP_CMD_DESTROY event is processed.
+   */
+  static void NativeAppDestroyed( Framework* framework )
+  {
+    if( framework )
+    {
+      framework->AppStatusHandler( APP_DESTROYED, nullptr );
+    }
+  }
+
+/*
+  Order of events:
+
+  APP_CMD_START
+  APP_CMD_RESUME
+  APP_CMD_INIT_WINDOW
+  APP_CMD_GAINED_FOCUS
+
+  APP_CMD_PAUSE
+  APP_CMD_LOST_FOCUS
+  APP_CMD_SAVE_STATE
+  APP_CMD_STOP
+  APP_CMD_TERM_WINDOW
+*/
+
+  static void HandleAppCmd(struct android_app* app, int32_t cmd)
+  {
+    Framework* framework = AndroidFramework::GetImplementation( AndroidFramework::Get() ).GetFramework();
+    switch( cmd )
+    {
+      case APP_CMD_SAVE_STATE:
+        break;
+      case APP_CMD_START:
+        break;
+      case APP_CMD_STOP:
+        break;
+      case APP_CMD_RESUME:
+        break;
+      case APP_CMD_PAUSE:
+        break;
+      case APP_CMD_INIT_WINDOW:
+        // The window is being shown, get it ready.
+        AndroidFramework::Get().SetApplicationWindow( app->window );
+        Dali::Internal::Adaptor::Framework::Impl::NativeWindowCreated( framework, app->window );
+        Dali::Internal::Adaptor::Framework::Impl::NativeAppResumed( framework );
+        break;
+      case APP_CMD_TERM_WINDOW:
+        // The window is being hidden or closed, clean it up.
+        AndroidFramework::Get().SetApplicationWindow( nullptr );
+        Dali::Internal::Adaptor::Framework::Impl::NativeAppPaused( framework );
+        Dali::Internal::Adaptor::Framework::Impl::NativeWindowDestroyed( framework, app->window );
+        break;
+      case APP_CMD_GAINED_FOCUS:
+        break;
+      case APP_CMD_LOST_FOCUS:
+        break;
+      case APP_CMD_DESTROY:
+        Dali::Internal::Adaptor::Framework::Impl::NativeAppPaused( framework );
+        Dali::Internal::Adaptor::Framework::Impl::NativeAppDestroyed( framework );
+        break;
+    }
+  }
+
+  static int32_t HandleAppInput(struct android_app* app, AInputEvent* event)
+  {
+    Framework* framework = AndroidFramework::GetImplementation( AndroidFramework::Get() ).GetFramework();
+
+    if( AInputEvent_getType( event ) == AINPUT_EVENT_TYPE_MOTION )
+    {
+      int32_t deviceId = AInputEvent_getDeviceId( event );
+      float x = AMotionEvent_getX( event, 0 );
+      float y = AMotionEvent_getY( event, 0 );
+      TouchPoint::State state = TouchPoint::Down;
+      int32_t action = AMotionEvent_getAction( event );
+      int64_t timeStamp = AMotionEvent_getEventTime( event );
+
+      switch ( action & AMOTION_EVENT_ACTION_MASK )
+      {
+      case AMOTION_EVENT_ACTION_DOWN:
+        break;
+      case AMOTION_EVENT_ACTION_UP:
+        state = TouchPoint::Up;
+        break;
+      case AMOTION_EVENT_ACTION_MOVE:
+        state = TouchPoint::Motion;
+        break;
+      case AMOTION_EVENT_ACTION_CANCEL:
+        state = TouchPoint::Interrupted;
+        break;
+      case AMOTION_EVENT_ACTION_OUTSIDE:
+        state = TouchPoint::Leave;
+        break;
+      }
+
+      Dali::TouchPoint point( deviceId, state, x, y );
+      Dali::Internal::Adaptor::Framework::Impl::NativeAppTouchEvent( framework, point, timeStamp );
+      return 1;
+    }
+    else if ( AInputEvent_getType( event ) == AINPUT_EVENT_TYPE_KEY )
+    {
+      int32_t deviceId = AInputEvent_getDeviceId( event );
+      int32_t keyCode = AKeyEvent_getKeyCode( event );
+      int32_t action = AKeyEvent_getAction( event );
+      int64_t timeStamp = AKeyEvent_getEventTime( event );
+
+      KeyEvent::State state = KeyEvent::Down;
+      switch ( action )
+      {
+      case AKEY_EVENT_ACTION_DOWN:
+        break;
+      case AKEY_EVENT_ACTION_UP:
+        state = KeyEvent::Up;
+        break;
+      }
+
+      std::string keyName = "";
+      switch( keyCode )
+      {
+      case 4:
+        keyName = "XF86Back";
+        break;
+      default:
+        break;
+      }
+      Dali::KeyEvent keyEvent( keyName, "", keyCode, 0, timeStamp, state );
+      Dali::Internal::Adaptor::Framework::Impl::NativeAppKeyEvent( framework, keyEvent );
+      return 1;
+    }
+
+    return 0;
+  }
+
+  static void HandleAppIdle(struct android_app* app, struct android_poll_source* source) {
+    Framework* framework = AndroidFramework::GetImplementation( AndroidFramework::Get() ).GetFramework();
+    if( framework && framework->mImpl )
+    {
+      framework->mImpl->OnIdle();
+    }
+  }
+
+};
+
+Framework::Framework( Framework::Observer& observer, int *argc, char ***argv, Type type )
+: mObserver( observer ),
+  mInitialised( false ),
+  mPaused(false),
+  mRunning( false ),
+  mArgc( argc ),
+  mArgv( argv ),
+  mBundleName( "" ),
+  mBundleId( "" ),
+  mAbortHandler( MakeCallback( this, &Framework::AbortCallback ) ),
+  mImpl( NULL )
+{
+  mImpl = new Impl( this );
+}
+
+Framework::~Framework()
+{
+  if( mRunning )
+  {
+    Quit();
+  }
+
+  delete mImpl;
+  mImpl = nullptr;
+}
+
+void Framework::Run()
+{
+  struct android_app* app = AndroidFramework::Get().GetNativeApplication();
+  app->onAppCmd = Framework::Impl::HandleAppCmd;
+  app->onInputEvent = Framework::Impl::HandleAppInput;
+
+  struct android_poll_source* source;
+  struct android_poll_source idlePollSource;
+  idlePollSource.id = LOOPER_ID_USER;
+  idlePollSource.app = app;
+  idlePollSource.process = Impl::HandleAppIdle;
+
+  int idlePipe[2];
+  if( pipe( idlePipe ) )
+  {
+    DALI_LOG_ERROR( "Failed to open idle pipe\n" );
+    return;
+  }
+
+  mImpl->mIdleReadPipe = idlePipe[0];
+  mImpl->mIdleWritePipe = idlePipe[1];
+  ALooper_addFd( app->looper,
+      idlePipe[0], LOOPER_ID_USER, ALOOPER_EVENT_INPUT, NULL, &idlePollSource );
+
+  mRunning = true;
+
+  // Read all pending events.
+  int events;
+  int idleTimeout = -1;
+
+  while( true )
+  {
+    if ( mImpl )
+    {
+      idleTimeout = mImpl->GetIdleTimeout();
+    }
+
+    int id = ALooper_pollAll( idleTimeout, NULL, &events, (void**)&source );
+
+    // Process the error.
+    if( id == ALOOPER_POLL_ERROR )
+    {
+       DALI_LOG_ERROR( "ALooper error\n" );
+       Quit();
+       std::abort();
+    }
+
+    // Process the timeout, trigger OnIdle.
+    if( id == ALOOPER_POLL_TIMEOUT )
+    {
+      int8_t msg = 1;
+      write( mImpl->mIdleWritePipe, &msg, sizeof( msg ) );
+    }
+
+    // Process the application event.
+    if( id >= 0 && source != NULL )
+    {
+      source->process( app, source );
+    }
+
+    // Check if we are exiting.
+    if( app->destroyRequested )
+    {
+      break;
+    }
+  }
+
+  while (!mImpl->mIdleCallbacks.empty())
+  {
+    mImpl->mIdleCallbacks.pop();
+  }
+
+  mImpl->mRemovedIdleCallbacks.clear();
+  mImpl->mIdleId = 0;
+
+  ALooper_removeFd( app->looper, idlePipe[0] );
+  if ( mImpl )
+  {
+    mImpl->mIdleReadPipe = -1;
+    mImpl->mIdleWritePipe = -1;
+  }
+  close( idlePipe[0] );
+  close( idlePipe[1] );
+
+  mRunning = false;
+}
+
+unsigned int Framework::AddIdle( int timeout, void* data, bool ( *callback )( void *data ) )
+{
+  if( mImpl )
+  {
+    return mImpl->AddIdle( timeout, data, callback );
+  }
+
+  return -1;
+}
+void Framework::RemoveIdle( unsigned int id )
+{
+  if( mImpl )
+  {
+    mImpl->RemoveIdle( id );
+  }
+}
+
+void Framework::Quit()
+{
+  struct android_app* app = AndroidFramework::Get().GetNativeApplication();
+  if( app && !app->destroyRequested && !mImpl->mFinishRequested )
+  {
+    mImpl->mFinishRequested = true;
+    ANativeActivity_finish( app->activity );
+  }
+}
+
+bool Framework::IsMainLoopRunning()
+{
+  return mRunning;
+}
+
+void Framework::AddAbortCallback( CallbackBase* callback )
+{
+  mImpl->mAbortCallBack = callback;
+}
+
+std::string Framework::GetBundleName() const
+{
+  return mBundleName;
+}
+
+void Framework::SetBundleName(const std::string& name)
+{
+  mBundleName = name;
+}
+
+std::string Framework::GetBundleId() const
+{
+  return mBundleId;
+}
+
+std::string Framework::GetResourcePath()
+{
+  return DALI_DATA_RO_DIR;
+}
+
+std::string Framework::GetDataPath()
+{
+  return "";
+}
+
+void Framework::SetBundleId(const std::string& id)
+{
+  mBundleId = id;
+}
+
+void Framework::AbortCallback( )
+{
+  // if an abort call back has been installed run it.
+  if( mImpl->mAbortCallBack )
+  {
+    CallbackBase::Execute( *mImpl->mAbortCallBack );
+  }
+  else
+  {
+    Quit();
+  }
+}
+
+bool Framework::AppStatusHandler(int type, void* data)
+{
+  switch (type)
+  {
+    case APP_WINDOW_CREATED:
+      if( !mInitialised )
+      {
+        mObserver.OnInit();
+        mInitialised = true;
+      }
+
+      mObserver.OnSurfaceCreated( data );
+      break;
+
+    case APP_RESET:
+      mObserver.OnReset();
+      break;
+
+    case APP_RESUME:
+      mObserver.OnResume();
+      break;
+
+    case APP_WINDOW_DESTROYED:
+      mObserver.OnSurfaceDestroyed( data );
+      break;
+
+    case APP_PAUSE:
+      mObserver.OnPause();
+      break;
+
+    case APP_LANGUAGE_CHANGE:
+      mObserver.OnLanguageChanged();
+      break;
+
+    case APP_DESTROYED:
+      mObserver.OnTerminate();
+      mInitialised = false;
+      break;
+
+    default:
+      break;
+  }
+
+  return true;
+}
+
+void Framework::InitThreads()
+{
+}
+
+std::string Framework::GetLanguage() const
+{
+  return mImpl->GetLanguage();
+}
+
+std::string Framework::GetRegion() const
+{
+  return mImpl->GetRegion();
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/adaptor/androidjni/framework-androidjni.cpp b/dali/internal/adaptor/androidjni/framework-androidjni.cpp
new file mode 100644 (file)
index 0000000..7e932c6
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor/common/framework.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/adaptor-framework/android/android-framework.h>
+#include <dali/public-api/adaptor-framework/application.h>
+#include <dali/devel-api/adaptor-framework/application-devel.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/application-impl.h>
+#include <dali/internal/adaptor/android/android-framework-impl.h>
+#include <dali/internal/system/common/callback-manager.h>
+
+using namespace Dali;
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Impl to hide android data members
+ */
+struct Framework::Impl
+{
+  // Constructor
+
+  Impl( Framework* framework )
+  : mAbortCallBack( nullptr ),
+    mCallbackManager( CallbackManager::New() ),
+    mLanguage( "NOT_SUPPORTED" ),
+    mRegion( "NOT_SUPPORTED" )
+  {
+    AndroidFramework::GetImplementation( AndroidFramework::Get() ).SetFramework( framework );
+  }
+
+  ~Impl()
+  {
+    AndroidFramework::GetImplementation( AndroidFramework::Get() ).SetFramework( nullptr );
+
+    delete mAbortCallBack;
+    mAbortCallBack = nullptr;
+
+    // we're quiting the main loop so
+    // mCallbackManager->RemoveAllCallBacks() does not need to be called
+    // to delete our abort handler
+    delete mCallbackManager;
+    mCallbackManager = nullptr;
+  }
+
+  std::string GetLanguage() const
+  {
+    return mLanguage;
+  }
+
+  std::string GetRegion() const
+  {
+    return mRegion;
+  }
+
+  CallbackBase* mAbortCallBack;
+  CallbackManager* mCallbackManager;
+  std::string mLanguage;
+  std::string mRegion;
+};
+
+Framework::Framework( Framework::Observer& observer, int *argc, char ***argv, Type type )
+: mObserver( observer ),
+  mInitialised( false ),
+  mPaused( false ),
+  mRunning( false ),
+  mArgc( argc ),
+  mArgv( argv ),
+  mBundleName( "" ),
+  mBundleId( "" ),
+  mAbortHandler( MakeCallback( this, &Framework::AbortCallback ) ),
+  mImpl( NULL )
+{
+  mImpl = new Impl( this );
+}
+
+Framework::~Framework()
+{
+  if( mRunning )
+  {
+    Quit();
+  }
+
+  delete mImpl;
+  mImpl = nullptr;
+}
+
+void Framework::Run()
+{
+  AndroidFramework::GetImplementation( AndroidFramework::Get() ).SetFramework( this );
+  mRunning = true;
+}
+
+unsigned int Framework::AddIdle( int timeout, void* data, bool ( *callback )( void *data ) )
+{
+  JNIEnv *env = nullptr;
+  JavaVM* javaVM = AndroidFramework::Get().GetJVM();
+  if( javaVM == nullptr || javaVM->GetEnv( reinterpret_cast<void **>( &env ), JNI_VERSION_1_6 ) != JNI_OK )
+  {
+    DALI_LOG_ERROR("Couldn't get JNI env.");
+    return -1;
+  }
+
+  jclass clazz = env->FindClass( "com/sec/daliview/DaliView" );
+  if ( !clazz )
+  {
+    DALI_LOG_ERROR("Couldn't find com.sec.daliview.DaliView.");
+    return -1;
+  }
+
+  jmethodID addIdle = env->GetStaticMethodID( clazz, "addIdle", "(JJJ)I" );
+  if (!addIdle)
+  {
+    DALI_LOG_ERROR("Couldn't find com.sec.daliview.DaliView.addIdle.");
+    return -1;
+  }
+
+  jint id = env->CallStaticIntMethod( clazz, addIdle, reinterpret_cast<jlong>( callback ), reinterpret_cast<jlong>( data ), static_cast<jlong>( timeout ) );
+  return static_cast<unsigned int>( id );
+}
+
+void Framework::RemoveIdle( unsigned int id )
+{
+  JNIEnv *env = nullptr;
+  JavaVM* javaVM = AndroidFramework::Get().GetJVM();
+  if( javaVM == nullptr || javaVM->GetEnv( reinterpret_cast<void **>( &env ), JNI_VERSION_1_6 ) != JNI_OK )
+  {
+    DALI_LOG_ERROR("Couldn't get JNI env.");
+    return;
+  }
+
+  jclass clazz = env->FindClass( "com/sec/daliview/DaliView" );
+  if( !clazz )
+  {
+    DALI_LOG_ERROR("Couldn't find com.sec.daliview.DaliView.");
+    return;
+  }
+
+  jmethodID removeIdle = env->GetStaticMethodID( clazz, "removeIdle", "(I)V" );
+  if( !removeIdle )
+  {
+    DALI_LOG_ERROR("Couldn't find com.sec.daliview.DaliView.removeIdle.");
+    return;
+  }
+
+  env->CallStaticVoidMethod( clazz, removeIdle, static_cast<jint>( id ) );
+}
+
+void Framework::Quit()
+{
+  DALI_LOG_ERROR("Quit does nothing for DaliView!");
+}
+
+bool Framework::IsMainLoopRunning()
+{
+  return mRunning;
+}
+
+void Framework::AddAbortCallback( CallbackBase* callback )
+{
+  mImpl->mAbortCallBack = callback;
+}
+
+std::string Framework::GetBundleName() const
+{
+  return mBundleName;
+}
+
+void Framework::SetBundleName(const std::string& name)
+{
+  mBundleName = name;
+}
+
+std::string Framework::GetBundleId() const
+{
+  return mBundleId;
+}
+
+std::string Framework::GetResourcePath()
+{
+  return DALI_DATA_RO_DIR;
+}
+
+std::string Framework::GetDataPath()
+{
+  return "";
+}
+
+void Framework::SetBundleId(const std::string& id)
+{
+  mBundleId = id;
+}
+
+void Framework::AbortCallback( )
+{
+  // if an abort call back has been installed run it.
+  if (mImpl->mAbortCallBack)
+  {
+    CallbackBase::Execute( *mImpl->mAbortCallBack );
+  }
+  else
+  {
+    Quit();
+  }
+}
+
+bool Framework::AppStatusHandler(int type, void* data)
+{
+  switch (type)
+  {
+    case APP_WINDOW_CREATED:
+      if( !mInitialised )
+      {
+        mObserver.OnInit();
+        mInitialised = true;
+      }
+
+      mObserver.OnSurfaceCreated( data );
+      break;
+
+    case APP_WINDOW_DESTROYED:
+      mObserver.OnSurfaceDestroyed( data );
+      break;
+
+    case APP_RESET:
+      mObserver.OnReset();
+      break;
+
+    case APP_RESUME:
+      mObserver.OnResume();
+      break;
+
+    case APP_PAUSE:
+      mObserver.OnPause();
+      break;
+
+    case APP_LANGUAGE_CHANGE:
+      mObserver.OnLanguageChanged();
+      break;
+
+    case APP_DESTROYED:
+      mObserver.OnTerminate();
+      mRunning = false;
+      mPaused = false;
+      mInitialised = false;
+      break;
+
+    default:
+      break;
+  }
+
+  return true;
+}
+
+void Framework::InitThreads()
+{
+}
+
+std::string Framework::GetLanguage() const
+{
+  return mImpl->GetLanguage();
+}
+
+std::string Framework::GetRegion() const
+{
+  return mImpl->GetRegion();
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/adaptor/common/adaptor-builder-impl.cpp b/dali/internal/adaptor/common/adaptor-builder-impl.cpp
new file mode 100644 (file)
index 0000000..37332b1
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor/common/adaptor-builder-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/internal/graphics/gles/egl-graphics-factory.h>
+#include <dali/internal/window-system/common/display-utils.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+AdaptorBuilder::AdaptorBuilder()
+{
+  // Construct Graphics Factory
+  mGraphicsFactory = Utils::MakeUnique< GraphicsFactory >();
+}
+
+GraphicsFactory& AdaptorBuilder::GetGraphicsFactory() const
+{
+  return *mGraphicsFactory.get();
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/adaptor/common/adaptor-builder-impl.h b/dali/internal/adaptor/common/adaptor-builder-impl.h
new file mode 100644 (file)
index 0000000..ab09a34
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef DALI_INTERNAL_ADAPTOR_BUILDER_IMPL_H
+#define DALI_INTERNAL_ADAPTOR_BUILDER_IMPL_H
+
+/*
+ * Copyright (c) 2018 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 <dali/internal/system/common/environment-options.h>
+#include <dali/internal/graphics/gles/egl-graphics-factory.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Implementation of the Adaptor Builder class.
+ */
+class AdaptorBuilder
+{
+public:
+
+  /**
+   * Constructor
+   */
+  AdaptorBuilder();
+
+
+  /**
+   * Destructor
+   */
+  ~AdaptorBuilder() {};
+
+
+public:
+
+  /**
+   * @return reference to the GraphicsFactory object
+   */
+  GraphicsFactory& GetGraphicsFactory() const;
+
+
+private:
+  // Eliminate copy and assigned operations
+  AdaptorBuilder(const AdaptorBuilder&) = delete;
+  AdaptorBuilder& operator=(AdaptorBuilder&) = delete;
+
+
+private:
+  std::unique_ptr< GraphicsFactory > mGraphicsFactory; ///< GraphicsFactory object
+
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_BUILDER_IMPL_H
diff --git a/dali/internal/adaptor/common/adaptor-impl.cpp b/dali/internal/adaptor/common/adaptor-impl.cpp
new file mode 100755 (executable)
index 0000000..e06310a
--- /dev/null
@@ -0,0 +1,1174 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/adaptor/common/adaptor-builder-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/object/any.h>
+#include <dali/devel-api/actors/actor-devel.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/core.h>
+#include <dali/integration-api/context-notifier.h>
+#include <dali/integration-api/profiling.h>
+#include <dali/integration-api/input-options.h>
+#include <dali/integration-api/events/key-event-integ.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/wheel-event-integ.h>
+#include <dali/integration-api/processor-interface.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/internal/system/common/thread-controller.h>
+#include <dali/internal/system/common/performance-interface-factory.h>
+#include <dali/internal/adaptor/common/lifecycle-observer.h>
+#include <dali/internal/adaptor/common/thread-controller-interface.h>
+
+#include <dali/internal/graphics/gles/egl-graphics-factory.h>
+#include <dali/internal/graphics/gles/egl-graphics.h> // Temporary until Core is abstracted
+
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+#include <dali/internal/system/common/callback-manager.h>
+#include <dali/internal/accessibility/common/tts-player-impl.h>
+#include <dali/internal/accessibility/common/accessibility-adaptor-impl.h>
+#include <dali/internal/window-system/common/event-handler.h>
+#include <dali/internal/graphics/gles/gl-proxy-implementation.h>
+#include <dali/internal/graphics/gles/gl-implementation.h>
+#include <dali/internal/graphics/gles/egl-sync-implementation.h>
+#include <dali/internal/graphics/common/egl-image-extensions.h>
+#include <dali/internal/clipboard/common/clipboard-impl.h>
+#include <dali/internal/system/common/object-profiler.h>
+#include <dali/internal/window-system/common/display-connection.h>
+#include <dali/internal/window-system/common/display-utils.h> // For Utils::MakeUnique
+#include <dali/internal/window-system/common/window-impl.h>
+#include <dali/internal/window-system/common/window-render-surface.h>
+
+#include <dali/internal/system/common/logging.h>
+
+#include <dali/internal/system/common/locale-utils.h>
+#include <dali/internal/imaging/common/image-loader-plugin-proxy.h>
+#include <dali/internal/imaging/common/image-loader.h>
+
+#include <dali/internal/system/common/configuration-manager.h>
+#include <dali/internal/system/common/environment-variables.h>
+
+using Dali::TextAbstraction::FontClient;
+
+extern std::string GetSystemCachePath();
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+thread_local Adaptor* gThreadLocalAdaptor = NULL; // raw thread specific pointer to allow Adaptor::Get
+
+} // unnamed namespace
+
+Dali::Adaptor* Adaptor::New( Dali::Integration::SceneHolder window, Dali::RenderSurfaceInterface *surface, Dali::Configuration::ContextLoss configuration, EnvironmentOptions* environmentOptions )
+{
+  Dali::Adaptor* adaptor = new Dali::Adaptor;
+  Adaptor* impl = new Adaptor( window, *adaptor, surface, environmentOptions );
+  adaptor->mImpl = impl;
+
+  Dali::Internal::Adaptor::AdaptorBuilder* mAdaptorBuilder = new AdaptorBuilder();
+  auto graphicsFactory = mAdaptorBuilder->GetGraphicsFactory();
+
+  impl->Initialize( graphicsFactory, configuration );
+  delete mAdaptorBuilder; // Not needed anymore as the graphics interface has now been created
+
+  return adaptor;
+}
+
+Dali::Adaptor* Adaptor::New( Dali::Integration::SceneHolder window, Dali::Configuration::ContextLoss configuration, EnvironmentOptions* environmentOptions )
+{
+  Internal::Adaptor::SceneHolder& windowImpl = Dali::GetImplementation( window );
+  Dali::Adaptor* adaptor = New( window, windowImpl.GetSurface(), configuration, environmentOptions );
+  windowImpl.SetAdaptor( *adaptor );
+  return adaptor;
+}
+
+Dali::Adaptor* Adaptor::New( GraphicsFactory& graphicsFactory, Dali::Integration::SceneHolder window, Dali::RenderSurfaceInterface *surface, Dali::Configuration::ContextLoss configuration, EnvironmentOptions* environmentOptions )
+{
+  Dali::Adaptor* adaptor = new Dali::Adaptor; // Public adaptor
+  Adaptor* impl = new Adaptor( window, *adaptor, surface, environmentOptions ); // Impl adaptor
+  adaptor->mImpl = impl;
+
+  impl->Initialize( graphicsFactory, configuration );
+
+  return adaptor;
+} // Called second
+
+Dali::Adaptor* Adaptor::New( GraphicsFactory& graphicsFactory, Dali::Integration::SceneHolder window, Dali::Configuration::ContextLoss configuration, EnvironmentOptions* environmentOptions )
+{
+  Internal::Adaptor::SceneHolder& windowImpl = Dali::GetImplementation( window );
+  Dali::Adaptor* adaptor = New( graphicsFactory, window, windowImpl.GetSurface(), configuration, environmentOptions );
+  windowImpl.SetAdaptor( *adaptor );
+  return adaptor;
+} // Called first
+
+void Adaptor::Initialize( GraphicsFactory& graphicsFactory, Dali::Configuration::ContextLoss configuration )
+{
+  // all threads here (event, update, and render) will send their logs to TIZEN Platform's LogMessage handler.
+  Dali::Integration::Log::LogFunction logFunction( Dali::TizenPlatform::LogMessage );
+  mEnvironmentOptions->SetLogFunction( logFunction );
+  mEnvironmentOptions->InstallLogFunction(); // install logging for main thread
+
+  mPlatformAbstraction = new TizenPlatform::TizenPlatformAbstraction;
+
+  std::string path;
+  GetDataStoragePath( path );
+  mPlatformAbstraction->SetDataStoragePath( path );
+
+  if( mEnvironmentOptions->PerformanceServerRequired() )
+  {
+    mPerformanceInterface = PerformanceInterfaceFactory::CreateInterface( *this, *mEnvironmentOptions );
+  }
+
+  mEnvironmentOptions->CreateTraceManager( mPerformanceInterface );
+  mEnvironmentOptions->InstallTraceFunction(); // install tracing for main thread
+
+  mCallbackManager = CallbackManager::New();
+
+  Dali::Internal::Adaptor::SceneHolder* defaultWindow = mWindows.front();
+
+  DALI_ASSERT_DEBUG( defaultWindow->GetSurface() && "Surface not initialized" );
+
+  mGraphics = &( graphicsFactory.Create() );
+  mGraphics->Initialize( mEnvironmentOptions );
+
+  auto eglGraphics = static_cast<EglGraphics *>( mGraphics ); // This interface is temporary until Core has been updated to match
+
+  // This will only be created once
+  eglGraphics->Create();
+
+  GlImplementation& mGLES = eglGraphics->GetGlesInterface();
+  EglSyncImplementation& eglSyncImpl = eglGraphics->GetSyncImplementation();
+  EglContextHelperImplementation& eglContextHelperImpl = eglGraphics->GetContextHelperImplementation();
+
+  mCore = Integration::Core::New( *this,
+                                  *mPlatformAbstraction,
+                                  mGLES,
+                                  eglSyncImpl,
+                                  eglContextHelperImpl,
+                                  ( 0u != mEnvironmentOptions->GetRenderToFboInterval() ) ? Integration::RenderToFrameBuffer::TRUE : Integration::RenderToFrameBuffer::FALSE,
+                                  mGraphics->GetDepthBufferRequired(),
+                                  mGraphics->GetStencilBufferRequired() );
+
+  defaultWindow->SetAdaptor( Get() );
+
+  Dali::Integration::SceneHolder defaultSceneHolder( defaultWindow );
+
+  mWindowCreatedSignal.Emit( defaultSceneHolder );
+
+  const unsigned int timeInterval = mEnvironmentOptions->GetObjectProfilerInterval();
+  if( 0u < timeInterval )
+  {
+    mObjectProfiler = new ObjectProfiler( timeInterval );
+  }
+
+  mNotificationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &Adaptor::ProcessCoreEvents ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER);
+
+  mDisplayConnection = Dali::DisplayConnection::New( *mGraphics, defaultWindow->GetSurface()->GetSurfaceType() );
+
+  mThreadController = new ThreadController( *this, *mEnvironmentOptions );
+
+  // Should be called after Core creation
+  if( mEnvironmentOptions->GetPanGestureLoggingLevel() )
+  {
+    Integration::EnableProfiling( Dali::Integration::PROFILING_TYPE_PAN_GESTURE );
+  }
+  if( mEnvironmentOptions->GetPanGesturePredictionMode() >= 0 )
+  {
+    Integration::SetPanGesturePredictionMode(mEnvironmentOptions->GetPanGesturePredictionMode());
+  }
+  if( mEnvironmentOptions->GetPanGesturePredictionAmount() >= 0 )
+  {
+    Integration::SetPanGesturePredictionAmount(mEnvironmentOptions->GetPanGesturePredictionAmount());
+  }
+  if( mEnvironmentOptions->GetPanGestureMaximumPredictionAmount() >= 0 )
+  {
+    Integration::SetPanGestureMaximumPredictionAmount(mEnvironmentOptions->GetPanGestureMaximumPredictionAmount());
+  }
+  if( mEnvironmentOptions->GetPanGestureMinimumPredictionAmount() >= 0 )
+  {
+    Integration::SetPanGestureMinimumPredictionAmount(mEnvironmentOptions->GetPanGestureMinimumPredictionAmount());
+  }
+  if( mEnvironmentOptions->GetPanGesturePredictionAmountAdjustment() >= 0 )
+  {
+    Integration::SetPanGesturePredictionAmountAdjustment(mEnvironmentOptions->GetPanGesturePredictionAmountAdjustment());
+  }
+  if( mEnvironmentOptions->GetPanGestureSmoothingMode() >= 0 )
+  {
+    Integration::SetPanGestureSmoothingMode(mEnvironmentOptions->GetPanGestureSmoothingMode());
+  }
+  if( mEnvironmentOptions->GetPanGestureSmoothingAmount() >= 0.0f )
+  {
+    Integration::SetPanGestureSmoothingAmount(mEnvironmentOptions->GetPanGestureSmoothingAmount());
+  }
+  if( mEnvironmentOptions->GetPanGestureUseActualTimes() >= 0 )
+  {
+    Integration::SetPanGestureUseActualTimes( mEnvironmentOptions->GetPanGestureUseActualTimes() == 0 ? true : false );
+  }
+  if( mEnvironmentOptions->GetPanGestureInterpolationTimeRange() >= 0 )
+  {
+    Integration::SetPanGestureInterpolationTimeRange( mEnvironmentOptions->GetPanGestureInterpolationTimeRange() );
+  }
+  if( mEnvironmentOptions->GetPanGestureScalarOnlyPredictionEnabled() >= 0 )
+  {
+    Integration::SetPanGestureScalarOnlyPredictionEnabled( mEnvironmentOptions->GetPanGestureScalarOnlyPredictionEnabled() == 0 ? true : false  );
+  }
+  if( mEnvironmentOptions->GetPanGestureTwoPointPredictionEnabled() >= 0 )
+  {
+    Integration::SetPanGestureTwoPointPredictionEnabled( mEnvironmentOptions->GetPanGestureTwoPointPredictionEnabled() == 0 ? true : false  );
+  }
+  if( mEnvironmentOptions->GetPanGestureTwoPointInterpolatePastTime() >= 0 )
+  {
+    Integration::SetPanGestureTwoPointInterpolatePastTime( mEnvironmentOptions->GetPanGestureTwoPointInterpolatePastTime() );
+  }
+  if( mEnvironmentOptions->GetPanGestureTwoPointVelocityBias() >= 0.0f )
+  {
+    Integration::SetPanGestureTwoPointVelocityBias( mEnvironmentOptions->GetPanGestureTwoPointVelocityBias() );
+  }
+  if( mEnvironmentOptions->GetPanGestureTwoPointAccelerationBias() >= 0.0f )
+  {
+    Integration::SetPanGestureTwoPointAccelerationBias( mEnvironmentOptions->GetPanGestureTwoPointAccelerationBias() );
+  }
+  if( mEnvironmentOptions->GetPanGestureMultitapSmoothingRange() >= 0 )
+  {
+    Integration::SetPanGestureMultitapSmoothingRange( mEnvironmentOptions->GetPanGestureMultitapSmoothingRange() );
+  }
+  if( mEnvironmentOptions->GetMinimumPanDistance() >= 0 )
+  {
+    Integration::SetPanGestureMinimumDistance( mEnvironmentOptions->GetMinimumPanDistance() );
+  }
+  if( mEnvironmentOptions->GetMinimumPanEvents() >= 0 )
+  {
+    Integration::SetPanGestureMinimumPanEvents( mEnvironmentOptions->GetMinimumPanEvents() );
+  }
+  if( mEnvironmentOptions->GetMinimumPinchDistance() >= 0 )
+  {
+    Integration::SetPinchGestureMinimumDistance( mEnvironmentOptions->GetMinimumPinchDistance() );
+  }
+  if( mEnvironmentOptions->GetMinimumPinchTouchEvents() >= 0 )
+  {
+    Integration::SetPinchGestureMinimumTouchEvents( mEnvironmentOptions->GetMinimumPinchTouchEvents() );
+  }
+  if( mEnvironmentOptions->GetMinimumPinchTouchEventsAfterStart() >= 0 )
+  {
+    Integration::SetPinchGestureMinimumTouchEventsAfterStart( mEnvironmentOptions->GetMinimumPinchTouchEventsAfterStart() );
+  }
+  if( mEnvironmentOptions->GetMinimumRotationTouchEvents() >= 0 )
+  {
+    Integration::SetRotationGestureMinimumTouchEvents( mEnvironmentOptions->GetMinimumRotationTouchEvents() );
+  }
+  if( mEnvironmentOptions->GetMinimumRotationTouchEventsAfterStart() >= 0 )
+  {
+    Integration::SetRotationGestureMinimumTouchEventsAfterStart( mEnvironmentOptions->GetMinimumRotationTouchEventsAfterStart() );
+  }
+  if( mEnvironmentOptions->GetLongPressMinimumHoldingTime() >= 0 )
+  {
+    Integration::SetLongPressMinimumHoldingTime( mEnvironmentOptions->GetLongPressMinimumHoldingTime() );
+  }
+
+  std::string systemCachePath = GetSystemCachePath();
+  if( ! systemCachePath.empty() )
+  {
+    const int dir_err = system( std::string( "mkdir " + systemCachePath ).c_str() );
+    if (-1 == dir_err)
+    {
+        printf( "Error creating system cache directory: %s!\n", systemCachePath.c_str() );
+        exit(1);
+    }
+  }
+
+  mConfigurationManager = Utils::MakeUnique<ConfigurationManager>( systemCachePath, eglGraphics, mThreadController );
+}
+
+Adaptor::~Adaptor()
+{
+  // Ensure stop status
+  Stop();
+
+  // set to NULL first as we do not want any access to Adaptor as it is being destroyed.
+  gThreadLocalAdaptor = NULL;
+
+  for ( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
+  {
+    (*iter)->OnDestroy();
+  }
+
+  // Clear out all the handles to Windows
+  mWindows.clear();
+
+  delete mThreadController; // this will shutdown render thread, which will call Core::ContextDestroyed before exit
+  delete mObjectProfiler;
+
+  delete mCore;
+
+  delete mDisplayConnection;
+  delete mPlatformAbstraction;
+  delete mCallbackManager;
+  delete mPerformanceInterface;
+
+  mGraphics->Destroy();
+
+  // uninstall it on this thread (main actor thread)
+  Dali::Integration::Log::UninstallLogFunction();
+
+  // Delete environment options if we own it
+  if( mEnvironmentOptionsOwned )
+  {
+    delete mEnvironmentOptions;
+  }
+}
+
+void Adaptor::Start()
+{
+  // It doesn't support restart after stop at this moment to support restarting, need more testing
+  if( READY != mState )
+  {
+    return;
+  }
+
+  mCore->Initialize();
+
+  SetupSystemInformation();
+
+  // Start the callback manager
+  mCallbackManager->Start();
+
+  Dali::Internal::Adaptor::SceneHolder* defaultWindow = mWindows.front();
+
+  unsigned int dpiHor, dpiVer;
+  dpiHor = dpiVer = 0;
+
+  defaultWindow->GetSurface()->GetDpi( dpiHor, dpiVer );
+
+  // set the DPI value for font rendering
+  FontClient fontClient = FontClient::Get();
+  fontClient.SetDpi( dpiHor, dpiVer );
+
+  // Initialize the thread controller
+  mThreadController->Initialize();
+
+  // Set max texture size
+  if( mEnvironmentOptions->GetMaxTextureSize() > 0 )
+  {
+    Dali::TizenPlatform::ImageLoader::SetMaxTextureSize( mEnvironmentOptions->GetMaxTextureSize() );
+  }
+  else
+  {
+    unsigned int maxTextureSize = mConfigurationManager->GetMaxTextureSize();
+    setenv( DALI_ENV_MAX_TEXTURE_SIZE, std::to_string( maxTextureSize ).c_str(), 1 );
+    Dali::TizenPlatform::ImageLoader::SetMaxTextureSize( maxTextureSize );
+  }
+
+  ProcessCoreEvents(); // Ensure any startup messages are processed.
+
+  // Initialize the image loader plugin
+  Internal::Adaptor::ImageLoaderPluginProxy::Initialize();
+
+  for ( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
+  {
+    (*iter)->OnStart();
+  }
+}
+
+// Dali::Internal::Adaptor::Adaptor::Pause
+void Adaptor::Pause()
+{
+  // Only pause the adaptor if we're actually running.
+  if( RUNNING == mState )
+  {
+    // Inform observers that we are about to be paused.
+    for( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
+    {
+      (*iter)->OnPause();
+    }
+
+    // Pause all windows event handlers when adaptor paused
+    for( auto window : mWindows )
+    {
+      window->Pause();
+    }
+
+    mThreadController->Pause();
+    mState = PAUSED;
+
+    // Ensure any messages queued during pause callbacks are processed by doing another update.
+    RequestUpdateOnce();
+
+    DALI_LOG_RELEASE_INFO( "Adaptor::Pause: Paused\n" );
+  }
+  else
+  {
+    DALI_LOG_RELEASE_INFO( "Adaptor::Pause: Not paused [%d]\n", mState );
+  }
+}
+
+// Dali::Internal::Adaptor::Adaptor::Resume
+void Adaptor::Resume()
+{
+  // Only resume the adaptor if we are in the suspended state.
+  if( PAUSED == mState )
+  {
+    mState = RUNNING;
+
+    // Reset the event handlers when adaptor resumed
+    for( auto window : mWindows )
+    {
+      window->Resume();
+    }
+
+    // Inform observers that we have resumed.
+    for( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
+    {
+      (*iter)->OnResume();
+    }
+
+    // Trigger processing of events queued up while paused
+    mCore->ProcessEvents();
+
+    // Do at end to ensure our first update/render after resumption includes the processed messages as well
+    mThreadController->Resume();
+
+    DALI_LOG_RELEASE_INFO( "Adaptor::Resume: Resumed\n");
+  }
+  else
+  {
+    DALI_LOG_RELEASE_INFO( "Adaptor::Resume: Not resumed [%d]\n", mState );
+  }
+}
+
+void Adaptor::Stop()
+{
+  if( RUNNING == mState ||
+      PAUSED  == mState ||
+      PAUSED_WHILE_HIDDEN == mState )
+  {
+    for( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
+    {
+      (*iter)->OnStop();
+    }
+
+    mThreadController->Stop();
+
+    // Delete the TTS player
+    for( int i =0; i < Dali::TtsPlayer::MODE_NUM; i++ )
+    {
+      if( mTtsPlayers[i] )
+      {
+        mTtsPlayers[i].Reset();
+      }
+    }
+
+    // Destroy the image loader plugin
+    Internal::Adaptor::ImageLoaderPluginProxy::Destroy();
+
+    delete mNotificationTrigger;
+    mNotificationTrigger = NULL;
+
+    mCallbackManager->Stop();
+
+    mState = STOPPED;
+
+    DALI_LOG_RELEASE_INFO( "Adaptor::Stop\n" );
+  }
+}
+
+void Adaptor::ContextLost()
+{
+  mCore->GetContextNotifier()->NotifyContextLost(); // Inform stage
+}
+
+void Adaptor::ContextRegained()
+{
+  // Inform core, so that texture resources can be reloaded
+  mCore->RecoverFromContextLoss();
+
+  mCore->GetContextNotifier()->NotifyContextRegained(); // Inform stage
+}
+
+void Adaptor::FeedTouchPoint( TouchPoint& point, int timeStamp )
+{
+  Integration::Point convertedPoint( point );
+  mWindows.front()->FeedTouchPoint( convertedPoint, timeStamp );
+}
+
+void Adaptor::FeedWheelEvent( WheelEvent& wheelEvent )
+{
+  Integration::WheelEvent event( static_cast< Integration::WheelEvent::Type >(wheelEvent.type), wheelEvent.direction, wheelEvent.modifiers, wheelEvent.point, wheelEvent.z, wheelEvent.timeStamp );
+  mWindows.front()->FeedWheelEvent( event );
+}
+
+void Adaptor::FeedKeyEvent( KeyEvent& keyEvent )
+{
+  Integration::KeyEvent convertedEvent( keyEvent );
+  mWindows.front()->FeedKeyEvent( convertedEvent );
+}
+
+void Adaptor::ReplaceSurface( Dali::Integration::SceneHolder window, Dali::RenderSurfaceInterface& newSurface )
+{
+  Internal::Adaptor::SceneHolder* windowImpl = &Dali::GetImplementation( window );
+  for( auto windowPtr : mWindows )
+  {
+    if( windowPtr == windowImpl ) // the window is not deleted
+    {
+      mResizedSignal.Emit( mAdaptor );
+
+      windowImpl->SetSurface( &newSurface );
+
+      // Flush the event queue to give the update-render thread chance
+      // to start processing messages for new camera setup etc as soon as possible
+      ProcessCoreEvents();
+
+      // This method blocks until the render thread has completed the replace.
+      mThreadController->ReplaceSurface( &newSurface );
+      break;
+    }
+  }
+}
+
+Dali::RenderSurfaceInterface& Adaptor::GetSurface() const
+{
+  return *mWindows.front()->GetSurface();
+}
+
+void Adaptor::ReleaseSurfaceLock()
+{
+  mWindows.front()->GetSurface()->ReleaseLock();
+}
+
+Dali::TtsPlayer Adaptor::GetTtsPlayer(Dali::TtsPlayer::Mode mode)
+{
+  if( !mTtsPlayers[mode] )
+  {
+    // Create the TTS player when it needed, because it can reduce launching time.
+    mTtsPlayers[mode] = TtsPlayer::New(mode);
+  }
+
+  return mTtsPlayers[mode];
+}
+
+bool Adaptor::AddIdle( CallbackBase* callback, bool hasReturnValue, bool forceAdd )
+{
+  bool idleAdded(false);
+
+  // Only add an idle if the Adaptor is actually running
+  if( RUNNING == mState || READY == mState || forceAdd )
+  {
+    idleAdded = mCallbackManager->AddIdleCallback( callback, hasReturnValue );
+  }
+
+  return idleAdded;
+}
+
+void Adaptor::RemoveIdle( CallbackBase* callback )
+{
+  mCallbackManager->RemoveIdleCallback( callback );
+}
+
+void Adaptor::ProcessIdle()
+{
+  bool idleProcessed = mCallbackManager->ProcessIdle();
+  mNotificationOnIdleInstalled = mNotificationOnIdleInstalled && !idleProcessed;
+}
+
+void Adaptor::SetPreRenderCallback( CallbackBase* callback )
+{
+  mThreadController->SetPreRenderCallback( callback );
+}
+
+bool Adaptor::AddWindow( Dali::Integration::SceneHolder childWindow, const std::string& childWindowName, const std::string& childWindowClassName, bool childWindowMode )
+{
+  Internal::Adaptor::SceneHolder& windowImpl = Dali::GetImplementation( childWindow );
+  windowImpl.SetAdaptor( Get() );
+
+  // Add the new Window to the container - the order is not important
+  mWindows.push_back( &windowImpl );
+
+  Dali::RenderSurfaceInterface* surface = windowImpl.GetSurface();
+
+  mThreadController->AddSurface( surface );
+
+  mWindowCreatedSignal.Emit( childWindow );
+
+  return true;
+}
+
+bool Adaptor::RemoveWindow( Dali::Integration::SceneHolder* childWindow )
+{
+  Internal::Adaptor::SceneHolder& windowImpl = Dali::GetImplementation( *childWindow );
+  for ( WindowContainer::iterator iter = mWindows.begin(); iter != mWindows.end(); ++iter )
+  {
+    if( *iter == &windowImpl )
+    {
+      mWindows.erase( iter );
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool Adaptor::RemoveWindow( std::string childWindowName )
+{
+  for ( WindowContainer::iterator iter = mWindows.begin(); iter != mWindows.end(); ++iter )
+  {
+    if( ( *iter )->GetName() == childWindowName )
+    {
+      mWindows.erase( iter );
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool Adaptor::RemoveWindow( Internal::Adaptor::SceneHolder* childWindow )
+{
+  for ( WindowContainer::iterator iter = mWindows.begin(); iter != mWindows.end(); ++iter )
+  {
+    if( ( *iter )->GetId() == childWindow->GetId() )
+    {
+      mWindows.erase( iter );
+      return true;
+    }
+  }
+
+  return false;
+}
+
+Dali::Adaptor& Adaptor::Get()
+{
+  DALI_ASSERT_ALWAYS( IsAvailable() && "Adaptor not instantiated" );
+  return gThreadLocalAdaptor->mAdaptor;
+}
+
+bool Adaptor::IsAvailable()
+{
+  return gThreadLocalAdaptor != NULL;
+}
+
+void Adaptor::SceneCreated()
+{
+  mCore->SceneCreated();
+}
+
+Dali::Integration::Core& Adaptor::GetCore()
+{
+  return *mCore;
+}
+
+void Adaptor::SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender )
+{
+  mThreadController->SetRenderRefreshRate( numberOfVSyncsPerRender );
+}
+
+Dali::DisplayConnection& Adaptor::GetDisplayConnectionInterface()
+{
+  DALI_ASSERT_DEBUG( mDisplayConnection && "Display connection not created" );
+  return *mDisplayConnection;
+}
+
+GraphicsInterface& Adaptor::GetGraphicsInterface()
+{
+  DALI_ASSERT_DEBUG( mGraphics && "Graphics interface not created" );
+  return *mGraphics;
+}
+
+Dali::Integration::PlatformAbstraction& Adaptor::GetPlatformAbstractionInterface()
+{
+  return *mPlatformAbstraction;
+}
+
+TriggerEventInterface& Adaptor::GetProcessCoreEventsTrigger()
+{
+  return *mNotificationTrigger;
+}
+
+SocketFactoryInterface& Adaptor::GetSocketFactoryInterface()
+{
+  return mSocketFactory;
+}
+
+Dali::RenderSurfaceInterface* Adaptor::GetRenderSurfaceInterface()
+{
+  if( !mWindows.empty() )
+  {
+    return mWindows.front()->GetSurface();
+  }
+
+  return nullptr;
+}
+
+TraceInterface& Adaptor::GetKernelTraceInterface()
+{
+  return mKernelTracer;
+}
+
+TraceInterface& Adaptor::GetSystemTraceInterface()
+{
+  return mSystemTracer;
+}
+
+PerformanceInterface* Adaptor::GetPerformanceInterface()
+{
+  return mPerformanceInterface;
+}
+
+Integration::PlatformAbstraction& Adaptor::GetPlatformAbstraction() const
+{
+  DALI_ASSERT_DEBUG( mPlatformAbstraction && "PlatformAbstraction not created" );
+  return *mPlatformAbstraction;
+}
+
+void Adaptor::GetWindowContainerInterface( WindowContainer& windows )
+{
+  windows = mWindows;
+}
+
+void Adaptor::DestroyTtsPlayer(Dali::TtsPlayer::Mode mode)
+{
+  if( mTtsPlayers[mode] )
+  {
+    mTtsPlayers[mode].Reset();
+  }
+}
+
+Any Adaptor::GetNativeWindowHandle()
+{
+  return mWindows.front()->GetNativeHandle();
+}
+
+Any Adaptor::GetNativeWindowHandle( Dali::Actor actor )
+{
+  Any nativeWindowHandle;
+
+  Dali::Integration::Scene scene = Dali::Integration::Scene::Get( actor );
+
+  for( auto sceneHolder : mWindows )
+  {
+    if ( scene == sceneHolder->GetScene() )
+    {
+      nativeWindowHandle = sceneHolder->GetNativeHandle();
+      break;
+    }
+  }
+
+  return nativeWindowHandle;
+}
+
+Any Adaptor::GetGraphicsDisplay()
+{
+  Any display;
+
+  if (mGraphics)
+  {
+    auto eglGraphics = static_cast<EglGraphics *>( mGraphics ); // This interface is temporary until Core has been updated to match
+
+    EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+    display = eglImpl.GetDisplay();
+  }
+
+  return display;
+}
+
+void Adaptor::SetUseRemoteSurface(bool useRemoteSurface)
+{
+  mUseRemoteSurface = useRemoteSurface;
+}
+
+void Adaptor::AddObserver( LifeCycleObserver& observer )
+{
+  ObserverContainer::iterator match ( find(mObservers.begin(), mObservers.end(), &observer) );
+
+  if ( match == mObservers.end() )
+  {
+    mObservers.push_back( &observer );
+  }
+}
+
+void Adaptor::RemoveObserver( LifeCycleObserver& observer )
+{
+  ObserverContainer::iterator match ( find(mObservers.begin(), mObservers.end(), &observer) );
+
+  if ( match != mObservers.end() )
+  {
+    mObservers.erase( match );
+  }
+}
+
+void Adaptor::QueueCoreEvent(const Dali::Integration::Event& event)
+{
+  if( mCore )
+  {
+    mCore->QueueEvent(event);
+  }
+}
+
+void Adaptor::ProcessCoreEvents()
+{
+  if( mCore )
+  {
+    if( mPerformanceInterface )
+    {
+      mPerformanceInterface->AddMarker( PerformanceInterface::PROCESS_EVENTS_START );
+    }
+
+    mCore->ProcessEvents();
+
+    if( mPerformanceInterface )
+    {
+      mPerformanceInterface->AddMarker( PerformanceInterface::PROCESS_EVENTS_END );
+    }
+  }
+}
+
+void Adaptor::RequestUpdate( bool forceUpdate )
+{
+  switch( mState )
+  {
+    case RUNNING:
+    {
+      mThreadController->RequestUpdate();
+      break;
+    }
+    case PAUSED:
+    case PAUSED_WHILE_HIDDEN:
+    {
+      if( forceUpdate )
+      {
+        // Update (and resource upload) without rendering
+        mThreadController->RequestUpdateOnce( UpdateMode::SKIP_RENDER );
+      }
+      break;
+    }
+    default:
+    {
+      // Do nothing
+      break;
+    }
+  }
+}
+
+void Adaptor::RequestProcessEventsOnIdle( bool forceProcess )
+{
+  // Only request a notification if the Adaptor is actually running
+  // and we haven't installed the idle notification
+  if( ( ! mNotificationOnIdleInstalled ) && ( RUNNING == mState || READY == mState || forceProcess ) )
+  {
+    mNotificationOnIdleInstalled = AddIdleEnterer( MakeCallback( this, &Adaptor::ProcessCoreEventsFromIdle ), forceProcess );
+  }
+}
+
+void Adaptor::OnWindowShown()
+{
+  if( PAUSED_WHILE_HIDDEN == mState )
+  {
+    // Adaptor can now be resumed
+    mState = PAUSED;
+
+    Resume();
+
+    // Force a render task
+    RequestUpdateOnce();
+  }
+  else if( RUNNING == mState )
+  {
+    // Force a render task
+    RequestUpdateOnce();
+
+    DALI_LOG_RELEASE_INFO( "Adaptor::OnWindowShown: Update requested.\n" );
+  }
+  else
+  {
+    DALI_LOG_RELEASE_INFO( "Adaptor::OnWindowShown: Adaptor is not paused state.[%d]\n", mState );
+  }
+}
+
+void Adaptor::OnWindowHidden()
+{
+  if( RUNNING == mState || READY == mState )
+  {
+    bool allWindowsHidden = true;
+
+    for( auto window : mWindows )
+    {
+      if ( window->IsVisible() )
+      {
+        allWindowsHidden = false;
+        break;
+      }
+    }
+
+    // Only pause the adaptor when all the windows are hidden
+    if( allWindowsHidden )
+    {
+      if( mState == RUNNING )
+      {
+        Pause();
+
+        // Adaptor cannot be resumed until any window is shown
+        mState = PAUSED_WHILE_HIDDEN;
+      }
+      else  // mState is READY
+      {
+        // Pause the adaptor after the state gets RUNNING
+        mState = PAUSED_WHILE_INITIALIZING;
+      }
+    }
+    else
+    {
+      DALI_LOG_RELEASE_INFO( "Adaptor::OnWindowHidden: Some windows are shown. Don't pause adaptor.\n" );
+    }
+  }
+  else
+  {
+    DALI_LOG_RELEASE_INFO( "Adaptor::OnWindowHidden: Adaptor is not running state.[%d]\n", mState );
+  }
+}
+
+// Dali::Internal::Adaptor::Adaptor::OnDamaged
+void Adaptor::OnDamaged( const DamageArea& area )
+{
+  // This is needed for the case where Dali window is partially obscured
+  RequestUpdate( false );
+}
+
+void Adaptor::SurfaceResizePrepare( Dali::RenderSurfaceInterface* surface, SurfaceSize surfaceSize )
+{
+  mResizedSignal.Emit( mAdaptor );
+}
+
+void Adaptor::SurfaceResizeComplete( Dali::RenderSurfaceInterface* surface, SurfaceSize surfaceSize )
+{
+  // Nofify surface resizing before flushing event queue
+  mThreadController->ResizeSurface();
+
+  // Flush the event queue to give the update-render thread chance
+  // to start processing messages for new camera setup etc as soon as possible
+  ProcessCoreEvents();
+}
+
+void Adaptor::NotifySceneCreated()
+{
+  GetCore().SceneCreated();
+
+  // Flush the event queue to give the update-render thread chance
+  // to start processing messages for new camera setup etc as soon as possible
+  ProcessCoreEvents();
+
+  // Start thread controller after the scene has been created
+  mThreadController->Start();
+
+  // Process after surface is created (registering to remote surface provider if required)
+  SurfaceInitialized();
+
+  if( mState != PAUSED_WHILE_INITIALIZING )
+  {
+    mState = RUNNING;
+
+    DALI_LOG_RELEASE_INFO( "Adaptor::NotifySceneCreated: Adaptor is running\n" );
+  }
+  else
+  {
+    mState = RUNNING;
+
+    Pause();
+
+    mState = PAUSED_WHILE_HIDDEN;
+
+    DALI_LOG_RELEASE_INFO( "Adaptor::NotifySceneCreated: Adaptor is paused\n" );
+  }
+}
+
+void Adaptor::NotifyLanguageChanged()
+{
+  mLanguageChangedSignal.Emit( mAdaptor );
+}
+
+void Adaptor::RenderOnce()
+{
+  RequestUpdateOnce();
+}
+
+const LogFactoryInterface& Adaptor::GetLogFactory()
+{
+  return *mEnvironmentOptions;
+}
+
+void Adaptor::RegisterProcessor( Integration::Processor& processor )
+{
+  GetCore().RegisterProcessor(processor);
+}
+
+void Adaptor::UnregisterProcessor( Integration::Processor& processor )
+{
+  GetCore().UnregisterProcessor(processor);
+}
+
+bool Adaptor::IsMultipleWindowSupported() const
+{
+  return mConfigurationManager->IsMultipleWindowSupported();
+}
+
+bool Adaptor::IsRenderingWindows() const
+{
+  return ( mThreadController && mThreadController->IsRenderingWindows() );
+}
+
+void Adaptor::RequestUpdateOnce()
+{
+  if( mThreadController )
+  {
+    mThreadController->RequestUpdateOnce( UpdateMode::NORMAL );
+  }
+}
+
+bool Adaptor::ProcessCoreEventsFromIdle()
+{
+  ProcessCoreEvents();
+
+  // the idle handle automatically un-installs itself
+  mNotificationOnIdleInstalled = false;
+
+  return false;
+}
+
+Dali::Internal::Adaptor::SceneHolder* Adaptor::GetWindow( Dali::Actor& actor )
+{
+  Dali::Integration::Scene scene = Dali::Integration::Scene::Get( actor );
+
+  for( auto window : mWindows )
+  {
+    if ( scene == window->GetScene() )
+    {
+      return window;
+    }
+  }
+
+  return nullptr;
+}
+
+Dali::WindowContainer Adaptor::GetWindows() const
+{
+  Dali::WindowContainer windows;
+
+  for ( auto iter = mWindows.begin(); iter != mWindows.end(); ++iter )
+  {
+    // Downcast to Dali::Window
+    Dali::Window window( dynamic_cast<Dali::Internal::Adaptor::Window*>( *iter ) );
+    if ( window )
+    {
+      windows.push_back( window );
+    }
+  }
+
+  return windows;
+}
+
+Dali::SceneHolderList Adaptor::GetSceneHolders() const
+{
+  Dali::SceneHolderList sceneHolderList;
+
+  for( auto iter = mWindows.begin(); iter != mWindows.end(); ++iter )
+  {
+    sceneHolderList.push_back( Dali::Integration::SceneHolder( *iter ) );
+  }
+
+  return sceneHolderList;
+}
+
+Adaptor::Adaptor(Dali::Integration::SceneHolder window, Dali::Adaptor& adaptor, Dali::RenderSurfaceInterface* surface, EnvironmentOptions* environmentOptions)
+: mResizedSignal(),
+  mLanguageChangedSignal(),
+  mWindowCreatedSignal(),
+  mAdaptor( adaptor ),
+  mState( READY ),
+  mCore( nullptr ),
+  mThreadController( nullptr ),
+  mGraphics( nullptr ),
+  mDisplayConnection( nullptr ),
+  mWindows(),
+  mConfigurationManager( nullptr ),
+  mPlatformAbstraction( nullptr ),
+  mCallbackManager( nullptr ),
+  mNotificationOnIdleInstalled( false ),
+  mNotificationTrigger( nullptr ),
+  mDaliFeedbackPlugin(),
+  mFeedbackController( nullptr ),
+  mTtsPlayers(),
+  mObservers(),
+  mEnvironmentOptions( environmentOptions ? environmentOptions : new EnvironmentOptions /* Create the options if not provided */),
+  mPerformanceInterface( nullptr ),
+  mKernelTracer(),
+  mSystemTracer(),
+  mObjectProfiler( nullptr ),
+  mSocketFactory(),
+  mEnvironmentOptionsOwned( environmentOptions ? false : true /* If not provided then we own the object */ ),
+  mUseRemoteSurface( false )
+{
+  DALI_ASSERT_ALWAYS( !IsAvailable() && "Cannot create more than one Adaptor per thread" );
+  mWindows.insert( mWindows.begin(), &Dali::GetImplementation( window ) );
+
+  gThreadLocalAdaptor = this;
+}
+
+void Adaptor::SetRootLayoutDirection( std::string locale )
+{
+  Dali::Stage stage = Dali::Stage::GetCurrent();
+
+  stage.GetRootLayer().SetProperty( Dali::Actor::Property::LAYOUT_DIRECTION,
+                                    static_cast< LayoutDirection::Type >( Internal::Adaptor::Locale::GetDirection( std::string( locale ) ) ) );
+}
+
+bool Adaptor::AddIdleEnterer( CallbackBase* callback, bool forceAdd )
+{
+  bool idleAdded( false );
+
+  // Only add an idle if the Adaptor is actually running
+  if( RUNNING == mState || READY == mState || forceAdd )
+  {
+    idleAdded = mCallbackManager->AddIdleEntererCallback( callback );
+  }
+
+  return idleAdded;
+}
+
+void Adaptor::RemoveIdleEnterer( CallbackBase* callback )
+{
+  mCallbackManager->RemoveIdleEntererCallback( callback );
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/adaptor/common/adaptor-impl.h b/dali/internal/adaptor/common/adaptor-impl.h
new file mode 100755 (executable)
index 0000000..c2a9ad4
--- /dev/null
@@ -0,0 +1,702 @@
+#ifndef DALI_INTERNAL_ADAPTOR_IMPL_H
+#define DALI_INTERNAL_ADAPTOR_IMPL_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/common/view-mode.h>
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/signals/callback.h>
+#include <dali/public-api/math/uint-16-pair.h>
+#include <dali/integration-api/render-controller.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/tts-player.h>
+#include <dali/devel-api/adaptor-framework/clipboard.h>
+#include <dali/integration-api/scene.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/integration-api/adaptor-framework/scene-holder-impl.h>
+#include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
+#include <dali/internal/adaptor/common/adaptor-internal-services.h>
+#include <dali/internal/graphics/common/graphics-interface.h>
+#include <dali/internal/legacy/common/tizen-platform-abstraction.h>
+#include <dali/internal/network/common/socket-factory.h>
+#include <dali/internal/system/common/core-event-interface.h>
+#include <dali/internal/system/common/environment-options.h>
+#include <dali/internal/system/common/kernel-trace.h>
+#include <dali/internal/system/common/system-trace.h>
+#include <dali/internal/window-system/common/damage-observer.h>
+#include <dali/internal/window-system/common/window-visibility-observer.h>
+
+namespace Dali
+{
+
+class RenderSurfaceInterface;
+
+namespace Integration
+{
+class Core;
+class GlAbstraction;
+class Processor;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class DisplayConnection;
+class GraphicsFactory;
+class GlImplementation;
+class GlSyncImplementation;
+class ThreadController;
+class TriggerEvent;
+class CallbackManager;
+class FeedbackPluginProxy;
+class FeedbackController;
+class VSyncMonitor;
+class PerformanceInterface;
+class LifeCycleObserver;
+class ObjectProfiler;
+class SceneHolder;
+class ConfigurationManager;
+
+/**
+ * Implementation of the Adaptor class.
+ */
+class Adaptor : public Integration::RenderController,
+                public AdaptorInternalServices,
+                public CoreEventInterface,
+                public DamageObserver,
+                public WindowVisibilityObserver
+{
+public:
+
+  using AdaptorSignalType =  Dali::Adaptor::AdaptorSignalType;
+  using WindowCreatedSignalType = Dali::Adaptor::WindowCreatedSignalType;
+
+  using SurfaceSize = Uint16Pair;          ///< Surface size type
+
+  /**
+   * Creates a New Adaptor
+   * @param[in]  window              The window handle
+   * @param[in]  surface             A render surface can be one of the following
+   *                                  - Pixmap, adaptor will use existing Pixmap to draw on to
+   *                                  - Window, adaptor will use existing Window to draw on to
+   * @param[in]  configuration       The context loss configuration ( to choose resource discard policy )
+   * @param[in]  environmentOptions  A pointer to the environment options. If NULL then one is created.
+   */
+  static Dali::Adaptor* New( Dali::Integration::SceneHolder window,
+                             Dali::RenderSurfaceInterface* surface,
+                             Dali::Configuration::ContextLoss configuration,
+                             EnvironmentOptions* environmentOptions );
+
+  /**
+   * Creates a New Adaptor
+   * @param[in]  window              The window handle
+   * @param[in]  configuration       The context loss configuration ( to choose resource discard policy )
+   * @param[in]  environmentOptions  A pointer to the environment options. If NULL then one is created.
+   */
+  static Dali::Adaptor* New( Dali::Integration::SceneHolder window,
+                             Dali::Configuration::ContextLoss configuration,
+                             EnvironmentOptions* environmentOptions );
+
+  /**
+   * Creates a New Adaptor
+   * @param[in]  graphicsFactory     A factory that creates the graphics interface
+   * @param[in]  window              The window handle
+   * @param[in]  surface             A render surface can be one of the following
+   *                                  - Pixmap, adaptor will use existing Pixmap to draw on to
+   *                                  - Window, adaptor will use existing Window to draw on to
+   * @param[in]  configuration       The context loss configuration ( to choose resource discard policy )
+   * @param[in]  environmentOptions  A pointer to the environment options. If NULL then one is created.
+   */
+  static Dali::Adaptor* New( GraphicsFactory& graphicsFactory,
+                             Dali::Integration::SceneHolder window,
+                             Dali::RenderSurfaceInterface* surface,
+                             Dali::Configuration::ContextLoss configuration,
+                             EnvironmentOptions* environmentOptions );
+
+  /**
+   * Creates a New Adaptor
+   * @param[in]  graphicsFactory     A factory that creates the graphics interface
+   * @param[in]  window              The window handle
+   * @param[in]  configuration       The context loss configuration ( to choose resource discard policy )
+   * @param[in]  environmentOptions  A pointer to the environment options. If NULL then one is created.
+   */
+  static Dali::Adaptor* New( GraphicsFactory& graphicsFactory,
+                             Dali::Integration::SceneHolder window,
+                             Dali::Configuration::ContextLoss configuration,
+                             EnvironmentOptions* environmentOptions );
+
+  /**
+   * 2-step initialisation, this should be called after creating an adaptor instance.
+   * @param[in]  graphicsFactory     A factory that creates the graphics interface
+   * @param[in]  configuration       The context loss configuration ( to choose resource discard policy )
+   */
+  void Initialize( GraphicsFactory& graphicsFactory, Dali::Configuration::ContextLoss configuration );
+
+  /**
+   * Virtual destructor.
+   */
+  virtual ~Adaptor();
+
+  /**
+   * @copydoc Dali::Adaptor::Get()
+   */
+  static Dali::Adaptor& Get();
+
+  /**
+   * @copydoc Dali::Adaptor::IsAvailable()
+   */
+  static bool IsAvailable();
+
+  /**
+   * @copydoc Dali::Core::SceneCreated();
+   */
+  void SceneCreated();
+
+public: // AdaptorInternalServices implementation
+  /**
+   * @copydoc Dali::Adaptor::Start()
+   */
+  virtual void Start();
+
+  /**
+   * @copydoc Dali::Adaptor::Pause()
+   */
+  virtual void Pause();
+
+  /**
+   * @copydoc Dali::Adaptor::Resume()
+   */
+  virtual void Resume();
+
+  /**
+   * @copydoc Dali::Adaptor::Stop()
+   */
+  virtual void Stop();
+
+  /**
+   * @copydoc Dali::Adaptor::ContextLost()
+   */
+  virtual void ContextLost();
+
+  /**
+   * @copydoc Dali::Adaptor::ContextRegained()
+   */
+  virtual void ContextRegained();
+
+  /**
+   * @copydoc Dali::EventFeeder::FeedTouchPoint()
+   */
+  virtual void FeedTouchPoint( TouchPoint& point, int timeStamp );
+
+  /**
+   * @copydoc Dali::EventFeeder::FeedWheelEvent()
+   */
+  virtual void FeedWheelEvent( WheelEvent& wheelEvent );
+
+  /**
+   * @copydoc Dali::EventFeeder::FeedKeyEvent()
+   */
+  virtual void FeedKeyEvent( KeyEvent& keyEvent );
+
+  /**
+   * @copydoc Dali::Adaptor::ReplaceSurface()
+   */
+  virtual void ReplaceSurface( Dali::Integration::SceneHolder window, Dali::RenderSurfaceInterface& surface );
+
+  /**
+   * @copydoc Dali::Adaptor::GetSurface()
+   */
+  virtual Dali::RenderSurfaceInterface& GetSurface() const;
+
+  /**
+   * @copydoc Dali::Adaptor::ReleaseSurfaceLock()
+   */
+  virtual void ReleaseSurfaceLock();
+
+  /**
+   * Retrieve the TtsPlayer.
+   * @param[in] mode The mode of TtsPlayer
+   * @return A handle to the TtsPlayer.
+   */
+  virtual Dali::TtsPlayer GetTtsPlayer(Dali::TtsPlayer::Mode mode);
+
+  /**
+   * @copydoc Dali::Adaptor::AddIdle()
+   */
+  virtual bool AddIdle( CallbackBase* callback, bool hasReturnValue, bool forceAdd );
+
+  /**
+   * Adds a new Window instance to the Adaptor
+   * @param[in]  childWindow The child window instance
+   * @param[in]  childWindowName The child window title/name
+   * @param[in]  childWindowClassName The class name that the child window belongs to
+   * @param[in]  childWindowMode The mode of the child window
+   */
+  virtual bool AddWindow( Dali::Integration::SceneHolder childWindow,
+                          const std::string& childWindowName,
+                          const std::string& childWindowClassName,
+                          bool childWindowMode );
+
+  /**
+   * Removes an existing Window instance from the Adaptor
+   * @param[in]  window The Window instance
+   */
+  virtual bool RemoveWindow( Dali::Integration::SceneHolder* childWindow );
+
+  /**
+   * Removes an existing Window instance from the Adaptor
+   * @param[in]  windowName The Window name
+   * @note If two Windows have the same name, the first one that matches will be removed
+   */
+  virtual bool RemoveWindow( std::string childWindowName );
+
+  /**
+   * @copydoc Dali::Adaptor::RemoveIdle()
+   */
+  virtual void RemoveIdle( CallbackBase* callback );
+
+  /**
+   * @copydoc Dali::Adaptor::ProcessIdle()
+   */
+  virtual void ProcessIdle();
+
+  /**
+   * Sets a pre-render callback.
+   */
+  void SetPreRenderCallback( CallbackBase* callback );
+
+  /**
+   * Removes an existing Window instance from the Adaptor
+   * @param[in]  childWindow The Window instance
+   */
+  bool RemoveWindow( Dali::Internal::Adaptor::SceneHolder* childWindow );
+
+  /**
+   * @brief Retrieve the window that the given actor is added to.
+   *
+   * @param[in] actor The actor
+   * @return The window the actor is added to or a null pointer if the actor is not added to any widnow.
+   */
+  Dali::Internal::Adaptor::SceneHolder* GetWindow( Dali::Actor& actor );
+
+  /**
+   * @copydoc Dali::Adaptor::GetWindows()
+   */
+  Dali::WindowContainer GetWindows() const;
+
+  /**
+   * @copydoc Dali::Adaptor::GetSceneHolders()
+   */
+  Dali::SceneHolderList GetSceneHolders() const;
+
+public:
+
+  /**
+   * @return the Core instance
+   */
+  virtual Dali::Integration::Core& GetCore();
+
+  /**
+   * @copydoc Dali::Adaptor::SetRenderRefreshRate()
+   */
+  void SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender );
+
+  /**
+   * Return the PlatformAbstraction.
+   * @return The PlatformAbstraction.
+   */
+  Integration::PlatformAbstraction& GetPlatformAbstraction() const;
+
+  /**
+   * Destroy the TtsPlayer of specific mode.
+   * @param[in] mode The mode of TtsPlayer to destroy
+   */
+  void DestroyTtsPlayer(Dali::TtsPlayer::Mode mode);
+
+  /**
+   * Gets native window handle
+   *
+   * @return native window handle
+   */
+  Any GetNativeWindowHandle();
+
+  /**
+   * @brief Retrieve native window handle that the given actor is added to.
+   *
+   * @param[in] actor The actor
+   * @return native window handle
+   */
+  Any GetNativeWindowHandle( Dali::Actor actor );
+
+  /**
+   * Get the native display associated with the graphics backend
+   *
+   * @return A handle to the native display
+   */
+  Any GetGraphicsDisplay();
+
+  /**
+   * Sets use remote surface for Surface output
+   * @param[in] useRemoteSurface True if the remote surface is used
+   */
+  void SetUseRemoteSurface(bool useRemoteSurface);
+
+public:
+
+  /**
+   * Adds an adaptor observer so that we can observe the adaptor's lifetime events.
+   * @param[in]  observer  The observer.
+   * @note Observers should remove themselves when they are destroyed.
+   */
+  void AddObserver( LifeCycleObserver& observer );
+
+  /**
+   * Removes the observer from the adaptor.
+   * @param[in]  observer  The observer to remove.
+   * @note Observers should remove themselves when they are destroyed.
+   */
+  void RemoveObserver( LifeCycleObserver& observer );
+
+  /**
+   * Emits the Notification event to the Dali core.
+   */
+  void SendNotificationEvent();
+
+  /**
+   * Request adaptor to update once
+   */
+  void RequestUpdateOnce();
+
+  /**
+   * @copydoc Dali::Adaptor::NotifySceneCreated()
+   */
+  void NotifySceneCreated();
+
+  /**
+   * @copydoc Dali::Adaptor::NotifyLanguageChanged()
+   */
+  void NotifyLanguageChanged();
+
+  /**
+   * Gets AppId of current application
+   */
+  void GetAppId( std::string& appId );
+
+  /**
+   * @copydoc Dali::Adaptor::SurfaceResizePrepare
+   */
+  void SurfaceResizePrepare( Dali::RenderSurfaceInterface* surface, SurfaceSize surfaceSize );
+
+  /**
+   * @copydoc Dali::Adaptor::SurfaceResizeComplete
+   */
+  void SurfaceResizeComplete( Dali::RenderSurfaceInterface* surface, SurfaceSize surfaceSize );
+
+  /**
+   * Sets layout direction of root by system language
+   * @param[in] locale System locale
+   */
+  void SetRootLayoutDirection( std::string locale );
+
+  /**
+   * @copydoc Dali::Adaptor::RenderOnce
+   */
+  void RenderOnce();
+
+  /**
+   * @copydoc Dali::Adaptor::GetLogFactory
+   */
+  const LogFactoryInterface& GetLogFactory();
+
+  /**
+   * @copydoc Dali::Adaptor::RegisterProcessor
+   */
+  void RegisterProcessor( Integration::Processor& processor );
+
+  /**
+   * @coydoc Dali::Adaptor::UnregisterProcessor
+   */
+  void UnregisterProcessor( Integration::Processor& processor );
+
+  /**
+   * Check MultipleWindow is supported
+   */
+  bool IsMultipleWindowSupported() const;
+
+  /**
+   * @brief Checks whether the windows are being rendered in the render thread.
+   *
+   * @return true if the windows are being rendered in the render thread, or false if not.
+   */
+  bool IsRenderingWindows() const;
+
+public:  //AdaptorInternalServices
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetPlatformAbstractionInterface()
+   */
+  virtual Dali::Integration::PlatformAbstraction& GetPlatformAbstractionInterface();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetDisplayConnectionInterface()
+   */
+  virtual Dali::DisplayConnection& GetDisplayConnectionInterface();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetGraphicsInterface()
+   */
+  virtual GraphicsInterface& GetGraphicsInterface();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetTriggerEventInterface()
+   */
+  virtual TriggerEventInterface& GetProcessCoreEventsTrigger();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetSocketFactoryInterface()
+   */
+  virtual SocketFactoryInterface& GetSocketFactoryInterface();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetRenderSurfaceInterface()
+   */
+  virtual Dali::RenderSurfaceInterface* GetRenderSurfaceInterface();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetPerformanceInterface()
+   */
+  virtual PerformanceInterface* GetPerformanceInterface();
+
+  /**
+   * copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetKernelTraceInterface()
+   */
+  virtual TraceInterface& GetKernelTraceInterface();
+
+  /**
+   * copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetSystemTraceInterface()
+   */
+  virtual TraceInterface& GetSystemTraceInterface();
+
+  /**
+   * copydoc Dali::Internal::Adaptor::AdaptorInternalServices::GetWindowContainerInterface()
+   */
+  virtual void GetWindowContainerInterface( WindowContainer& windows );
+
+public: // Signals
+
+  /**
+   * @copydoc Dali::Adaptor::SignalResized
+   */
+  AdaptorSignalType& ResizedSignal()
+  {
+    return mResizedSignal;
+  }
+
+  /**
+   * @copydoc Dali::Adaptor::LanguageChangedSignal
+   */
+  AdaptorSignalType& LanguageChangedSignal()
+  {
+    return mLanguageChangedSignal;
+  }
+
+  /**
+   * @copydoc Dali::Adaptor::WindowCreatedSignal
+   */
+  WindowCreatedSignalType& WindowCreatedSignal()
+  {
+    return mWindowCreatedSignal;
+  }
+
+public: // From Dali::Internal::Adaptor::CoreEventInterface
+
+  /**
+   * @copydoc Dali::Internal::Adaptor:CoreEventInterface:::ProcessCoreEvents()
+   */
+  virtual void ProcessCoreEvents();
+
+private: // From Dali::Internal::Adaptor::CoreEventInterface
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::CoreEventInterface::QueueCoreEvent()
+   */
+  virtual void QueueCoreEvent(const Dali::Integration::Event& event);
+
+private: // From Dali::Integration::RenderController
+
+  /**
+   * @copydoc Dali::Integration::RenderController::RequestUpdate()
+   */
+  virtual void RequestUpdate( bool forceUpdate );
+
+  /**
+   * @copydoc Dali::Integration::RenderController::RequestProcessEventsOnIdle()
+   */
+  virtual void RequestProcessEventsOnIdle( bool forceProcess );
+
+public: // From Dali::Internal::Adaptor::WindowVisibilityObserver
+
+  /**
+   * Called when the window becomes fully or partially visible.
+   */
+  virtual void OnWindowShown();
+
+  /**
+   * Called when the window is fully hidden.
+   */
+  virtual void OnWindowHidden();
+
+private: // From Dali::Internal::Adaptor::DamageObserver
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::DamageObserver::OnDamaged()
+   */
+  void OnDamaged( const DamageArea& area );
+
+private:
+
+  // Undefined
+  Adaptor(const Adaptor&) = delete;
+  Adaptor& operator=(Adaptor&) = delete;
+
+private:
+
+  /**
+   * Assigns the render surface to the adaptor
+   *
+   */
+  void SetSurface(Dali::RenderSurfaceInterface *surface);
+
+  /**
+   * called after surface is created
+   */
+  void SurfaceInitialized();
+
+  /**
+   * Sends an notification message from main loop idle handler
+   */
+  bool ProcessCoreEventsFromIdle();
+
+  /**
+   * Gets path for data/resource storage.
+   * @param[out] path Path for data/resource storage
+   */
+  void GetDataStoragePath(std::string& path);
+
+  /**
+   * Sets up system information if needs
+   */
+  void SetupSystemInformation();
+
+  /**
+   * Adds a callback to be run when entering an idle state.
+   *
+   * A callback of the following type should be used:
+   * @code
+   *   bool MyFunction();
+   * @endcode
+   * This callback will be called repeatedly as long as it returns true. A return of 0 deletes this callback.
+   */
+  bool AddIdleEnterer( CallbackBase* callback, bool forceAdd );
+
+  /**
+   * Removes a previously added the idle enterer callback.
+   */
+  void RemoveIdleEnterer( CallbackBase* callback );
+
+private:
+
+  /**
+   * Constructor
+   * @param[in]  window       window handle
+   * @param[in]  adaptor      The public adaptor
+   * @param[in]  surface      A render surface can be one of the following
+   *                          - Pixmap, adaptor will use existing Pixmap to draw on to
+   *                          - Window, adaptor will use existing Window to draw on to
+   * @param[in]  environmentOptions  A pointer to the environment options. If NULL then one is created.
+   */
+  Adaptor( Dali::Integration::SceneHolder window, Dali::Adaptor& adaptor, Dali::RenderSurfaceInterface* surface, EnvironmentOptions* environmentOptions );
+
+private: // Types
+
+  enum State
+  {
+    READY,                     ///< Initial state before Adaptor::Start is called.
+    RUNNING,                   ///< Adaptor is running.
+    PAUSED,                    ///< Adaptor has been paused.
+    PAUSED_WHILE_HIDDEN,       ///< Adaptor is paused while window is hidden (& cannot be resumed until window is shown).
+    PAUSED_WHILE_INITIALIZING, ///< Adaptor is paused while application is initializing.
+    STOPPED,                   ///< Adaptor has been stopped.
+  };
+
+  // There is no weak handle for BaseHandle in DALi, but we can't ref count the window here,
+  // so we have to store the raw pointer.
+  using WindowContainer = std::vector<Dali::Internal::Adaptor::SceneHolder*>;
+  using ObserverContainer = std::vector<LifeCycleObserver*>;
+
+private: // Data
+
+  AdaptorSignalType                     mResizedSignal;               ///< Resized signal.
+  AdaptorSignalType                     mLanguageChangedSignal;       ///< Language changed signal.
+  WindowCreatedSignalType               mWindowCreatedSignal;    ///< Window created signal.
+
+  Dali::Adaptor&                        mAdaptor;                     ///< Reference to public adaptor instance.
+  State                                 mState;                       ///< Current state of the adaptor
+  Dali::Integration::Core*              mCore;                        ///< Dali Core
+  ThreadController*                     mThreadController;            ///< Controls the threads
+
+  GraphicsInterface*                    mGraphics;                    ///< Graphics interface
+  Dali::DisplayConnection*              mDisplayConnection;           ///< Display connection
+  WindowContainer                       mWindows;                     ///< A container of all the Windows that are currently created
+
+  std::unique_ptr<ConfigurationManager> mConfigurationManager;        ///< Configuration manager
+
+  TizenPlatform::TizenPlatformAbstraction* mPlatformAbstraction;      ///< Platform abstraction
+
+  CallbackManager*                      mCallbackManager;             ///< Used to install callbacks
+  bool                                  mNotificationOnIdleInstalled; ///< whether the idle handler is installed to send an notification event
+  TriggerEventInterface*                mNotificationTrigger;         ///< Notification event trigger
+  FeedbackPluginProxy*                  mDaliFeedbackPlugin;          ///< Used to access feedback support
+  FeedbackController*                   mFeedbackController;          ///< Plays feedback effects for Dali-Toolkit UI Controls.
+  Dali::TtsPlayer                       mTtsPlayers[Dali::TtsPlayer::MODE_NUM];                   ///< Provides TTS support
+  ObserverContainer                     mObservers;                   ///< A list of adaptor observer pointers
+  EnvironmentOptions*                   mEnvironmentOptions;          ///< environment options
+  PerformanceInterface*                 mPerformanceInterface;        ///< Performance interface
+  KernelTrace                           mKernelTracer;                ///< Kernel tracer
+  SystemTrace                           mSystemTracer;                ///< System tracer
+  ObjectProfiler*                       mObjectProfiler;              ///< Tracks object lifetime for profiling
+  SocketFactory                         mSocketFactory;               ///< Socket factory
+  const bool                            mEnvironmentOptionsOwned:1;   ///< Whether we own the EnvironmentOptions (and thus, need to delete it)
+  bool                                  mUseRemoteSurface:1;          ///< whether the remoteSurface is used or not
+
+public:
+  inline static Adaptor& GetImplementation(Dali::Adaptor& adaptor) { return *adaptor.mImpl; }
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_IMPL_H
diff --git a/dali/internal/adaptor/common/adaptor-internal-services.h b/dali/internal/adaptor/common/adaptor-internal-services.h
new file mode 100644 (file)
index 0000000..ab88729
--- /dev/null
@@ -0,0 +1,147 @@
+#ifndef DALI_INTERNAL_ADAPTOR_INTERNAL_SERVICES_H
+#define DALI_INTERNAL_ADAPTOR_INTERNAL_SERVICES_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/core.h>
+#include <dali/integration-api/gl-abstraction.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/render-surface-interface.h>
+#include <dali/integration-api/adaptor-framework/trigger-event-interface.h>
+#include <dali/internal/graphics/common/graphics-interface.h>
+#include <dali/internal/graphics/gles/egl-factory-interface.h>
+#include <dali/internal/network/common/socket-factory-interface.h>
+#include <dali/internal/network/common/trace-interface.h>
+#include <dali/internal/system/common/performance-interface.h>
+#include <dali/internal/window-system/common/display-connection.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class SceneHolder;
+using WindowContainer = std::vector<Internal::Adaptor::SceneHolder*>;
+
+/**
+ * A class to contain various interfaces provided by the adaptor which
+ * can be used by the cross platform parts of adaptor.
+ * E.g. any files held in adaptors/base/ directory
+ *
+ */
+class AdaptorInternalServices
+{
+
+public:
+
+  /**
+   * @return core
+   */
+  virtual Dali::Integration::Core& GetCore() = 0;
+
+  /**
+   * @return platform abstraction
+   */
+  virtual Dali::Integration::PlatformAbstraction& GetPlatformAbstractionInterface() = 0;
+
+  /**
+   * Used to access the Display Connection interface from the Render thread
+   * @return the Display Connection interface
+   */
+  virtual Dali::DisplayConnection& GetDisplayConnectionInterface() = 0;
+
+  /**
+   * Used to access the abstracted graphics interface
+   * This also contains the depth and stencil buffers
+   * @return the graphics interface
+   */
+  virtual GraphicsInterface& GetGraphicsInterface() = 0;
+
+  /**
+   * Used by update-thread to notify core (main-thread) it has messages to process
+   * @return trigger event ProcessCoreEvents
+   */
+  virtual TriggerEventInterface& GetProcessCoreEventsTrigger() = 0;
+
+  /**
+   * @return socket factory interface
+   */
+  virtual SocketFactoryInterface& GetSocketFactoryInterface() = 0;
+
+  /**
+   * @return render surface
+   */
+  virtual Dali::RenderSurfaceInterface* GetRenderSurfaceInterface() = 0;
+
+  /**
+   * @return performance interface
+   */
+  virtual PerformanceInterface* GetPerformanceInterface() = 0;
+
+  /**
+   * @return interface for logging to the kernel ( e.g. using ftrace )
+   */
+  virtual TraceInterface& GetKernelTraceInterface() = 0;
+
+  /**
+   * @return system trace interface, e.g. for using Tizen Trace (ttrace) or Android Trace (atrace)
+   */
+  virtual TraceInterface& GetSystemTraceInterface() = 0;
+
+  /**
+   * Used to access the list of windows from the Render thread
+   * @param[out] windows The list of created windows
+   */
+  virtual void GetWindowContainerInterface( WindowContainer& windows ) = 0;
+
+protected:
+
+  /**
+   * constructor
+   */
+  AdaptorInternalServices()
+  {
+  };
+
+  /**
+   * virtual destructor
+   */
+  virtual ~AdaptorInternalServices()
+  {
+  };
+
+  // Undefined copy constructor.
+  AdaptorInternalServices( const AdaptorInternalServices& ) = delete;
+
+  // Undefined assignment operator.
+  AdaptorInternalServices& operator=( const AdaptorInternalServices& ) = delete;
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_INTERNAL_SERVICES_H
diff --git a/dali/internal/adaptor/common/adaptor.cpp b/dali/internal/adaptor/common/adaptor.cpp
new file mode 100755 (executable)
index 0000000..e77dea8
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/accessibility-adaptor.h>
+#include <dali/devel-api/adaptor-framework/style-monitor.h>
+#include <dali/integration-api/adaptor-framework/render-surface-interface.h>
+#include <dali/integration-api/adaptor-framework/scene-holder.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/window-system/common/window-impl.h>
+
+namespace Dali
+{
+
+Adaptor& Adaptor::New( Window window )
+{
+  return New( window, Configuration::APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS );
+}
+
+Adaptor& Adaptor::New( Window window, Configuration::ContextLoss configuration )
+{
+  Internal::Adaptor::SceneHolder* sceneHolder = &Dali::GetImplementation( window );
+  Adaptor* adaptor = Internal::Adaptor::Adaptor::New( Dali::Integration::SceneHolder( sceneHolder ), configuration, NULL );
+  return *adaptor;
+}
+
+Adaptor& Adaptor::New( Window window, const Dali::RenderSurfaceInterface& surface )
+{
+  return New( window, surface, Configuration::APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS );
+}
+
+Adaptor& Adaptor::New( Window window, const Dali::RenderSurfaceInterface& surface, Configuration::ContextLoss configuration )
+{
+  Internal::Adaptor::SceneHolder* sceneHolder = &Dali::GetImplementation( window );
+  Dali::RenderSurfaceInterface* pSurface = const_cast<Dali::RenderSurfaceInterface *>(&surface);
+  Adaptor* adaptor = Internal::Adaptor::Adaptor::New( Dali::Integration::SceneHolder( sceneHolder ), pSurface, configuration, NULL );
+  return *adaptor;
+}
+
+Adaptor& Adaptor::New( Dali::Integration::SceneHolder window )
+{
+  return New( window, Configuration::APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS );
+}
+
+Adaptor& Adaptor::New( Dali::Integration::SceneHolder window, Configuration::ContextLoss configuration )
+{
+  Adaptor* adaptor = Internal::Adaptor::Adaptor::New( window, configuration, NULL );
+  return *adaptor;
+}
+
+Adaptor& Adaptor::New( Dali::Integration::SceneHolder window, const Dali::RenderSurfaceInterface& surface )
+{
+  return New( window, surface, Configuration::APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS );
+}
+
+Adaptor& Adaptor::New( Dali::Integration::SceneHolder window, const Dali::RenderSurfaceInterface& surface, Configuration::ContextLoss configuration )
+{
+  Dali::RenderSurfaceInterface* pSurface = const_cast<Dali::RenderSurfaceInterface *>(&surface);
+  Adaptor* adaptor = Internal::Adaptor::Adaptor::New( window, pSurface, configuration, NULL );
+  return *adaptor;
+}
+
+Adaptor::~Adaptor()
+{
+  delete mImpl;
+}
+
+void Adaptor::Start()
+{
+  mImpl->Start();
+}
+
+void Adaptor::Pause()
+{
+  mImpl->Pause();
+}
+
+void Adaptor::Resume()
+{
+  mImpl->Resume();
+}
+
+void Adaptor::Stop()
+{
+  mImpl->Stop();
+}
+
+bool Adaptor::AddIdle( CallbackBase* callback, bool hasReturnValue )
+{
+  return mImpl->AddIdle( callback, hasReturnValue, false );
+}
+
+bool Adaptor::AddWindow( Dali::Integration::SceneHolder childWindow, const std::string& childWindowName, const std::string& childWindowClassName, bool childWindowMode )
+{
+  return mImpl->AddWindow( childWindow, childWindowName, childWindowClassName, childWindowMode );
+}
+
+void Adaptor::RemoveIdle( CallbackBase* callback )
+{
+  mImpl->RemoveIdle( callback );
+}
+
+void Adaptor::ProcessIdle()
+{
+  mImpl->ProcessIdle();
+}
+
+void Adaptor::ReplaceSurface( Window window, Dali::RenderSurfaceInterface& surface )
+{
+  Internal::Adaptor::SceneHolder* sceneHolder = &Dali::GetImplementation( window );
+  mImpl->ReplaceSurface( Dali::Integration::SceneHolder( sceneHolder ), surface );
+}
+
+void Adaptor::ReplaceSurface( Dali::Integration::SceneHolder window, Dali::RenderSurfaceInterface& surface )
+{
+  mImpl->ReplaceSurface( window, surface );
+}
+
+Adaptor::AdaptorSignalType& Adaptor::ResizedSignal()
+{
+  return mImpl->ResizedSignal();
+}
+
+Adaptor::AdaptorSignalType& Adaptor::LanguageChangedSignal()
+{
+  return mImpl->LanguageChangedSignal();
+}
+
+Adaptor::WindowCreatedSignalType& Adaptor::WindowCreatedSignal()
+{
+  return mImpl->WindowCreatedSignal();
+}
+
+Dali::RenderSurfaceInterface& Adaptor::GetSurface()
+{
+  return mImpl->GetSurface();
+}
+
+Any Adaptor::GetNativeWindowHandle()
+{
+  return mImpl->GetNativeWindowHandle();
+}
+
+Any Adaptor::GetNativeWindowHandle( Actor actor )
+{
+  return mImpl->GetNativeWindowHandle( actor );
+}
+
+Any Adaptor::GetGraphicsDisplay()
+{
+  return mImpl->GetGraphicsDisplay();
+}
+
+void Adaptor::ReleaseSurfaceLock()
+{
+  mImpl->ReleaseSurfaceLock();
+}
+
+void Adaptor::SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender )
+{
+  mImpl->SetRenderRefreshRate( numberOfVSyncsPerRender );
+}
+
+void Adaptor::SetPreRenderCallback( CallbackBase* callback )
+{
+  mImpl->SetPreRenderCallback( callback );
+}
+
+Adaptor& Adaptor::Get()
+{
+  return Internal::Adaptor::Adaptor::Get();
+}
+
+bool Adaptor::IsAvailable()
+{
+  return Internal::Adaptor::Adaptor::IsAvailable();
+}
+
+void Adaptor::NotifySceneCreated()
+{
+  mImpl->NotifySceneCreated();
+}
+
+void Adaptor::NotifyLanguageChanged()
+{
+  mImpl->NotifyLanguageChanged();
+}
+
+void Adaptor::FeedTouchPoint( TouchPoint& point, int timeStamp )
+{
+  mImpl->FeedTouchPoint(point, timeStamp);
+}
+
+void Adaptor::FeedWheelEvent( WheelEvent& wheelEvent )
+{
+  mImpl->FeedWheelEvent(wheelEvent);
+}
+
+void Adaptor::FeedKeyEvent( KeyEvent& keyEvent )
+{
+  mImpl->FeedKeyEvent(keyEvent);
+}
+
+void Adaptor::SceneCreated()
+{
+  mImpl->SceneCreated();
+}
+
+void Adaptor::SurfaceResizePrepare( Dali::RenderSurfaceInterface* surface, SurfaceSize surfaceSize )
+{
+  mImpl->SurfaceResizePrepare( surface, surfaceSize );
+}
+
+void Adaptor::SurfaceResizeComplete( Dali::RenderSurfaceInterface* surface, SurfaceSize surfaceSize )
+{
+  mImpl->SurfaceResizeComplete( surface, surfaceSize );
+}
+
+void Adaptor::RenderOnce()
+{
+  mImpl->RenderOnce();
+}
+
+const LogFactoryInterface& Adaptor::GetLogFactory()
+{
+  return mImpl->GetLogFactory();
+}
+
+void Adaptor::RegisterProcessor( Integration::Processor& processor )
+{
+  mImpl->RegisterProcessor( processor );
+}
+
+void Adaptor::UnregisterProcessor( Integration::Processor& processor )
+{
+  mImpl->UnregisterProcessor( processor );
+}
+
+Dali::WindowContainer Adaptor::GetWindows() const
+{
+  return mImpl->GetWindows();
+}
+
+SceneHolderList Adaptor::GetSceneHolders() const
+{
+  return mImpl->GetSceneHolders();
+}
+
+void Adaptor::OnWindowShown()
+{
+  mImpl->OnWindowShown();
+}
+
+void Adaptor::OnWindowHidden()
+{
+  mImpl->OnWindowHidden();
+}
+
+Adaptor::Adaptor()
+: mImpl( NULL )
+{
+}
+
+} // namespace Dali
diff --git a/dali/internal/adaptor/common/application-impl.cpp b/dali/internal/adaptor/common/application-impl.cpp
new file mode 100755 (executable)
index 0000000..65d562b
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor/common/application-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/common/singleton-service.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/style-monitor.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/system/common/command-line-options.h>
+#include <dali/internal/adaptor/common/framework.h>
+#include <dali/internal/adaptor/common/lifecycle-controller-impl.h>
+#include <dali/internal/window-system/common/window-impl.h>
+#include <dali/internal/window-system/common/window-render-surface.h>
+#include <dali/internal/window-system/common/render-surface-factory.h>
+
+// To disable a macro with the same name from one of OpenGL headers
+#undef Status
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+class TizenPlatformAbstraction;
+}
+
+namespace Integration
+{
+class Core;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+const float DEFAULT_STEREO_BASE( 65.0f );
+
+} // unnamed namespace
+
+ApplicationPtr Application::gPreInitializedApplication( NULL );
+
+ApplicationPtr Application::New(
+  int* argc,
+  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, positionSize, applicationType ) );
+  return application;
+}
+
+void Application::PreInitialize( int* argc, char** argv[] )
+{
+  if( !gPreInitializedApplication )
+  {
+    Dali::TextAbstraction::FontClientPreInitialize();
+
+    gPreInitializedApplication = new Application ( argc, argv, "", Dali::Application::OPAQUE, PositionSize(), Framework::NORMAL );
+    gPreInitializedApplication->CreateWindow();    // Only create window
+    gPreInitializedApplication->mLaunchpadState = Launchpad::PRE_INITIALIZED;
+  }
+}
+
+Application::Application( int* argc, char** argv[], const std::string& stylesheet,
+  Dali::Application::WINDOW_MODE windowMode, const PositionSize& positionSize, Framework::Type applicationType )
+: mInitSignal(),
+  mTerminateSignal(),
+  mPauseSignal(),
+  mResumeSignal(),
+  mResetSignal(),
+  mResizeSignal(),
+  mAppControlSignal(),
+  mLanguageChangedSignal(),
+  mRegionChangedSignal(),
+  mBatteryLowSignal(),
+  mMemoryLowSignal(),
+  mEventLoop( nullptr ),
+  mFramework( nullptr ),
+  mContextLossConfiguration( Configuration::APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS ),
+  mCommandLineOptions( nullptr ),
+  mAdaptorBuilder( nullptr ),
+  mAdaptor( nullptr ),
+  mMainWindow(),
+  mMainWindowMode( windowMode ),
+  mMainWindowName(),
+  mMainWindowReplaced( false ),
+  mStylesheet( stylesheet ),
+  mEnvironmentOptions(),
+  mWindowPositionSize( positionSize ),
+  mLaunchpadState( Launchpad::NONE ),
+  mSlotDelegate( this ),
+  mViewMode( MONO ),
+  mStereoBase( DEFAULT_STEREO_BASE )
+{
+  // Get mName from environment options
+  mMainWindowName = mEnvironmentOptions.GetWindowName();
+  if( mMainWindowName.empty() && argc && ( *argc > 0 ) )
+  {
+    // Set mName from command-line args if environment option not set
+    mMainWindowName = (*argv)[0];
+  }
+
+  mCommandLineOptions = new CommandLineOptions(argc, argv);
+  mFramework = new Framework( *this, argc, argv, applicationType );
+  mUseRemoteSurface = (applicationType == Framework::WATCH);
+}
+
+Application::~Application()
+{
+  SingletonService service = SingletonService::Get();
+  // Note this can be false i.e. if Application has never created a Core instance
+  if( service )
+  {
+    service.UnregisterAll();
+  }
+
+  mMainWindow.Reset();
+  delete mAdaptor;
+  delete mAdaptorBuilder;
+  delete mCommandLineOptions;
+  delete mFramework;
+}
+
+void Application::CreateWindow()
+{
+  if( mWindowPositionSize.width == 0 && mWindowPositionSize.height == 0 )
+  {
+    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();
+
+  Internal::Adaptor::Window* window = Internal::Adaptor::Window::New(mWindowPositionSize, mMainWindowName, windowClassName, mMainWindowMode == Dali::Application::TRANSPARENT);
+  mMainWindow = Dali::Window( window );
+
+  // Quit the application when the window is closed
+  GetImplementation( mMainWindow ).DeleteRequestSignal().Connect( mSlotDelegate, &Application::Quit );
+}
+
+void Application::CreateAdaptor()
+{
+  DALI_ASSERT_ALWAYS( mMainWindow && "Window required to create adaptor" );
+
+  auto graphicsFactory = mAdaptorBuilder->GetGraphicsFactory();
+
+  Integration::SceneHolder sceneHolder = Integration::SceneHolder( &Dali::GetImplementation( mMainWindow ) );
+
+  mAdaptor = Adaptor::New( graphicsFactory, sceneHolder, mContextLossConfiguration, &mEnvironmentOptions );
+
+  mAdaptor->ResizedSignal().Connect( mSlotDelegate, &Application::OnResize );
+
+  Adaptor::GetImplementation( *mAdaptor ).SetUseRemoteSurface( mUseRemoteSurface );
+}
+
+void Application::CreateAdaptorBuilder()
+{
+  mAdaptorBuilder = new AdaptorBuilder();
+}
+
+void Application::MainLoop(Dali::Configuration::ContextLoss configuration)
+{
+  mContextLossConfiguration = configuration;
+
+  // Run the application
+  mFramework->Run();
+}
+
+void Application::Lower()
+{
+  // Lower the application without quitting it.
+  mMainWindow.Lower();
+}
+
+void Application::Quit()
+{
+  // Actually quit the application.
+  // Force a call to Quit even if adaptor is not running.
+  Internal::Adaptor::Adaptor::GetImplementation(*mAdaptor).AddIdle( MakeCallback( this, &Application::QuitFromMainLoop ), false, true );
+}
+
+void Application::QuitFromMainLoop()
+{
+  mAdaptor->Stop();
+
+  mFramework->Quit();
+  // This will trigger OnTerminate(), below, after the main loop has completed.
+}
+
+void Application::OnInit()
+{
+  mFramework->AddAbortCallback( MakeCallback( this, &Application::QuitFromMainLoop ) );
+
+  CreateAdaptorBuilder();
+  // If an application was pre-initialized, a window was made in advance
+  if( mLaunchpadState == Launchpad::NONE )
+  {
+    CreateWindow();
+  }
+
+  CreateAdaptor();
+
+  // Run the adaptor
+  mAdaptor->Start();
+
+  if( ! mStylesheet.empty() )
+  {
+    Dali::StyleMonitor::Get().SetTheme( mStylesheet );
+  }
+
+  // Wire up the LifecycleController
+  Dali::LifecycleController lifecycleController = Dali::LifecycleController::Get();
+
+  InitSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnInit );
+  TerminateSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnTerminate );
+  PauseSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnPause );
+  ResumeSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnResume );
+  ResetSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnReset );
+  ResizeSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnResize );
+  LanguageChangedSignal().Connect( &GetImplementation( lifecycleController ), &LifecycleController::OnLanguageChanged );
+
+  Dali::Application application(this);
+  mInitSignal.Emit( application );
+
+  mAdaptor->NotifySceneCreated();
+}
+
+void Application::OnTerminate()
+{
+  // We've been told to quit by AppCore, ecore_x_destroy has been called, need to quit synchronously
+  // delete the window as ecore_x has been destroyed by AppCore
+
+  Dali::Application application(this);
+  mTerminateSignal.Emit( application );
+
+  if( mAdaptor )
+  {
+    // Ensure that the render-thread is not using the surface(window) after we delete it
+    mAdaptor->Stop();
+  }
+
+  mMainWindow.Reset(); // This only resets (clears) the default Window
+}
+
+void Application::OnPause()
+{
+  // A DALi app should handle Pause/Resume events.
+  // DALi just delivers the framework Pause event to the application, but not actually pause DALi core.
+  // Pausing DALi core only occurs on the Window Hidden framework event
+  Dali::Application application(this);
+  mPauseSignal.Emit( application );
+}
+
+void Application::OnResume()
+{
+  // Emit the signal first so the application can queue any messages before we do an update/render
+  // This ensures we do not just redraw the last frame before pausing if that's not required
+  Dali::Application application(this);
+  mResumeSignal.Emit( application );
+
+  // DALi just delivers the framework Resume event to the application.
+  // Resuming DALi core only occurs on the Window Show framework event
+
+  // Trigger processing of events queued up while paused
+  CoreEventInterface& coreEventInterface = Internal::Adaptor::Adaptor::GetImplementation( GetAdaptor() );
+  coreEventInterface.ProcessCoreEvents();
+}
+
+void Application::OnReset()
+{
+  /*
+   * usually, reset callback was called when a caller request to launch this application via aul.
+   * because Application class already handled initialization in OnInit(), OnReset do nothing.
+   */
+  Dali::Application application(this);
+  mResetSignal.Emit( application );
+}
+
+void Application::OnAppControl(void *data)
+{
+  Dali::Application application(this);
+  mAppControlSignal.Emit( application , data );
+}
+
+void Application::OnLanguageChanged()
+{
+  mAdaptor->NotifyLanguageChanged();
+  Dali::Application application(this);
+  mLanguageChangedSignal.Emit( application );
+}
+
+void Application::OnRegionChanged()
+{
+  Dali::Application application(this);
+  mRegionChangedSignal.Emit( application );
+}
+
+void Application::OnBatteryLow( Dali::DeviceStatus::Battery::Status status )
+{
+  Dali::Application application(this);
+  mBatteryLowSignal.Emit( application );
+
+  mLowBatterySignal.Emit( status );
+}
+
+void Application::OnMemoryLow( Dali::DeviceStatus::Memory::Status status )
+{
+  Dali::Application application(this);
+  mMemoryLowSignal.Emit( application );
+
+  mLowMemorySignal.Emit( status );
+}
+
+void Application::OnSurfaceCreated( Any newSurface )
+{
+  void* newWindow = AnyCast< void* >( newSurface );
+  void* oldWindow = AnyCast< void* >( mMainWindow.GetNativeHandle() );
+  if( oldWindow != newWindow )
+  {
+    auto renderSurfaceFactory = Dali::Internal::Adaptor::GetRenderSurfaceFactory();
+    std::unique_ptr< WindowRenderSurface > newSurfacePtr
+      = renderSurfaceFactory->CreateWindowRenderSurface( PositionSize(), newSurface, true );
+
+    mAdaptor->ReplaceSurface( mMainWindow, *newSurfacePtr.release() );
+  }
+}
+
+void Application::OnSurfaceDestroyed( Any surface )
+{
+}
+
+void Application::OnResize(Dali::Adaptor& adaptor)
+{
+  Dali::Application application(this);
+  mResizeSignal.Emit( application );
+}
+
+bool Application::AddIdle( CallbackBase* callback, bool hasReturnValue )
+{
+  return mAdaptor->AddIdle( callback, hasReturnValue );
+}
+
+std::string Application::GetRegion() const
+{
+  return mFramework->GetRegion();
+}
+
+std::string Application::GetLanguage() const
+{
+  return mFramework->GetLanguage();
+}
+
+Dali::Adaptor& Application::GetAdaptor()
+{
+  return *mAdaptor;
+}
+
+Dali::Window Application::GetWindow()
+{
+  // Changed to return a different window handle after ReplaceWindow is called
+  // just for backward compatibility to make the test case pass
+  if ( mMainWindowReplaced )
+  {
+    Internal::Adaptor::Window* window = Internal::Adaptor::Window::New(PositionSize(), "ReplacedWindow", "", false);
+    return Dali::Window( window );
+  }
+  else
+  {
+    return mMainWindow;
+  }
+}
+
+// Stereoscopy
+
+void Application::SetViewMode( ViewMode viewMode )
+{
+  mViewMode = viewMode;
+}
+
+ViewMode Application::GetViewMode() const
+{
+  return mViewMode;
+}
+
+void Application::SetStereoBase( float stereoBase )
+{
+  mStereoBase = stereoBase;
+}
+
+float Application::GetStereoBase() const
+{
+  return mStereoBase;
+}
+
+void Application::ReplaceWindow( const PositionSize& positionSize, const std::string& name )
+{
+  // This API is kept just for backward compatibility to make the test case pass.
+
+  mMainWindowReplaced = true;
+  OnResize( *mAdaptor );
+}
+
+std::string Application::GetResourcePath()
+{
+  return Internal::Adaptor::Framework::GetResourcePath();
+}
+
+std::string Application::GetDataPath()
+{
+  return Internal::Adaptor::Framework::GetDataPath();
+}
+
+void Application::SetStyleSheet( const std::string& stylesheet )
+{
+  mStylesheet = stylesheet;
+}
+
+void Application::SetCommandLineOptions( int* argc, char **argv[] )
+{
+  delete mCommandLineOptions;
+
+  mCommandLineOptions = new CommandLineOptions( argc, argv );
+
+  mFramework->SetCommandLineOptions( argc, argv );
+}
+
+ApplicationPtr Application::GetPreInitializedApplication()
+{
+  return gPreInitializedApplication;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/adaptor/common/application-impl.h b/dali/internal/adaptor/common/application-impl.h
new file mode 100755 (executable)
index 0000000..82826cd
--- /dev/null
@@ -0,0 +1,451 @@
+#ifndef DALI_INTERNAL_APPLICATION_H
+#define DALI_INTERNAL_APPLICATION_H
+
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/math/rect.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/application.h>
+#include <dali/devel-api/common/singleton-service.h>
+
+#include <dali/internal/adaptor/common/framework.h>
+#include <dali/internal/system/common/environment-options.h>
+#include <dali/internal/adaptor/common/adaptor-builder-impl.h>
+
+namespace Dali
+{
+class Adaptor;
+class Window;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace Launchpad
+{
+
+/**
+ * @brief Launchpad is used to improve application launch performance.
+ * When an application is pre-initialized, so files are preloaded, some functions are initialized and a window is made in advance.
+ */
+enum State
+{
+  NONE,              ///< The default state
+  PRE_INITIALIZED    ///< Application is pre-initialized.
+};
+
+} // namespace Launchpad
+
+class CommandLineOptions;
+class EventLoop;
+
+typedef Dali::Rect<int> PositionSize;
+
+class Application;
+typedef IntrusivePtr<Application> ApplicationPtr;
+
+/**
+ * Implementation of the Application class.
+ */
+class Application : public BaseObject, public Framework::Observer
+{
+public:
+
+  typedef Dali::Application::LowBatterySignalType LowBatterySignalType;
+  typedef Dali::Application::LowMemorySignalType LowMemorySignalType;
+  typedef Dali::Application::AppSignalType AppSignalType;
+  typedef Dali::Application::AppControlSignalType AppControlSignalType;
+  typedef Dali::Application::WINDOW_MODE WINDOW_MODE;
+
+  /**
+   * 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]  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, const PositionSize& positionSize, Framework::Type applicationType );
+
+  /**
+   * @copydoc Dali::DevelApplication::PreInitialize()
+   */
+  static void PreInitialize( int* argc, char** argv[] );
+
+public:
+
+  /**
+   * @copydoc Dali::Application::MainLoop()
+   */
+  void MainLoop(Dali::Configuration::ContextLoss configuration);
+
+  /**
+   * @copydoc Dali::Application::Lower()
+   */
+  void Lower();
+
+  /**
+   * @copydoc Dali::Application::Quit()
+   */
+  void Quit();
+
+  /**
+   * @copydoc Dali::Application::AddIdle()
+   */
+  bool AddIdle( CallbackBase* callback, bool hasReturnValue );
+
+  /**
+   * @copydoc Dali::Application::GetAdaptor();
+   */
+  Dali::Adaptor& GetAdaptor();
+
+  /**
+   * @copydoc Dali::Application::GetWindow();
+   */
+  Dali::Window GetWindow();
+
+  /**
+   * @copydoc Dali::Application::GetRegion();
+   */
+  std::string GetRegion() const;
+
+  /**
+   * @copydoc Dali::Application::GetLanguage();
+   */
+  std::string GetLanguage() const;
+
+  /**
+   * @copydoc Dali::Application::ReplaceWindow();
+   */
+  void ReplaceWindow( const PositionSize& positionSize, const std::string& name);
+
+  /**
+   * @copydoc Dali::Application::GetResourcePath();
+   */
+  static std::string GetResourcePath();
+
+  /**
+   * @copydoc Dali::DevelApplication::GetDataPath()
+   */
+  static std::string GetDataPath();
+
+  /**
+   * Retrieves the pre-initialized application.
+   *
+   * @return A pointer to the pre-initialized application
+   */
+  static ApplicationPtr GetPreInitializedApplication();
+
+public: // Stereoscopy
+
+  /**
+   * @copydoc Dali::Application::SetViewMode()
+   */
+  void SetViewMode( ViewMode viewMode );
+
+  /**
+   * @copydoc Dali::Application::GetViewMode()
+   */
+  ViewMode GetViewMode() const;
+
+  /**
+   * @copydoc Dali::Application::SetStereoBase()
+   */
+  void SetStereoBase( float stereoBase );
+
+  /**
+   * @copydoc Dali::Application::GetStereoBase()
+   */
+  float GetStereoBase() const;
+
+public: // From Framework::Observer
+
+  /**
+   * Called when the framework is initialised.
+   */
+  virtual void OnInit();
+
+  /**
+   * Called when the framework is terminated.
+   */
+  virtual void OnTerminate();
+
+  /**
+   * Called when the framework is paused.
+   */
+  virtual void OnPause();
+
+  /**
+   * Called when the framework resumes from a paused state.
+   */
+  virtual void OnResume();
+
+  /**
+  * Called when the framework received AppControlSignal.
+  * @param[in] The bundle data of AppControl event.
+  */
+  virtual void OnAppControl(void *data);
+
+  /**
+   * Called when the framework informs the application that it should reset itself.
+   */
+  virtual void OnReset();
+
+  /**
+   * Called when the framework informs the application that the language of the device has changed.
+   */
+  virtual void OnLanguageChanged();
+
+  /**
+  * Called when the framework informs the application that the region of the device has changed.
+  */
+  virtual void OnRegionChanged();
+
+  /**
+  * Called when the framework informs the application that the battery level of the device is low.
+  */
+  virtual void OnBatteryLow( Dali::DeviceStatus::Battery::Status status );
+
+  /**
+  * Called when the framework informs the application that the memory level of the device is low.
+  */
+  virtual void OnMemoryLow( Dali::DeviceStatus::Memory::Status status );
+
+  /**
+   * Called when the framework informs the application that the platform surface is created.
+   */
+  virtual void OnSurfaceCreated( Any newSurface );
+
+  /**
+   * Called when the framework informs the application that the platform surface is destroyed.
+   */
+  virtual void OnSurfaceDestroyed( Any newSurface );
+
+public:
+
+  /**
+   * Signal handler when the adaptor's window resizes itself.
+   * @param[in]  adaptor  The adaptor
+   */
+  void OnResize(Dali::Adaptor& adaptor);
+
+  /**
+   * Sets a user defined theme file.
+   * This should be called before initialization.
+   * @param[in] stylesheet The path to user defined theme file
+   */
+  void SetStyleSheet( const std::string& stylesheet );
+
+  /**
+   * Sets a command line options.
+   * This is used in case of the preinitialized application.
+   * @param[in] argc A pointer to the number of arguments
+   * @param[in] argv A pointer to the argument list
+   */
+  void SetCommandLineOptions( int* argc, char **argv[] );
+
+public:  // Signals
+
+  /**
+   * @copydoc Dali::Application::InitSignal()
+   */
+  Dali::Application::AppSignalType& InitSignal() { return mInitSignal; }
+
+  /**
+   * @copydoc Dali::Application::TerminateSignal()
+   */
+  Dali::Application::AppSignalType& TerminateSignal() { return mTerminateSignal; }
+
+  /**
+   * @copydoc Dali::Application::PauseSignal()
+   */
+  Dali::Application::AppSignalType& PauseSignal() { return mPauseSignal; }
+
+  /**
+   * @copydoc Dali::Application::ResumeSignal()
+   */
+  Dali::Application::AppSignalType& ResumeSignal() { return mResumeSignal; }
+
+  /**
+   * @copydoc Dali::Application::ResetSignal()
+   */
+  Dali::Application::AppSignalType& ResetSignal() { return mResetSignal; }
+
+  /**
+  * @copydoc Dali::Application::AppControlSignal()
+  */
+  Dali::Application::AppControlSignalType& AppControlSignal() { return mAppControlSignal; }
+
+  /**
+   * @copydoc Dali::Application::ResizeSignal()
+   */
+  Dali::Application::AppSignalType& ResizeSignal() { return mResizeSignal; }
+
+  /**
+   * @copydoc Dali::Application::LanguageChangedSignal()
+   */
+  Dali::Application::AppSignalType& LanguageChangedSignal() { return mLanguageChangedSignal; }
+
+  /**
+  * @copydoc Dali::Application::RegionChangedSignal()
+  */
+  Dali::Application::AppSignalType& RegionChangedSignal() { return mRegionChangedSignal; }
+
+  /**
+  * @copydoc Dali::Application::BatteryLowSignal()
+  */
+  Dali::Application::AppSignalType& BatteryLowSignal() { return mBatteryLowSignal; }
+
+  /**
+  * @copydoc Dali::Application::MemoryLowSignal()
+  */
+  Dali::Application::AppSignalType& MemoryLowSignal() { return mMemoryLowSignal; }
+
+  /**
+  * @copydoc Dali::Application::LowBatterySignal()
+  */
+  Dali::Application::LowBatterySignalType& LowBatterySignal() { return mLowBatterySignal; }
+
+  /**
+  * @copydoc Dali::Application:::LowMemorySignal()
+  */
+  Dali::Application::LowMemorySignalType& LowMemorySignal() { return mLowMemorySignal; }
+
+protected:
+
+  /**
+   * 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]  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, const PositionSize& positionSize, Framework::Type applicationType );
+
+  /**
+   * Destructor
+   */
+  virtual ~Application();
+
+  // Undefined
+  Application(const Application&);
+  Application& operator=(Application&);
+
+  /**
+   * Creates the window
+   */
+  void CreateWindow();
+
+  /**
+   * Creates the adaptor
+   */
+  void CreateAdaptor();
+
+  /**
+   * Creates the adaptor builder
+   */
+  void CreateAdaptorBuilder();
+
+  /**
+   * Quits from the main loop
+   */
+  void QuitFromMainLoop();
+
+private:
+
+  AppSignalType                         mInitSignal;
+  AppSignalType                         mTerminateSignal;
+  AppSignalType                         mPauseSignal;
+  AppSignalType                         mResumeSignal;
+  AppSignalType                         mResetSignal;
+  AppSignalType                         mResizeSignal;
+  AppControlSignalType                  mAppControlSignal;
+  AppSignalType                         mLanguageChangedSignal;
+  AppSignalType                         mRegionChangedSignal;
+  AppSignalType                         mBatteryLowSignal;
+  AppSignalType                         mMemoryLowSignal;
+  LowBatterySignalType                  mLowBatterySignal;
+  LowMemorySignalType                   mLowMemorySignal;
+
+  EventLoop*                            mEventLoop;
+  Framework*                            mFramework;
+
+  Dali::Configuration::ContextLoss      mContextLossConfiguration;
+  CommandLineOptions*                   mCommandLineOptions;
+
+  Dali::Internal::Adaptor::AdaptorBuilder* mAdaptorBuilder;   ///< The adaptor builder
+  Dali::Adaptor*                           mAdaptor;
+
+  // The Main Window is that window created by the Application during initial startup
+  // (previously this was the only window)
+  Dali::Window                             mMainWindow;       ///< Main Window instance
+  Dali::Application::WINDOW_MODE           mMainWindowMode;   ///< Window mode of the main window
+  std::string                              mMainWindowName;   ///< Name of the main window as obtained from environment options
+
+  bool                                     mMainWindowReplaced;   ///< Whether the main window has been replaced
+
+  std::string                              mStylesheet;
+  EnvironmentOptions                       mEnvironmentOptions;
+  PositionSize                             mWindowPositionSize;
+  Launchpad::State                         mLaunchpadState;
+  bool                                     mUseRemoteSurface;
+
+  SlotDelegate< Application >              mSlotDelegate;
+
+  ViewMode                                 mViewMode;
+  float                                    mStereoBase;
+
+  static ApplicationPtr                    gPreInitializedApplication;
+};
+
+inline Application& GetImplementation(Dali::Application& application)
+{
+  DALI_ASSERT_ALWAYS(application && "application handle is empty");
+
+  BaseObject& handle = application.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::Application&>(handle);
+}
+
+inline const Application& GetImplementation(const Dali::Application& application)
+{
+  DALI_ASSERT_ALWAYS(application && "application handle is empty");
+
+  const BaseObject& handle = application.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::Application&>(handle);
+}
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_APPLICATION_H
diff --git a/dali/internal/adaptor/common/combined-update-render-controller-debug.h b/dali/internal/adaptor/common/combined-update-render-controller-debug.h
new file mode 100755 (executable)
index 0000000..91f9f76
--- /dev/null
@@ -0,0 +1,140 @@
+#ifndef DALI_INTERNAL_COMBINED_UPDATE_RENDER_CONTROLLER_DEBUG_H
+#define DALI_INTERNAL_COMBINED_UPDATE_RENDER_CONTROLLER_DEBUG_H
+
+/*
+ * Copyright (c) 2019 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/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+// Uncomment next line for FULL logging of the ThreadSynchronization class in release mode
+//#define RELEASE_BUILD_LOGGING
+
+#ifdef DEBUG_ENABLED
+
+#define ENABLE_LOG_IN_COLOR
+#define ENABLE_COUNTER_LOGGING
+#define ENABLE_UPDATE_RENDER_THREAD_LOGGING
+#define ENABLE_EVENT_LOGGING
+
+#define DEBUG_LEVEL_COUNTER         Debug::Verbose
+#define DEBUG_LEVEL_UPDATE_RENDER   Debug::General
+#define DEBUG_LEVEL_EVENT           Debug::Concise
+
+Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_THREAD_SYNC" );
+
+#define LOG_THREAD_SYNC(level, color, format, ...) \
+  DALI_LOG_INFO( gLogFilter, level, "%s" format "%s\n", color, ## __VA_ARGS__, COLOR_CLEAR )
+
+#define LOG_THREAD_SYNC_TRACE(color) \
+  Dali::Integration::Log::TraceObj debugTraceObj( gLogFilter, "%s%s%s", color, __FUNCTION__, COLOR_CLEAR ); \
+  if( ! gLogFilter->IsTraceEnabled() ) { LOG_THREAD_SYNC( Debug::Concise, color, "%s", __FUNCTION__ ); }
+
+#define LOG_THREAD_SYNC_TRACE_FMT(color, format, ...) \
+  Dali::Integration::Log::TraceObj debugTraceObj( gLogFilter, "%s%s: " format "%s", color, __FUNCTION__, ## __VA_ARGS__, COLOR_CLEAR ); \
+  if( ! gLogFilter->IsTraceEnabled() ) { LOG_THREAD_SYNC( Debug::Concise, color, "%s: " format, __FUNCTION__, ## __VA_ARGS__ ); }
+
+#elif defined( RELEASE_BUILD_LOGGING )
+
+#define ENABLE_LOG_IN_COLOR
+#define ENABLE_COUNTER_LOGGING
+#define ENABLE_UPDATE_RENDER_THREAD_LOGGING
+#define ENABLE_EVENT_LOGGING
+
+#define DEBUG_LEVEL_COUNTER     0
+#define DEBUG_LEVEL_UPDATE_RENDER      0
+#define DEBUG_LEVEL_EVENT       0
+
+#define LOG_THREAD_SYNC(level, color, format, ...) \
+  Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s" format "%s\n", color, ## __VA_ARGS__, COLOR_CLEAR )
+
+#define LOG_THREAD_SYNC_TRACE(color) \
+  Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s%s%s\n", color, __FUNCTION__, COLOR_CLEAR )
+
+#define LOG_THREAD_SYNC_TRACE_FMT(color, format, ...) \
+  Dali::Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, "%s%s: " format "%s\n", color, __FUNCTION__, ## __VA_ARGS__, COLOR_CLEAR )
+
+#else
+
+#define LOG_THREAD_SYNC(level, color, format, ...)
+#define LOG_THREAD_SYNC_TRACE(color)
+#define LOG_THREAD_SYNC_TRACE_FMT(color, format, ...)
+
+#endif // DEBUG_ENABLED
+
+#ifdef ENABLE_LOG_IN_COLOR
+#define COLOR_YELLOW         "\033[33m"
+#define COLOR_LIGHT_RED      "\033[91m"
+#define COLOR_LIGHT_YELLOW   "\033[93m"
+#define COLOR_WHITE          "\033[97m"
+#define COLOR_CLEAR          "\033[0m"
+#else
+#define COLOR_YELLOW
+#define COLOR_LIGHT_RED
+#define COLOR_LIGHT_YELLOW
+#define COLOR_WHITE
+#define COLOR_CLEAR
+#endif
+
+#ifdef ENABLE_COUNTER_LOGGING
+#define LOG_COUNTER_EVENT(format, ...)            LOG_THREAD_SYNC(DEBUG_LEVEL_COUNTER, COLOR_LIGHT_RED, "%s: " format, __FUNCTION__, ## __VA_ARGS__)
+#define LOG_COUNTER_UPDATE_RENDER(format, ...)    LOG_THREAD_SYNC(DEBUG_LEVEL_COUNTER, COLOR_LIGHT_YELLOW, "%s: " format, __FUNCTION__, ## __VA_ARGS__)
+#else
+#define LOG_COUNTER_EVENT(format, ...)
+#define LOG_COUNTER_UPDATE_RENDER(format, ...)
+#endif
+
+#ifdef ENABLE_UPDATE_RENDER_THREAD_LOGGING
+#define LOG_UPDATE_RENDER(format, ...)            LOG_THREAD_SYNC(DEBUG_LEVEL_UPDATE_RENDER, COLOR_YELLOW, "%s: " format, __FUNCTION__, ## __VA_ARGS__)
+#define LOG_UPDATE_RENDER_TRACE                       LOG_THREAD_SYNC_TRACE(COLOR_YELLOW)
+#define LOG_UPDATE_RENDER_TRACE_FMT(format, ...)  LOG_THREAD_SYNC_TRACE_FMT(COLOR_YELLOW, format, ## __VA_ARGS__)
+#else
+#define LOG_UPDATE_RENDER(format, ...)
+#define LOG_UPDATE_RENDER_TRACE
+#define LOG_UPDATE_RENDER_TRACE_FMT(format, ...)
+#endif
+
+#ifdef ENABLE_EVENT_LOGGING
+#define LOG_EVENT(format, ...)             LOG_THREAD_SYNC(DEBUG_LEVEL_EVENT, COLOR_WHITE, "%s: " format, __FUNCTION__, ## __VA_ARGS__)
+#define LOG_EVENT_TRACE                        LOG_THREAD_SYNC_TRACE(COLOR_WHITE)
+#define LOG_EVENT_TRACE_FMT(format, ...)   LOG_THREAD_SYNC_TRACE_FMT(COLOR_WHITE, format, ## __VA_ARGS__)
+#else
+#define LOG_EVENT(format, ...)
+#define LOG_EVENT_TRACE
+#define LOG_EVENT_TRACE_FMT(format, ...)
+#endif
+
+} // unnamed namespace
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_COMBINED_UPDATE_RENDER_CONTROLLER_DEBUG_H
diff --git a/dali/internal/adaptor/common/combined-update-render-controller.cpp b/dali/internal/adaptor/common/combined-update-render-controller.cpp
new file mode 100644 (file)
index 0000000..80bc0a3
--- /dev/null
@@ -0,0 +1,920 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor/common/combined-update-render-controller.h>
+
+// EXTERNAL INCLUDES
+#include <errno.h>
+#include <dali/integration-api/platform-abstraction.h>
+#include <unistd.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
+#include <dali/devel-api/adaptor-framework/thread-settings.h>
+#include <dali/internal/adaptor/common/adaptor-internal-services.h>
+#include <dali/internal/adaptor/common/combined-update-render-controller-debug.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+#include <dali/internal/graphics/gles/egl-implementation.h>
+#include <dali/internal/graphics/common/graphics-interface.h>
+#include <dali/internal/system/common/environment-options.h>
+#include <dali/internal/system/common/time-service.h>
+#include <dali/internal/window-system/common/window-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+const unsigned int CREATED_THREAD_COUNT = 1u;
+
+const int CONTINUOUS = -1;
+const int ONCE = 1;
+
+const unsigned int TRUE = 1u;
+const unsigned int FALSE = 0u;
+
+const unsigned int MILLISECONDS_PER_SECOND( 1e+3 );
+const float        NANOSECONDS_TO_SECOND( 1e-9f );
+const unsigned int NANOSECONDS_PER_SECOND( 1e+9 );
+const unsigned int NANOSECONDS_PER_MILLISECOND( 1e+6 );
+
+// The following values will get calculated at compile time
+const float        DEFAULT_FRAME_DURATION_IN_SECONDS( 1.0f / 60.0f );
+const uint64_t DEFAULT_FRAME_DURATION_IN_MILLISECONDS( DEFAULT_FRAME_DURATION_IN_SECONDS * MILLISECONDS_PER_SECOND );
+const uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS( DEFAULT_FRAME_DURATION_IN_SECONDS * NANOSECONDS_PER_SECOND );
+
+/**
+ * Handles the use case when an update-request is received JUST before we process a sleep-request. If we did not have an update-request count then
+ * there is a danger that, on the event-thread we could have:
+ *  1) An update-request where we do nothing as Update/Render thread still running.
+ *  2) Quickly followed by a sleep-request being handled where we pause the Update/Render Thread (even though we have an update to process).
+ *
+ * Using a counter means we increment the counter on an update-request, and decrement it on a sleep-request. This handles the above scenario because:
+ *  1) MAIN THREAD:           Update Request: COUNTER = 1
+ *  2) UPDATE/RENDER THREAD:  Do Update/Render, then no Updates required -> Sleep Trigger
+ *  3) MAIN THREAD:           Update Request: COUNTER = 2
+ *  4) MAIN THREAD:           Sleep Request:  COUNTER = 1 -> We do not sleep just yet
+ *
+ * Also ensures we preserve battery life by only doing ONE update when the above use case is not triggered.
+ *  1) MAIN THREAD:           Update Request: COUNTER = 1
+ *  2) UPDATE/RENDER THREAD:  Do Update/Render, then no Updates required -> Sleep Trigger
+ *  3) MAIN THREAD:           Sleep Request:  COUNTER = 0 -> Go to sleep
+ */
+const unsigned int MAXIMUM_UPDATE_REQUESTS = 2;
+} // unnamed namespace
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// EVENT THREAD
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+CombinedUpdateRenderController::CombinedUpdateRenderController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions )
+: mFpsTracker( environmentOptions ),
+  mUpdateStatusLogger( environmentOptions ),
+  mEventThreadSemaphore(),
+  mGraphicsInitializeSemaphore(),
+  mUpdateRenderThreadWaitCondition(),
+  mAdaptorInterfaces( adaptorInterfaces ),
+  mPerformanceInterface( adaptorInterfaces.GetPerformanceInterface() ),
+  mCore( adaptorInterfaces.GetCore() ),
+  mEnvironmentOptions( environmentOptions ),
+  mNotificationTrigger( adaptorInterfaces.GetProcessCoreEventsTrigger() ),
+  mSleepTrigger( NULL ),
+  mPreRenderCallback( NULL ),
+  mUpdateRenderThread( NULL ),
+  mDefaultFrameDelta( 0.0f ),
+  mDefaultFrameDurationMilliseconds( 0u ),
+  mDefaultFrameDurationNanoseconds( 0u ),
+  mDefaultHalfFrameNanoseconds( 0u ),
+  mUpdateRequestCount( 0u ),
+  mRunning( FALSE ),
+  mUpdateRenderRunCount( 0 ),
+  mDestroyUpdateRenderThread( FALSE ),
+  mUpdateRenderThreadCanSleep( FALSE ),
+  mPendingRequestUpdate( FALSE ),
+  mUseElapsedTimeAfterWait( FALSE ),
+  mNewSurface( NULL ),
+  mPostRendering( FALSE ),
+  mSurfaceResized( FALSE ),
+  mForceClear( FALSE ),
+  mUploadWithoutRendering( FALSE ),
+  mFirstFrameAfterResume( FALSE ),
+  mIsRenderingWindows( false )
+{
+  LOG_EVENT_TRACE;
+
+  // Initialise frame delta/duration variables first
+  SetRenderRefreshRate( environmentOptions.GetRenderRefreshRate() );
+
+  // Set the thread-synchronization interface on the render-surface
+  Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
+  if( currentSurface )
+  {
+    currentSurface->SetThreadSynchronization( *this );
+  }
+
+  mSleepTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &CombinedUpdateRenderController::ProcessSleepRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
+
+  // Initialize to 0 so that it just waits if sem_post has not been called
+  sem_init( &mEventThreadSemaphore, 0, 0 );
+  sem_init( &mGraphicsInitializeSemaphore, 0, 0 );
+}
+
+CombinedUpdateRenderController::~CombinedUpdateRenderController()
+{
+  LOG_EVENT_TRACE;
+
+  Stop();
+
+  delete mPreRenderCallback;
+  delete mSleepTrigger;
+}
+
+void CombinedUpdateRenderController::Initialize()
+{
+  LOG_EVENT_TRACE;
+
+  // Ensure Update/Render Thread not already created
+  DALI_ASSERT_ALWAYS( ! mUpdateRenderThread );
+
+  // Create Update/Render Thread
+  mUpdateRenderThread = new pthread_t();
+  int error = pthread_create( mUpdateRenderThread, NULL, InternalUpdateRenderThreadEntryFunc, this );
+  DALI_ASSERT_ALWAYS( !error && "Return code from pthread_create() when creating UpdateRenderThread" );
+
+  // The Update/Render thread will now run and initialise the graphics interface etc. and will then wait for Start to be called
+  // When this function returns, the application initialisation on the event thread should occur
+}
+
+void CombinedUpdateRenderController::Start()
+{
+  LOG_EVENT_TRACE;
+
+  DALI_ASSERT_ALWAYS( !mRunning && mUpdateRenderThread );
+
+  // Wait until all threads created in Initialise are up and running
+  for( unsigned int i = 0; i < CREATED_THREAD_COUNT; ++i )
+  {
+    sem_wait( &mEventThreadSemaphore );
+  }
+
+  Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
+  if( currentSurface )
+  {
+    currentSurface->StartRender();
+  }
+
+  mRunning = TRUE;
+
+  LOG_EVENT( "Startup Complete, starting Update/Render Thread" );
+
+  RunUpdateRenderThread( CONTINUOUS, AnimationProgression::NONE, UpdateMode::NORMAL );
+
+  DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Start\n" );
+}
+
+void CombinedUpdateRenderController::Pause()
+{
+  LOG_EVENT_TRACE;
+
+  mRunning = FALSE;
+
+  PauseUpdateRenderThread();
+
+  AddPerformanceMarker( PerformanceInterface::PAUSED );
+
+  DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Pause\n" );
+}
+
+void CombinedUpdateRenderController::Resume()
+{
+  LOG_EVENT_TRACE;
+
+  if( !mRunning && IsUpdateRenderThreadPaused() )
+  {
+    LOG_EVENT( "Resuming" );
+
+    RunUpdateRenderThread( CONTINUOUS, AnimationProgression::USE_ELAPSED_TIME, UpdateMode::NORMAL );
+
+    AddPerformanceMarker( PerformanceInterface::RESUME );
+
+    mRunning = TRUE;
+    mForceClear = TRUE;
+    mFirstFrameAfterResume = TRUE;
+
+    DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Resume\n" );
+  }
+  else
+  {
+    DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Resume: Already resumed [%d, %d, %d]\n", mRunning, mUpdateRenderRunCount, mUpdateRenderThreadCanSleep );
+  }
+}
+
+void CombinedUpdateRenderController::Stop()
+{
+  LOG_EVENT_TRACE;
+
+  // Stop Rendering and the Update/Render Thread
+  Dali::RenderSurfaceInterface* currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
+  if( currentSurface )
+  {
+    currentSurface->StopRender();
+  }
+
+  StopUpdateRenderThread();
+
+  if( mUpdateRenderThread )
+  {
+    LOG_EVENT( "Destroying UpdateRenderThread" );
+
+    // wait for the thread to finish
+    pthread_join( *mUpdateRenderThread, NULL );
+
+    delete mUpdateRenderThread;
+    mUpdateRenderThread = NULL;
+  }
+
+  mRunning = FALSE;
+
+  DALI_LOG_RELEASE_INFO( "CombinedUpdateRenderController::Stop\n" );
+}
+
+void CombinedUpdateRenderController::RequestUpdate()
+{
+  LOG_EVENT_TRACE;
+
+  // Increment the update-request count to the maximum
+  if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
+  {
+    ++mUpdateRequestCount;
+  }
+
+  if( mRunning && IsUpdateRenderThreadPaused() )
+  {
+    LOG_EVENT( "Processing" );
+
+    RunUpdateRenderThread( CONTINUOUS, AnimationProgression::NONE, UpdateMode::NORMAL );
+  }
+
+  ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
+  mPendingRequestUpdate = TRUE;
+}
+
+void CombinedUpdateRenderController::RequestUpdateOnce( UpdateMode updateMode )
+{
+  // Increment the update-request count to the maximum
+  if( mUpdateRequestCount < MAXIMUM_UPDATE_REQUESTS )
+  {
+    ++mUpdateRequestCount;
+  }
+
+  if( IsUpdateRenderThreadPaused() )
+  {
+    LOG_EVENT_TRACE;
+
+    // Run Update/Render once
+    RunUpdateRenderThread( ONCE, AnimationProgression::NONE, updateMode );
+  }
+}
+
+void CombinedUpdateRenderController::ReplaceSurface( Dali::RenderSurfaceInterface* newSurface )
+{
+  LOG_EVENT_TRACE;
+
+  if( mUpdateRenderThread )
+  {
+    // Set the ThreadSyncronizationInterface on the new surface
+    newSurface->SetThreadSynchronization( *this );
+
+    LOG_EVENT( "Starting to replace the surface, event-thread blocked" );
+
+    // Start replacing the surface.
+    {
+      ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+      mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will replace the surface now
+      mNewSurface = newSurface;
+      mUpdateRenderThreadWaitCondition.Notify( lock );
+    }
+
+    // Wait until the surface has been replaced
+    sem_wait( &mEventThreadSemaphore );
+
+    LOG_EVENT( "Surface replaced, event-thread continuing" );
+  }
+}
+
+void CombinedUpdateRenderController::WaitForGraphicsInitialization()
+{
+  LOG_EVENT_TRACE;
+
+  if( mUpdateRenderThread )
+  {
+    LOG_EVENT( "Waiting for graphics initialisation, event-thread blocked" );
+
+    // Wait until the graphics has been initialised
+    sem_wait( &mGraphicsInitializeSemaphore );
+
+    LOG_EVENT( "graphics initialised, event-thread continuing" );
+  }
+}
+
+void CombinedUpdateRenderController::ResizeSurface()
+{
+  LOG_EVENT_TRACE;
+
+  LOG_EVENT( "Resize the surface" );
+
+  {
+    ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+    mPostRendering = FALSE; // Clear the post-rendering flag as Update/Render thread will resize the surface now
+    mSurfaceResized = TRUE;
+    mUpdateRenderThreadWaitCondition.Notify( lock );
+  }
+}
+
+void CombinedUpdateRenderController::SetRenderRefreshRate( unsigned int numberOfFramesPerRender )
+{
+  // Not protected by lock, but written to rarely so not worth adding a lock when reading
+  mDefaultFrameDelta                  = numberOfFramesPerRender * DEFAULT_FRAME_DURATION_IN_SECONDS;
+  mDefaultFrameDurationMilliseconds   = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_MILLISECONDS;
+  mDefaultFrameDurationNanoseconds    = uint64_t( numberOfFramesPerRender ) * DEFAULT_FRAME_DURATION_IN_NANOSECONDS;
+  mDefaultHalfFrameNanoseconds        = mDefaultFrameDurationNanoseconds / 2u;
+
+  LOG_EVENT( "mDefaultFrameDelta(%.6f), mDefaultFrameDurationMilliseconds(%lld), mDefaultFrameDurationNanoseconds(%lld)", mDefaultFrameDelta, mDefaultFrameDurationMilliseconds, mDefaultFrameDurationNanoseconds );
+}
+
+void CombinedUpdateRenderController::SetPreRenderCallback( CallbackBase* callback )
+{
+  LOG_EVENT_TRACE;
+  LOG_EVENT( "Set PreRender Callback" );
+
+  ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
+  if( mPreRenderCallback )
+  {
+    delete mPreRenderCallback;
+  }
+  mPreRenderCallback = callback;
+}
+
+void CombinedUpdateRenderController::AddSurface( Dali::RenderSurfaceInterface* surface )
+{
+  LOG_EVENT_TRACE;
+  LOG_EVENT( "Surface is added" );
+  if( mUpdateRenderThread )
+  {
+    // Set the ThreadSyncronizationInterface on the added surface
+    surface->SetThreadSynchronization( *this );
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// EVENT THREAD
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void CombinedUpdateRenderController::RunUpdateRenderThread( int numberOfCycles, AnimationProgression animationProgression, UpdateMode updateMode )
+{
+  ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+  mUpdateRenderRunCount = numberOfCycles;
+  mUpdateRenderThreadCanSleep = FALSE;
+  mUseElapsedTimeAfterWait = ( animationProgression == AnimationProgression::USE_ELAPSED_TIME );
+  mUploadWithoutRendering = ( updateMode == UpdateMode::SKIP_RENDER );
+  LOG_COUNTER_EVENT( "mUpdateRenderRunCount: %d, mUseElapsedTimeAfterWait: %d", mUpdateRenderRunCount, mUseElapsedTimeAfterWait );
+  mUpdateRenderThreadWaitCondition.Notify( lock );
+}
+
+void CombinedUpdateRenderController::PauseUpdateRenderThread()
+{
+  ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+  mUpdateRenderRunCount = 0;
+}
+
+void CombinedUpdateRenderController::StopUpdateRenderThread()
+{
+  ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+  mDestroyUpdateRenderThread = TRUE;
+  mUpdateRenderThreadWaitCondition.Notify( lock );
+}
+
+bool CombinedUpdateRenderController::IsUpdateRenderThreadPaused()
+{
+  ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+  return ( mUpdateRenderRunCount != CONTINUOUS ) || // Report paused if NOT continuously running
+         mUpdateRenderThreadCanSleep;               // Report paused if sleeping
+}
+
+void CombinedUpdateRenderController::ProcessSleepRequest()
+{
+  LOG_EVENT_TRACE;
+
+  // Decrement Update request count
+  if( mUpdateRequestCount > 0 )
+  {
+    --mUpdateRequestCount;
+  }
+
+  // Can sleep if our update-request count is 0
+  // Update/Render thread can choose to carry on updating if it determines more update/renders are required
+  if( mUpdateRequestCount == 0 )
+  {
+    LOG_EVENT( "Going to sleep" );
+
+    ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+    mUpdateRenderThreadCanSleep = TRUE;
+  }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// UPDATE/RENDER THREAD
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void CombinedUpdateRenderController::UpdateRenderThread()
+{
+  SetThreadName("RenderThread\0");
+
+  // Install a function for logging
+  mEnvironmentOptions.InstallLogFunction();
+
+  // Install a function for tracing
+  mEnvironmentOptions.InstallTraceFunction();
+
+  LOG_UPDATE_RENDER( "THREAD CREATED" );
+
+  // Initialize EGL & OpenGL
+  Dali::DisplayConnection& displayConnection = mAdaptorInterfaces.GetDisplayConnectionInterface();
+  displayConnection.Initialize();
+
+  // EGL has been initialised at this point
+  NotifyGraphicsInitialised();
+
+  RenderSurfaceInterface* currentSurface = nullptr;
+
+  GraphicsInterface& graphics = mAdaptorInterfaces.GetGraphicsInterface();
+  EglGraphics* eglGraphics = static_cast<EglGraphics *>(&graphics);
+
+  // This will only be created once
+  EglInterface* eglInterface = &eglGraphics->GetEglInterface();
+
+  Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( *eglInterface );
+
+  // Try to use OpenGL es 3.0
+  // ChooseConfig returns false here when the device only support gles 2.0.
+  // Because eglChooseConfig with gles 3.0 setting fails when the device only support gles 2.0 and Our default setting is gles 3.0.
+  if( !eglImpl.ChooseConfig( true, COLOR_DEPTH_32 ) )
+  {
+    // Retry to use OpenGL es 2.0
+    eglGraphics->SetGlesVersion( 20 );
+    eglImpl.ChooseConfig( true, COLOR_DEPTH_32 );
+  }
+
+  // Check whether surfaceless context is supported
+  bool isSurfacelessContextSupported = eglImpl.IsSurfacelessContextSupported();
+  eglGraphics->SetIsSurfacelessContextSupported( isSurfacelessContextSupported );
+
+  if ( isSurfacelessContextSupported )
+  {
+    // Create a surfaceless OpenGL context for shared resources
+    eglImpl.CreateContext();
+    eglImpl.MakeContextCurrent( EGL_NO_SURFACE, eglImpl.GetContext() );
+  }
+  else
+  {
+    currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
+    if( currentSurface )
+    {
+      currentSurface->InitializeGraphics();
+      currentSurface->MakeContextCurrent();
+    }
+  }
+
+  eglGraphics->GetGlesInterface().ContextCreated();
+
+  // Tell core it has a context
+  mCore.ContextCreated();
+
+  NotifyThreadInitialised();
+
+  // Update time
+  uint64_t lastFrameTime;
+  TimeService::GetNanoseconds( lastFrameTime );
+
+  LOG_UPDATE_RENDER( "THREAD INITIALISED" );
+
+  bool useElapsedTime = true;
+  bool updateRequired = true;
+  uint64_t timeToSleepUntil = 0;
+  int extraFramesDropped = 0;
+
+  const unsigned int renderToFboInterval = mEnvironmentOptions.GetRenderToFboInterval();
+  const bool renderToFboEnabled = 0u != renderToFboInterval;
+  unsigned int frameCount = 0u;
+
+  while( UpdateRenderReady( useElapsedTime, updateRequired, timeToSleepUntil ) )
+  {
+    LOG_UPDATE_RENDER_TRACE;
+
+    // Performance statistics are logged upon a VSYNC tick so use this point for a VSync marker
+    AddPerformanceMarker( PerformanceInterface::VSYNC );
+
+    uint64_t currentFrameStartTime = 0;
+    TimeService::GetNanoseconds( currentFrameStartTime );
+
+    const uint64_t timeSinceLastFrame = currentFrameStartTime - lastFrameTime;
+
+    // Optional FPS Tracking when continuously rendering
+    if( useElapsedTime && mFpsTracker.Enabled() )
+    {
+      float absoluteTimeSinceLastRender = timeSinceLastFrame * NANOSECONDS_TO_SECOND;
+      mFpsTracker.Track( absoluteTimeSinceLastRender );
+    }
+
+    lastFrameTime = currentFrameStartTime; // Store frame start time
+
+    //////////////////////////////
+    // REPLACE SURFACE
+    //////////////////////////////
+
+    Dali::RenderSurfaceInterface* newSurface = ShouldSurfaceBeReplaced();
+    if( DALI_UNLIKELY( newSurface ) )
+    {
+      LOG_UPDATE_RENDER_TRACE_FMT( "Replacing Surface" );
+      // This is designed for replacing pixmap surfaces, but should work for window as well
+      // we need to delete the surface and renderable (pixmap / window)
+      // Then create a new pixmap/window and new surface
+      // If the new surface has a different display connection, then the context will be lost
+      mAdaptorInterfaces.GetDisplayConnectionInterface().Initialize();
+      newSurface->InitializeGraphics();
+      newSurface->MakeContextCurrent();
+      // TODO: ReplaceGraphicsSurface doesn't work, InitializeGraphics()
+      // already creates new surface window, the surface and the context.
+      // We probably don't need ReplaceGraphicsSurface at all.
+      // newSurface->ReplaceGraphicsSurface();
+      SurfaceReplaced();
+    }
+
+    const bool isRenderingToFbo = renderToFboEnabled && ( ( 0u == frameCount ) || ( 0u != frameCount % renderToFboInterval ) );
+    ++frameCount;
+
+    //////////////////////////////
+    // UPDATE
+    //////////////////////////////
+
+    const unsigned int currentTime = currentFrameStartTime / NANOSECONDS_PER_MILLISECOND;
+    const unsigned int nextFrameTime = currentTime + mDefaultFrameDurationMilliseconds;
+
+    uint64_t noOfFramesSinceLastUpdate = 1;
+    float frameDelta = 0.0f;
+    if( useElapsedTime )
+    {
+      // If using the elapsed time, then calculate frameDelta as a multiple of mDefaultFrameDelta
+      noOfFramesSinceLastUpdate += extraFramesDropped;
+
+      frameDelta = mDefaultFrameDelta * noOfFramesSinceLastUpdate;
+    }
+    LOG_UPDATE_RENDER( "timeSinceLastFrame(%llu) noOfFramesSinceLastUpdate(%u) frameDelta(%.6f)", timeSinceLastFrame, noOfFramesSinceLastUpdate, frameDelta );
+
+    Integration::UpdateStatus updateStatus;
+
+    AddPerformanceMarker( PerformanceInterface::UPDATE_START );
+    mCore.Update( frameDelta,
+                  currentTime,
+                  nextFrameTime,
+                  updateStatus,
+                  renderToFboEnabled,
+                  isRenderingToFbo );
+    AddPerformanceMarker( PerformanceInterface::UPDATE_END );
+
+    unsigned int keepUpdatingStatus = updateStatus.KeepUpdating();
+
+    // Tell the event-thread to wake up (if asleep) and send a notification event to Core if required
+    if( updateStatus.NeedsNotification() )
+    {
+      mNotificationTrigger.Trigger();
+      LOG_UPDATE_RENDER( "Notification Triggered" );
+    }
+
+    // Check resize
+    bool surfaceResized = false;
+    bool shouldSurfaceBeResized = ShouldSurfaceBeResized();
+    if( DALI_UNLIKELY( shouldSurfaceBeResized ) )
+    {
+      if( updateStatus.SurfaceRectChanged() )
+      {
+        LOG_UPDATE_RENDER_TRACE_FMT( "Resizing Surface" );
+        SurfaceResized();
+        surfaceResized = true;
+      }
+    }
+
+    // Optional logging of update/render status
+    mUpdateStatusLogger.Log( keepUpdatingStatus );
+
+    //////////////////////////////
+    // RENDER
+    //////////////////////////////
+
+    mAdaptorInterfaces.GetDisplayConnectionInterface().ConsumeEvents();
+
+    if( mPreRenderCallback != NULL )
+    {
+      bool keepCallback = CallbackBase::ExecuteReturn<bool>(*mPreRenderCallback);
+      if( ! keepCallback )
+      {
+        delete mPreRenderCallback;
+        mPreRenderCallback = NULL;
+      }
+    }
+
+    if( eglImpl.IsSurfacelessContextSupported() )
+    {
+      // Make the shared surfaceless context as current before rendering
+      eglImpl.MakeContextCurrent( EGL_NO_SURFACE, eglImpl.GetContext() );
+    }
+
+    if( mFirstFrameAfterResume )
+    {
+      // mFirstFrameAfterResume is set to true when the thread is resumed
+      // Let eglImplementation know the first frame after thread initialized or resumed.
+      eglImpl.SetFirstFrameAfterResume();
+      mFirstFrameAfterResume = FALSE;
+    }
+
+    Integration::RenderStatus renderStatus;
+
+    AddPerformanceMarker( PerformanceInterface::RENDER_START );
+
+    mIsRenderingWindows = true;
+
+    // Upload shared resources
+    mCore.PreRender( renderStatus, mForceClear, mUploadWithoutRendering );
+
+    if ( !mUploadWithoutRendering )
+    {
+      // Go through each window
+      WindowContainer windows;
+      mAdaptorInterfaces.GetWindowContainerInterface( windows );
+
+      for( auto&& window : windows )
+      {
+        if ( window && !window->IsBeingDeleted() )
+        {
+          Dali::Integration::Scene scene = window->GetScene();
+          Dali::RenderSurfaceInterface* windowSurface = window->GetSurface();
+
+          if ( scene && windowSurface )
+          {
+            windowSurface->InitializeGraphics();
+
+            // Render off-screen frame buffers first if any
+            mCore.RenderScene( scene, true );
+
+            // Switch to the EGL context of the surface
+            windowSurface->PreRender( surfaceResized ); // Switch GL context
+
+            // Render the surface
+            mCore.RenderScene( scene, false );
+
+            windowSurface->PostRender( false, false, surfaceResized ); // Swap Buffer
+          }
+        }
+      }
+    }
+
+    mCore.PostRender( mUploadWithoutRendering );
+
+    mIsRenderingWindows = false;
+
+    AddPerformanceMarker( PerformanceInterface::RENDER_END );
+
+    mForceClear = false;
+
+    // Trigger event thread to request Update/Render thread to sleep if update not required
+    if( ( Integration::KeepUpdating::NOT_REQUESTED == keepUpdatingStatus ) && !renderStatus.NeedsUpdate() )
+    {
+      mSleepTrigger->Trigger();
+      updateRequired = false;
+      LOG_UPDATE_RENDER( "Sleep Triggered" );
+    }
+    else
+    {
+      updateRequired = true;
+    }
+
+    //////////////////////////////
+    // 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++;
+      }
+    }
+
+    // Render to FBO is intended to measure fps above 60 so sleep is not wanted.
+    if( 0u == renderToFboInterval )
+    {
+      // 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( timeToSleepUntil );
+    }
+  }
+
+  // Inform core of context destruction & shutdown EGL
+  mCore.ContextDestroyed();
+  currentSurface = mAdaptorInterfaces.GetRenderSurfaceInterface();
+  if( currentSurface )
+  {
+    currentSurface->DestroySurface();
+    currentSurface = nullptr;
+  }
+
+  LOG_UPDATE_RENDER( "THREAD DESTROYED" );
+
+  // Uninstall the logging function
+  mEnvironmentOptions.UnInstallLogFunction();
+}
+
+bool CombinedUpdateRenderController::UpdateRenderReady( bool& useElapsedTime, bool updateRequired, uint64_t& timeToSleepUntil )
+{
+  useElapsedTime = true;
+
+  ConditionalWait::ScopedLock updateLock( mUpdateRenderThreadWaitCondition );
+  while( ( ! mUpdateRenderRunCount || // Should try to wait if event-thread has paused the Update/Render thread
+           ( mUpdateRenderThreadCanSleep && ! updateRequired && ! mPendingRequestUpdate ) ) && // Ensure we wait if we're supposed to be sleeping AND do not require another update
+         ! mDestroyUpdateRenderThread && // Ensure we don't wait if the update-render-thread is supposed to be destroyed
+         ! mNewSurface &&  // Ensure we don't wait if we need to replace the surface
+         ! mSurfaceResized ) // Ensure we don't wait if we need to resize the surface
+  {
+    LOG_UPDATE_RENDER( "WAIT: mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
+    LOG_UPDATE_RENDER( "      mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
+    LOG_UPDATE_RENDER( "      mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
+    LOG_UPDATE_RENDER( "      mNewSurface:                 %d", mNewSurface );
+    LOG_UPDATE_RENDER( "      mSurfaceResized:             %d", mSurfaceResized );
+
+    // 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 )
+    {
+      useElapsedTime = false;
+    }
+  }
+
+  LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderRunCount:       %d", mUpdateRenderRunCount );
+  LOG_COUNTER_UPDATE_RENDER( "mUpdateRenderThreadCanSleep: %d, updateRequired: %d, mPendingRequestUpdate: %d", mUpdateRenderThreadCanSleep, updateRequired, mPendingRequestUpdate );
+  LOG_COUNTER_UPDATE_RENDER( "mDestroyUpdateRenderThread:  %d", mDestroyUpdateRenderThread );
+  LOG_COUNTER_UPDATE_RENDER( "mNewSurface:                 %d", mNewSurface );
+  LOG_COUNTER_UPDATE_RENDER( "mSurfaceResized:             %d", mSurfaceResized );
+
+  mUseElapsedTimeAfterWait = FALSE;
+  mUpdateRenderThreadCanSleep = FALSE;
+  mPendingRequestUpdate = FALSE;
+
+  // If we've been asked to run Update/Render cycles a finite number of times then decrement so we wait after the
+  // requested number of cycles
+  if( mUpdateRenderRunCount > 0 )
+  {
+    --mUpdateRenderRunCount;
+  }
+
+  // Keep the update-render thread alive if this thread is NOT to be destroyed
+  return ! mDestroyUpdateRenderThread;
+}
+
+Dali::RenderSurfaceInterface* CombinedUpdateRenderController::ShouldSurfaceBeReplaced()
+{
+  ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+
+  Dali::RenderSurfaceInterface* newSurface = mNewSurface;
+  mNewSurface = NULL;
+
+  return newSurface;
+}
+
+void CombinedUpdateRenderController::SurfaceReplaced()
+{
+  // Just increment the semaphore
+  sem_post( &mEventThreadSemaphore );
+}
+
+bool CombinedUpdateRenderController::ShouldSurfaceBeResized()
+{
+  ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+  return mSurfaceResized;
+}
+
+void CombinedUpdateRenderController::SurfaceResized()
+{
+  ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+  mSurfaceResized = FALSE;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// ALL THREADS
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void CombinedUpdateRenderController::NotifyThreadInitialised()
+{
+  // Just increment the semaphore
+  sem_post( &mEventThreadSemaphore );
+}
+
+void CombinedUpdateRenderController::NotifyGraphicsInitialised()
+{
+  sem_post( &mGraphicsInitializeSemaphore );
+}
+
+void CombinedUpdateRenderController::AddPerformanceMarker( PerformanceInterface::MarkerType type )
+{
+  if( mPerformanceInterface )
+  {
+    mPerformanceInterface->AddMarker( type );
+  }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// POST RENDERING: EVENT THREAD
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+void CombinedUpdateRenderController::PostRenderComplete()
+{
+  ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+  mPostRendering = FALSE;
+  mUpdateRenderThreadWaitCondition.Notify( lock );
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// POST RENDERING: RENDER THREAD
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void CombinedUpdateRenderController::PostRenderStarted()
+{
+  ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+  mPostRendering = TRUE;
+}
+
+void CombinedUpdateRenderController::PostRenderWaitForCompletion()
+{
+  ConditionalWait::ScopedLock lock( mUpdateRenderThreadWaitCondition );
+  while( mPostRendering &&
+         ! mNewSurface &&                // We should NOT wait if we're replacing the surface
+         ! mDestroyUpdateRenderThread )
+  {
+    mUpdateRenderThreadWaitCondition.Wait( lock );
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/adaptor/common/combined-update-render-controller.h b/dali/internal/adaptor/common/combined-update-render-controller.h
new file mode 100644 (file)
index 0000000..ca22517
--- /dev/null
@@ -0,0 +1,386 @@
+#ifndef DALI_INTERNAL_COMBINED_UPDATE_RENDER_CONTROLLER_H
+#define DALI_INTERNAL_COMBINED_UPDATE_RENDER_CONTROLLER_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <pthread.h>
+#include <semaphore.h>
+#include <atomic>
+#include <stdint.h>
+#include <dali/devel-api/threading/conditional-wait.h>
+#include <dali/integration-api/core.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/thread-synchronization-interface.h>
+#include <dali/internal/adaptor/common/thread-controller-interface.h>
+#include <dali/internal/system/common/fps-tracker.h>
+#include <dali/internal/system/common/performance-interface.h>
+#include <dali/internal/system/common/update-status-logger.h>
+#include <dali/internal/window-system/common/display-connection.h>
+
+namespace Dali
+{
+
+class RenderSurfaceInterface;
+class TriggerEventInterface;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class AdaptorInternalServices;
+class EnvironmentOptions;
+
+/**
+ * @brief Two threads where events/application interaction is handled on the main/event thread and the Update & Render
+ * happen on the other thread.
+ *
+ * Key Points:
+ *  1. Two Threads:
+ *    a. Main/Event Thread.
+ *    b. Update/Render Thread.
+ *  2. There is NO VSync thread:
+ *    a. We retrieve the time before Update.
+ *    b. Then retrieve the time after Render.
+ *    c. We calculate the difference between these two times and if:
+ *      i.  The difference is less than the default frame time, we sleep.
+ *      ii. If it’s more or the same, we continue.
+ *  3. On the update/render thread, if we discover that we do not need to do any more updates, we use a trigger-event
+ *     to inform the main/event thread. This is then processed as soon as the event thread is able to do so where it
+ *     is easier to make a decision about whether we should stop the update/render thread or not (depending on any
+ *     update requests etc.).
+ *  4. The main thread is blocked while the surface is being replaced.
+ *  5. When we resume from paused, elapsed time is used for the animations, i.e. the could have finished while we were paused.
+ *     However, FinishedSignal emission will only happen upon resumption.
+ *  6. Elapsed time is NOT used while if we are waking up from a sleep state or doing an UpdateOnce.
+ */
+class CombinedUpdateRenderController : public ThreadControllerInterface,
+                                       public ThreadSynchronizationInterface
+{
+public:
+
+  /**
+   * Constructor
+   */
+  CombinedUpdateRenderController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions );
+
+  /**
+   * Non virtual destructor. Not intended as base class.
+   */
+  ~CombinedUpdateRenderController();
+
+  /**
+   * @copydoc ThreadControllerInterface::Initialize()
+   */
+  virtual void Initialize();
+
+  /**
+   * @copydoc ThreadControllerInterface::Start()
+   */
+  virtual void Start();
+
+  /**
+   * @copydoc ThreadControllerInterface::Pause()
+   */
+  virtual void Pause();
+
+  /**
+   * @copydoc ThreadControllerInterface::Resume()
+   */
+  virtual void Resume();
+
+  /**
+   * @copydoc ThreadControllerInterface::Stop()
+   */
+  virtual void Stop();
+
+  /**
+   * @copydoc ThreadControllerInterface::RequestUpdate()
+   */
+  virtual void RequestUpdate();
+
+  /**
+   * @copydoc ThreadControllerInterface::RequestUpdateOnce()
+   */
+  virtual void RequestUpdateOnce( UpdateMode updateMode );
+
+  /**
+   * @copydoc ThreadControllerInterface::ReplaceSurface()
+   */
+  virtual void ReplaceSurface( Dali::RenderSurfaceInterface* surface );
+
+  /**
+   * @copydoc ThreadControllerInterface::ResizeSurface()
+   */
+  virtual void ResizeSurface();
+
+  /**
+   * @copydoc ThreadControllerInterface::WaitForGraphicsInitialization()
+   */
+  virtual void WaitForGraphicsInitialization();
+
+  /**
+   * @copydoc ThreadControllerInterface::SetRenderRefreshRate()
+   */
+  virtual void SetRenderRefreshRate( unsigned int numberOfFramesPerRender );
+
+  /**
+   * @copydoc ThreadControllerInterface::SetPreRenderCallback
+   */
+  void SetPreRenderCallback( CallbackBase* callback ) override;
+
+  /**
+   * @copydoc ThreadControllerInterface::AddSurface()
+   */
+  virtual void AddSurface( Dali::RenderSurfaceInterface* surface );
+
+  /**
+   * @copydoc ThreadControllerInterface::IsRenderingWindows()
+   */
+  bool IsRenderingWindows() const override { return mIsRenderingWindows; }
+
+private:
+
+  // Undefined copy constructor.
+  CombinedUpdateRenderController( const CombinedUpdateRenderController& );
+
+  // Undefined assignment operator.
+  CombinedUpdateRenderController& operator=( const CombinedUpdateRenderController& );
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // EventThread
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  enum AnimationProgression
+  {
+    USE_ELAPSED_TIME,          ///< Animation progression using elapsed time
+    NONE                       ///< No animation progression
+  };
+
+  /**
+   * Runs the Update/Render Thread.
+   * This will lock the mutex in mUpdateRenderThreadWaitCondition.
+   *
+   * @param[in]  numberOfCycles           The number of times the update/render cycle should run. If -1, then it will run continuously.
+   * @param[in]  animationProgression     Whether to progress animation using time elapsed since the last frame.
+   * @param[in]  updateMode               The update mode (i.e. either update & render or skip rendering)
+   */
+  inline void RunUpdateRenderThread( int numberOfCycles, AnimationProgression animationProgression, UpdateMode updateMode );
+
+  /**
+   * Pauses the Update/Render Thread.
+   * This will lock the mutex in mUpdateRenderThreadWaitCondition.
+   */
+  inline void PauseUpdateRenderThread();
+
+  /**
+   * Stops the Update/Render Thread.
+   * This will lock the mutex in mUpdateRenderThreadWaitCondition.
+   *
+   * @note Should only be called in Stop as calling this will kill the update-thread.
+   */
+  inline void StopUpdateRenderThread();
+
+  /**
+   * Checks if the the Update/Render Thread is paused.
+   * This will lock the mutex in mUpdateRenderThreadWaitCondition.
+   *
+   * @return true if paused, false otherwise
+   */
+  inline bool IsUpdateRenderThreadPaused();
+
+  /**
+   * Used as the callback for the sleep-trigger.
+   *
+   * Will sleep when enough requests are made without any requests.
+   */
+  void ProcessSleepRequest();
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // UpdateRenderThread
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * The Update/Render thread loop. This thread will be destroyed on exit from this function.
+   */
+  void UpdateRenderThread();
+
+  /**
+   * 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] 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, uint64_t& timeToSleepUntil );
+
+  /**
+   * Checks to see if the surface needs to be replaced.
+   * This will lock the mutex in mUpdateRenderThreadWaitCondition.
+   *
+   * @return Pointer to the new surface, NULL otherwise
+   */
+  Dali::RenderSurfaceInterface* ShouldSurfaceBeReplaced();
+
+  /**
+   * Called by the Update/Render thread after a surface has been replaced.
+   *
+   * This will lock the mutex in mEventThreadWaitCondition
+   */
+  void SurfaceReplaced();
+
+  /**
+   * Checks to see if the surface needs to be resized.
+   * This will lock the mutex in mUpdateRenderThreadWaitCondition.
+   *
+   * @return true if the surface should be resized, false otherwise
+   */
+  bool ShouldSurfaceBeResized();
+
+  /**
+   * Called by the Update/Render thread after a surface has been resized.
+   *
+   * This will lock the mutex in mEventThreadWaitCondition
+   */
+  void SurfaceResized();
+
+  /**
+   * Helper for the thread calling the entry function
+   * @param[in] This A pointer to the current object
+   */
+  static void* InternalUpdateRenderThreadEntryFunc( void* This )
+  {
+    ( static_cast<CombinedUpdateRenderController*>( This ) )->UpdateRenderThread();
+    return NULL;
+  }
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // ALL Threads
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * Called by the update-render & v-sync threads when they up and running.
+   *
+   * This will lock the mutex in mEventThreadWaitCondition.
+   */
+  void NotifyThreadInitialised();
+
+  /**
+   * Called by the update-render thread when graphics has been initialised.
+   */
+  void NotifyGraphicsInitialised();
+
+  /**
+   * Helper to add a performance marker to the performance server (if it's active)
+   * @param[in]  type  performance marker type
+   */
+  void AddPerformanceMarker( PerformanceInterface::MarkerType type );
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  // POST RENDERING - ThreadSynchronizationInterface overrides
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  //// Called by the Event Thread if post-rendering is required
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * @copydoc ThreadSynchronizationInterface::PostRenderComplete()
+   */
+  virtual void PostRenderComplete();
+
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+  //// Called by the Render Thread if post-rendering is required
+  /////////////////////////////////////////////////////////////////////////////////////////////////
+
+  /**
+   * @copydoc ThreadSynchronizationInterface::PostRenderStarted()
+   */
+  virtual void PostRenderStarted();
+
+  /**
+   * @copydoc ThreadSynchronizationInterface::PostRenderStarted()
+   */
+  virtual void PostRenderWaitForCompletion();
+
+private:
+
+  FpsTracker                        mFpsTracker;                       ///< Object that tracks the FPS
+  UpdateStatusLogger                mUpdateStatusLogger;               ///< Object that logs the update-status as required.
+
+  sem_t                             mEventThreadSemaphore;             ///< Used by the event thread to ensure all threads have been initialised, and when replacing the surface.
+  sem_t                             mGraphicsInitializeSemaphore;      ///< Used by the render thread to ensure the graphics has been initialised.
+
+  ConditionalWait                   mUpdateRenderThreadWaitCondition;  ///< The wait condition for the update-render-thread.
+
+  AdaptorInternalServices&          mAdaptorInterfaces;                ///< The adaptor internal interface
+  PerformanceInterface*             mPerformanceInterface;             ///< The performance logging interface
+  Integration::Core&                mCore;                             ///< Dali core reference
+  const EnvironmentOptions&         mEnvironmentOptions;               ///< Environment options
+  TriggerEventInterface&            mNotificationTrigger;              ///< Reference to notification event trigger
+  TriggerEventInterface*            mSleepTrigger;                     ///< Used by the update-render thread to trigger the event thread when it no longer needs to do any updates
+  CallbackBase*                     mPreRenderCallback;                ///< Used by Update/Render thread when PreRender is about to be called on graphics.
+
+  pthread_t*                        mUpdateRenderThread;               ///< The Update/Render thread.
+
+  float                             mDefaultFrameDelta;                ///< Default time delta between each frame (used for animations). Not protected by lock, but written to rarely so not worth adding a lock when reading.
+  // TODO: mDefaultFrameDurationMilliseconds is defined as uint64_t, the only place where it is used, it is converted to an unsigned int!!!
+  uint64_t                          mDefaultFrameDurationMilliseconds; ///< Default duration of a frame (used for predicting the time of the next frame). Not protected by lock, but written to rarely so not worth adding a lock when reading.
+  uint64_t                          mDefaultFrameDurationNanoseconds;  ///< Default duration of a frame (used for sleeping if not enough time elapsed). Not protected by lock, but written to rarely so not worth adding a lock when reading.
+  uint64_t                          mDefaultHalfFrameNanoseconds;      ///< Is half of mDefaultFrameDurationNanoseconds. Using a member variable avoids having to do the calculation every frame. Not protected by lock, but written to rarely so not worth adding a lock when reading.
+
+  unsigned int                      mUpdateRequestCount;               ///< Count of update-requests we have received to ensure we do not go to sleep too early.
+  unsigned int                      mRunning;                          ///< Read and set on the event-thread only to state whether we are running.
+
+  //
+  // NOTE: cannot use booleans as these are used from multiple threads, must use variable with machine word size for atomic read/write
+  //
+
+  volatile int                      mUpdateRenderRunCount;             ///< The number of times Update/Render cycle should run. If -1, then will run continuously (set by the event-thread, read by v-sync-thread).
+  volatile unsigned int             mDestroyUpdateRenderThread;        ///< Whether the Update/Render thread be destroyed (set by the event-thread, read by the update-render-thread).
+  volatile unsigned int             mUpdateRenderThreadCanSleep;       ///< Whether the Update/Render thread can sleep (set by the event-thread, read by the update-render-thread).
+  volatile unsigned int             mPendingRequestUpdate;             ///< Is set as soon as an RequestUpdate is made and unset when the next update happens (set by the event-thread and update-render thread, read by the update-render-thread).
+                                                                       ///< Ensures we do not go to sleep if we have not processed the most recent update-request.
+
+  volatile unsigned int             mUseElapsedTimeAfterWait;          ///< Whether we should use the elapsed time after waiting (set by the event-thread, read by the update-render-thread).
+
+  Dali::RenderSurfaceInterface* volatile mNewSurface;                  ///< Will be set to the new-surface if requested (set by the event-thread, read & cleared by the update-render thread).
+
+  volatile unsigned int             mPostRendering;                    ///< Whether post-rendering is taking place (set by the event & render threads, read by the render-thread).
+  volatile unsigned int             mSurfaceResized;                   ///< Will be set to resize the surface (set by the event-thread, read & cleared by the update-render thread).
+  volatile unsigned int             mForceClear;                       ///< Will be set to clear forcibly
+
+  volatile unsigned int             mUploadWithoutRendering;           ///< Will be set to upload the resource only (with no rendering)
+
+  volatile unsigned int             mFirstFrameAfterResume;            ///< Will be set to check the first frame after resume (for log)
+
+  std::atomic<bool>                 mIsRenderingWindows;               ///< This is set only from the render thread and read only from the event thread
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_COMBINED_UPDATE_RENDER_CONTROLLER_H
diff --git a/dali/internal/adaptor/common/framework.h b/dali/internal/adaptor/common/framework.h
new file mode 100644 (file)
index 0000000..d95388c
--- /dev/null
@@ -0,0 +1,319 @@
+#ifndef DALI_INTERNAL_FRAMEWORK_H
+#define DALI_INTERNAL_FRAMEWORK_H
+
+/*
+ * Copyright (c) 2019 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/signals/callback.h>
+#ifdef APPCORE_WATCH_AVAILABLE
+#include <dali/public-api/watch/watch-application.h>
+#endif
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/abort-handler.h>
+#include <dali/public-api/adaptor-framework/device-status.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * The Framework class is ideally placed to provide key API required by Applications.
+ *
+ * The class is also used to register callbacks with the TIZEN platform so that
+ * we know when any of the application lifecycle events occur.  This includes events
+ * like when our application is to be initialised, terminated, paused, resumed etc.
+ *
+ */
+class Framework
+{
+public:
+
+  enum Type
+  {
+    NORMAL,       ///< normal appFramework
+    WATCH,        ///< watch appFramework
+    WIDGET        ///< widget appFramework
+  };
+
+  /**
+   * Observer class for the framework.
+   */
+  class Observer
+  {
+  public:
+
+    /**
+     * Invoked when the application is to be initialised.
+     */
+    virtual void OnInit() {}
+
+    /**
+     * Invoked when the application is to be terminated.
+     */
+    virtual void OnTerminate() {}
+
+    /**
+     * Invoked when the application is to be paused.
+     */
+    virtual void OnPause() {}
+
+    /**
+     * Invoked when the application is to be resumed.
+     */
+    virtual void OnResume() {}
+
+    /**
+     * Invoked when the application is to be reset.
+     */
+    virtual void OnReset() {}
+
+    /**
+    * Invoked when the AppControl message is received.
+    * @param[in] The bundle data of AppControl message.
+    */
+    virtual void OnAppControl(void *) {}
+
+#ifdef APPCORE_WATCH_AVAILABLE
+    /**
+     * Invoked at every second
+     */
+    virtual void OnTimeTick(WatchTime&) {}
+
+    /**
+     * Invoked at every second in ambient mode
+     */
+    virtual void OnAmbientTick(WatchTime&) {}
+
+    /**
+     * Invoked when the device enters or exits ambient mode
+     */
+    virtual void OnAmbientChanged(bool ambient) {}
+#endif
+
+    /**
+     * Invoked when the language of the device is changed.
+     */
+    virtual void OnLanguageChanged() {}
+
+    /**
+     * Invoked when the region is changed.
+     */
+    virtual void OnRegionChanged() {}
+
+    /**
+     * Invoked when the battery level of the device is low.
+     */
+    virtual void OnBatteryLow( Dali::DeviceStatus::Battery::Status status ) {}
+
+    /**
+     * Invoked when the memory level of the device is low.
+     */
+    virtual void OnMemoryLow( Dali::DeviceStatus::Memory::Status status ) {}
+
+    /**
+     * Invoked when the platform surface is created.
+     */
+    virtual void OnSurfaceCreated( Any newSurface ) {}
+
+    /**
+     * Invoked when the platform surface is destroyed.
+     */
+    virtual void OnSurfaceDestroyed( Any newSurface ) {}
+  };
+
+public:
+
+  /**
+   * Constructor
+   * @param[in]  observer  The observer of the Framework.
+   * @param[in]  argc      A pointer to the number of arguments.
+   * @param[in]  argv      A pointer the the argument list.
+   * @param[in]  type      The type of application
+   */
+  Framework( Observer& observer, int* argc, char ***argv, Type type = NORMAL );
+
+  /**
+   * Destructor
+   */
+  ~Framework();
+
+public:
+
+  /**
+   * Runs the main loop of framework
+   */
+  void Run();
+
+  /**
+   * Quits the main loop
+   */
+  void Quit();
+
+  /**
+   * Checks whether the main loop of the framework is running.
+   * @return true, if the main loop is running, false otherwise.
+   */
+  bool IsMainLoopRunning();
+
+  /**
+   * If the main loop aborts unexpectedly, then the connected callback function is called.
+   * @param[in]  callBack  The function to call.
+   * @note Only one callback can be registered.  The last callback to be set will be called on abort.
+   * @note The ownership of callback is passed onto this class.
+   */
+  void AddAbortCallback( CallbackBase* callback );
+
+  /**
+   * Gets bundle name which was passed in app_reset callback.
+   */
+  std::string GetBundleName() const;
+
+  /**
+   * Gets bundle id which was passed in app_reset callback.
+   */
+  std::string GetBundleId() const;
+
+  /**
+   * Sets a command line options.
+   * This is used in case of the preinitialized application.
+   * @param[in] argc A pointer to the number of arguments
+   * @param[in] argv A pointer to the argument list
+   */
+  void SetCommandLineOptions( int* argc, char **argv[] )
+  {
+    mArgc = argc;
+    mArgv = argv;
+  }
+
+
+  /**
+   *  Gets the path at which application resources are stored.
+   */
+  static std::string GetResourcePath();
+
+  /**
+   *  Gets the path at which application data are stored.
+   */
+  static std::string GetDataPath();
+
+  /**
+   * Sets system language.
+   */
+  void SetLanguage( const std::string& language );
+
+  /**
+   * Sets system region.
+   */
+  void SetRegion( const std::string& region );
+
+  /**
+   * Gets system language.
+   */
+  std::string GetLanguage() const;
+
+  /**
+   * Gets system region.
+   */
+  std::string GetRegion() const;
+
+  /**
+   * Called by the App framework when an application lifecycle event occurs.
+   * @param[in] type The type of event occurred.
+   * @param[in] data The data of event occurred.
+   */
+  bool AppStatusHandler(int type, void* data);
+
+  /**
+   * Called by the adaptor when an idle callback is added.
+   * @param[in] timeout The timeout of the callback.
+   * @param[in] data The data of of the callback.
+   * @param[in] callback The callback.
+   * @return The callback id.
+   */
+  unsigned int AddIdle( int timeout, void* data, bool ( *callback )( void *data ) );
+
+  /**
+   * Called by the adaptor when an idle callback is removed.
+   * @param[in] id The callback id.
+   */
+  void RemoveIdle( unsigned int id );
+
+private:
+
+  // Undefined
+  Framework(const Framework&);
+  Framework& operator=(Framework&);
+
+private:
+
+  /**
+   * Called when the application is created.
+   */
+  bool Create();
+
+  /**
+   * Called app_reset callback was called with bundle.
+   */
+  void SetBundleName(const std::string& name);
+
+  /**
+   * Called app_reset callback was called with bundle.
+   */
+  void SetBundleId(const std::string& id);
+
+  /**
+   * Called if the application is aborted.
+   */
+  void AbortCallback();
+
+  /**
+   * Called for initializing on specified backend. (X11 or Wayland)
+   */
+  void InitThreads();
+
+private:
+  Observer&          mObserver;
+  bool               mInitialised;
+  bool               mPaused;
+  bool               mRunning;
+  int*               mArgc;
+  char***            mArgv;
+  std::string        mBundleName;
+  std::string        mBundleId;
+  AbortHandler       mAbortHandler;
+
+private: // impl members
+
+  struct Impl;
+  Impl* mImpl;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_FRAMEWORK_H
diff --git a/dali/internal/adaptor/common/lifecycle-controller-impl.cpp b/dali/internal/adaptor/common/lifecycle-controller-impl.cpp
new file mode 100644 (file)
index 0000000..e4cd45e
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor/common/lifecycle-controller-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/devel-api/common/singleton-service.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+Dali::LifecycleController LifecycleController::Get()
+{
+  Dali::LifecycleController lifecycleController;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::LifecycleController ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      lifecycleController = Dali::LifecycleController( dynamic_cast< LifecycleController* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      lifecycleController = Dali::LifecycleController( new LifecycleController() );
+      service.Register( typeid( lifecycleController ), lifecycleController );
+    }
+  }
+
+  return lifecycleController;
+}
+
+LifecycleController::LifecycleController()
+{
+}
+
+LifecycleController::~LifecycleController()
+{
+}
+
+Dali::LifecycleController::LifecycleSignalType& LifecycleController::InitSignal()
+{
+  return mInitSignal;
+}
+
+void LifecycleController::EmitInitSignal()
+{
+  if( !mInitSignal.Empty() )
+  {
+    mInitSignal.Emit();
+  }
+}
+
+Dali::LifecycleController::LifecycleSignalType& LifecycleController::TerminateSignal()
+{
+  return mTerminateSignal;
+}
+
+void LifecycleController::EmitTerminateSignal()
+{
+  if( !mTerminateSignal.Empty() )
+  {
+    mTerminateSignal.Emit();
+  }
+}
+
+Dali::LifecycleController::LifecycleSignalType& LifecycleController::PauseSignal()
+{
+  return mPauseSignal;
+}
+
+void LifecycleController::EmitPauseSignal()
+{
+  if( !mPauseSignal.Empty() )
+  {
+    mPauseSignal.Emit();
+  }
+}
+
+Dali::LifecycleController::LifecycleSignalType& LifecycleController::ResumeSignal()
+{
+  return mResumeSignal;
+}
+
+void LifecycleController::EmitResumeSignal()
+{
+  if( !mResumeSignal.Empty() )
+  {
+    mResumeSignal.Emit();
+  }
+}
+
+Dali::LifecycleController::LifecycleSignalType& LifecycleController::ResetSignal()
+{
+  return mResetSignal;
+}
+
+void LifecycleController::EmitResetSignal()
+{
+  if( !mResetSignal.Empty() )
+  {
+    mResetSignal.Emit();
+  }
+}
+
+Dali::LifecycleController::LifecycleSignalType& LifecycleController::ResizeSignal()
+{
+  return mResizeSignal;
+}
+
+void LifecycleController::EmitResizeSignal()
+{
+  if( !mResizeSignal.Empty() )
+  {
+    mResizeSignal.Emit();
+  }
+}
+
+Dali::LifecycleController::LifecycleSignalType& LifecycleController::LanguageChangedSignal()
+{
+  return mLanguageChangedSignal;
+}
+
+void LifecycleController::EmitLanguageChangedSignal()
+{
+  if( !mLanguageChangedSignal.Empty() )
+  {
+    mLanguageChangedSignal.Emit();
+  }
+}
+
+void LifecycleController::OnInit( Dali::Application& app )
+{
+  EmitInitSignal();
+}
+
+void LifecycleController::OnTerminate( Dali::Application& app )
+{
+  EmitTerminateSignal();
+}
+
+void LifecycleController::OnPause( Dali::Application& app )
+{
+  EmitPauseSignal();
+}
+
+void LifecycleController::OnResume( Dali::Application& app )
+{
+  EmitResumeSignal();
+}
+
+void LifecycleController::OnReset( Dali::Application& app )
+{
+  EmitResetSignal();
+}
+
+void LifecycleController::OnLanguageChanged( Dali::Application& app )
+{
+  EmitLanguageChangedSignal();
+}
+
+void LifecycleController::OnResize( Dali::Application& app )
+{
+  EmitResizeSignal();
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/adaptor/common/lifecycle-controller-impl.h b/dali/internal/adaptor/common/lifecycle-controller-impl.h
new file mode 100644 (file)
index 0000000..904ba1e
--- /dev/null
@@ -0,0 +1,227 @@
+#ifndef DALI_INTERNAL_LIFECYCLE_CONTROLLER_H
+#define DALI_INTERNAL_LIFECYCLE_CONTROLLER_H
+
+/*
+ * Copyright (c) 2019 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/object/ref-object.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/lifecycle-controller.h>
+#include <dali/public-api/adaptor-framework/application.h>
+
+namespace Dali
+{
+
+class Adaptor;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * This provides signals that are emitted according the lifecylce of the program.
+ */
+class LifecycleController : public BaseObject, public ConnectionTracker
+{
+public:
+
+  // Creation & Destruction
+
+  /**
+   * Constructor.
+   */
+  LifecycleController();
+
+  /**
+   * Retrieve the initialized instance of the LifecycleController.
+   * @return Handle to LifecycleController.
+   */
+  static Dali::LifecycleController Get();
+
+  // Signals
+
+  /**
+   * @copydoc Dali::StyleMonitor::InitSignal()
+   */
+  Dali::LifecycleController::LifecycleSignalType& InitSignal();
+
+  /**
+   * @copydoc Dali::StyleMonitor::TerminateSignal()
+   */
+  Dali::LifecycleController::LifecycleSignalType& TerminateSignal();
+
+  /**
+   * @copydoc Dali::StyleMonitor::PauseSignal()
+   */
+  Dali::LifecycleController::LifecycleSignalType& PauseSignal();
+
+  /**
+   * @copydoc Dali::StyleMonitor::ResumeSignal()
+   */
+  Dali::LifecycleController::LifecycleSignalType& ResumeSignal();
+
+  /**
+   * @copydoc Dali::StyleMonitor::ResetSignal()
+   */
+  Dali::LifecycleController::LifecycleSignalType& ResetSignal();
+
+  /**
+   * @copydoc Dali::StyleMonitor::ResizeSignal()
+   */
+  Dali::LifecycleController::LifecycleSignalType& ResizeSignal();
+
+  /**
+   * @copydoc Dali::StyleMonitor::LanguageChangedSignal()
+   */
+  Dali::LifecycleController::LifecycleSignalType& LanguageChangedSignal();
+
+public:
+
+  /**
+   * Called when the framework is initialised.
+   *
+   * @param[in] app The application instance
+   */
+  void OnInit( Dali::Application& app );
+
+  /**
+   * Called when the framework is terminated.
+   *
+   * @param[in] app The application instance
+   */
+  void OnTerminate( Dali::Application& app );
+
+  /**
+   * Called when the framework is paused.
+   *
+   * @param[in] app The application instance
+   */
+  void OnPause( Dali::Application& app );
+
+  /**
+   * Called when the framework resumes from a paused state.
+   *
+   * @param[in] app The application instance
+   */
+  void OnResume( Dali::Application& app );
+
+  /**
+   * Called when the framework informs the application that it should reset itself.
+   *
+   * @param[in] app The application instance
+   */
+  void OnReset( Dali::Application& app );
+
+  /**
+   * Called when the framework informs the application that the language of the device has changed.
+   *
+   * @param[in] app The application instance
+   */
+  void OnLanguageChanged( Dali::Application& app );
+
+  /**
+   * Signal handler when the adaptor's window resizes itself.
+   *
+   * @param[in] app The application instance
+   */
+  void OnResize( Dali::Application& app );
+
+protected:
+
+  /**
+   * Virtual Destructor.
+   */
+  virtual ~LifecycleController();
+
+private:
+
+  /**
+   * Emit the init signal.
+   */
+  void EmitInitSignal();
+
+  /**
+   * Emit the init signal.
+   */
+  void EmitTerminateSignal();
+
+  /**
+   * Emit the init signal.
+   */
+  void EmitPauseSignal();
+
+  /**
+   * Emit the init signal.
+   */
+  void EmitResumeSignal();
+
+  /**
+   * Emit the init signal.
+   */
+  void EmitResetSignal();
+
+  /**
+   * Emit the init signal.
+   */
+  void EmitResizeSignal();
+
+  /**
+   * Emit the init signal.
+   */
+  void EmitLanguageChangedSignal();
+
+private:
+
+  // Signals
+  Dali::LifecycleController::LifecycleSignalType mInitSignal;
+  Dali::LifecycleController::LifecycleSignalType mTerminateSignal;
+  Dali::LifecycleController::LifecycleSignalType mPauseSignal;
+  Dali::LifecycleController::LifecycleSignalType mResumeSignal;
+  Dali::LifecycleController::LifecycleSignalType mResetSignal;
+  Dali::LifecycleController::LifecycleSignalType mResizeSignal;
+  Dali::LifecycleController::LifecycleSignalType mLanguageChangedSignal;
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Additional Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::LifecycleController& GetImplementation(Dali::LifecycleController& controller)
+{
+  DALI_ASSERT_ALWAYS(controller && "Controller handle is empty");
+  BaseObject& handle = controller.GetBaseObject();
+  return static_cast<Internal::Adaptor::LifecycleController&>(handle);
+}
+
+inline const Internal::Adaptor::LifecycleController& GetImplementation(const Dali::LifecycleController& controller)
+{
+  DALI_ASSERT_ALWAYS(controller && "Controller handle is empty");
+  const BaseObject& handle = controller.GetBaseObject();
+  return static_cast<const Internal::Adaptor::LifecycleController&>(handle);
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_LIFECYCLE_CONTROLLER_H
diff --git a/dali/internal/adaptor/common/lifecycle-observer.h b/dali/internal/adaptor/common/lifecycle-observer.h
new file mode 100644 (file)
index 0000000..d84ac8c
--- /dev/null
@@ -0,0 +1,97 @@
+#ifndef DALI_INTERNAL_BASE_LIFECYCLE_OBSERVER_H
+#define DALI_INTERNAL_BASE_LIFECYCLE_OBSERVER_H
+
+/*
+ * Copyright (c) 2019 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
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Adaptor life cycle observer
+ */
+class LifeCycleObserver
+{
+public:
+  /**
+   * Called when the adaptor has started.
+   */
+  virtual void OnStart() = 0;
+
+  /**
+   * Called when the adaptor is about to pause.
+   */
+  virtual void OnPause() = 0;
+
+  /**
+   * Called when the adaptor is about to resume.
+   */
+  virtual void OnResume() = 0;
+
+  /**
+   * Called when the adaptor is about to stop.
+   */
+  virtual void OnStop() = 0;
+
+  /**
+   * Called when the adaptor is about to be destroyed.
+   */
+  virtual void OnDestroy() = 0;
+
+protected:
+
+  /**
+   * Constructor
+   */
+  LifeCycleObserver()
+  {
+  }
+
+  /**
+   * Virtual destructor
+   */
+  virtual ~LifeCycleObserver()
+  {
+  }
+
+private:
+
+  // Undefined copy constructor.
+  LifeCycleObserver( const LifeCycleObserver& );
+
+  // Undefined assignment operator.
+  LifeCycleObserver& operator=( const LifeCycleObserver& );
+
+};
+
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_BASE_LIFECYCLE_OBSERVER_H
diff --git a/dali/internal/adaptor/common/thread-controller-interface.h b/dali/internal/adaptor/common/thread-controller-interface.h
new file mode 100644 (file)
index 0000000..94276ff
--- /dev/null
@@ -0,0 +1,148 @@
+#ifndef DALI_INTERNAL_THREAD_CONTROLLER_INTERFACE_H
+#define DALI_INTERNAL_THREAD_CONTROLLER_INTERFACE_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/public-api/signals/callback.h>
+
+namespace Dali
+{
+
+class RenderSurfaceInterface;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+enum class UpdateMode
+{
+  NORMAL,                     ///< Update and render
+  SKIP_RENDER                 ///< Update and resource upload but no rendering
+};
+
+/**
+ * Interface Class for all controlling threads.
+ */
+class ThreadControllerInterface
+{
+public:
+
+  /**
+   * Virtual destructor. Not intended as base class.
+   */
+  virtual ~ThreadControllerInterface() { }
+
+  /**
+   * Initializes the thread controller
+   */
+  virtual void Initialize() = 0;
+
+  /**
+   * @copydoc Dali::Adaptor::Start()
+   */
+  virtual void Start() = 0;
+
+  /**
+   * @copydoc Dali::Adaptor::Pause()
+   */
+  virtual void Pause() = 0;
+
+  /**
+   * @copydoc Dali::Adaptor::Resume()
+   */
+  virtual void Resume() = 0;
+
+  /**
+   * @copydoc Dali::Adaptor::Stop()
+   */
+  virtual void Stop() = 0;
+
+  /**
+   * Called by the adaptor when core requires another update
+   */
+  virtual void RequestUpdate() = 0;
+
+  /**
+   * Called by the adaptor when core requires one update
+   * If Adaptor is paused, we do one update/render and return to pause
+   * @param updateMode The update mode (i.e. i.e. either update & render or skip rendering)
+   */
+  virtual void RequestUpdateOnce( UpdateMode updateMode ) = 0;
+
+  /**
+   * Replaces the surface.
+   * @param surface new surface
+   */
+  virtual void ReplaceSurface( Dali::RenderSurfaceInterface* surface ) = 0;
+
+  /**
+   * Resize the surface.
+   */
+  virtual void ResizeSurface() = 0;
+
+  /**
+   * Wait until the graphics is initialised.
+   */
+  virtual void WaitForGraphicsInitialization() = 0;
+
+  /**
+   * @copydoc Dali::Adaptor::SetRenderRefreshRate()
+   */
+  virtual void SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender ) = 0;
+
+  /**
+   * @copydoc Dali::Adaptor::SetPreRenderCallback()
+   */
+  virtual void SetPreRenderCallback( CallbackBase* callback ) = 0;
+
+  /**
+   * @brief Adds the new surface.
+   * @param surface new surface
+   */
+  virtual void AddSurface( Dali::RenderSurfaceInterface* surface ) = 0;
+
+  /**
+   * @copydoc Dali::Adaptor::IsRenderingWindows()
+   */
+  virtual bool IsRenderingWindows() const = 0;
+
+protected:
+
+  /**
+   * Constructor
+   */
+  ThreadControllerInterface() { }
+
+private:
+
+  // Undefined copy constructor.
+  ThreadControllerInterface( const ThreadControllerInterface& );
+
+  // Undefined assignment operator.
+  ThreadControllerInterface& operator=( const ThreadControllerInterface& );
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_THREAD_CONTROLLER_INTERFACE_H
diff --git a/dali/internal/adaptor/common/threading-mode.h b/dali/internal/adaptor/common/threading-mode.h
new file mode 100644 (file)
index 0000000..d113c3a
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef DALI_INTERNAL_ADAPTOR_THREADING_MODE_H
+#define DALI_INTERNAL_ADAPTOR_THREADING_MODE_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+struct ThreadingMode
+{
+  enum Type
+  {
+    COMBINED_UPDATE_RENDER = 1,      ///< Three threads: Event, V-Sync & a Joint Update/Render thread.
+  };
+};
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_THREADING_MODE_H
diff --git a/dali/internal/adaptor/file.list b/dali/internal/adaptor/file.list
new file mode 100644 (file)
index 0000000..defd518
--- /dev/null
@@ -0,0 +1,51 @@
+
+# module: adaptor, backend: common
+SET( adaptor_adaptor_common_src_files 
+    ${adaptor_adaptor_dir}/common/lifecycle-controller-impl.cpp 
+    ${adaptor_adaptor_dir}/common/adaptor-impl.cpp 
+    ${adaptor_adaptor_dir}/common/adaptor.cpp 
+    ${adaptor_adaptor_dir}/common/adaptor-builder-impl.cpp 
+    ${adaptor_adaptor_dir}/common/application-impl.cpp 
+    ${adaptor_adaptor_dir}/common/combined-update-render-controller.cpp 
+    ${adaptor_adaptor_dir}/common/system-cache-path.cpp
+)
+
+# module: adaptor, backend: tizen-wayland
+SET( adaptor_adaptor_tizen_wayland_src_files 
+    ${adaptor_adaptor_dir}/tizen-wayland/adaptor-impl-tizen.cpp 
+    ${adaptor_adaptor_dir}/tizen-wayland/framework-tizen.cpp
+)
+
+# module: adaptor, backend: tizen-wearable
+SET( adaptor_adaptor_tizen_wearable_src_files 
+    ${adaptor_adaptor_dir}/tizen-wayland/tizen-wearable/watch-application.cpp 
+    ${adaptor_adaptor_dir}/tizen-wayland/tizen-wearable/watch-application-impl.cpp
+)
+
+# module: adaptor, backend: ubuntu
+SET( adaptor_adaptor_ubuntu_src_files 
+    ${adaptor_adaptor_dir}/generic/adaptor-impl-generic.cpp 
+    ${adaptor_adaptor_dir}/ubuntu/framework-ubuntu.cpp
+)
+
+# module: adaptor, backend: android
+SET( adaptor_adaptor_android_src_files
+    ${adaptor_adaptor_dir}/generic/adaptor-impl-generic.cpp
+    ${adaptor_adaptor_dir}/android/android-framework-impl.cpp
+    ${adaptor_adaptor_dir}/android/framework-android.cpp
+)
+
+# module: adaptor, backend: androidjni
+SET( adaptor_adaptor_androidjni_src_files
+    ${adaptor_adaptor_dir}/generic/adaptor-impl-generic.cpp
+    ${adaptor_adaptor_dir}/android/android-framework-impl.cpp
+    ${adaptor_adaptor_dir}/androidjni/framework-androidjni.cpp
+)
+
+# module: adaptor, backend: windows
+SET( adaptor_adaptor_windows_src_files
+    ${adaptor_adaptor_dir}/generic/adaptor-impl-generic.cpp
+    ${adaptor_adaptor_dir}/windows/framework-win.cpp
+)
+
+
diff --git a/dali/internal/adaptor/generic/adaptor-impl-generic.cpp b/dali/internal/adaptor/generic/adaptor-impl-generic.cpp
new file mode 100644 (file)
index 0000000..1b05919
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+void Adaptor::GetDataStoragePath( std::string& path)
+{
+  path = "";
+}
+
+void Adaptor::GetAppId( std::string& appId )
+{
+  appId = "";
+}
+
+void Adaptor::SurfaceInitialized()
+{
+}
+
+void Adaptor::SetupSystemInformation()
+{
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/adaptor/tizen-wayland/adaptor-impl-tizen.cpp b/dali/internal/adaptor/tizen-wayland/adaptor-impl-tizen.cpp
new file mode 100755 (executable)
index 0000000..fb0cddd
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+
+// EXTERNAL INCLUDES
+#include <app_common.h>
+#include <system_settings.h>
+
+#ifdef APPCORE_WATCH_AVAILABLE
+#include <screen_connector_provider.h>
+#endif
+
+#ifdef ECORE_WAYLAND2
+#include <dali/internal/adaptor/tizen-wayland/dali-ecore-wl2.h>
+#else
+#include <dali/internal/adaptor/tizen-wayland/dali-ecore-wayland.h>
+#endif
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+static void OnSystemLanguageChanged( system_settings_key_e key, void* data )
+{
+  char* locale = NULL;
+  if( system_settings_get_value_string( SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &locale ) != SYSTEM_SETTINGS_ERROR_NONE ||
+      locale == NULL )
+  {
+    DALI_LOG_ERROR( "DALI OnSystemLanguageChanged failed " );
+    return;
+  }
+
+  Adaptor* adaptor = static_cast< Adaptor* >( data );
+  if( adaptor != NULL )
+  {
+    adaptor->SetRootLayoutDirection( locale );
+  }
+
+  free( locale );
+}
+
+} // namesapce
+
+void Adaptor::GetDataStoragePath( std::string& path)
+{
+#ifdef USE_APPFW
+  char *pathInt = app_get_data_path();
+  if ( pathInt )
+  {
+    path = pathInt;
+    free( pathInt );
+  }
+  else
+  {
+    path = "";
+  }
+#endif
+
+}
+
+void Adaptor::GetAppId( std::string& appId )
+{
+#ifdef USE_APPFW
+  char *id;
+  app_get_id(&id);
+  if ( id )
+  {
+    appId = id;
+  }
+  else
+  {
+    appId = "";
+  }
+#endif
+}
+
+void Adaptor::SurfaceInitialized()
+{
+#ifdef APPCORE_WATCH_AVAILABLE
+  if ( !mUseRemoteSurface )
+  {
+    return;
+  }
+  char *appId;
+  app_get_id(&appId);
+
+  // Use strdup() in app_get_id(), so need to free memory
+  if( appId )
+  {
+#ifdef ECORE_WAYLAND2
+    Ecore_Wl2_Window* ecoreWlWindow = AnyCast< Ecore_Wl2_Window* >( mWindows.front()->GetNativeHandle() );
+    screen_connector_provider_remote_enable( appId, ecore_wl2_window_surface_get( ecoreWlWindow ) );
+#else
+    Ecore_Wl_Window* ecoreWlWindow = AnyCast< Ecore_Wl_Window* >( mWindows.front()->GetNativeHandle() );
+    screen_connector_provider_remote_enable( appId, ecore_wl_window_surface_get( ecoreWlWindow ) );
+#endif
+    free( appId );
+  }
+#endif
+}
+
+void Adaptor::SetupSystemInformation()
+{
+  if( system_settings_add_changed_cb( SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, OnSystemLanguageChanged, this ) != SYSTEM_SETTINGS_ERROR_NONE )
+  {
+    DALI_LOG_ERROR( "DALI system_settings_add_changed_cb failed.\n" );
+    return;
+  }
+
+  char* locale = NULL;
+  if( system_settings_get_value_string( SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &locale ) != SYSTEM_SETTINGS_ERROR_NONE ||
+      locale == NULL )
+  {
+    DALI_LOG_ERROR( "DALI OnSystemLanguageChanged failed " );
+    return;
+  }
+
+  SetRootLayoutDirection( locale );
+
+  free( locale );
+
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/adaptor/tizen-wayland/dali-ecore-wayland.h b/dali/internal/adaptor/tizen-wayland/dali-ecore-wayland.h
new file mode 100644 (file)
index 0000000..6eb6038
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef DALI_INTERNAL_ADAPTOR_TIZEN_WAYLAND_DALI_ECORE_WAYLAND_H
+#define DALI_INTERNAL_ADAPTOR_TIZEN_WAYLAND_DALI_ECORE_WAYLAND_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#pragma GCC system_header
+#include <Ecore_Wayland.h>
+
+
+
+#endif /* DALI_INTERNAL_ADAPTOR_TIZEN_WAYLAND_DALI_ECORE_WAYLAND_H */
diff --git a/dali/internal/adaptor/tizen-wayland/dali-ecore-wl2.h b/dali/internal/adaptor/tizen-wayland/dali-ecore-wl2.h
new file mode 100644 (file)
index 0000000..c733e31
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef DALI_INTERNAL_ADAPTOR_TIZEN_WAYLAND_DALI_ECORE_WL2_H
+#define DALI_INTERNAL_ADAPTOR_TIZEN_WAYLAND_DALI_ECORE_WL2_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#pragma GCC system_header
+#include <Ecore_Wl2.h>
+
+
+
+#endif /* DALI_INTERNAL_ADAPTOR_TIZEN_WAYLAND_DALI_ECORE_WL2_H */
diff --git a/dali/internal/adaptor/tizen-wayland/framework-tizen.cpp b/dali/internal/adaptor/tizen-wayland/framework-tizen.cpp
new file mode 100644 (file)
index 0000000..c440eeb
--- /dev/null
@@ -0,0 +1,891 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor/common/framework.h>
+
+// EXTERNAL INCLUDES
+#include <appcore_ui_base.h>
+#include <app_control_internal.h>
+#include <app_common.h>
+#include <bundle.h>
+#include <dali/internal/system/linux/dali-ecore.h>
+
+#include <system_info.h>
+#include <system_settings.h>
+#include <bundle_internal.h>
+#include <widget_base.h>
+// CONDITIONAL INCLUDES
+#ifdef APPCORE_WATCH_AVAILABLE
+#include <appcore-watch/watch_app.h>
+#endif
+#ifdef DALI_ELDBUS_AVAILABLE
+#include <Eldbus.h>
+#endif // DALI_ELDBUS_AVAILABLE
+
+#if defined( TIZEN_PLATFORM_CONFIG_SUPPORTED ) && TIZEN_PLATFORM_CONFIG_SUPPORTED
+#include <tzplatform_config.h>
+#endif // TIZEN_PLATFORM_CONFIG_SUPPORTED
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/callback-manager.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Integration::Log::Filter* gDBusLogging = Integration::Log::Filter::New( Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_DBUS" );
+#endif
+
+bool IsWidgetFeatureEnabled()
+{
+  static bool feature = false;
+  static bool retrieved = false;
+  int ret;
+
+  if(retrieved == true)
+  {
+    return feature;
+  }
+
+  ret = system_info_get_platform_bool("http://tizen.org/feature/shell.appwidget", &feature);
+  if(ret != SYSTEM_INFO_ERROR_NONE)
+  {
+    DALI_LOG_ERROR("failed to get system info");
+    return false;
+  }
+
+  retrieved = true;
+  return feature;
+}
+
+} // anonymous namespace
+
+namespace AppCore
+{
+
+typedef enum
+{
+  LOW_MEMORY,                 //< The low memory event
+  LOW_BATTERY,                //< The low battery event
+  LANGUAGE_CHANGED,           //< The system language changed event
+  DEVICE_ORIENTATION_CHANGED, //< The device orientation changed event
+  REGION_FORMAT_CHANGED,      //< The region format changed event
+  SUSPENDED_STATE_CHANGED,    //< The suspended state changed event of the application
+  UPDATE_REQUESTED,           //< The update requested event. This event can occur when an app needs to be updated. It is dependent on target devices.
+} AppEventType;
+
+static int AppEventConverter[APPCORE_BASE_EVENT_MAX] =
+{
+  [LOW_MEMORY] = APPCORE_BASE_EVENT_LOW_MEMORY,
+  [LOW_BATTERY] = APPCORE_BASE_EVENT_LOW_BATTERY,
+  [LANGUAGE_CHANGED] = APPCORE_BASE_EVENT_LANG_CHANGE,
+  [DEVICE_ORIENTATION_CHANGED] = APPCORE_BASE_EVENT_DEVICE_ORIENTATION_CHANGED,
+  [REGION_FORMAT_CHANGED] = APPCORE_BASE_EVENT_REGION_CHANGE,
+  [SUSPENDED_STATE_CHANGED] = APPCORE_BASE_EVENT_SUSPENDED_STATE_CHANGE,
+};
+
+struct AppEventInfo
+{
+  AppEventType type;
+  void *value;
+};
+
+typedef struct AppEventInfo *AppEventInfoPtr;
+
+typedef void (*AppEventCallback)(AppEventInfoPtr eventInfo, void *userData);
+
+struct AppEventHandler
+{
+  AppEventType type;
+  AppEventCallback cb;
+  void *data;
+  void *raw;
+};
+
+typedef struct AppEventHandler *AppEventHandlerPtr;
+
+int EventCallback(void *event, void *data)
+{
+  AppEventHandlerPtr handler = static_cast<AppEventHandlerPtr>(data);
+
+  struct AppEventInfo appEvent;
+
+  appEvent.type = handler->type;
+  appEvent.value = event;
+
+  if (handler->cb)
+    handler->cb(&appEvent, handler->data);
+
+  return 0;
+}
+
+int AppAddEventHandler(AppEventHandlerPtr *eventHandler, AppEventType eventType, AppEventCallback callback, void *userData)
+{
+  AppEventHandlerPtr handler;
+
+  handler = static_cast<AppEventHandlerPtr>( calloc(1, sizeof(struct AppEventHandler)) );
+  if (!handler)
+  {
+    DALI_LOG_ERROR( "failed to create handler" );
+    return TIZEN_ERROR_UNKNOWN;
+  }
+  else
+  {
+    handler->type = eventType;
+    handler->cb = callback;
+    handler->data = userData;
+    handler->raw = appcore_base_add_event( static_cast<appcore_base_event>(AppEventConverter[static_cast<int>(eventType)]), EventCallback, handler);
+
+    *eventHandler = handler;
+
+    return TIZEN_ERROR_NONE;
+  }
+}
+
+} // namespace Appcore
+
+/**
+ * Impl to hide EFL data members
+ */
+struct Framework::Impl
+{
+// Constructor
+  Impl(void* data, Type type )
+  : mAbortCallBack( NULL ),
+    mCallbackManager( NULL )
+#ifdef APPCORE_WATCH_AVAILABLE
+    , mWatchCallback()
+#endif
+  {
+    mFramework = static_cast<Framework*>(data);
+
+#ifndef APPCORE_WATCH_AVAILABLE
+    if ( type == WATCH )
+    {
+      throw Dali::DaliException( "", "Watch Application is not supported." );
+    }
+#endif
+    mApplicationType = type;
+    mCallbackManager = CallbackManager::New();
+
+    char* region = nullptr;
+    char* language = nullptr;
+    system_settings_get_value_string( SYSTEM_SETTINGS_KEY_LOCALE_COUNTRY, &region );
+    system_settings_get_value_string( SYSTEM_SETTINGS_KEY_LOCALE_LANGUAGE, &language );
+
+    if (region != nullptr)
+    {
+      mRegion = std::string( region );
+    }
+
+    if ( language != nullptr)
+    {
+      mLanguage = std::string( language );
+    }
+  }
+
+  ~Impl()
+  {
+    delete mAbortCallBack;
+
+    // we're quiting the main loop so
+    // mCallbackManager->RemoveAllCallBacks() does not need to be called
+    // to delete our abort handler
+    delete mCallbackManager;
+  }
+
+  int AppMain()
+  {
+    int ret;
+
+    if (mApplicationType == NORMAL)
+    {
+      ret = AppNormalMain();
+    }
+    else if(mApplicationType == WIDGET)
+    {
+      ret = AppWidgetMain();
+    }
+    else
+    {
+      ret = AppWatchMain();
+    }
+    return ret;
+  }
+
+  void AppExit()
+  {
+    if (mApplicationType == NORMAL)
+    {
+      AppNormalExit();
+    }
+    else if(mApplicationType == WIDGET)
+    {
+      AppWidgetExit();
+    }
+    else
+    {
+      AppWatchExit();
+    }
+  }
+
+  void SetLanguage( const std::string& language )
+  {
+    mLanguage = language;
+  }
+
+  void SetRegion( const std::string& region )
+  {
+    mRegion = region;
+  }
+
+  std::string GetLanguage() const
+  {
+    return mLanguage;
+  }
+
+  std::string GetRegion() const
+  {
+    return mRegion;
+  }
+
+  // Data
+  Type mApplicationType;
+  CallbackBase* mAbortCallBack;
+  CallbackManager *mCallbackManager;
+  std::string mLanguage;
+  std::string mRegion;
+
+  Framework* mFramework;
+  AppCore::AppEventHandlerPtr handlers[5];
+#ifdef APPCORE_WATCH_AVAILABLE
+  watch_app_lifecycle_callback_s mWatchCallback;
+  app_event_handler_h watchHandlers[5];
+#endif
+
+  static int AppCreate(void *data)
+  {
+    appcore_ui_base_on_create();
+    return static_cast<int>( static_cast<Framework*>(data)->Create() );
+  }
+
+  static int AppTerminate(void *data)
+  {
+    appcore_ui_base_on_terminate();
+    Observer *observer = &static_cast<Framework*>(data)->mObserver;
+
+    observer->OnTerminate();
+
+    return 0;
+  }
+
+  static int AppPause(void *data)
+  {
+    appcore_ui_base_on_pause();
+    Observer *observer = &static_cast<Framework*>(data)->mObserver;
+
+    observer->OnPause();
+
+    return 0;
+  }
+
+  static int AppResume(void *data)
+  {
+    appcore_ui_base_on_resume();
+    Observer *observer = &static_cast<Framework*>(data)->mObserver;
+
+    observer->OnResume();
+
+    return 0;
+  }
+
+  static void ProcessBundle(Framework* framework, bundle *bundleData)
+  {
+    if(bundleData == NULL)
+    {
+      return;
+    }
+
+    // get bundle name
+    char* bundleName = const_cast<char*>(bundle_get_val(bundleData, "name"));
+    if(bundleName != NULL)
+    {
+      framework->SetBundleName(bundleName);
+    }
+
+    // get bundle? id
+    char* bundleId = const_cast<char*>(bundle_get_val(bundleData, "id"));
+    if(bundleId != NULL)
+    {
+      framework->SetBundleId(bundleId);
+    }
+  }
+
+  /**
+   * Called by AppCore when the application is launched from another module (e.g. homescreen).
+   * @param[in] b the bundle data which the launcher module sent
+   */
+  static int AppControl(bundle* bundleData, void *data)
+  {
+    app_control_h appControl = NULL;
+
+    appcore_ui_base_on_control(bundleData);
+
+    if (bundleData)
+    {
+      if (app_control_create_event(bundleData, &appControl) != TIZEN_ERROR_NONE)
+      {
+        DALI_LOG_ERROR("Failed to create an app_control handle");
+      }
+    }
+    else
+    {
+      if (app_control_create(&appControl) != TIZEN_ERROR_NONE)
+      {
+        DALI_LOG_ERROR("Failed to create an app_control handle");
+      }
+    }
+
+    Framework* framework = static_cast<Framework*>(data);
+    Observer *observer = &framework->mObserver;
+
+    ProcessBundle(framework, bundleData);
+
+    observer->OnReset();
+    observer->OnAppControl(appControl);
+
+    app_control_destroy(appControl);
+
+    return 0;
+  }
+
+  static void AppInit(int argc, char **argv, void *data)
+  {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+
+    ecore_init();
+    ecore_app_args_set( argc, (const char **)argv );
+
+#pragma GCC diagnostic pop
+  }
+
+  static void AppFinish(void)
+  {
+    ecore_shutdown();
+
+    if(getenv("AUL_LOADER_INIT"))
+    {
+      unsetenv("AUL_LOADER_INIT");
+      ecore_shutdown();
+    }
+  }
+
+  static void AppRun(void *data)
+  {
+    ecore_main_loop_begin();
+  }
+
+  static void AppExit(void *data)
+  {
+    ecore_main_loop_quit();
+  }
+
+  static void AppLanguageChanged(AppCore::AppEventInfoPtr event, void *data)
+  {
+    Framework* framework = static_cast<Framework*>(data);
+    Observer *observer = &framework->mObserver;
+
+    if( event && event->value )
+    {
+      framework->SetLanguage( std::string( static_cast<const char *>(event->value) ) );
+      observer->OnLanguageChanged();
+    }
+    else
+    {
+      DALI_LOG_ERROR( "NULL pointer in Language changed event\n" );
+    }
+  }
+
+  static void AppDeviceRotated(AppCore::AppEventInfoPtr event_info, void *data)
+  {
+  }
+
+  static void AppRegionChanged(AppCore::AppEventInfoPtr event, void *data)
+  {
+    Framework* framework = static_cast<Framework*>(data);
+    Observer *observer = &framework->mObserver;
+
+    if( event && event->value )
+    {
+      framework->SetRegion( std::string( static_cast<const char *>(event->value) ) );
+      observer->OnRegionChanged();
+    }
+    else
+    {
+      DALI_LOG_ERROR( "NULL pointer in Region changed event\n" );
+    }
+  }
+
+  static void AppBatteryLow(AppCore::AppEventInfoPtr event, void *data)
+  {
+    Observer *observer = &static_cast<Framework*>(data)->mObserver;
+    int status = *static_cast<int *>(event->value);
+    Dali::DeviceStatus::Battery::Status result = Dali::DeviceStatus::Battery::NORMAL;
+
+    // convert to dali battery status
+    switch( status )
+    {
+      case 1:
+      {
+        result = Dali::DeviceStatus::Battery::POWER_OFF;
+        break;
+      }
+      case 2:
+      {
+        result = Dali::DeviceStatus::Battery::CRITICALLY_LOW;
+        break;
+      }
+      default :
+        break;
+    }
+    observer->OnBatteryLow(result);
+  }
+
+  static void AppMemoryLow(AppCore::AppEventInfoPtr event, void *data)
+  {
+    Observer *observer = &static_cast<Framework*>(data)->mObserver;
+    int status = *static_cast<int *>(event->value);
+    Dali::DeviceStatus::Memory::Status result = Dali::DeviceStatus::Memory::NORMAL;
+
+    // convert to dali memmory status
+    switch( status )
+    {
+      case 1:
+      {
+        result = Dali::DeviceStatus::Memory::NORMAL;
+        break;
+      }
+      case 2:
+      {
+        result = Dali::DeviceStatus::Memory::LOW;
+        break;
+      }
+      case 4:
+      {
+        result = Dali::DeviceStatus::Memory::CRITICALLY_LOW;
+        break;
+      }
+      default :
+        break;
+    }
+    observer->OnMemoryLow(result);
+  }
+
+
+  int AppNormalMain()
+  {
+    int ret;
+
+    AppCore::AppAddEventHandler(&handlers[AppCore::LOW_BATTERY], AppCore::LOW_BATTERY, AppBatteryLow, mFramework);
+    AppCore::AppAddEventHandler(&handlers[AppCore::LOW_MEMORY], AppCore::LOW_MEMORY, AppMemoryLow, mFramework);
+    AppCore::AppAddEventHandler(&handlers[AppCore::DEVICE_ORIENTATION_CHANGED], AppCore::DEVICE_ORIENTATION_CHANGED, AppDeviceRotated, mFramework);
+    AppCore::AppAddEventHandler(&handlers[AppCore::LANGUAGE_CHANGED], AppCore::LANGUAGE_CHANGED, AppLanguageChanged, mFramework);
+    AppCore::AppAddEventHandler(&handlers[AppCore::REGION_FORMAT_CHANGED], AppCore::REGION_FORMAT_CHANGED, AppRegionChanged, mFramework);
+
+    appcore_ui_base_ops ops = appcore_ui_base_get_default_ops();
+
+    /* override methods */
+    ops.base.create = AppCreate;
+    ops.base.control = AppControl;
+    ops.base.terminate = AppTerminate;
+    ops.pause = AppPause;
+    ops.resume = AppResume;
+    ops.base.init = AppInit;
+    ops.base.finish = AppFinish;
+    ops.base.run = AppRun;
+    ops.base.exit = AppExit;
+
+    ret = appcore_ui_base_init(ops, *mFramework->mArgc, *mFramework->mArgv, mFramework, APPCORE_UI_BASE_HINT_WINDOW_GROUP_CONTROL |
+                                                                                        APPCORE_UI_BASE_HINT_WINDOW_STACK_CONTROL |
+                                                                                        APPCORE_UI_BASE_HINT_BG_LAUNCH_CONTROL |
+                                                                                        APPCORE_UI_BASE_HINT_HW_ACC_CONTROL |
+                                                                                        APPCORE_UI_BASE_HINT_WINDOW_AUTO_CONTROL );
+
+    if (ret != TIZEN_ERROR_NONE)
+      return ret;
+
+    appcore_ui_base_fini();
+
+    return TIZEN_ERROR_NONE;
+  }
+
+  void AppNormalExit()
+  {
+    appcore_ui_base_exit();
+  }
+
+  void AppWidgetExit()
+  {
+    widget_base_exit();
+  }
+
+  static int WidgetAppCreate( void *data )
+  {
+    widget_base_on_create();
+    return static_cast<int>( static_cast<Framework*>(data)->Create() );
+  }
+
+  static int WidgetAppTerminate( void *data )
+  {
+    Observer *observer = &static_cast<Framework*>(data)->mObserver;
+    observer->OnTerminate();
+
+    widget_base_on_terminate();
+    return 0;
+  }
+
+  int AppWidgetMain()
+  {
+    if( !IsWidgetFeatureEnabled() )
+    {
+      DALI_LOG_ERROR("widget feature is not supported");
+      return 0;
+    }
+
+    AppCore::AppAddEventHandler(&handlers[AppCore::LOW_BATTERY], AppCore::LOW_BATTERY, AppBatteryLow, mFramework);
+    AppCore::AppAddEventHandler(&handlers[AppCore::LOW_MEMORY], AppCore::LOW_MEMORY, AppMemoryLow, mFramework);
+    AppCore::AppAddEventHandler(&handlers[AppCore::DEVICE_ORIENTATION_CHANGED], AppCore::DEVICE_ORIENTATION_CHANGED, AppDeviceRotated, mFramework);
+    AppCore::AppAddEventHandler(&handlers[AppCore::LANGUAGE_CHANGED], AppCore::LANGUAGE_CHANGED, AppLanguageChanged, mFramework);
+    AppCore::AppAddEventHandler(&handlers[AppCore::REGION_FORMAT_CHANGED], AppCore::REGION_FORMAT_CHANGED, AppRegionChanged, mFramework);
+
+    widget_base_ops ops = widget_base_get_default_ops();
+
+    /* override methods */
+    ops.create = WidgetAppCreate;
+    ops.terminate = WidgetAppTerminate;
+    ops.init = AppInit;
+    ops.finish = AppFinish;
+    ops.run = AppRun;
+    ops.exit = AppExit;
+
+    int result = widget_base_init(ops, *mFramework->mArgc, *mFramework->mArgv, mFramework);
+
+    widget_base_fini();
+
+    return result;
+  }
+
+#ifdef APPCORE_WATCH_AVAILABLE
+  static bool WatchAppCreate(int width, int height, void *data)
+  {
+    return static_cast<Framework*>(data)->Create();
+  }
+
+  static void WatchAppTimeTick(watch_time_h time, void *data)
+  {
+    Observer *observer = &static_cast<Framework*>(data)->mObserver;
+    WatchTime curTime(time);
+
+    observer->OnTimeTick(curTime);
+  }
+
+  static void WatchAppAmbientTick(watch_time_h time, void *data)
+  {
+    Observer *observer = &static_cast<Framework*>(data)->mObserver;
+    WatchTime curTime(time);
+
+    observer->OnAmbientTick(curTime);
+  }
+
+  static void WatchAppAmbientChanged(bool ambient, void *data)
+  {
+    Observer *observer = &static_cast<Framework*>(data)->mObserver;
+
+    observer->OnAmbientChanged(ambient);
+  }
+
+  static void WatchAppControl(app_control_h app_control, void *data)
+  {
+    Framework* framework = static_cast<Framework*>(data);
+    Observer *observer = &framework->mObserver;
+    bundle *bundleData = NULL;
+
+    app_control_to_bundle(app_control, &bundleData);
+    ProcessBundle(framework, bundleData);
+
+    observer->OnReset();
+    observer->OnAppControl(app_control);
+  }
+
+  static void WatchAppTerminate(void *data)
+  {
+    Observer *observer = &static_cast<Framework*>(data)->mObserver;
+
+    observer->OnTerminate();
+  }
+
+  static void WatchAppPause(void *data)
+  {
+    Observer *observer = &static_cast<Framework*>(data)->mObserver;
+
+    observer->OnPause();
+  }
+
+  static void WatchAppResume(void *data)
+  {
+    Observer *observer = &static_cast<Framework*>(data)->mObserver;
+
+    observer->OnResume();
+  }
+
+#endif
+
+  int AppWatchMain()
+  {
+    int ret = true;
+
+#ifdef APPCORE_WATCH_AVAILABLE
+    mWatchCallback.create = WatchAppCreate;
+    mWatchCallback.app_control = WatchAppControl;
+    mWatchCallback.terminate = WatchAppTerminate;
+    mWatchCallback.pause = WatchAppPause;
+    mWatchCallback.resume = WatchAppResume;
+    mWatchCallback.time_tick = WatchAppTimeTick;
+    mWatchCallback.ambient_tick = WatchAppAmbientTick;
+    mWatchCallback.ambient_changed = WatchAppAmbientChanged;
+
+    AppCore::AppAddEventHandler(&handlers[AppCore::LOW_BATTERY], AppCore::LOW_BATTERY, AppBatteryLow, mFramework);
+    AppCore::AppAddEventHandler(&handlers[AppCore::LOW_MEMORY], AppCore::LOW_MEMORY, AppMemoryLow, mFramework);
+    AppCore::AppAddEventHandler(&handlers[AppCore::LANGUAGE_CHANGED], AppCore::LANGUAGE_CHANGED, AppLanguageChanged, mFramework);
+    AppCore::AppAddEventHandler(&handlers[AppCore::REGION_FORMAT_CHANGED], AppCore::REGION_FORMAT_CHANGED, AppRegionChanged, mFramework);
+
+    ret = watch_app_main(*mFramework->mArgc, *mFramework->mArgv, &mWatchCallback, mFramework);
+#endif
+    return ret;
+  }
+
+  void AppWatchExit()
+  {
+#ifdef APPCORE_WATCH_AVAILABLE
+    watch_app_exit();
+#endif
+  }
+
+private:
+  // Undefined
+  Impl( const Impl& impl );
+
+  // Undefined
+  Impl& operator=( const Impl& impl );
+};
+
+Framework::Framework( Framework::Observer& observer, int *argc, char ***argv, Type type )
+: mObserver(observer),
+  mInitialised(false),
+  mPaused(false),
+  mRunning(false),
+  mArgc(argc),
+  mArgv(argv),
+  mBundleName(""),
+  mBundleId(""),
+  mAbortHandler( MakeCallback( this, &Framework::AbortCallback ) ),
+  mImpl(NULL)
+{
+  bool featureFlag = true;
+  system_info_get_platform_bool( "tizen.org/feature/opengles.version.2_0", &featureFlag );
+
+  if( featureFlag == false )
+  {
+    set_last_result( TIZEN_ERROR_NOT_SUPPORTED );
+  }
+#ifdef DALI_ELDBUS_AVAILABLE
+  // Initialize ElDBus.
+  DALI_LOG_INFO( gDBusLogging, Debug::General, "Starting DBus Initialization\n" );
+  eldbus_init();
+#endif
+  InitThreads();
+
+  mImpl = new Impl(this, type);
+}
+
+Framework::~Framework()
+{
+  if (mRunning)
+  {
+    Quit();
+  }
+
+#ifdef DALI_ELDBUS_AVAILABLE
+  // Shutdown ELDBus.
+  DALI_LOG_INFO( gDBusLogging, Debug::General, "Shutting down DBus\n" );
+  eldbus_shutdown();
+#endif
+
+  delete mImpl;
+}
+
+bool Framework::Create()
+{
+  mInitialised = true;
+  mObserver.OnInit();
+  return true;
+}
+
+void Framework::Run()
+{
+  mRunning = true;
+  int ret;
+
+  ret = mImpl->AppMain();
+  if (ret != APP_ERROR_NONE)
+  {
+    DALI_LOG_ERROR("Framework::Run(), ui_app_main() is failed. err = %d\n", ret);
+  }
+  mRunning = false;
+}
+
+void Framework::Quit()
+{
+  mImpl->AppExit();
+}
+
+bool Framework::IsMainLoopRunning()
+{
+  return mRunning;
+}
+
+void Framework::AddAbortCallback( CallbackBase* callback )
+{
+  mImpl->mAbortCallBack = callback;
+}
+
+std::string Framework::GetBundleName() const
+{
+  return mBundleName;
+}
+
+void Framework::SetBundleName(const std::string& name)
+{
+  mBundleName = name;
+}
+
+std::string Framework::GetBundleId() const
+{
+  return mBundleId;
+}
+
+std::string Framework::GetResourcePath()
+{
+  std::string resourcePath = "";
+#if defined( TIZEN_PLATFORM_CONFIG_SUPPORTED ) && TIZEN_PLATFORM_CONFIG_SUPPORTED
+  char* app_rsc_path = app_get_resource_path();
+  if (app_rsc_path)
+  {
+    resourcePath = app_rsc_path;
+    free(app_rsc_path);
+  }
+#else // For backwards compatibility with older Tizen versions
+
+  // "DALI_APPLICATION_PACKAGE" is used to get the already configured Application package path.
+  const char* environmentVariable = "DALI_APPLICATION_PACKAGE";
+  char* value = getenv( environmentVariable );
+  if ( value != NULL )
+  {
+    resourcePath = value;
+  }
+
+  if( resourcePath.back() != '/' )
+  {
+    resourcePath+="/";
+  }
+
+#endif //TIZEN_PLATFORM_CONFIG_SUPPORTED
+
+  return resourcePath;
+}
+
+std::string Framework::GetDataPath()
+{
+  std::string result;
+  char* dataPath = app_get_data_path();
+  if( dataPath )
+  {
+    result = dataPath;
+    free(dataPath);
+  }
+  return result;
+}
+
+void Framework::SetBundleId(const std::string& id)
+{
+  mBundleId = id;
+}
+
+void Framework::AbortCallback( )
+{
+  // if an abort call back has been installed run it.
+  if (mImpl->mAbortCallBack)
+  {
+    CallbackBase::Execute( *mImpl->mAbortCallBack );
+  }
+  else
+  {
+    Quit();
+  }
+}
+
+void Framework::InitThreads()
+{
+}
+
+void Framework::SetLanguage( const std::string& language )
+{
+  mImpl->SetLanguage( language );
+}
+
+void Framework::SetRegion( const std::string& region )
+{
+  mImpl->SetRegion( region );
+}
+
+std::string Framework::GetLanguage() const
+{
+  return mImpl->GetLanguage();
+}
+
+std::string Framework::GetRegion() const
+{
+  return mImpl->GetRegion();
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/adaptor/tizen-wayland/tizen-wearable/watch-application-impl.cpp b/dali/internal/adaptor/tizen-wayland/tizen-wearable/watch-application-impl.cpp
new file mode 100644 (file)
index 0000000..f937172
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor/tizen-wayland/tizen-wearable/watch-application-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/system/common/environment-variables.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+unsigned int GetEnvWatchRenderRefreshRate()
+{
+  const char* envVariable = std::getenv( DALI_WATCH_REFRESH_RATE );
+
+  return envVariable ? std::atoi( envVariable ) : 2u; // Default 30 fps
+}
+
+} // unnamed namespace
+
+WatchApplicationPtr WatchApplication::New(
+  int* argc,
+  char **argv[],
+  const std::string& stylesheet,
+  Dali::WatchApplication::WINDOW_MODE windowMode)
+{
+  WatchApplicationPtr watch ( new WatchApplication (argc, argv, stylesheet, windowMode ) );
+  return watch;
+}
+
+WatchApplication::WatchApplication( int* argc, char** argv[], const std::string& stylesheet, Dali::Application::WINDOW_MODE windowMode )
+: Application(argc, argv, stylesheet, windowMode, PositionSize(), Framework::WATCH),
+  mState( UNINITIALIZED )
+{
+}
+
+WatchApplication::~WatchApplication()
+{
+}
+
+void WatchApplication::OnInit()
+{
+  Application::OnInit();
+
+  Dali::Adaptor::Get().SetRenderRefreshRate( GetEnvWatchRenderRefreshRate() );
+
+  mState = INITIALIZED;
+}
+
+void WatchApplication::OnTerminate()
+{
+  Application::OnTerminate();
+
+  mState = TERMINATED;
+}
+
+void WatchApplication::OnResume()
+{
+  Application::OnResume();
+
+  mState = RESUMED;
+}
+
+void WatchApplication::OnPause()
+{
+  Application::OnPause();
+
+  mState = PAUSED;
+}
+
+void WatchApplication::OnTimeTick(WatchTime& time)
+{
+  Dali::WatchApplication watch(this);
+  mTickSignal.Emit( watch, time );
+
+  if(mState == PAUSED)
+  {
+    // This is a pre-resume scenario. All rendering engine of tizen SHOULD forcely update once at this time.
+    Internal::Adaptor::Adaptor::GetImplementation( GetAdaptor() ).RequestUpdateOnce();
+  }
+
+  // A watch application will queue messages to update the UI in the signal emitted above
+  // Process these immediately to avoid a blinking issue where the old time is briefly visible
+  CoreEventInterface& eventInterface = Internal::Adaptor::Adaptor::GetImplementation( GetAdaptor() );
+  eventInterface.ProcessCoreEvents();
+}
+
+void WatchApplication::OnAmbientTick(WatchTime& time)
+{
+  Dali::WatchApplication watch(this);
+  mAmbientTickSignal.Emit( watch, time );
+
+  // A watch application will queue messages to update the UI in the signal emitted above
+  // Process these immediately to avoid a blinking issue where the old time is briefly visible
+  CoreEventInterface& eventInterface = Internal::Adaptor::Adaptor::GetImplementation( GetAdaptor() );
+  eventInterface.ProcessCoreEvents();
+}
+
+void WatchApplication::OnAmbientChanged(bool ambient)
+{
+  Dali::WatchApplication watch(this);
+  mAmbientChangeSignal.Emit( watch, ambient );
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/adaptor/tizen-wayland/tizen-wearable/watch-application-impl.h b/dali/internal/adaptor/tizen-wayland/tizen-wearable/watch-application-impl.h
new file mode 100644 (file)
index 0000000..4701bba
--- /dev/null
@@ -0,0 +1,158 @@
+#ifndef DALI_INTERNAL_WATCH_APPLICATION_H
+#define DALI_INTERNAL_WATCH_APPLICATION_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/watch/watch-application.h>
+#include <dali/internal/adaptor/common/application-impl.h>
+
+namespace Dali
+{
+class Adaptor;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class WatchApplication;
+typedef IntrusivePtr<WatchApplication> WatchApplicationPtr;
+
+enum WatchApplicationState
+{
+  UNINITIALIZED,
+  INITIALIZED,
+  PAUSED,
+  RESUMED = INITIALIZED,
+  TERMINATED
+};
+
+/**
+ * Implementation of the WatchApplication class.
+ */
+class WatchApplication : public Application
+{
+public:
+  typedef Dali::WatchApplication::WatchTimeSignal WatchTimeSignal;
+  typedef Dali::WatchApplication::WatchBoolSignal WatchBoolSignal;
+
+  /**
+   * Create a new watch
+   * @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::Watch::WINDOW_MODE
+   */
+  static WatchApplicationPtr New( int* argc, char **argv[], const std::string& stylesheet, WINDOW_MODE windowMode );
+
+  /**
+   * 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::Watch::WINDOW_MODE
+   */
+  WatchApplication( int* argc, char **argv[], const std::string& stylesheet, WINDOW_MODE windowMode );
+
+  /**
+   * Destructor
+   */
+  virtual ~WatchApplication();
+
+  /**
+   * Called when the framework is initialised.
+   */
+  virtual void OnInit();
+
+  /**
+   * Called when the framework is terminated.
+   */
+  virtual void OnTerminate();
+
+  /**
+   * Called when the framework is paused.
+   */
+  virtual void OnPause();
+
+  /**
+   * Called when the framework resumes from a paused state.
+   */
+  virtual void OnResume();
+
+  /**
+   * Called every second
+   */
+  void OnTimeTick(WatchTime& time);
+
+  /**
+   * Called every second in ambient mode
+   */
+  void OnAmbientTick(WatchTime& time);
+
+  /**
+   * Called when the device enters or exits ambient mode
+   */
+  void OnAmbientChanged(bool ambient);
+
+private:
+
+  // @brief Undefined copy constructor.
+  WatchApplication( const WatchApplication& );
+
+  // @brief Undefined assignment operator.
+  WatchApplication& operator=( const WatchApplication& );
+
+public:
+
+  // Signals
+  WatchTimeSignal                        mTickSignal;
+  WatchTimeSignal                        mAmbientTickSignal;
+  WatchBoolSignal                        mAmbientChangeSignal;
+
+private:
+  WatchApplicationState                  mState;
+};
+
+inline WatchApplication& GetImplementation(Dali::WatchApplication& watch)
+{
+  DALI_ASSERT_ALWAYS(watch && "watch handle is empty");
+
+  BaseObject& handle = watch.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::WatchApplication&>(handle);
+}
+
+inline const WatchApplication& GetImplementation(const Dali::WatchApplication& watch)
+{
+  DALI_ASSERT_ALWAYS(watch && "Time handle is empty");
+
+  const BaseObject& handle = watch.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::WatchApplication&>(handle);
+}
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WATCH_APPLICATION_H
diff --git a/dali/internal/adaptor/tizen-wayland/tizen-wearable/watch-application.cpp b/dali/internal/adaptor/tizen-wayland/tizen-wearable/watch-application.cpp
new file mode 100644 (file)
index 0000000..fd5e8a0
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/public-api/watch/watch-application.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/tizen-wayland/tizen-wearable/watch-application-impl.h>
+
+namespace Dali
+{
+
+WatchApplication WatchApplication::New()
+{
+  return New( NULL, NULL );
+}
+
+WatchApplication WatchApplication::New( int* argc, char **argv[] )
+{
+  Internal::Adaptor::WatchApplicationPtr internal = Internal::Adaptor::WatchApplication::New( argc, argv, "", OPAQUE );
+  return WatchApplication(internal.Get());
+}
+
+WatchApplication WatchApplication::New( int* argc, char **argv[], const std::string& stylesheet )
+{
+  Internal::Adaptor::WatchApplicationPtr internal = Internal::Adaptor::WatchApplication::New( argc, argv, stylesheet, OPAQUE );
+  return WatchApplication(internal.Get());
+}
+
+WatchApplication::~WatchApplication()
+{
+}
+
+WatchApplication::WatchApplication()
+{
+}
+
+WatchApplication::WatchApplication(const WatchApplication& implementation)
+: Application(implementation)
+{
+}
+
+WatchApplication& WatchApplication::operator=(const WatchApplication& application)
+{
+  if( *this != application )
+  {
+    BaseHandle::operator=( application );
+  }
+  return *this;
+}
+
+WatchApplication::WatchTimeSignal& WatchApplication::TimeTickSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).mTickSignal;
+}
+
+WatchApplication::WatchTimeSignal& WatchApplication::AmbientTickSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).mAmbientTickSignal;
+}
+
+WatchApplication::WatchBoolSignal& WatchApplication::AmbientChangedSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).mAmbientChangeSignal;
+}
+
+WatchApplication::WatchApplication(Internal::Adaptor::WatchApplication* implementation)
+: Application(implementation)
+{
+}
+
+
+} // namespace Dali
diff --git a/dali/internal/adaptor/ubuntu/framework-ubuntu.cpp b/dali/internal/adaptor/ubuntu/framework-ubuntu.cpp
new file mode 100644 (file)
index 0000000..fe29484
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/adaptor/common/framework.h>
+
+// EXTERNAL INCLUDES
+#include <dali/internal/system/linux/dali-ecore.h>
+#include <dali/internal/system/linux/dali-elementary.h>
+#include <X11/Xlib.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/callback-manager.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+/// Application Status Enum
+enum
+{
+  APP_CREATE,
+  APP_TERMINATE,
+  APP_PAUSE,
+  APP_RESUME,
+  APP_RESET,
+  APP_LANGUAGE_CHANGE,
+};
+
+} // Unnamed namespace
+
+/**
+ * Impl to hide EFL data members
+ */
+struct Framework::Impl
+{
+  // Constructor
+
+  Impl(void* data)
+  : mAbortCallBack( NULL ),
+    mCallbackManager( CallbackManager::New() ),
+    mLanguage( "NOT_SUPPORTED" ),
+    mRegion( "NOT_SUPPORTED" )
+  {
+  }
+
+  ~Impl()
+  {
+    delete mAbortCallBack;
+
+    // we're quiting the main loop so
+    // mCallbackManager->RemoveAllCallBacks() does not need to be called
+    // to delete our abort handler
+    delete mCallbackManager;
+  }
+
+  std::string GetLanguage() const
+  {
+    return mLanguage;
+  }
+
+  std::string GetRegion() const
+  {
+    return mRegion;
+  }
+
+  // Data
+  CallbackBase* mAbortCallBack;
+  CallbackManager *mCallbackManager;
+  std::string mLanguage;
+  std::string mRegion;
+
+  // Static methods
+
+  /**
+   * Called by AppCore on application creation.
+   */
+  static bool AppCreate(void *data)
+  {
+    return static_cast<Framework*>(data)->AppStatusHandler(APP_CREATE, NULL);
+  }
+
+  /**
+   * Called by AppCore when the application should terminate.
+   */
+  static void AppTerminate(void *data)
+  {
+    static_cast<Framework*>(data)->AppStatusHandler(APP_TERMINATE, NULL);
+  }
+
+  /**
+   * Called by AppCore when the application is paused.
+   */
+  static void AppPause(void *data)
+  {
+    static_cast<Framework*>(data)->AppStatusHandler(APP_PAUSE, NULL);
+  }
+
+  /**
+   * Called by AppCore when the application is resumed.
+   */
+  static void AppResume(void *data)
+  {
+    static_cast<Framework*>(data)->AppStatusHandler(APP_RESUME, NULL);
+  }
+
+  /**
+   * Called by AppCore when the language changes on the device.
+   */
+  static void AppLanguageChange(void* data)
+  {
+    static_cast<Framework*>(data)->AppStatusHandler(APP_LANGUAGE_CHANGE, NULL);
+  }
+
+};
+
+Framework::Framework( Framework::Observer& observer, int *argc, char ***argv, Type type )
+: mObserver(observer),
+  mInitialised(false),
+  mPaused(false),
+  mRunning(false),
+  mArgc(argc),
+  mArgv(argv),
+  mBundleName(""),
+  mBundleId(""),
+  mAbortHandler( MakeCallback( this, &Framework::AbortCallback ) ),
+  mImpl(NULL)
+{
+  InitThreads();
+  mImpl = new Impl(this);
+}
+
+Framework::~Framework()
+{
+  if (mRunning)
+  {
+    Quit();
+  }
+
+  delete mImpl;
+}
+
+void Framework::Run()
+{
+  mRunning = true;
+
+  elm_init( mArgc ? *mArgc : 0, mArgv ? *mArgv : nullptr );
+
+  Impl::AppCreate(this);
+
+  elm_run();
+
+  mRunning = false;
+}
+
+void Framework::Quit()
+{
+  Impl::AppTerminate(this);
+
+  elm_exit();
+}
+
+bool Framework::IsMainLoopRunning()
+{
+  return mRunning;
+}
+
+void Framework::AddAbortCallback( CallbackBase* callback )
+{
+  mImpl->mAbortCallBack = callback;
+}
+
+std::string Framework::GetBundleName() const
+{
+  return mBundleName;
+}
+
+void Framework::SetBundleName(const std::string& name)
+{
+  mBundleName = name;
+}
+
+std::string Framework::GetBundleId() const
+{
+  return mBundleId;
+}
+
+std::string Framework::GetResourcePath()
+{
+  // "DALI_APPLICATION_PACKAGE" is used by Ubuntu specifically to get the already configured Application package path.
+  const char* ubuntuEnvironmentVariable = "DALI_APPLICATION_PACKAGE";
+  char* value = getenv( ubuntuEnvironmentVariable );
+  std::string resourcePath;
+  if ( value != NULL )
+  {
+    resourcePath = value;
+  }
+
+  if( resourcePath.back() != '/' )
+  {
+    resourcePath+="/";
+  }
+
+  return resourcePath;
+}
+
+std::string Framework::GetDataPath()
+{
+  const char* ubuntuEnvironmentVariable = "DALI_APPLICATION_DATA_DIR";
+  char* value = getenv( ubuntuEnvironmentVariable );
+  std::string dataPath;
+  if ( value != NULL )
+  {
+    dataPath = value;
+  }
+
+  return dataPath;
+}
+
+void Framework::SetBundleId(const std::string& id)
+{
+  mBundleId = id;
+}
+
+void Framework::AbortCallback( )
+{
+  // if an abort call back has been installed run it.
+  if (mImpl->mAbortCallBack)
+  {
+    CallbackBase::Execute( *mImpl->mAbortCallBack );
+  }
+  else
+  {
+    Quit();
+  }
+}
+
+bool Framework::AppStatusHandler(int type, void *bundleData)
+{
+  switch (type)
+  {
+    case APP_CREATE:
+    {
+      mInitialised = true;
+
+      mObserver.OnInit();
+      break;
+    }
+
+    case APP_RESET:
+      mObserver.OnReset();
+      break;
+
+    case APP_RESUME:
+      mObserver.OnResume();
+      break;
+
+    case APP_TERMINATE:
+      mObserver.OnTerminate();
+      break;
+
+    case APP_PAUSE:
+      mObserver.OnPause();
+      break;
+
+    case APP_LANGUAGE_CHANGE:
+      mObserver.OnLanguageChanged();
+      break;
+
+    default:
+      break;
+  }
+
+  return true;
+}
+
+void Framework::InitThreads()
+{
+  XInitThreads();
+}
+
+std::string Framework::GetLanguage() const
+{
+  return mImpl->GetLanguage();
+}
+
+std::string Framework::GetRegion() const
+{
+  return mImpl->GetRegion();
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/adaptor/windows/framework-win.cpp b/dali/internal/adaptor/windows/framework-win.cpp
new file mode 100755 (executable)
index 0000000..01c334a
--- /dev/null
@@ -0,0 +1,359 @@
+/*\r
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// CLASS HEADER\r
+#include <dali/internal/adaptor/common/framework.h>\r
+\r
+// EXTERNAL INCLUDES\r
+#include <dali/integration-api/debug.h>\r
+#include <windows.h>\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali/internal/window-system/windows/platform-implement-win.h>\r
+#include <dali/internal/system/common/callback-manager.h>\r
+\r
+namespace Dali\r
+{\r
+\r
+namespace Internal\r
+{\r
+\r
+namespace Adaptor\r
+{\r
+\r
+namespace\r
+{\r
+\r
+/// Application Status Enum\r
+enum\r
+{\r
+  APP_CREATE,\r
+  APP_TERMINATE,\r
+  APP_PAUSE,\r
+  APP_RESUME,\r
+  APP_RESET,\r
+  APP_LANGUAGE_CHANGE,\r
+};\r
+\r
+} // Unnamed namespace\r
+/**\r
+ * Impl to hide WindowsSystem data members\r
+ */\r
+struct Framework::Impl\r
+{\r
+  // Constructor\r
+\r
+  Impl(void* data)\r
+  : mAbortCallBack( NULL ),\r
+    mCallbackManager( CallbackManager::New() ),\r
+    mLanguage( "NOT_SUPPORTED" ),\r
+    mRegion( "NOT_SUPPORTED" )\r
+  {\r
+  }\r
+\r
+  ~Impl()\r
+  {\r
+    delete mAbortCallBack;\r
+\r
+    // we're quiting the main loop so\r
+    // mCallbackManager->RemoveAllCallBacks() does not need to be called\r
+    // to delete our abort handler\r
+    delete mCallbackManager;\r
+  }\r
+\r
+  std::string GetLanguage() const\r
+  {\r
+    return mLanguage;\r
+  }\r
+\r
+  std::string GetRegion() const\r
+  {\r
+    return mRegion;\r
+  }\r
+\r
+  // Static methods\r
+\r
+  /**\r
+   * Called by AppCore on application creation.\r
+   */\r
+  static bool AppCreate(void *data)\r
+  {\r
+    return static_cast<Framework*>(data)->AppStatusHandler(APP_CREATE, NULL);\r
+  }\r
+\r
+  /**\r
+   * Called by AppCore when the application should terminate.\r
+   */\r
+  static void AppTerminate(void *data)\r
+  {\r
+    static_cast<Framework*>(data)->AppStatusHandler(APP_TERMINATE, NULL);\r
+  }\r
+\r
+  /**\r
+   * Called by AppCore when the application is paused.\r
+   */\r
+  static void AppPause(void *data)\r
+  {\r
+    static_cast<Framework*>(data)->AppStatusHandler(APP_PAUSE, NULL);\r
+  }\r
+\r
+  /**\r
+   * Called by AppCore when the application is resumed.\r
+   */\r
+  static void AppResume(void *data)\r
+  {\r
+    static_cast<Framework*>(data)->AppStatusHandler(APP_RESUME, NULL);\r
+  }\r
+\r
+  /**\r
+   * Called by AppCore when the language changes on the device.\r
+   */\r
+  static void AppLanguageChange(void* data)\r
+  {\r
+    static_cast<Framework*>(data)->AppStatusHandler(APP_LANGUAGE_CHANGE, NULL);\r
+  }\r
+\r
+  void Run()\r
+  {\r
+    MSG nMsg = { 0 };\r
+\r
+    while (GetMessage(&nMsg, 0, NULL, NULL))\r
+    {\r
+      if (WIN_CALLBACK_EVENT == nMsg.message)\r
+      {\r
+        Dali::CallbackBase *callback = (Dali::CallbackBase*)nMsg.wParam;\r
+        Dali::CallbackBase::Execute(*callback);\r
+      }\r
+\r
+      TranslateMessage(&nMsg);\r
+      DispatchMessage(&nMsg);\r
+\r
+      mCallbackManager->ClearIdleCallbacks();\r
+\r
+      if (WM_CLOSE == nMsg.message)\r
+      {\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  void Quit()\r
+  {\r
+  }\r
+\r
+  void SetCallbackBase( CallbackBase *base )\r
+  {\r
+    mAbortCallBack = base;\r
+  }\r
+\r
+  bool ExcuteCallback()\r
+  {\r
+    if( NULL != mAbortCallBack )\r
+    {\r
+      CallbackBase::Execute( *mAbortCallBack );\r
+      return true;\r
+    }\r
+    else\r
+    {\r
+      return false;\r
+    }\r
+  }\r
+\r
+private:\r
+  // Undefined\r
+  Impl( const Impl& impl ) = delete;\r
+\r
+  // Undefined\r
+  Impl& operator=( const Impl& impl ) = delete;\r
+\r
+private:\r
+  // Data\r
+  CallbackBase* mAbortCallBack;\r
+  CallbackManager *mCallbackManager;\r
+  std::string mLanguage;\r
+  std::string mRegion;\r
+};\r
+\r
+Framework::Framework( Framework::Observer& observer, int *argc, char ***argv, Type type )\r
+: mObserver(observer),\r
+  mInitialised(false),\r
+  mPaused(false),\r
+  mRunning(false),\r
+  mArgc(argc),\r
+  mArgv(argv),\r
+  mBundleName(""),\r
+  mBundleId(""),\r
+  mAbortHandler( MakeCallback( this, &Framework::AbortCallback ) ),\r
+  mImpl(NULL)\r
+{\r
+    InitThreads();\r
+    mImpl = new Impl(this);\r
+}\r
+\r
+Framework::~Framework()\r
+{\r
+  if (mRunning)\r
+  {\r
+    Quit();\r
+  }\r
+\r
+  delete mImpl;\r
+}\r
+\r
+void Framework::Run()\r
+{\r
+    mRunning = true;\r
+\r
+    Impl::AppCreate(this);\r
+    mImpl->Run();\r
+    mRunning = false;\r
+}\r
+\r
+void Framework::Quit()\r
+{\r
+  Impl::AppTerminate(this);\r
+}\r
+\r
+bool Framework::IsMainLoopRunning()\r
+{\r
+  return mRunning;\r
+}\r
+\r
+void Framework::AddAbortCallback( CallbackBase* callback )\r
+{\r
+  mImpl->SetCallbackBase( callback );\r
+}\r
+\r
+std::string Framework::GetBundleName() const\r
+{\r
+  return mBundleName;\r
+}\r
+\r
+void Framework::SetBundleName(const std::string& name)\r
+{\r
+  mBundleName = name;\r
+}\r
+\r
+std::string Framework::GetBundleId() const\r
+{\r
+  return mBundleId;\r
+}\r
+\r
+std::string Framework::GetResourcePath()\r
+{\r
+  // "DALI_APPLICATION_PACKAGE" is used by Windows specifically to get the already configured Application package path.\r
+  const char* winEnvironmentVariable = "DALI_APPLICATION_PACKAGE";\r
+  char* value = getenv( winEnvironmentVariable );\r
+\r
+  std::string resourcePath;\r
+  if ( value != NULL )\r
+  {\r
+    resourcePath = value;\r
+  }\r
+\r
+  if( resourcePath.back() != '/' )\r
+  {\r
+    resourcePath+="/";\r
+  }\r
+\r
+  return resourcePath;\r
+}\r
+\r
+std::string Framework::GetDataPath()\r
+{\r
+  std::string result = app_get_data_path();\r
+  return result;\r
+}\r
+\r
+void Framework::SetBundleId(const std::string& id)\r
+{\r
+  mBundleId = id;\r
+}\r
+\r
+void Framework::AbortCallback( )\r
+{\r
+  // if an abort call back has been installed run it.\r
+  if( false == mImpl->ExcuteCallback() )\r
+  {\r
+    Quit();\r
+  }\r
+}\r
+\r
+bool Framework::AppStatusHandler(int type, void *bundleData)\r
+{\r
+  switch (type)\r
+  {\r
+    case APP_CREATE:\r
+    {\r
+      mInitialised = true;\r
+\r
+      mObserver.OnInit();\r
+      break;\r
+    }\r
+    case APP_RESET:\r
+    {\r
+      mObserver.OnReset();\r
+      break;\r
+    }\r
+    case APP_RESUME:\r
+    {\r
+      mObserver.OnResume();\r
+      break;\r
+    }\r
+    case APP_TERMINATE:\r
+    {\r
+      mObserver.OnTerminate();\r
+      break;\r
+    }\r
+    case APP_PAUSE:\r
+    {\r
+      mObserver.OnPause();\r
+      break;\r
+    }\r
+    case APP_LANGUAGE_CHANGE:\r
+    {\r
+      mObserver.OnLanguageChanged();\r
+      break;\r
+    }\r
+    default:\r
+    {\r
+      break;\r
+    }\r
+  }\r
+\r
+  return true;\r
+}\r
+\r
+void Framework::InitThreads()\r
+{\r
+}\r
+\r
+std::string Framework::GetLanguage() const\r
+{\r
+  return mImpl->GetLanguage();\r
+}\r
+\r
+std::string Framework::GetRegion() const\r
+{\r
+  return mImpl->GetRegion();\r
+}\r
+\r
+} // namespace Adaptor\r
+\r
+} // namespace Internal\r
+\r
+} // namespace Dali\r
diff --git a/dali/internal/clipboard/common/clipboard-event-notifier-impl.cpp b/dali/internal/clipboard/common/clipboard-event-notifier-impl.cpp
new file mode 100644 (file)
index 0000000..ff5acd6
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/clipboard/common/clipboard-event-notifier-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/common/singleton-service.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+Dali::ClipboardEventNotifier ClipboardEventNotifier::New()
+{
+  Dali::ClipboardEventNotifier notifier = Dali::ClipboardEventNotifier(new ClipboardEventNotifier());
+
+  return notifier;
+}
+
+Dali::ClipboardEventNotifier ClipboardEventNotifier::Get()
+{
+  Dali::ClipboardEventNotifier notifier;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::ClipboardEventNotifier ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      notifier = Dali::ClipboardEventNotifier( dynamic_cast< ClipboardEventNotifier* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      notifier = Dali::ClipboardEventNotifier( ClipboardEventNotifier::New() );
+      service.Register( typeid( notifier ), notifier );
+    }
+  }
+
+  return notifier;
+}
+
+const std::string& ClipboardEventNotifier::GetContent() const
+{
+  return mContent;
+}
+
+void ClipboardEventNotifier::SetContent( const std::string& content )
+{
+  mContent = content;
+}
+
+void ClipboardEventNotifier::ClearContent()
+{
+  mContent.clear();
+}
+
+void ClipboardEventNotifier::EmitContentSelectedSignal()
+{
+  if ( !mContentSelectedSignal.Empty() )
+  {
+    Dali::ClipboardEventNotifier handle( this );
+    mContentSelectedSignal.Emit( handle );
+  }
+}
+
+ClipboardEventNotifier::ClipboardEventNotifier()
+: mContent()
+{
+}
+
+ClipboardEventNotifier::~ClipboardEventNotifier()
+{
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/clipboard/common/clipboard-event-notifier-impl.h b/dali/internal/clipboard/common/clipboard-event-notifier-impl.h
new file mode 100755 (executable)
index 0000000..993b680
--- /dev/null
@@ -0,0 +1,148 @@
+#ifndef DALI_INTERNAL_CLIPBOARD_EVENT_NOTIFIER_H
+#define DALI_INTERNAL_CLIPBOARD_EVENT_NOTIFIER_H
+
+/*
+ * Copyright (c) 2019 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/object/base-object.h>
+#include <dali/public-api/math/vector2.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/clipboard-event-notifier.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * This class listens to Clipboard events.
+ */
+class ClipboardEventNotifier : public Dali::BaseObject
+{
+public:
+
+  typedef Dali::ClipboardEventNotifier::ClipboardEventSignalType ClipboardEventSignalType;
+
+  // Creation
+
+  /**
+   * Create a ClipboardEventNotifier.
+   * @return A newly allocated clipboard-event-notifier.
+   */
+  static Dali::ClipboardEventNotifier New();
+
+  /**
+   * @copydoc Dali::ClipboardEventNotifier::Get()
+   */
+  static Dali::ClipboardEventNotifier Get();
+
+  // Public API
+
+  /**
+   * @copydoc Dali::ClipboardEventNotifier::GetContent() const
+   */
+  const std::string& GetContent() const;
+
+  /**
+   * Sets the selected content.
+   * @param[in] content  A string that represents the content that has been selected.
+   */
+  void SetContent( const std::string& content );
+
+  /**
+   * Clears the stored content.
+   */
+  void ClearContent();
+
+  /**
+   * Called when content is selected in the clipboard.
+   */
+  void EmitContentSelectedSignal();
+
+public: // Signals
+
+  /**
+   * @copydoc Dali::ClipboardEventNotifier::ContentSelectedSignal
+   */
+  ClipboardEventSignalType& ContentSelectedSignal()
+  {
+    return mContentSelectedSignal;
+  }
+
+private:
+
+  // Construction & Destruction
+
+  /**
+   * Constructor.
+   */
+  ClipboardEventNotifier();
+
+  /**
+   * Destructor.
+   */
+  virtual ~ClipboardEventNotifier();
+
+  // Undefined
+  ClipboardEventNotifier( const ClipboardEventNotifier& );
+  ClipboardEventNotifier& operator=( ClipboardEventNotifier& );
+
+private:
+
+  std::string mContent;    ///< The current selected content.
+
+  ClipboardEventSignalType mContentSelectedSignal;
+
+public:
+
+  // Helpers for public-api forwarding methods
+
+  inline static Internal::Adaptor::ClipboardEventNotifier& GetImplementation(Dali::ClipboardEventNotifier& detector)
+  {
+    DALI_ASSERT_ALWAYS( detector && "ClipboardEventNotifier handle is empty" );
+
+    BaseObject& handle = detector.GetBaseObject();
+
+    return static_cast<Internal::Adaptor::ClipboardEventNotifier&>(handle);
+  }
+
+  inline static const Internal::Adaptor::ClipboardEventNotifier& GetImplementation(const Dali::ClipboardEventNotifier& detector)
+  {
+    DALI_ASSERT_ALWAYS( detector && "ClipboardEventNotifier handle is empty" );
+
+    const BaseObject& handle = detector.GetBaseObject();
+
+    return static_cast<const Internal::Adaptor::ClipboardEventNotifier&>(handle);
+  }
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_CLIPBOARD_EVENT_NOTIFIER_H
diff --git a/dali/internal/clipboard/common/clipboard-impl.h b/dali/internal/clipboard/common/clipboard-impl.h
new file mode 100644 (file)
index 0000000..376d788
--- /dev/null
@@ -0,0 +1,136 @@
+#ifndef DALI_INTERNAL_CLIPBOARD_H
+#define DALI_INTERNAL_CLIPBOARD_H
+
+/*
+ * Copyright (c) 2019 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/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/clipboard.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Implementation of the Clip Board
+ */
+
+class Clipboard :  public Dali::BaseObject
+{
+public:
+
+  // Hide the specific windowing system
+  struct Impl;
+
+  /**
+   * @copydoc Dali::ClipboardEventNotifier::Get()
+   */
+  static Dali::Clipboard Get();
+
+  /**
+   * Constructor
+   * @param[in] impl Some data from a specific windowing system.
+   */
+  Clipboard(Impl* impl);
+
+  /**
+   * Destructor
+   */
+  virtual ~Clipboard();
+
+  /**
+   * @copydoc Dali::Clipboard::SetItem()
+   */
+  bool SetItem(const std::string &itemData);
+
+  /**
+   * @copydoc Dali::Clipboard::RequestItem()
+   */
+  void RequestItem();
+
+  /**
+   * @copydoc Dali::Clipboard::NumberOfClipboardItems()
+   */
+  unsigned int NumberOfItems();
+
+  /**
+   * @copydoc Dali::Clipboard::ShowClipboard()
+   */
+  void ShowClipboard();
+
+  /**
+   * @copydoc Dali::Clipboard::HideClipboard()
+   */
+  void HideClipboard(bool skipFirstHide);
+
+  /**
+  * @copydoc Dali::Clipboard::IsVisible()
+  */
+  bool IsVisible() const;
+
+  /**
+  * @brief exchange either sending or receiving buffered data
+  *
+  * @param[in] type true for send buffered data, false for receive data to buffer
+  * @param[in] event information pointer
+  * @return The buffer pointer for send or receive data
+  */
+  char* ExcuteBuffered( bool type, void *event );
+
+private:
+
+  // Undefined
+  Clipboard( const Clipboard& );
+  Clipboard& operator=( Clipboard& );
+
+private:
+
+  Impl* mImpl;
+
+public:
+
+}; // class clipboard
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+inline static Internal::Adaptor::Clipboard& GetImplementation(Dali::Clipboard& clipboard)
+{
+  DALI_ASSERT_ALWAYS( clipboard && "Clipboard handle is empty" );
+  BaseObject& handle = clipboard.GetBaseObject();
+  return static_cast<Internal::Adaptor::Clipboard&>(handle);
+}
+
+inline static const  Internal::Adaptor::Clipboard& GetImplementation(const Dali::Clipboard& clipboard)
+{
+  DALI_ASSERT_ALWAYS( clipboard && "Clipboard handle is empty" );
+  const BaseObject& handle = clipboard.GetBaseObject();
+  return static_cast<const Internal::Adaptor::Clipboard&>(handle);
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_CLIPBOARD_H
diff --git a/dali/internal/clipboard/file.list b/dali/internal/clipboard/file.list
new file mode 100644 (file)
index 0000000..7ac026a
--- /dev/null
@@ -0,0 +1,26 @@
+
+# module: clipboard, backend: common
+SET( adaptor_clipboard_common_src_files
+    ${adaptor_clipboard_dir}/common/clipboard-event-notifier-impl.cpp
+)
+
+# module: clipboard, backend: tizen-wayland
+SET( adaptor_clipboard_tizen_wayland_src_files
+    ${adaptor_clipboard_dir}/tizen-wayland/clipboard-impl-ecore-wl.cpp
+)
+
+# module: clipboard, backend: ubuntu-x11
+SET( adaptor_clipboard_ubuntu_x11_src_files
+    ${adaptor_clipboard_dir}/ubuntu-x11/clipboard-impl-x.cpp
+)
+
+# module: clipboard, backend: android
+SET( adaptor_clipboard_android_src_files
+    ${adaptor_clipboard_dir}/generic/clipboard-impl-generic.cpp
+)
+
+# module: clipboard, backend: windows
+SET( adaptor_clipboard_windows_src_files
+    ${adaptor_clipboard_dir}/generic/clipboard-impl-generic.cpp
+)
+
diff --git a/dali/internal/clipboard/generic/clipboard-impl-generic.cpp b/dali/internal/clipboard/generic/clipboard-impl-generic.cpp
new file mode 100755 (executable)
index 0000000..8e08371
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/clipboard/common/clipboard-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/common/singleton-service.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+struct Clipboard::Impl
+{
+};
+
+Clipboard::Clipboard( Impl* impl )
+: mImpl( impl )
+{
+}
+
+Clipboard::~Clipboard()
+{
+}
+
+Dali::Clipboard Clipboard::Get()
+{
+  Dali::Clipboard clipboard;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::Clipboard ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      clipboard = Dali::Clipboard( dynamic_cast< Clipboard* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      Clipboard::Impl* impl( new Clipboard::Impl() );
+      clipboard = Dali::Clipboard( new Clipboard(impl) );
+      service.Register( typeid(Dali::Clipboard), clipboard );
+    }
+  }
+
+  return clipboard;
+}
+
+bool Clipboard::SetItem(const std::string &itemData )
+{
+  return true;
+}
+
+void Clipboard::RequestItem()
+{
+}
+
+unsigned int Clipboard::NumberOfItems()
+{
+  return 0u;
+}
+
+void Clipboard::ShowClipboard()
+{
+}
+
+void Clipboard::HideClipboard(bool skipFirstHide)
+{
+}
+
+bool Clipboard::IsVisible() const
+{
+  return false;
+}
+
+char* Clipboard::ExcuteBuffered( bool type, void *event )
+{
+  return NULL;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/clipboard/tizen-wayland/clipboard-impl-ecore-wl.cpp b/dali/internal/clipboard/tizen-wayland/clipboard-impl-ecore-wl.cpp
new file mode 100755 (executable)
index 0000000..e411b45
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/clipboard/common/clipboard-impl.h>
+#include <dali/devel-api/adaptor-framework/clipboard-event-notifier.h>
+
+// EXTERNAL INCLUDES
+#include <dali/internal/system/linux/dali-ecore.h>
+
+#ifdef ECORE_WAYLAND2
+#include <dali/internal/adaptor/tizen-wayland/dali-ecore-wl2.h>
+#else
+#include <dali/internal/adaptor/tizen-wayland/dali-ecore-wayland.h>
+#endif
+
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/integration-api/debug.h>
+#include <unistd.h>
+
+#ifdef DALI_ELDBUS_AVAILABLE
+#include <Eldbus.h>
+#endif // DALI_ELDBUS_AVAILABLE
+
+#define CBHM_DBUS_OBJPATH "/org/tizen/cbhm/dbus"
+#ifndef CBHM_DBUS_INTERFACE
+#define CBHM_DBUS_INTERFACE "org.tizen.cbhm.dbus"
+#endif /* CBHM_DBUS_INTERFACE */
+#define CBHM_COUNT_ALL 0    // ATOM_INDEX_CBHM_COUNT_ALL
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Clipboard
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+struct Clipboard::Impl
+{
+  Impl()
+  {
+    Eldbus_Object *eldbus_obj;
+    cbhm_conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION);
+    eldbus_obj = eldbus_object_get(cbhm_conn, CBHM_DBUS_INTERFACE, CBHM_DBUS_OBJPATH);
+    eldbus_proxy = eldbus_proxy_get(eldbus_obj, CBHM_DBUS_INTERFACE);
+    eldbus_name_owner_changed_callback_add(cbhm_conn, CBHM_DBUS_INTERFACE, NULL, cbhm_conn, EINA_TRUE);
+    eldbus_proxy_signal_handler_add(eldbus_proxy, "ItemClicked", _on_item_clicked, this);
+    mVisible = false;
+    mIsFirstTimeHidden = true;
+  }
+
+  ~Impl()
+  {
+    if (cbhm_conn)
+      eldbus_connection_unref(cbhm_conn);
+  }
+
+  Eldbus_Proxy* cbhm_proxy_get()
+  {
+    return eldbus_proxy;
+  }
+
+  Eldbus_Connection* cbhm_connection_get()
+  {
+    return cbhm_conn;
+  }
+
+  void SetItem( const std::string &itemData )
+  {
+    const char *types[10] = {0, };
+    int i = -1;
+
+    if (itemData.length() == 0)
+    {
+      return;
+    }
+    mSendBuffer = itemData;
+
+    // ELM_SEL_TYPE_CLIPBOARD - To distinguish clipboard selection in cbhm
+    types[++i] = "CLIPBOARD_BEGIN";
+
+    types[++i] = "text/plain;charset=utf-8";
+
+    // ELM_SEL_TYPE_CLIPBOARD - To distinguish clipboard selection in cbhm
+    types[++i] = "CLIPBOARD_END";
+
+#ifdef ECORE_WAYLAND2
+    Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get( ecore_wl2_connected_display_get( NULL ) );
+    ecore_wl2_dnd_selection_set( input, types );
+#else
+    ecore_wl_dnd_selection_set( ecore_wl_input_get(), types );
+#endif
+  }
+
+  void RequestItem()
+  {
+#ifdef ECORE_WAYLAND2
+    Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get( ecore_wl2_connected_display_get( NULL ) );
+    ecore_wl2_dnd_selection_get( input );
+#else
+    const char *types[10] = {0, };
+    int i = -1;
+
+    types[++i] = "text/plain;charset=utf-8";
+    ecore_wl_dnd_selection_get(ecore_wl_input_get(), *types);
+#endif
+
+    Dali::ClipboardEventNotifier clipboardEventNotifier(Dali::ClipboardEventNotifier::Get());
+    if ( clipboardEventNotifier )
+    {
+      clipboardEventNotifier.SetContent( mSendBuffer );
+      clipboardEventNotifier.EmitContentSelectedSignal();
+    }
+  }
+
+  char *ExcuteSend( void *event )
+  {
+#ifdef ECORE_WAYLAND2
+    Ecore_Wl2_Event_Data_Source_Send *ev = reinterpret_cast<Ecore_Wl2_Event_Data_Source_Send *>( event );
+#else
+    Ecore_Wl_Event_Data_Source_Send *ev = reinterpret_cast<Ecore_Wl_Event_Data_Source_Send *>( event );
+#endif
+
+    int len_buf = mSendBuffer.length();
+    int len_remained = len_buf;
+    int len_written = 0, ret;
+    const char *buf = mSendBuffer.c_str();
+
+    while (len_written < len_buf)
+    {
+       ret = write(ev->fd, buf, len_remained);
+       if (ret == -1) break;
+       buf += ret;
+       len_written += ret;
+       len_remained -= ret;
+    }
+    close(ev->fd);
+    return NULL;
+  }
+
+  char *ExcuteReceive( void *event )
+  {
+#ifdef ECORE_WAYLAND2
+    Ecore_Wl2_Event_Selection_Data_Ready *ev = reinterpret_cast<Ecore_Wl2_Event_Selection_Data_Ready *>( event );
+#else
+    Ecore_Wl_Event_Selection_Data_Ready *ev = reinterpret_cast<Ecore_Wl_Event_Selection_Data_Ready *>( event );
+#endif
+
+    return reinterpret_cast<char *>( ev->data );
+  }
+
+  int GetCount()
+  {
+    Eldbus_Message *reply, *req;
+    const char *errname = NULL, *errmsg = NULL;
+    int count = -1;
+
+    if (!(req = eldbus_proxy_method_call_new(eldbus_proxy, "CbhmGetCount")))
+    {
+      DALI_LOG_ERROR("Failed to create method call on org.freedesktop.DBus.Properties.Get");
+      return -1;
+    }
+
+    eldbus_message_ref(req);
+    eldbus_message_arguments_append(req, "i", CBHM_COUNT_ALL) ;
+    reply = eldbus_proxy_send_and_block(eldbus_proxy, req, 100);
+    if (!reply || eldbus_message_error_get(reply, &errname, &errmsg))
+    {
+      DALI_LOG_ERROR("Unable to call method org.freedesktop.DBus.Properties.Get: %s %s",
+      errname, errmsg);
+      eldbus_message_unref(req);
+      if( reply )
+      {
+        eldbus_message_unref(reply);
+      }
+      return -1;
+    }
+
+    if (!eldbus_message_arguments_get(reply, "i", &count))
+    {
+      DALI_LOG_ERROR("Cannot get arguments from eldbus");
+      eldbus_message_unref(req);
+      eldbus_message_unref(reply);
+      return -1;
+    }
+
+    eldbus_message_unref(req);
+    eldbus_message_unref(reply);
+    DALI_LOG_ERROR("cbhm item count(%d)", count);
+    return count;
+  }
+
+  void ShowClipboard()
+  {
+    eldbus_proxy_call(cbhm_proxy_get(), "CbhmShow", NULL, NULL, -1, "s", "0");
+    mIsFirstTimeHidden = true;
+    mVisible = true;
+  }
+
+  void HideClipboard( bool skipFirstHide )
+  {
+    if ( skipFirstHide && mIsFirstTimeHidden )
+    {
+      mIsFirstTimeHidden = false;
+      return;
+    }
+    eldbus_proxy_call(cbhm_proxy_get(), "CbhmHide", NULL, NULL, -1, "");
+    mIsFirstTimeHidden = false;
+    mVisible = false;
+  }
+
+  bool IsVisible() const
+  {
+    return mVisible;
+  }
+
+  static void _on_item_clicked(void *data, const Eldbus_Message *msg EINA_UNUSED)
+  {
+    static_cast<Clipboard::Impl*>(data)->RequestItem();
+  }
+
+  Eldbus_Proxy *eldbus_proxy;
+  Eldbus_Connection *cbhm_conn;
+
+  std::string mSendBuffer;
+  bool mVisible;
+  bool mIsFirstTimeHidden;
+};
+
+Clipboard::Clipboard(Impl* impl)
+: mImpl(impl)
+{
+}
+
+Clipboard::~Clipboard()
+{
+  delete mImpl;
+}
+
+Dali::Clipboard Clipboard::Get()
+{
+  Dali::Clipboard clipboard;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::Clipboard ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      clipboard = Dali::Clipboard( dynamic_cast< Clipboard* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      Clipboard::Impl* impl( new Clipboard::Impl() );
+      clipboard = Dali::Clipboard( new Clipboard(impl) );
+      service.Register( typeid(Dali::Clipboard), clipboard );
+    }
+  }
+
+  return clipboard;
+}
+
+bool Clipboard::SetItem(const std::string &itemData )
+{
+  mImpl->SetItem( itemData );
+  return true;
+}
+
+/*
+ * Request clipboard service to give an item
+ */
+void Clipboard::RequestItem()
+{
+  mImpl->RequestItem();
+}
+
+/*
+ * Get number of items in clipboard
+ */
+unsigned int Clipboard::NumberOfItems()
+{
+  return mImpl->GetCount();
+}
+
+void Clipboard::ShowClipboard()
+{
+  mImpl->ShowClipboard();
+}
+
+void Clipboard::HideClipboard(bool skipFirstHide)
+{
+  mImpl->HideClipboard(skipFirstHide);
+}
+
+bool Clipboard::IsVisible() const
+{
+  return mImpl->IsVisible();
+}
+
+char* Clipboard::ExcuteBuffered( bool type, void *event )
+{
+  return (type ?  mImpl->ExcuteSend( event ) : mImpl->ExcuteReceive( event ));
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/clipboard/ubuntu-x11/clipboard-impl-x.cpp b/dali/internal/clipboard/ubuntu-x11/clipboard-impl-x.cpp
new file mode 100644 (file)
index 0000000..1cb8704
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/clipboard/common/clipboard-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/internal/system/linux/dali-ecore-x.h>
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/window-system/ubuntu-x11/window-interface-ecore-x.h>
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/internal/clipboard/common/clipboard-event-notifier-impl.h>
+
+namespace //unnamed namespace
+{
+const char* const CBHM_WINDOW = "CBHM_XWIN";
+const char* const CBHM_MSG = "CBHM_MSG";
+const char* const CBHM_ITEM = "CBHM_ITEM";
+const char* const CBHM_cCOUNT = "CBHM_cCOUNT";
+const char* const CBHM_ERROR = "CBHM_ERROR";
+const char* const SET_ITEM = "SET_ITEM";
+const char* const SHOW = "show0";
+const char* const HIDE = "cbhm_hide";
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+// Clipboard
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+struct Clipboard::Impl
+{
+  Impl( Ecore_X_Window ecoreXwin )
+  {
+    mApplicationWindow = ecoreXwin;
+  }
+
+  Ecore_X_Window mApplicationWindow;
+};
+
+Clipboard::Clipboard(Impl* impl)
+: mImpl( impl )
+{
+}
+
+Clipboard::~Clipboard()
+{
+  delete mImpl;
+}
+
+Dali::Clipboard Clipboard::Get()
+{
+  Dali::Clipboard clipboard;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::Clipboard ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      clipboard = Dali::Clipboard( dynamic_cast< Clipboard* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      Adaptor& adaptorImpl( Adaptor::GetImplementation( Adaptor::Get() ) );
+      Any nativewindow = adaptorImpl.GetNativeWindowHandle();
+
+      // The Ecore_X_Window needs to use the Clipboard.
+      // Only when the render surface is window, we can get the Ecore_X_Window.
+      Ecore_X_Window ecoreXwin( AnyCast<Ecore_X_Window>(nativewindow) );
+      if (ecoreXwin)
+      {
+        // If we fail to get Ecore_X_Window, we can't use the Clipboard correctly.
+        // Thus you have to call "ecore_imf_context_client_window_set" somewhere.
+        // In EvasPlugIn, this function is called in EvasPlugin::ConnectEcoreEvent().
+        Clipboard::Impl* impl( new Clipboard::Impl( ecoreXwin ) );
+        clipboard = Dali::Clipboard( new Clipboard( impl ) );
+        service.Register( typeid( clipboard ), clipboard );
+      }
+    }
+  }
+
+  return clipboard;
+}
+bool Clipboard::SetItem(const std::string &itemData )
+{
+  Ecore_X_Window cbhmWin = ECore::WindowInterface::GetWindow();
+  Ecore_X_Atom atomCbhmItem = ecore_x_atom_get( CBHM_ITEM );
+  Ecore_X_Atom dataType = ECORE_X_ATOM_STRING;
+
+  // Set item (property) to send
+  ecore_x_window_prop_property_set( cbhmWin, atomCbhmItem, dataType, 8, const_cast<char*>( itemData.c_str() ), itemData.length() + 1 );
+  ecore_x_sync();
+
+  // Trigger sending of item (property)
+  Ecore_X_Atom atomCbhmMsg = ecore_x_atom_get( CBHM_MSG );
+  ECore::WindowInterface::SendXEvent(ecore_x_display_get(), cbhmWin, False, NoEventMask, atomCbhmMsg, 8, SET_ITEM );
+  return true;
+}
+
+/*
+ * Request clipboard service to retrieve an item
+ */
+void Clipboard::RequestItem()
+{
+  int index = 0;
+  char sendBuf[20];
+  snprintf( sendBuf, 20,  "%s%d", CBHM_ITEM, index );
+  Ecore_X_Atom xAtomCbhmItem = ecore_x_atom_get( sendBuf );
+  Ecore_X_Atom xAtomItemType = 0;
+
+  std::string clipboardString( ECore::WindowInterface::GetWindowProperty(xAtomCbhmItem, &xAtomItemType, index ) );
+
+  // Only return the text string if the Atom type is text (Do not return a text string/URL for images).
+  if( !clipboardString.empty() &&
+      ( xAtomItemType == ECORE_X_ATOM_TEXT || xAtomItemType == ECORE_X_ATOM_COMPOUND_TEXT || xAtomItemType == ECORE_X_ATOM_STRING || xAtomItemType == ECORE_X_ATOM_UTF8_STRING ) )
+  {
+    Ecore_X_Atom xAtomCbhmError = ecore_x_atom_get( CBHM_ERROR );
+    if ( xAtomItemType != xAtomCbhmError )
+    {
+      // Call ClipboardEventNotifier to notify event observe of retrieved string
+      Dali::ClipboardEventNotifier clipboardEventNotifier(ClipboardEventNotifier::Get());
+      if ( clipboardEventNotifier )
+      {
+        ClipboardEventNotifier& notifierImpl( ClipboardEventNotifier::GetImplementation( clipboardEventNotifier ) );
+
+        notifierImpl.SetContent( clipboardString );
+        notifierImpl.EmitContentSelectedSignal();
+      }
+    }
+  }
+}
+
+/*
+ * Get number of items in clipboard
+ */
+unsigned int Clipboard::NumberOfItems()
+{
+  Ecore_X_Atom xAtomCbhmCountGet = ecore_x_atom_get( CBHM_cCOUNT );
+
+  std::string ret( ECore::WindowInterface::GetWindowProperty( xAtomCbhmCountGet, NULL, 0 ) );
+  int count = 0;
+
+  if ( !ret.empty() )
+  {
+    count = atoi( ret.c_str() );
+  }
+
+  return count;
+}
+
+/**
+ * Show clipboard window
+ * Function to send message to show the Clipboard (cbhm) as no direct API available
+ * Reference elementary/src/modules/ctxpopup_copypasteUI/cbhm_helper.c
+ */
+void Clipboard::ShowClipboard()
+{
+  // Claim the ownership of the SECONDARY selection.
+  ecore_x_selection_secondary_set(mImpl->mApplicationWindow, "", 1);
+  Ecore_X_Window cbhmWin = ECore::WindowInterface::GetWindow();
+
+  // Launch the clipboard window
+  Ecore_X_Atom atomCbhmMsg = ecore_x_atom_get( CBHM_MSG );
+  ECore::WindowInterface::SendXEvent( ecore_x_display_get(), cbhmWin, False, NoEventMask, atomCbhmMsg, 8, SHOW );
+}
+
+void Clipboard::HideClipboard(bool skipFirstHide)
+{
+  Ecore_X_Window cbhmWin = ECore::WindowInterface::GetWindow();
+  // Launch the clipboard window
+  Ecore_X_Atom atomCbhmMsg = ecore_x_atom_get( CBHM_MSG );
+  ECore::WindowInterface::SendXEvent( ecore_x_display_get(), cbhmWin, False, NoEventMask, atomCbhmMsg, 8, HIDE );
+
+  // release the ownership of SECONDARY selection
+  ecore_x_selection_secondary_clear();
+}
+
+bool Clipboard::IsVisible() const
+{
+  return false;
+}
+
+char* Clipboard::ExcuteBuffered( bool type, void *event )
+{
+  if( !type )
+  {
+    // Receive
+    Ecore_X_Event_Selection_Notify* selectionNotifyEvent = static_cast< Ecore_X_Event_Selection_Notify* >( event );
+
+    Ecore_X_Selection_Data* selectionData = static_cast< Ecore_X_Selection_Data* >( selectionNotifyEvent->data );
+    if( selectionData->data )
+    {
+      if( selectionNotifyEvent->selection == ECORE_X_SELECTION_SECONDARY )
+      {
+        // Claim the ownership of the SECONDARY selection.
+        ecore_x_selection_secondary_set( mImpl->mApplicationWindow, "", 1 );
+
+        return ( reinterpret_cast< char* >( selectionData->data ) );
+      }
+    }
+  }
+  return NULL;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/graphics/android/egl-image-extensions-android.cpp b/dali/internal/graphics/android/egl-image-extensions-android.cpp
new file mode 100644 (file)
index 0000000..7630148
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+// CLASS HEADER
+#include <dali/internal/graphics/common/egl-image-extensions.h>
+
+// EXTERNAL INCLUDES
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+
+#include <EGL/eglext.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/gles/egl-implementation.h>
+
+
+namespace
+{
+// function pointers assigned in InitializeEglImageKHR
+PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHRProc = 0;
+PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHRProc = 0;
+PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOESProc = 0;
+} // unnamed namespace
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+EglImageExtensions::EglImageExtensions(EglImplementation* eglImpl)
+: mEglImplementation( eglImpl ),
+  mImageKHRInitialized( false ),
+  mImageKHRInitializeFailed( false )
+{
+  DALI_ASSERT_ALWAYS( eglImpl && "EGL Implementation not instantiated" );
+}
+
+EglImageExtensions::~EglImageExtensions() = default;
+
+void* EglImageExtensions::CreateImageKHR(EGLClientBuffer clientBuffer)
+{
+  if( mImageKHRInitialized == false )
+  {
+    InitializeEglImageKHR();
+  }
+
+  if( mImageKHRInitialized == false )
+  {
+    return NULL;
+  }
+
+  // No extensions
+  const EGLint attribs[] =
+  {
+    EGL_NONE
+  };
+
+// EGL constants use C casts
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+  EGLImageKHR eglImage  = eglCreateImageKHRProc( mEglImplementation->GetDisplay(),
+                                             EGL_NO_CONTEXT,
+                                             EGL_NATIVE_BUFFER_ANDROID,
+                                             clientBuffer,
+                                             attribs );
+
+  DALI_ASSERT_DEBUG( EGL_NO_IMAGE_KHR != eglImage && "eglCreateImageKHR failed!\n");
+  if( EGL_NO_IMAGE_KHR == eglImage )
+  {
+    switch( eglGetError() )
+    {
+      case EGL_SUCCESS :
+      {
+        break;
+      }
+      case EGL_BAD_DISPLAY:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_DISPLAY: Invalid EGLDisplay object\n" );
+        break;
+      }
+      case EGL_BAD_CONTEXT:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_CONTEXT: Invalid EGLContext object\n" );
+        break;
+      }
+      case EGL_BAD_PARAMETER:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_PARAMETER: Invalid target parameter or attribute in attrib_list\n" );
+        break;
+      }
+      case EGL_BAD_MATCH:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_MATCH: attrib_list does not match target\n" );
+        break;
+      }
+      case EGL_BAD_ACCESS:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_ACCESS: Previously bound off-screen, or EGLImage sibling error\n" );
+        break;
+      }
+      case EGL_BAD_ALLOC:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_ALLOC: Insufficient memory is available\n" );
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+#pragma GCC diagnostic pop
+
+  return eglImage;
+}
+
+void EglImageExtensions::DestroyImageKHR(void* eglImageKHR)
+{
+  DALI_ASSERT_DEBUG( mImageKHRInitialized );
+
+  if( ! mImageKHRInitialized )
+  {
+    return;
+  }
+
+  if( eglImageKHR == NULL )
+  {
+    return;
+  }
+
+  EGLImageKHR eglImage = static_cast<EGLImageKHR>( eglImageKHR );
+
+  EGLBoolean result = eglDestroyImageKHRProc( mEglImplementation->GetDisplay(), eglImage );
+
+  if( EGL_FALSE == result )
+  {
+    switch( eglGetError() )
+    {
+      case EGL_BAD_DISPLAY:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_DISPLAY: Invalid EGLDisplay object\n" );
+        break;
+      }
+      case EGL_BAD_PARAMETER:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_PARAMETER: eglImage is not a valid EGLImageKHR object created with respect to EGLDisplay\n" );
+        break;
+      }
+      case EGL_BAD_ACCESS:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_ACCESS: EGLImage sibling error\n" );
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+}
+
+void EglImageExtensions::TargetTextureKHR(void* eglImageKHR)
+{
+  DALI_ASSERT_DEBUG( mImageKHRInitialized );
+
+  if( eglImageKHR != NULL )
+  {
+    EGLImageKHR eglImage = static_cast<EGLImageKHR>(eglImageKHR);
+
+#ifdef EGL_ERROR_CHECKING
+    GLint glError = glGetError();
+#endif
+
+    glEGLImageTargetTexture2DOESProc(GL_TEXTURE_2D, reinterpret_cast< GLeglImageOES >( eglImage ) );
+
+#ifdef EGL_ERROR_CHECKING
+    glError = glGetError();
+    if( GL_NO_ERROR != glError )
+    {
+      DALI_LOG_ERROR(" glEGLImageTargetTexture2DOES returned error %0x04x\n", glError );
+    }
+#endif
+  }
+}
+
+void EglImageExtensions::InitializeEglImageKHR()
+{
+  // avoid trying to reload extended KHR functions, if it fails the first time
+  if( ! mImageKHRInitializeFailed )
+  {
+    eglCreateImageKHRProc  = reinterpret_cast< PFNEGLCREATEIMAGEKHRPROC >( eglGetProcAddress("eglCreateImageKHR") );
+    eglDestroyImageKHRProc = reinterpret_cast< PFNEGLDESTROYIMAGEKHRPROC >( eglGetProcAddress("eglDestroyImageKHR") );
+    glEGLImageTargetTexture2DOESProc = reinterpret_cast< PFNGLEGLIMAGETARGETTEXTURE2DOESPROC >( eglGetProcAddress("glEGLImageTargetTexture2DOES") );
+  }
+
+  if( eglCreateImageKHRProc && eglDestroyImageKHRProc && glEGLImageTargetTexture2DOESProc )
+  {
+    mImageKHRInitialized = true;
+  }
+  else
+  {
+    mImageKHRInitializeFailed = true;
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/graphics/common/egl-image-extensions.h b/dali/internal/graphics/common/egl-image-extensions.h
new file mode 100644 (file)
index 0000000..82f8459
--- /dev/null
@@ -0,0 +1,94 @@
+#ifndef DALI_INTERNAL_EGL_IMAGE_EXTENSIONS_H
+#define DALI_INTERNAL_EGL_IMAGE_EXTENSIONS_H
+
+/*
+ * Copyright (c) 2019 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/images/pixel.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/common/egl-include.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class EglImplementation;
+
+/**
+ * EglImageExtensions class provides EGL image extension support
+ */
+class EglImageExtensions
+{
+public:
+  /**
+   * Constructor
+   */
+  EglImageExtensions(EglImplementation* impl);
+
+  /**
+   * Destructor
+   */
+  ~EglImageExtensions();
+
+
+public:   // EGLImageKHR extension support
+
+  /**
+   * If the EGL Image extension is available this function returns a
+   * EGLImageKHR
+   * @param clientBuffer Client buffer to use for image creation
+   * @return an object that holds a EGLImageKHR
+   */
+  void* CreateImageKHR(EGLClientBuffer clientBuffer);
+
+  /**
+   * If the EGL Image extension is available this function
+   * destroys the a EGLImageKHR
+   * @param eglImageKHR Object that holds a EGLImageKHR
+   */
+  void DestroyImageKHR(void* eglImageKHR);
+
+  /**
+   * defines a 2D texture
+   * @param eglImageKHR Object that holds a EGLImageKHR
+   */
+  void TargetTextureKHR(void* eglImageKHR);
+
+  /**
+   * Get the functions for using ImageKHR
+   */
+  void InitializeEglImageKHR();
+
+private:
+  EglImplementation* mEglImplementation;
+
+  bool mImageKHRInitialized;             ///< Flag for whether extended KHR functions loaded
+  bool mImageKHRInitializeFailed;        ///< Flag to avoid trying to reload extended KHR functions, if
+                                         /// it fails the first time
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_EGL_IMAGE_EXTENSIONS_H
diff --git a/dali/internal/graphics/common/egl-include.h b/dali/internal/graphics/common/egl-include.h
new file mode 100644 (file)
index 0000000..d0d1cad
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef EGL_INCLUDE_H
+#define EGL_INCLUDE_H
+
+// EXTERNAL INCLUDES
+#include <EGL/egl.h>
+
+// Undef unneded symbols that fail to compile on MS Windows
+#undef ERROR
+
+#undef OPAQUE
+#undef TRANSPARENT
+
+#undef TRUE
+#undef FALSE
+
+#undef CopyMemory
+#undef CreateWindow
+
+#include <EGL/eglext.h>
+
+#endif // EGL_INCLUDE_H
diff --git a/dali/internal/graphics/common/graphics-factory-interface.h b/dali/internal/graphics/common/graphics-factory-interface.h
new file mode 100644 (file)
index 0000000..bcec0af
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef DALI_INTERNAL_BASE_GRAPHICS_FACTORY_INTERFACE_H
+#define DALI_INTERNAL_BASE_GRAPHICS_FACTORY_INTERFACE_H
+
+/*
+ * Copyright (c) 2018 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 <dali/internal/system/common/environment-options.h>
+#include <dali/internal/graphics/common/graphics-interface.h>
+
+namespace Dali
+{
+class GraphicsInterface;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Factory interface for creating Graphics Factory implementation
+ */
+class GraphicsFactoryInterface
+{
+public:
+  /**
+   * Create a Graphics interface implementation
+   * @return An implementation of the Graphics interface
+   */
+  virtual GraphicsInterface& Create() = 0;
+
+  /**
+   * Destroy the Graphics Factory implementation
+   */
+  virtual void Destroy() = 0;
+
+protected:
+  /**
+   * Virtual protected destructor - no deletion through this interface
+   */
+  virtual ~GraphicsFactoryInterface() {};
+};
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
+
+#endif // DALI_INTERNAL_BASE_GRAPHICS_FACTORY_INTERFACE_H
diff --git a/dali/internal/graphics/common/graphics-interface.h b/dali/internal/graphics/common/graphics-interface.h
new file mode 100644 (file)
index 0000000..5e80ef7
--- /dev/null
@@ -0,0 +1,98 @@
+#ifndef DALI_INTERNAL_BASE_GRAPHICS_INTERFACE_H
+#define DALI_INTERNAL_BASE_GRAPHICS_INTERFACE_H
+
+/*
+ * Copyright (c) 2018 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 <dali/internal/system/common/environment-options.h>
+#include <dali/integration-api/core-enumerations.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Factory interface for creating Graphics Factory implementation
+ */
+class GraphicsInterface
+{
+public:
+
+  /**
+   * Constructor
+   */
+  GraphicsInterface()
+: mDepthBufferRequired( Integration::DepthBufferAvailable::FALSE ),
+  mStencilBufferRequired( Integration::StencilBufferAvailable::FALSE )
+  {
+  };
+
+  /**
+   * Initialize the graphics interface
+   * @param[in]  environmentOptions  The environment options.
+   */
+  virtual void Initialize( EnvironmentOptions* environmentOptions ) = 0;
+
+  /**
+   * Destroy the Graphics Factory implementation
+   */
+  virtual void Destroy() = 0;
+
+  /**
+   * Get whether the depth buffer is required
+   * @return TRUE if the depth buffer is required
+   */
+  Integration::DepthBufferAvailable& GetDepthBufferRequired()
+  {
+    return mDepthBufferRequired;
+  };
+
+  /**
+   * Get whether the stencil buffer is required
+   * @return TRUE if the stencil buffer is required
+   */
+  Integration::StencilBufferAvailable GetStencilBufferRequired()
+  {
+    return mStencilBufferRequired;
+  };
+
+protected:
+  /**
+   * Virtual protected destructor - no deletion through this interface
+   */
+  virtual ~GraphicsInterface() {};
+
+
+protected:
+
+  Integration::DepthBufferAvailable mDepthBufferRequired;       ///< Whether the depth buffer is required
+  Integration::StencilBufferAvailable mStencilBufferRequired;   ///< Whether the stencil buffer is required
+};
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
+
+#endif // DALI_INTERNAL_BASE_GRAPHICS_INTERFACE_H
diff --git a/dali/internal/graphics/file.list b/dali/internal/graphics/file.list
new file mode 100644 (file)
index 0000000..97d4fb9
--- /dev/null
@@ -0,0 +1,33 @@
+
+# module: graphics, backend: gles
+SET( adaptor_graphics_gles_src_files
+    ${adaptor_graphics_dir}/gles/egl-debug.cpp
+    ${adaptor_graphics_dir}/gles/egl-implementation.cpp
+    ${adaptor_graphics_dir}/gles/egl-sync-implementation.cpp
+    ${adaptor_graphics_dir}/gles/egl-context-helper-implementation.cpp
+    ${adaptor_graphics_dir}/gles/gl-extensions.cpp
+    ${adaptor_graphics_dir}/gles/gl-proxy-implementation.cpp
+    ${adaptor_graphics_dir}/gles/egl-graphics-factory.cpp
+    ${adaptor_graphics_dir}/gles/egl-graphics.cpp
+)
+
+# module: graphics, backend: tizen
+SET( adaptor_graphics_tizen_src_files
+    ${adaptor_graphics_dir}/tizen/egl-image-extensions-tizen.cpp
+)
+
+# module: graphics, backend: generic
+SET( adaptor_graphics_ubuntu_src_files
+    ${adaptor_graphics_dir}/generic/egl-image-extensions-generic.cpp
+)
+
+# module: graphics, backend: android
+SET( adaptor_graphics_android_src_files
+    ${adaptor_graphics_dir}/android/egl-image-extensions-android.cpp
+)
+
+# module: graphics, backend: windows
+SET( adaptor_graphics_windows_src_files
+    ${adaptor_graphics_dir}/windows-gl/egl-image-extensions.cpp
+)
+
diff --git a/dali/internal/graphics/generic/egl-image-extensions-generic.cpp b/dali/internal/graphics/generic/egl-image-extensions-generic.cpp
new file mode 100644 (file)
index 0000000..70ddfde
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+// CLASS HEADER
+#include <dali/internal/graphics/common/egl-image-extensions.h>
+
+// EXTERNAL INCLUDES
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+
+#include <EGL/eglext.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/gles/egl-implementation.h>
+
+
+namespace
+{
+// function pointers assigned in InitializeEglImageKHR
+PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHRProc = 0;
+PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHRProc = 0;
+PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOESProc = 0;
+} // unnamed namespace
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+EglImageExtensions::EglImageExtensions(EglImplementation* eglImpl)
+: mEglImplementation(eglImpl),
+  mImageKHRInitialized(false),
+  mImageKHRInitializeFailed(false)
+{
+  DALI_ASSERT_ALWAYS( eglImpl && "EGL Implementation not instantiated" );
+}
+
+EglImageExtensions::~EglImageExtensions()
+{
+}
+
+void* EglImageExtensions::CreateImageKHR(EGLClientBuffer clientBuffer)
+{
+  if (mImageKHRInitialized == false)
+  {
+    InitializeEglImageKHR();
+  }
+
+  if (mImageKHRInitialized == false)
+  {
+    return NULL;
+  }
+
+  // Use the EGL image extension
+  const EGLint attribs[] =
+  {
+    EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+    EGL_NONE
+  };
+
+  EGLImageKHR eglImage  = eglCreateImageKHRProc( mEglImplementation->GetDisplay(),
+                                             EGL_NO_CONTEXT,
+                                             EGL_NATIVE_PIXMAP_KHR,
+                                             clientBuffer,
+                                             attribs );
+
+  DALI_ASSERT_DEBUG( EGL_NO_IMAGE_KHR != eglImage && "X11Image::GlExtensionCreate eglCreateImageKHR failed!\n");
+  if( EGL_NO_IMAGE_KHR == eglImage )
+  {
+    switch( eglGetError() )
+    {
+      case EGL_SUCCESS :
+      {
+        break;
+      }
+      case EGL_BAD_DISPLAY:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_DISPLAY: Invalid EGLDisplay object\n" );
+        break;
+      }
+      case EGL_BAD_CONTEXT:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_CONTEXT: Invalid EGLContext object\n" );
+        break;
+      }
+      case EGL_BAD_PARAMETER:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_PARAMETER: Invalid target parameter or attribute in attrib_list\n" );
+        break;
+      }
+      case EGL_BAD_MATCH:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_MATCH: attrib_list does not match target\n" );
+        break;
+      }
+      case EGL_BAD_ACCESS:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_ACCESS: Previously bound off-screen, or EGLImage sibling error\n" );
+        break;
+      }
+      case EGL_BAD_ALLOC:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_ALLOC: Insufficient memory is available\n" );
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+
+  return eglImage;
+}
+
+void EglImageExtensions::DestroyImageKHR(void* eglImageKHR)
+{
+  DALI_ASSERT_DEBUG( mImageKHRInitialized );
+
+  if( ! mImageKHRInitialized )
+  {
+    return;
+  }
+
+  if( eglImageKHR == NULL )
+  {
+    return;
+  }
+
+  EGLImageKHR eglImage = static_cast<EGLImageKHR>(eglImageKHR);
+
+  EGLBoolean result = eglDestroyImageKHRProc(mEglImplementation->GetDisplay(), eglImage);
+
+  if( EGL_FALSE == result )
+  {
+    switch( eglGetError() )
+    {
+      case EGL_BAD_DISPLAY:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_DISPLAY: Invalid EGLDisplay object\n" );
+        break;
+      }
+      case EGL_BAD_PARAMETER:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_PARAMETER: eglImage is not a valid EGLImageKHR object created with respect to EGLDisplay\n" );
+        break;
+      }
+      case EGL_BAD_ACCESS:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_ACCESS: EGLImage sibling error\n" );
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+}
+
+void EglImageExtensions::TargetTextureKHR(void* eglImageKHR)
+{
+  DALI_ASSERT_DEBUG( mImageKHRInitialized );
+
+  if( eglImageKHR != NULL )
+  {
+    EGLImageKHR eglImage = static_cast<EGLImageKHR>(eglImageKHR);
+
+#ifdef EGL_ERROR_CHECKING
+    GLint glError = glGetError();
+#endif
+
+    glEGLImageTargetTexture2DOESProc(GL_TEXTURE_2D, reinterpret_cast< GLeglImageOES >( eglImage ) );
+
+#ifdef EGL_ERROR_CHECKING
+    glError = glGetError();
+    if( GL_NO_ERROR != glError )
+    {
+      DALI_LOG_ERROR(" glEGLImageTargetTexture2DOES returned error %0x04x\n", glError );
+    }
+#endif
+  }
+}
+
+void EglImageExtensions::InitializeEglImageKHR()
+{
+  // avoid trying to reload extended KHR functions, if it fails the first time
+  if( ! mImageKHRInitializeFailed )
+  {
+    eglCreateImageKHRProc  = reinterpret_cast< PFNEGLCREATEIMAGEKHRPROC >( eglGetProcAddress("eglCreateImageKHR") );
+    eglDestroyImageKHRProc = reinterpret_cast< PFNEGLDESTROYIMAGEKHRPROC >( eglGetProcAddress("eglDestroyImageKHR") );
+    glEGLImageTargetTexture2DOESProc = reinterpret_cast< PFNGLEGLIMAGETARGETTEXTURE2DOESPROC >( eglGetProcAddress("glEGLImageTargetTexture2DOES") );
+  }
+
+  if (eglCreateImageKHRProc && eglDestroyImageKHRProc && glEGLImageTargetTexture2DOESProc)
+  {
+    mImageKHRInitialized = true;
+  }
+  else
+  {
+    mImageKHRInitializeFailed = true;
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/graphics/gles/egl-context-helper-implementation.cpp b/dali/internal/graphics/gles/egl-context-helper-implementation.cpp
new file mode 100644 (file)
index 0000000..15085a1
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/graphics/gles/egl-context-helper-implementation.h>
+
+// EXTERNAL INCLUDES
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/gles/egl-implementation.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+EglContextHelperImplementation::EglContextHelperImplementation()
+: mEglImplementation( NULL )
+{
+}
+
+void EglContextHelperImplementation::Initialize( EglImplementation* eglImpl )
+{
+  mEglImplementation = eglImpl;
+}
+
+void EglContextHelperImplementation::MakeSurfacelessContextCurrent()
+{
+  if ( mEglImplementation && mEglImplementation->IsSurfacelessContextSupported() )
+  {
+    mEglImplementation->MakeContextCurrent( EGL_NO_SURFACE, mEglImplementation->GetContext() );
+  }
+}
+
+void EglContextHelperImplementation::MakeContextNull()
+{
+  if ( mEglImplementation )
+  {
+    mEglImplementation->MakeContextNull();
+  }
+}
+
+void EglContextHelperImplementation::WaitClient()
+{
+  if ( mEglImplementation )
+  {
+    mEglImplementation->WaitClient();
+  }
+}
+
+} // namespace Dali
+} // namespace Internal
+} // namespace Adaptor
diff --git a/dali/internal/graphics/gles/egl-context-helper-implementation.h b/dali/internal/graphics/gles/egl-context-helper-implementation.h
new file mode 100644 (file)
index 0000000..ef38426
--- /dev/null
@@ -0,0 +1,90 @@
+#ifndef DALI_INTERNAL_ADAPTOR_EGL_CONTEXT_HELPER_IMPLEMENTATION_H
+#define DALI_INTERNAL_ADAPTOR_EGL_CONTEXT_HELPER_IMPLEMENTATION_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <dali/internal/graphics/common/egl-include.h>
+// EXTERNAL INCLUDES
+#include <dali/integration-api/gl-context-helper-abstraction.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+class RenderSurface;
+}
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+class EglImplementation;
+
+/**
+ * EglContextHelperImplementation is a concrete implementation for GlContextHelperAbstraction.
+ * It provides helper functions to access EGL context APIs
+ */
+class EglContextHelperImplementation : public Integration::GlContextHelperAbstraction
+{
+public:
+  /**
+   * Constructor
+   */
+  EglContextHelperImplementation();
+
+  /**
+   * Destructor
+   */
+  virtual ~EglContextHelperImplementation() = default;
+
+  /**
+   * Initialize with the Egl implementation.
+   * @param[in] impl The EGL implementation (to access the EGL context)
+   */
+  void Initialize( EglImplementation* impl );
+
+  /**
+   * @copydoc Dali::Integration::GlContextHelperAbstraction::MakeSurfacelessContextCurrent()
+   */
+  virtual void MakeSurfacelessContextCurrent() override;
+
+  /**
+   * @copydoc Dali::Integration::GlContextHelperAbstraction::MakeContextNull()
+   */
+  virtual void MakeContextNull() override;
+
+  /**
+   * @copydoc Dali::Integration::GlContextHelperAbstraction::WaitClient()
+   */
+  virtual void WaitClient() override;
+
+private:
+
+  EglImplementation* mEglImplementation; ///< Egl implementation (to access the EGL context)
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_EGL_CONTEXT_HELPER_IMPLEMENTATION_H
diff --git a/dali/internal/graphics/gles/egl-debug.cpp b/dali/internal/graphics/gles/egl-debug.cpp
new file mode 100644 (file)
index 0000000..1f5bbfa
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/graphics/gles/egl-debug.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace Egl
+{
+
+void PrintError( EGLint error)
+{
+  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 with code: %d\n", error);
+      break;
+    }
+  }
+}
+
+}  // namespace Egl
+
+}  // namespace Adaptor
+
+}  // namespace Internal
+
+}  // namespace Dali
diff --git a/dali/internal/graphics/gles/egl-debug.h b/dali/internal/graphics/gles/egl-debug.h
new file mode 100644 (file)
index 0000000..81b6a5e
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef DALI_INTERNAL_EGL_DEBUG_H
+#define DALI_INTERNAL_EGL_DEBUG_H
+
+/*
+ * Copyright (c) 2019 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/internal/graphics/common/egl-include.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace Egl
+{
+
+void PrintError( EGLint error);
+
+}  // namespace Egl
+
+}  // namespace Adaptor
+
+}  // namespace Internal
+
+}  // namespace Dali
+
+#endif //DALI_INTERNAL_EGL_DEBUG_H
diff --git a/dali/internal/graphics/gles/egl-factory-interface.h b/dali/internal/graphics/gles/egl-factory-interface.h
new file mode 100644 (file)
index 0000000..3a8f9f6
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef DALI_INTERNAL_BASE_EGL_FACTORY_INTERFACE_H
+#define DALI_INTERNAL_BASE_EGL_FACTORY_INTERFACE_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.
+ *
+ */
+
+namespace Dali
+{
+
+class EglInterface;
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * Factory interface for creating EGL implementation
+ */
+class EglFactoryInterface
+{
+public:
+  /**
+   * Create an EGL implementation
+   * @return An implementation of the EGL interface
+   */
+  virtual EglInterface* Create() = 0;
+
+  /**
+   * Destroy the EGL implementation
+   */
+  virtual void Destroy() = 0;
+
+protected:
+  /**
+   * Virtual protected destructor - no deletion through this interface
+   */
+  virtual ~EglFactoryInterface() {};
+};
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // DALI_INTERNAL_BASE_EGL_FACTORY_INTERFACE_H
diff --git a/dali/internal/graphics/gles/egl-graphics-factory.cpp b/dali/internal/graphics/gles/egl-graphics-factory.cpp
new file mode 100644 (file)
index 0000000..5588bc6
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+// CLASS HEADER
+#include <dali/internal/graphics/gles/egl-graphics-factory.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+GraphicsFactory::GraphicsFactory()
+{
+}
+
+GraphicsFactory::~GraphicsFactory()
+{
+  /* Deleted by Adaptor destructor */
+}
+
+GraphicsInterface& GraphicsFactory::Create()
+{
+  GraphicsInterface* eglGraphicsInterface = new EglGraphics;
+  return *eglGraphicsInterface;
+}
+
+void GraphicsFactory::Destroy()
+{
+  /* Deleted by EglGraphics */
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/dali/internal/graphics/gles/egl-graphics-factory.h b/dali/internal/graphics/gles/egl-graphics-factory.h
new file mode 100644 (file)
index 0000000..6ba1d91
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef DALI_INTERNAL_GRAPHICS_FACTORY_H
+#define DALI_INTERNAL_GRAPHICS_FACTORY_H
+
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/graphics/common/graphics-factory-interface.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class GraphicsFactory : public GraphicsFactoryInterface
+{
+public:
+
+  /**
+   * Constructor
+   */
+  GraphicsFactory();
+
+  /**
+   * Destructor
+   */
+  virtual ~GraphicsFactory();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::GraphicsFactoryInterface::Create()
+   */
+  GraphicsInterface& Create() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::GraphicsFactoryInterface::Destroy()
+   */
+  void Destroy();
+};
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
+
+#endif // DALI_INTERNAL_GRAPHICS_FACTORY_H
diff --git a/dali/internal/graphics/gles/egl-graphics.cpp b/dali/internal/graphics/gles/egl-graphics.cpp
new file mode 100644 (file)
index 0000000..406e69c
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+// CLASS HEADER
+#include <dali/internal/graphics/gles/egl-graphics.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/window-system/common/display-utils.h> // For Utils::MakeUnique
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+EglGraphics::EglGraphics( )
+: mMultiSamplingLevel( 0 )
+{
+}
+
+EglGraphics::~EglGraphics()
+{
+}
+
+void EglGraphics::SetGlesVersion( const int32_t glesVersion )
+{
+  mEglImplementation->SetGlesVersion( glesVersion );
+  mGLES->SetGlesVersion( glesVersion );
+}
+
+void EglGraphics::SetIsSurfacelessContextSupported( const bool isSupported )
+{
+  mGLES->SetIsSurfacelessContextSupported( isSupported );
+}
+
+void EglGraphics::Initialize( EnvironmentOptions* environmentOptions )
+{
+  if( environmentOptions->GetGlesCallTime() > 0 )
+  {
+    mGLES = Utils::MakeUnique< GlProxyImplementation >( *environmentOptions );
+  }
+  else
+  {
+    mGLES.reset ( new GlImplementation() );
+  }
+
+  mDepthBufferRequired = static_cast< Integration::DepthBufferAvailable >( environmentOptions->DepthBufferRequired() );
+  mStencilBufferRequired = static_cast< Integration::StencilBufferAvailable >( environmentOptions->StencilBufferRequired() );
+
+  mMultiSamplingLevel = environmentOptions->GetMultiSamplingLevel();
+
+  mEglSync = Utils::MakeUnique< EglSyncImplementation >();
+
+  mEglContextHelper = Utils::MakeUnique< EglContextHelperImplementation >();
+}
+
+EglInterface* EglGraphics::Create()
+{
+  mEglImplementation = Utils::MakeUnique< EglImplementation >( mMultiSamplingLevel, mDepthBufferRequired, mStencilBufferRequired );
+  mEglImageExtensions = Utils::MakeUnique< EglImageExtensions >( mEglImplementation.get() );
+
+  mEglSync->Initialize( mEglImplementation.get() ); // The sync impl needs the EglDisplay
+
+  mEglContextHelper->Initialize( mEglImplementation.get() ); // The context helper impl needs the EglContext
+
+  return mEglImplementation.get();
+}
+
+void EglGraphics::Destroy()
+{
+}
+
+GlImplementation& EglGraphics::GetGlesInterface()
+{
+  return *mGLES;
+}
+
+Integration::GlAbstraction& EglGraphics::GetGlAbstraction() const
+{
+  DALI_ASSERT_DEBUG( mGLES && "GLImplementation not created" );
+  return *mGLES;
+}
+
+EglImplementation& EglGraphics::GetEglImplementation() const
+{
+  DALI_ASSERT_DEBUG( mEglImplementation && "EGLImplementation not created" );
+  return *mEglImplementation;
+}
+
+EglInterface& EglGraphics::GetEglInterface() const
+{
+  DALI_ASSERT_DEBUG( mEglImplementation && "EGLImplementation not created" );
+  EglInterface* eglInterface = mEglImplementation.get();
+  return *eglInterface;
+}
+
+EglSyncImplementation& EglGraphics::GetSyncImplementation()
+{
+  DALI_ASSERT_DEBUG( mEglSync && "EglSyncImplementation not created" );
+  return *mEglSync;
+}
+
+EglContextHelperImplementation& EglGraphics::GetContextHelperImplementation()
+{
+  DALI_ASSERT_DEBUG( mEglContextHelper && "EglContextHelperImplementation not created" );
+  return *mEglContextHelper;
+}
+
+EglImageExtensions* EglGraphics::GetImageExtensions()
+{
+  DALI_ASSERT_DEBUG( mEglImageExtensions && "EglImageExtensions not created" );
+  return mEglImageExtensions.get();
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/dali/internal/graphics/gles/egl-graphics.h b/dali/internal/graphics/gles/egl-graphics.h
new file mode 100644 (file)
index 0000000..8ee45bc
--- /dev/null
@@ -0,0 +1,155 @@
+#ifndef DALI_INTERNAL_BASE_GRAPHICS_IMPLEMENTATION_H
+#define DALI_INTERNAL_BASE_GRAPHICS_IMPLEMENTATION_H
+
+/*
+ * Copyright (c) 2019 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 <dali/integration-api/adaptor-framework/egl-interface.h>
+#include <dali/internal/graphics/common/egl-image-extensions.h>
+#include <dali/internal/graphics/common/graphics-interface.h>
+#include <dali/internal/graphics/gles/gl-implementation.h>
+#include <dali/internal/graphics/gles/gl-proxy-implementation.h>
+#include <dali/internal/graphics/gles/egl-context-helper-implementation.h>
+#include <dali/internal/graphics/gles/egl-implementation.h>
+#include <dali/internal/graphics/gles/egl-sync-implementation.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class EglGraphics : public GraphicsInterface
+{
+public:
+
+  /**
+   * Constructor
+   */
+  EglGraphics();
+
+  /**
+   * Destructor
+   */
+  virtual ~EglGraphics();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::GraphicsInterface::Initialize()
+   */
+  void Initialize( EnvironmentOptions* environmentOptions ) override;
+
+  /**
+   * Creates the graphics interface for EGL
+   * @return The graphics interface for EGL
+   */
+  EglInterface* Create();
+
+  /**
+   * Set gles version
+   * Default version is gles 3.0
+   */
+  void SetGlesVersion( const int32_t glesVersion );
+
+  /**
+   * Set whether the surfaceless context is supported
+   * @param[in] isSupported Whether the surfaceless context is supported
+   */
+  void SetIsSurfacelessContextSupported( const bool isSupported );
+
+  /**
+   * Gets the GL abstraction
+   * @return The GL abstraction
+   */
+  Integration::GlAbstraction& GetGlAbstraction() const;
+
+  /**
+   * Gets the implementation of EGL
+   * @return The implementation of EGL
+   */
+  EglImplementation& GetEglImplementation() const;
+
+  /**
+   * Gets the graphics interface for EGL
+   * @return The graphics interface for EGL
+   */
+  EglInterface& GetEglInterface() const;
+
+  /**
+   * @copydoc Dali::Integration::GlAbstraction& GetGlesInterface()
+   */
+  GlImplementation& GetGlesInterface();
+
+  /**
+   * Gets the implementation of GlSyncAbstraction for EGL.
+   * @return The implementation of GlSyncAbstraction for EGL.
+   */
+  EglSyncImplementation& GetSyncImplementation();
+
+  /**
+   * Gets the implementation of GlContextHelperAbstraction for EGL.
+   * @return The implementation of GlContextHelperAbstraction for EGL.
+   */
+  EglContextHelperImplementation& GetContextHelperImplementation();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::GraphicsInterface::GetDepthBufferRequired()
+   */
+  Integration::DepthBufferAvailable& GetDepthBufferRequired();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::GraphicsInterface::GetStencilBufferRequired()
+   */
+  Integration::StencilBufferAvailable GetStencilBufferRequired();
+
+  /**
+   * Gets the EGL image extension
+   * @return The EGL image extension
+   */
+  EglImageExtensions* GetImageExtensions();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::GraphicsInterface::Destroy()
+   */
+  void Destroy() override;
+
+private:
+  // Eliminate copy and assigned operations
+  EglGraphics(const EglGraphics& rhs) = delete;
+  EglGraphics& operator=(const EglGraphics& rhs) = delete;
+
+
+private:
+  std::unique_ptr< GlImplementation > mGLES;                    ///< GL implementation
+  std::unique_ptr< EglImplementation > mEglImplementation;      ///< EGL implementation
+  std::unique_ptr< EglImageExtensions > mEglImageExtensions;    ///< EGL image extension
+  std::unique_ptr< EglSyncImplementation > mEglSync;            ///< GlSyncAbstraction implementation for EGL
+  std::unique_ptr< EglContextHelperImplementation > mEglContextHelper; ///< GlContextHelperAbstraction implementation for EGL
+
+  int mMultiSamplingLevel;                                      ///< The multiple sampling level
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_BASE_GRAPHICS_IMPLEMENTATION_H
diff --git a/dali/internal/graphics/gles/egl-implementation.cpp b/dali/internal/graphics/gles/egl-implementation.cpp
new file mode 100755 (executable)
index 0000000..c653ab6
--- /dev/null
@@ -0,0 +1,600 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+// CLASS HEADER
+#include <dali/internal/graphics/gles/egl-implementation.h>
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/internal/graphics/gles/gl-implementation.h>
+#include <dali/internal/graphics/gles/egl-debug.h>
+
+// EGL constants use C style casts
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+
+namespace
+{
+  const uint32_t THRESHOLD_SWAPBUFFER_COUNT = 5;
+  const uint32_t CHECK_EXTENSION_NUMBER = 2;
+  const std::string EGL_KHR_SURFACELESS_CONTEXT = "EGL_KHR_surfaceless_context";
+  const std::string EGL_KHR_CREATE_CONTEXT = "EGL_KHR_create_context";
+}
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+#define TEST_EGL_ERROR(lastCommand) \
+{ \
+  EGLint err = eglGetError(); \
+  if (err != EGL_SUCCESS) \
+  { \
+    DALI_LOG_ERROR("EGL error after %s\n", lastCommand); \
+    Egl::PrintError(err); \
+    DALI_ASSERT_ALWAYS(0 && "EGL error"); \
+  } \
+}
+
+EglImplementation::EglImplementation( int multiSamplingLevel,
+                                      Integration::DepthBufferAvailable depthBufferRequired,
+                                      Integration::StencilBufferAvailable stencilBufferRequired )
+: mContextAttribs(),
+  mEglNativeDisplay( 0 ),
+  mEglNativeWindow( 0 ),
+  mCurrentEglNativePixmap( 0 ),
+  mEglDisplay( 0 ),
+  mEglConfig( 0 ),
+  mEglContext( 0 ),
+  mCurrentEglSurface( 0 ),
+  mCurrentEglContext( EGL_NO_CONTEXT ),
+  mMultiSamplingLevel( multiSamplingLevel ),
+  mGlesVersion( 30 ),
+  mColorDepth( COLOR_DEPTH_24 ),
+  mGlesInitialized( false ),
+  mIsOwnSurface( true ),
+  mIsWindow( true ),
+  mDepthBufferRequired( depthBufferRequired == Integration::DepthBufferAvailable::TRUE ),
+  mStencilBufferRequired( stencilBufferRequired == Integration::StencilBufferAvailable::TRUE ),
+  mIsSurfacelessContextSupported( false ),
+  mIsKhrCreateContextSupported( false ),
+  mSwapBufferCountAfterResume( 0 )
+{
+}
+
+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 error = eglGetError();
+
+    if( mEglDisplay == NULL && error != EGL_SUCCESS )
+    {
+      throw Dali::DaliException( "", "OpenGL ES is not supported");
+    }
+
+    EGLint majorVersion = 0;
+    EGLint minorVersion = 0;
+    if ( !eglInitialize( mEglDisplay, &majorVersion, &minorVersion ) )
+    {
+      return false;
+    }
+    eglBindAPI(EGL_OPENGL_ES_API);
+
+    mIsOwnSurface = isOwnSurface;
+  }
+
+  // Query EGL extensions to check whether surfaceless context is supported
+  const char* const extensionStr = eglQueryString( mEglDisplay, EGL_EXTENSIONS );
+  std::istringstream stream( extensionStr );
+  std::string currentExtension;
+  uint32_t extensionCheckCount = 0;
+  while( std::getline( stream, currentExtension, ' ' ) && extensionCheckCount < CHECK_EXTENSION_NUMBER )
+  {
+    if( currentExtension == EGL_KHR_SURFACELESS_CONTEXT )
+    {
+      mIsSurfacelessContextSupported = true;
+      extensionCheckCount++;
+    }
+    if( currentExtension == EGL_KHR_CREATE_CONTEXT )
+    {
+      mIsKhrCreateContextSupported = true;
+      extensionCheckCount++;
+    }
+  }
+
+  mGlesInitialized = true;
+
+  // We want to display this information all the time, so use the LogMessage directly
+  Integration::Log::LogMessage(Integration::Log::DebugInfo, "EGL Information\n"
+      "            Vendor:        %s\n"
+      "            Version:       %s\n"
+      "            Client APIs:   %s\n"
+      "            Extensions:    %s\n",
+      eglQueryString( mEglDisplay, EGL_VENDOR ),
+      eglQueryString( mEglDisplay, EGL_VERSION ),
+      eglQueryString( mEglDisplay, EGL_CLIENT_APIS ),
+      extensionStr);
+
+  return mGlesInitialized;
+}
+
+bool EglImplementation::CreateContext()
+{
+  // make sure a context isn't created twice
+  DALI_ASSERT_ALWAYS( (mEglContext == 0) && "EGL context recreated" );
+
+  mEglContext = eglCreateContext(mEglDisplay, mEglConfig, NULL, &(mContextAttribs[0]));
+  TEST_EGL_ERROR("eglCreateContext render thread");
+
+  DALI_ASSERT_ALWAYS( EGL_NO_CONTEXT != mEglContext && "EGL context not created" );
+
+  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VENDOR : %s ***\n", glGetString(GL_VENDOR));
+  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_RENDERER : %s ***\n", glGetString(GL_RENDERER));
+  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VERSION : %s ***\n", glGetString(GL_VERSION));
+  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_SHADING_LANGUAGE_VERSION : %s***\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
+  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** Supported Extensions ***\n%s\n\n", glGetString(GL_EXTENSIONS));
+
+  return true;
+}
+
+bool EglImplementation::CreateWindowContext( EGLContext& eglContext )
+{
+  // make sure a context isn't created twice
+  DALI_ASSERT_ALWAYS( (eglContext == 0) && "EGL context recreated" );
+
+  eglContext = eglCreateContext(mEglDisplay, mEglConfig, mEglContext, &(mContextAttribs[0]));
+  TEST_EGL_ERROR("eglCreateContext render thread");
+
+  DALI_ASSERT_ALWAYS( EGL_NO_CONTEXT != eglContext && "EGL context not created" );
+
+  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VENDOR : %s ***\n", glGetString(GL_VENDOR));
+  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_RENDERER : %s ***\n", glGetString(GL_RENDERER));
+  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_VERSION : %s ***\n", glGetString(GL_VERSION));
+  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** GL_SHADING_LANGUAGE_VERSION : %s***\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
+  DALI_LOG_INFO(Debug::Filter::gShader, Debug::General, "*** Supported Extensions ***\n%s\n\n", glGetString(GL_EXTENSIONS));
+
+  mEglWindowContexts.push_back( eglContext );
+
+  return true;
+}
+
+void EglImplementation::DestroyContext( EGLContext& eglContext )
+{
+  DALI_ASSERT_ALWAYS( mEglContext && "no EGL context" );
+
+  eglDestroyContext( mEglDisplay, eglContext );
+  eglContext = 0;
+}
+
+void EglImplementation::DestroySurface( EGLSurface& eglSurface )
+{
+  if(mIsOwnSurface && eglSurface)
+  {
+    // Make context null to prevent crash in driver side
+    MakeContextNull();
+    eglDestroySurface( mEglDisplay, eglSurface );
+    eglSurface = 0;
+  }
+}
+
+void EglImplementation::MakeContextCurrent( EGLSurface eglSurface, EGLContext eglContext )
+{
+  if (mCurrentEglContext == eglContext)
+  {
+    return;
+  }
+
+  mCurrentEglSurface = eglSurface;
+
+  if(mIsOwnSurface)
+  {
+    eglMakeCurrent( mEglDisplay, eglSurface, eglSurface, eglContext );
+
+    mCurrentEglContext = eglContext;
+  }
+
+  EGLint error = eglGetError();
+
+  if ( error != EGL_SUCCESS )
+  {
+    Egl::PrintError(error);
+
+    DALI_ASSERT_ALWAYS(false && "MakeContextCurrent failed!");
+  }
+}
+
+void EglImplementation::MakeCurrent( EGLNativePixmapType pixmap, EGLSurface eglSurface )
+{
+  if (mCurrentEglContext == mEglContext)
+  {
+    return;
+  }
+
+  mCurrentEglNativePixmap = pixmap;
+  mCurrentEglSurface = eglSurface;
+
+  if(mIsOwnSurface)
+  {
+    eglMakeCurrent( mEglDisplay, eglSurface, eglSurface, mEglContext );
+
+    mCurrentEglContext = mEglContext;
+  }
+
+  EGLint error = eglGetError();
+
+  if ( error != EGL_SUCCESS )
+  {
+    Egl::PrintError(error);
+
+    DALI_ASSERT_ALWAYS(false && "MakeCurrent failed!");
+  }
+}
+
+void EglImplementation::MakeContextNull()
+{
+  // clear the current context
+  eglMakeCurrent( mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
+  mCurrentEglContext = EGL_NO_CONTEXT;
+}
+
+void EglImplementation::TerminateGles()
+{
+  if ( mGlesInitialized )
+  {
+    // Make context null to prevent crash in driver side
+    MakeContextNull();
+
+    for ( auto eglSurface : mEglWindowSurfaces )
+    {
+      if(mIsOwnSurface && eglSurface)
+      {
+        eglDestroySurface(mEglDisplay, eglSurface);
+      }
+    }
+    eglDestroyContext(mEglDisplay, mEglContext);
+    for ( auto eglContext : mEglWindowContexts )
+    {
+      eglDestroyContext(mEglDisplay, eglContext);
+    }
+
+    eglTerminate(mEglDisplay);
+
+    mEglDisplay = NULL;
+    mEglConfig  = NULL;
+    mEglContext = NULL;
+    mCurrentEglSurface = NULL;
+    mCurrentEglContext = EGL_NO_CONTEXT;
+
+    mGlesInitialized = false;
+  }
+}
+
+bool EglImplementation::IsGlesInitialized() const
+{
+  return mGlesInitialized;
+}
+
+void EglImplementation::SwapBuffers( EGLSurface& eglSurface )
+{
+  if ( eglSurface != EGL_NO_SURFACE ) // skip if using surfaceless context
+  {
+#ifndef DALI_PROFILE_UBUNTU
+    if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
+    {
+      DALI_LOG_RELEASE_INFO( "EglImplementation::SwapBuffers started.\n" );
+    }
+#endif //DALI_PROFILE_UBUNTU
+
+    eglSwapBuffers( mEglDisplay, eglSurface );
+
+#ifndef DALI_PROFILE_UBUNTU
+    if( mSwapBufferCountAfterResume < THRESHOLD_SWAPBUFFER_COUNT )
+    {
+      DALI_LOG_RELEASE_INFO( "EglImplementation::SwapBuffers finished.\n" );
+      mSwapBufferCountAfterResume++;
+    }
+#endif //DALI_PROFILE_UBUNTU
+  }
+}
+
+void EglImplementation::CopyBuffers( EGLSurface& eglSurface )
+{
+  eglCopyBuffers( mEglDisplay, eglSurface, mCurrentEglNativePixmap );
+}
+
+void EglImplementation::WaitGL()
+{
+  eglWaitGL();
+}
+
+bool EglImplementation::ChooseConfig( bool isWindowType, ColorDepth depth )
+{
+  if(mEglConfig && isWindowType == mIsWindow && mColorDepth == depth)
+  {
+    return true;
+  }
+
+  mColorDepth = depth;
+  mIsWindow = isWindowType;
+
+  EGLint numConfigs;
+  Vector<EGLint> configAttribs;
+  configAttribs.Reserve(31);
+
+  if(isWindowType)
+  {
+    configAttribs.PushBack( EGL_SURFACE_TYPE );
+    configAttribs.PushBack( EGL_WINDOW_BIT );
+  }
+  else
+  {
+    configAttribs.PushBack( EGL_SURFACE_TYPE );
+    configAttribs.PushBack( EGL_PIXMAP_BIT );
+  }
+
+  configAttribs.PushBack( EGL_RENDERABLE_TYPE );
+
+  if( mGlesVersion >= 30 )
+  {
+    configAttribs.PushBack( EGL_OPENGL_ES3_BIT_KHR );
+  }
+  else
+  {
+    configAttribs.PushBack( EGL_OPENGL_ES2_BIT );
+  }
+
+// TODO: enable this flag when it becomes supported
+//  configAttribs.PushBack( EGL_CONTEXT_FLAGS_KHR );
+//  configAttribs.PushBack( EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR );
+
+  configAttribs.PushBack( EGL_RED_SIZE );
+  configAttribs.PushBack( 8 );
+  configAttribs.PushBack( EGL_GREEN_SIZE );
+  configAttribs.PushBack( 8 );
+  configAttribs.PushBack( EGL_BLUE_SIZE );
+  configAttribs.PushBack( 8 );
+
+//  For underlay video playback, we also need to set the alpha value of the 24/32bit window.
+  configAttribs.PushBack( EGL_ALPHA_SIZE );
+  configAttribs.PushBack( 8 );
+
+  configAttribs.PushBack( EGL_DEPTH_SIZE );
+  configAttribs.PushBack( mDepthBufferRequired ? 24 : 0 );
+  configAttribs.PushBack( EGL_STENCIL_SIZE );
+  configAttribs.PushBack( mStencilBufferRequired ? 8 : 0 );
+
+#ifndef DALI_PROFILE_UBUNTU
+  if( mMultiSamplingLevel != EGL_DONT_CARE )
+  {
+    configAttribs.PushBack( EGL_SAMPLES );
+    configAttribs.PushBack( mMultiSamplingLevel );
+    configAttribs.PushBack( EGL_SAMPLE_BUFFERS );
+    configAttribs.PushBack( 1 );
+  }
+#endif // DALI_PROFILE_UBUNTU
+  configAttribs.PushBack( EGL_NONE );
+
+  // Ensure number of configs is set to 1 as on some drivers,
+  // eglChooseConfig succeeds but does not actually create a proper configuration.
+  if ( ( eglChooseConfig( mEglDisplay, &(configAttribs[0]), &mEglConfig, 1, &numConfigs ) != EGL_TRUE ) ||
+       ( numConfigs != 1 ) )
+  {
+    if( mGlesVersion >= 30 )
+    {
+      mEglConfig = NULL;
+      DALI_LOG_ERROR("Fail to use OpenGL es 3.0. Retrying to use OpenGL es 2.0.");
+      return false;
+    }
+
+    if ( numConfigs != 1 )
+    {
+      DALI_LOG_ERROR("No configurations found.\n");
+
+      TEST_EGL_ERROR("eglChooseConfig");
+    }
+
+    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 configAttribs 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!");
+    return false;
+  }
+  Integration::Log::LogMessage(Integration::Log::DebugInfo, "Using OpenGL es %d.%d.\n", mGlesVersion / 10, mGlesVersion % 10 );
+
+  mContextAttribs.Clear();
+  if( mIsKhrCreateContextSupported )
+  {
+    mContextAttribs.Reserve(5);
+    mContextAttribs.PushBack( EGL_CONTEXT_MAJOR_VERSION_KHR );
+    mContextAttribs.PushBack( mGlesVersion / 10 );
+    mContextAttribs.PushBack( EGL_CONTEXT_MINOR_VERSION_KHR );
+    mContextAttribs.PushBack( mGlesVersion % 10 );
+  }
+  else
+  {
+    mContextAttribs.Reserve(3);
+    mContextAttribs.PushBack( EGL_CONTEXT_CLIENT_VERSION );
+    mContextAttribs.PushBack( mGlesVersion / 10 );
+  }
+  mContextAttribs.PushBack( EGL_NONE );
+
+  return true;
+}
+
+EGLSurface EglImplementation::CreateSurfaceWindow( EGLNativeWindowType window, ColorDepth depth )
+{
+  mEglNativeWindow = window;
+  mColorDepth = depth;
+  mIsWindow = true;
+
+  // egl choose config
+  ChooseConfig(mIsWindow, mColorDepth);
+
+  mCurrentEglSurface = eglCreateWindowSurface( mEglDisplay, mEglConfig, mEglNativeWindow, NULL );
+  TEST_EGL_ERROR("eglCreateWindowSurface");
+
+  DALI_ASSERT_ALWAYS( mCurrentEglSurface && "Create window surface failed" );
+
+  return mCurrentEglSurface;
+}
+
+EGLSurface EglImplementation::CreateSurfacePixmap( EGLNativePixmapType pixmap, ColorDepth depth )
+{
+  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, EGLSurface& eglSurface, EGLContext& eglContext )
+{
+  bool contextLost = false;
+
+  // display connection has not changed, then we can just create a new surface
+  //  the surface is bound to the context, so set the context to null
+  MakeContextNull();
+
+  if( eglSurface )
+  {
+    // destroy the surface
+    DestroySurface( eglSurface );
+  }
+
+  // create the EGL surface
+  EGLSurface newEglSurface = CreateSurfaceWindow( window, mColorDepth );
+
+  // set the context to be current with the new surface
+  MakeContextCurrent( newEglSurface, eglContext );
+
+  return contextLost;
+}
+
+bool EglImplementation::ReplaceSurfacePixmap( EGLNativePixmapType pixmap, EGLSurface& eglSurface )
+{
+  bool contextLost = false;
+
+  // display connection has not changed, then we can just create a new surface
+  // create the EGL surface
+  eglSurface = CreateSurfacePixmap( pixmap, mColorDepth );
+
+  // set the eglSurface to be current
+  MakeCurrent( pixmap, eglSurface );
+
+  return contextLost;
+}
+
+void EglImplementation::SetGlesVersion( const int32_t glesVersion )
+{
+  mGlesVersion = glesVersion;
+}
+
+void EglImplementation::SetFirstFrameAfterResume()
+{
+  mSwapBufferCountAfterResume = 0;
+}
+
+EGLDisplay EglImplementation::GetDisplay() const
+{
+  return mEglDisplay;
+}
+
+EGLContext EglImplementation::GetContext() const
+{
+  return mEglContext;
+}
+
+int32_t EglImplementation::GetGlesVersion() const
+{
+  return mGlesVersion;
+}
+
+bool EglImplementation::IsSurfacelessContextSupported() const
+{
+  return mIsSurfacelessContextSupported;
+}
+
+void EglImplementation::WaitClient()
+{
+  // Wait for EGL to finish executing all rendering calls for the current context
+  if ( eglWaitClient() != EGL_TRUE )
+  {
+    TEST_EGL_ERROR("eglWaitClient");
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#pragma GCC diagnostic pop
diff --git a/dali/internal/graphics/gles/egl-implementation.h b/dali/internal/graphics/gles/egl-implementation.h
new file mode 100644 (file)
index 0000000..efb9754
--- /dev/null
@@ -0,0 +1,261 @@
+#ifndef DALI_INTERNAL_EGL_IMPLEMENTATION_H
+#define DALI_INTERNAL_EGL_IMPLEMENTATION_H
+
+/*
+ * Copyright (c) 2019 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/internal/graphics/common/egl-include.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/integration-api/core-enumerations.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/egl-interface.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * EglImplementation class provides an EGL implementation.
+ */
+class EglImplementation : public EglInterface
+{
+public:
+
+  /**
+   * Constructor
+   * @param[in] multiSamplingLevel The Multi-sampling level required
+   * @param[in] depthBufferRequired Whether the depth buffer is required
+   * @param[in] stencilBufferRequired Whether the stencil buffer is required
+   */
+  EglImplementation( int multiSamplingLevel,
+                     Integration::DepthBufferAvailable depthBufferRequired,
+                     Integration::StencilBufferAvailable stencilBufferRequired );
+
+  /**
+   * Destructor
+   */
+  virtual ~EglImplementation();
+
+public:
+
+  /**
+   * (Called from  ECoreX::RenderSurface, not RenderThread, so not in i/f, hence, not virtual)
+   * Initialize GL
+   * @param display The display
+   * @param isOwnSurface whether the surface is own or not
+   * @return true on success, false on failure
+   */
+  bool InitializeGles( EGLNativeDisplayType display, bool isOwnSurface = true );
+
+  /**
+    * Create the OpenGL context for the shared resource.
+    * @return true if successful
+    */
+  virtual bool CreateContext();
+
+  /**
+    * Create the OpenGL context for the window.
+    * @return true if successful
+    */
+  bool CreateWindowContext( EGLContext& mEglContext );
+
+  /**
+    * Destroy the OpenGL context.
+    */
+  void DestroyContext( EGLContext& eglContext );
+
+  /**
+    * Destroy the OpenGL surface.
+    */
+  void DestroySurface( EGLSurface& eglSurface );
+
+  /**
+   * Make the OpenGL context current
+   */
+  virtual void MakeContextCurrent( EGLSurface eglSurface, EGLContext eglContext );
+
+  /**
+   * clear the OpenGL context
+   */
+  void MakeContextNull();
+
+  /**
+   * @brief Make the OpenGL surface current
+   *
+   * @param pixmap The pixmap to replace the current surface
+   * @param eglSurface The eglSurface to replace the current OpenGL surface.
+   */
+  void MakeCurrent( EGLNativePixmapType pixmap, EGLSurface eglSurface );
+
+  /**
+   * Terminate GL
+   */
+  virtual void TerminateGles();
+
+  /**
+   * Checks if GL is initialised
+   * @return true if it is
+   */
+  bool IsGlesInitialized() const;
+
+  /**
+   * Performs an OpenGL swap buffers command
+   */
+  virtual void SwapBuffers( EGLSurface& eglSurface );
+
+  /**
+   * Performs an OpenGL copy buffers command
+   */
+  virtual void CopyBuffers( EGLSurface& eglSurface );
+
+  /**
+   * Performs an EGL wait GL command
+   */
+  virtual void WaitGL();
+
+  /**
+   * Choose config of egl
+   * @param isWindowType whether the config for window or pixmap
+   * @param colorDepth Bit per pixel value (ex. 32 or 24)
+   * @return true if the eglChooseConfig is succeed.
+  */
+  bool ChooseConfig( bool isWindowType, ColorDepth depth );
+
+  /**
+    * Create an OpenGL surface using a window
+    * @param window The window to create the surface on
+    * @param colorDepth Bit per pixel value (ex. 32 or 24)
+    * @return Handle to an on-screen EGL window surface (the requester has an ownership of this egl surface)
+    */
+  EGLSurface CreateSurfaceWindow( EGLNativeWindowType window, ColorDepth depth );
+
+  /**
+   * Create the OpenGL surface using a pixmap
+   * @param pixmap The pixmap to create the surface on
+   * @param colorDepth Bit per pixel value (ex. 32 or 24)
+   * @return Handle to an off-screen EGL pixmap surface (the requester has an ownership of this egl surface)
+   */
+  EGLSurface CreateSurfacePixmap( EGLNativePixmapType pixmap, ColorDepth depth );
+
+  /**
+   * Replaces the render surface
+   * @param[in] window, the window to create the new surface on
+   * @return true if the context was lost due to a change in display
+   *         between old surface and new surface
+   */
+  bool ReplaceSurfaceWindow( EGLNativeWindowType window, EGLSurface& eglSurface, EGLContext& eglContext );
+
+  /**
+   * Replaces the render surface
+   * @param[in] pixmap, the pixmap to replace the new surface on
+   * @param[out] eglSurface, the eglSurface is created using a pixmap.
+   * @return true if the context was lost due to a change in x-display
+   *         between old surface and new surface
+   */
+  bool ReplaceSurfacePixmap( EGLNativePixmapType pixmap, EGLSurface& eglSurface );
+
+  /**
+   * Sets gles version
+   */
+  void SetGlesVersion( const int32_t glesVersion );
+
+  /**
+   * Sets Whether the frame is the first after Resume.
+   */
+  void SetFirstFrameAfterResume();
+
+  /**
+   * returns the display with which this object was initialized
+   * @return the EGL Display.
+   */
+  EGLDisplay GetDisplay() const;
+
+  /**
+   * Returns the EGL context
+   * @return the EGL context.
+   */
+  EGLContext GetContext() const;
+
+  /**
+   * Returns the gles version
+   * @return the gles version
+   */
+  int32_t GetGlesVersion() const;
+
+  /**
+   * Returns whether the surfaceless context is supported
+   * @return true if the surfaceless context is supported
+   */
+  bool IsSurfacelessContextSupported() const;
+
+  /**
+   * @brief Wait until all rendering calls for the currently context are executed
+   */
+  void WaitClient();
+
+private:
+
+  Vector<EGLint>       mContextAttribs;
+
+  EGLNativeDisplayType mEglNativeDisplay;
+
+  EGLNativeWindowType  mEglNativeWindow;
+
+  EGLNativePixmapType  mCurrentEglNativePixmap;
+
+  EGLDisplay           mEglDisplay;
+  EGLConfig            mEglConfig;
+  EGLContext           mEglContext;                            ///< The resource context holding assets such as textures to be shared
+
+  typedef std::vector<EGLContext> EglWindowContextContainer;
+  EglWindowContextContainer mEglWindowContexts;                ///< The EGL context for the window
+
+  EGLSurface           mCurrentEglSurface;
+  EGLContext           mCurrentEglContext;
+
+  typedef std::vector<EGLSurface> EglWindowSurfaceContainer;
+  EglWindowSurfaceContainer mEglWindowSurfaces;                ///< The EGL surface for the window
+
+  int32_t              mMultiSamplingLevel;
+  int32_t              mGlesVersion;
+
+  ColorDepth           mColorDepth;
+
+  bool                 mGlesInitialized;
+  bool                 mIsOwnSurface;
+  bool                 mIsWindow;
+  bool                 mDepthBufferRequired;
+  bool                 mStencilBufferRequired;
+  bool                 mIsSurfacelessContextSupported;
+  bool                 mIsKhrCreateContextSupported;
+
+  uint32_t              mSwapBufferCountAfterResume;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_EGL_IMPLEMENTATION_H
diff --git a/dali/internal/graphics/gles/egl-sync-implementation.cpp b/dali/internal/graphics/gles/egl-sync-implementation.cpp
new file mode 100644 (file)
index 0000000..a941f02
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * 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 <dali/internal/graphics/gles/egl-sync-implementation.h>
+
+// EXTERNAL INCLUDES
+
+#ifdef _ARCH_ARM_
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <EGL/eglext.h>
+
+#endif
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/gles/egl-implementation.h>
+
+#ifdef _ARCH_ARM_
+
+// function pointers
+static PFNEGLCREATESYNCKHRPROC     eglCreateSyncKHR = NULL;
+static PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncKHR = NULL;
+static PFNEGLDESTROYSYNCKHRPROC    eglDestroySyncKHR = NULL;
+
+#endif
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+#ifdef _ARCH_ARM_
+
+EglSyncObject::EglSyncObject( EglImplementation& eglSyncImpl )
+: mEglSync(NULL),
+  mEglImplementation(eglSyncImpl)
+{
+  EGLDisplay display = mEglImplementation.GetDisplay();
+  mEglSync = eglCreateSyncKHR( display, EGL_SYNC_FENCE_KHR, NULL );
+  if (mEglSync == EGL_NO_SYNC_KHR)
+  {
+    DALI_LOG_ERROR("eglCreateSyncKHR failed %#0.4x\n", eglGetError());
+    mEglSync = NULL;
+  }
+}
+
+EglSyncObject::~EglSyncObject()
+{
+  if( mEglSync != NULL )
+  {
+    eglDestroySyncKHR( mEglImplementation.GetDisplay(), mEglSync );
+    EGLint error = eglGetError();
+    if( EGL_SUCCESS != error )
+    {
+      DALI_LOG_ERROR("eglDestroySyncKHR failed %#0.4x\n", error);
+    }
+  }
+}
+
+bool EglSyncObject::IsSynced()
+{
+  bool synced = false;
+
+  if( mEglSync != NULL )
+  {
+    EGLint result = eglClientWaitSyncKHR( mEglImplementation.GetDisplay(), mEglSync, 0, 0ull );
+    EGLint error = eglGetError();
+    if( EGL_SUCCESS != error )
+    {
+      DALI_LOG_ERROR("eglClientWaitSyncKHR failed %#0.4x\n", error);
+    }
+    else if( result == EGL_CONDITION_SATISFIED_KHR )
+    {
+      synced = true;
+    }
+  }
+
+  return synced;
+}
+
+EglSyncImplementation::EglSyncImplementation()
+: mEglImplementation( NULL ),
+  mSyncInitialized( false ),
+  mSyncInitializeFailed( false )
+{
+}
+
+EglSyncImplementation::~EglSyncImplementation()
+{
+}
+
+void EglSyncImplementation::Initialize( EglImplementation* eglImpl )
+{
+  mEglImplementation = eglImpl;
+}
+
+Integration::GlSyncAbstraction::SyncObject* EglSyncImplementation::CreateSyncObject()
+{
+  DALI_ASSERT_ALWAYS( mEglImplementation && "Sync Implementation not initialized" );
+  if( mSyncInitialized == false )
+  {
+    InitializeEglSync();
+  }
+
+  EglSyncObject* syncObject = new EglSyncObject(*mEglImplementation);
+  mSyncObjects.PushBack( syncObject );
+  return syncObject;
+}
+
+void EglSyncImplementation::DestroySyncObject( Integration::GlSyncAbstraction::SyncObject* syncObject )
+{
+  DALI_ASSERT_ALWAYS( mEglImplementation && "Sync Implementation not initialized" );
+
+  if( mSyncInitialized == false )
+  {
+    InitializeEglSync();
+  }
+
+  for( SyncIter iter=mSyncObjects.Begin(), end=mSyncObjects.End(); iter != end; ++iter )
+  {
+    if( *iter == syncObject )
+    {
+      mSyncObjects.Erase(iter);
+      break;
+    }
+  }
+  EglSyncObject* eglSyncObject = static_cast<EglSyncObject*>(syncObject);
+  delete eglSyncObject;
+}
+
+void EglSyncImplementation::InitializeEglSync()
+{
+  if( ! mSyncInitializeFailed )
+  {
+    eglCreateSyncKHR = reinterpret_cast< PFNEGLCREATESYNCKHRPROC >( eglGetProcAddress("eglCreateSyncKHR") );
+    eglClientWaitSyncKHR = reinterpret_cast< PFNEGLCLIENTWAITSYNCKHRPROC >( eglGetProcAddress("eglClientWaitSyncKHR") );
+    eglDestroySyncKHR = reinterpret_cast< PFNEGLDESTROYSYNCKHRPROC >( eglGetProcAddress("eglDestroySyncKHR") );
+  }
+
+  if( eglCreateSyncKHR && eglClientWaitSyncKHR && eglDestroySyncKHR )
+  {
+    mSyncInitialized = true;
+  }
+  else
+  {
+    mSyncInitializeFailed = true;
+  }
+}
+
+#else
+
+EglSyncObject::EglSyncObject( EglImplementation& eglImpl )
+: mPollCounter(3),
+  mEglImplementation(eglImpl)
+{
+}
+
+EglSyncObject::~EglSyncObject()
+{
+}
+
+bool EglSyncObject::IsSynced()
+{
+  if(mPollCounter <= 0)
+  {
+    return true;
+  }
+  --mPollCounter;
+  return false;
+}
+
+EglSyncImplementation::EglSyncImplementation()
+: mEglImplementation( NULL ),
+  mSyncInitialized( false ),
+  mSyncInitializeFailed( false )
+{
+}
+
+EglSyncImplementation::~EglSyncImplementation()
+{
+}
+
+void EglSyncImplementation::Initialize( EglImplementation* eglImpl )
+{
+  mEglImplementation = eglImpl;
+}
+
+Integration::GlSyncAbstraction::SyncObject* EglSyncImplementation::CreateSyncObject()
+{
+  DALI_ASSERT_ALWAYS( mEglImplementation && "Sync Implementation not initialized" );
+  return new EglSyncObject(*mEglImplementation);
+}
+
+void EglSyncImplementation::DestroySyncObject(Integration::GlSyncAbstraction::SyncObject* syncObject)
+{
+  DALI_ASSERT_ALWAYS( mEglImplementation && "Sync Implementation not initialized" );
+
+  // The abstraction's virtual destructor is protected, so that Core can't delete the sync objects
+  // directly (This object also needs removing from the mSyncObject container in the ARM
+  // implementation above). We therefore need to cast to the actual implementation object first.
+  EglSyncObject* eglSyncObject = static_cast<EglSyncObject*>(syncObject);
+  delete eglSyncObject;
+}
+
+void EglSyncImplementation::InitializeEglSync()
+{
+}
+
+#endif
+
+} // namespace Dali
+} // namespace Internal
+} // namespace Adaptor
diff --git a/dali/internal/graphics/gles/egl-sync-implementation.h b/dali/internal/graphics/gles/egl-sync-implementation.h
new file mode 100644 (file)
index 0000000..fbb3bdb
--- /dev/null
@@ -0,0 +1,123 @@
+#ifndef DALI_INTERNAL_ADAPTOR_EGL_SYNC_IMPLEMENTATION_H
+#define DALI_INTERNAL_ADAPTOR_EGL_SYNC_IMPLEMENTATION_H
+
+/*
+ * Copyright (c) 2019 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/internal/graphics/common/egl-include.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/integration-api/gl-sync-abstraction.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class EglImplementation;
+
+class EglSyncObject : public Integration::GlSyncAbstraction::SyncObject
+{
+public:
+  /**
+   * Constructor
+   */
+  EglSyncObject( EglImplementation& eglSyncImpl );
+
+  /**
+   * Destructor
+   */
+  virtual ~EglSyncObject();
+
+  /**
+   * @copydoc Dali::Integration::GlSyncAbstraction::SyncObject::IsSynced()
+   */
+  virtual bool IsSynced();
+
+private:
+#ifdef _ARCH_ARM_
+  EGLSyncKHR mEglSync;
+#else
+  int mPollCounter; // Implementations without fence sync use a 3 frame counter
+#endif
+  EglImplementation& mEglImplementation;
+};
+
+
+/**
+ * GlSyncImplementation is a concrete implementation for GlSyncAbstraction.
+ * It provides fence syncing for resources such as FrameBuffers using EGL extensions
+ *
+ * Sync objects are created in the render thread after a render instruction
+ * has been processed (i.e. GL draw calls have completed for a given FB), and
+ * tested in the update
+ */
+class EglSyncImplementation : public Integration::GlSyncAbstraction
+{
+public:
+  /**
+   * Constructor
+   */
+  EglSyncImplementation();
+
+  /**
+   * Destructor
+   */
+  virtual ~EglSyncImplementation();
+
+  /**
+   * Initialize the sync object with the Egl implementation.
+   * @param[in] impl The EGL implementation (to access display)
+   */
+  void Initialize( EglImplementation* impl );
+
+  /**
+   * @copydoc Dali::Integration::GlSyncAbstraction::CreateSyncObject()
+   */
+  virtual SyncObject* CreateSyncObject();
+
+  /**
+   * @copydoc Dali::Integration::GlSyncAbstraction::DestroySyncObject()
+   */
+  virtual void DestroySyncObject(SyncObject* syncObject);
+
+private:
+  /**
+   * Set up the function pointers
+   */
+  void InitializeEglSync();
+
+private:
+  typedef Vector<EglSyncObject*>   SyncContainer;
+  typedef SyncContainer::Iterator  SyncIter;
+
+  EglImplementation* mEglImplementation; ///< Egl implementation (to get display)
+  bool mSyncInitialized;        ///< Flag to perform initialization on first use
+  bool mSyncInitializeFailed;   ///< Flag to avoid reloading functions if failed once
+
+  SyncContainer mSyncObjects;
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_INTERNAL_EGL_ADAPTOR_SYNC_IMPLEMENTATION_H
diff --git a/dali/internal/graphics/gles/gl-extensions.cpp b/dali/internal/graphics/gles/gl-extensions.cpp
new file mode 100644 (file)
index 0000000..429cbd5
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/graphics/gles/gl-extensions.h>
+
+// EXTERNAL INCLUDES
+#include <dali/internal/graphics/common/egl-include.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace ECoreX
+{
+
+GlExtensions::GlExtensions()
+:
+#ifdef GL_EXT_discard_framebuffer
+  mGlDiscardFramebuffer( NULL ),
+#endif
+#ifdef GL_OES_get_program_binary
+  mGlGetProgramBinaryOES( NULL ),
+  mGlProgramBinaryOES( NULL ),
+#endif
+  mInitialized( false )
+{
+}
+
+GlExtensions::~GlExtensions()
+{
+}
+
+void GlExtensions::DiscardFrameBuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments)
+{
+  // initialize extension on first use as on some hw platforms a context
+  // has to be bound for the extensions to return correct pointer
+  if( !mInitialized )
+  {
+    Initialize();
+  }
+
+#ifdef GL_EXT_discard_framebuffer
+  if( mGlDiscardFramebuffer )
+  {
+    mGlDiscardFramebuffer(target, numAttachments, attachments);
+  }
+  else
+  {
+    DALI_LOG_ERROR("Error: glDiscardFramebufferEXT extension is not available\n");
+  }
+#endif
+}
+
+void GlExtensions::GetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary)
+{
+  // initialize extension on first use as on some hw platforms a context
+  // has to be bound for the extensions to return correct pointer
+  if( !mInitialized )
+  {
+    Initialize();
+  }
+
+#ifdef GL_OES_get_program_binary
+  if (mGlGetProgramBinaryOES)
+  {
+    mGlGetProgramBinaryOES(program, bufSize, length, binaryFormat, binary);
+  }
+  else
+  {
+    DALI_LOG_ERROR("Error: glGetProgramBinaryOES extension is not available\n");
+    DALI_ASSERT_DEBUG(0);
+  }
+#endif
+}
+
+void GlExtensions::ProgramBinaryOES(GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length)
+{
+  // initialize extension on first use as on some hw platforms a context
+  // has to be bound for the extensions to return correct pointer
+  if( !mInitialized )
+  {
+    Initialize();
+  }
+
+#ifdef GL_OES_get_program_binary
+  if (mGlProgramBinaryOES)
+  {
+    mGlProgramBinaryOES(program, binaryFormat, binary, length);
+  }
+  else
+  {
+    DALI_LOG_ERROR("Error: glProgramBinaryOES extension is not available\n");
+    DALI_ASSERT_DEBUG(0);
+  }
+#endif
+}
+
+void GlExtensions::Initialize()
+{
+  mInitialized = true;
+
+#ifdef GL_EXT_discard_framebuffer
+  mGlDiscardFramebuffer = reinterpret_cast< PFNGLDISCARDFRAMEBUFFEREXTPROC >( eglGetProcAddress("glDiscardFramebufferEXT") );
+#endif
+
+#ifdef GL_OES_get_program_binary
+  mGlGetProgramBinaryOES = reinterpret_cast< PFNGLGETPROGRAMBINARYOESPROC >( eglGetProcAddress("glGetProgramBinaryOES") );
+  mGlProgramBinaryOES = reinterpret_cast< PFNGLPROGRAMBINARYOESPROC >( eglGetProcAddress("glProgramBinaryOES") );
+#endif
+}
+
+} // namespace ECoreX
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/graphics/gles/gl-extensions.h b/dali/internal/graphics/gles/gl-extensions.h
new file mode 100644 (file)
index 0000000..b3a8085
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef DALI_INTERNAL_GL_EXTENSION_H
+#define DALI_INTERNAL_GL_EXTENSION_H
+
+/*
+ * Copyright (c) 2019 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 <GLES3/gl3.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace ECoreX
+{
+
+/**
+ * GlExtensions class provides GL extensions support
+ */
+class GlExtensions
+{
+public:
+
+  /**
+   * Constructor
+   */
+  GlExtensions();
+
+  /**
+   * Destructor
+   */
+  ~GlExtensions();
+
+
+public:
+
+  /**
+   * If the GL extension is available this function discards specified data in attachments
+   * from being copied from the target to improve performance.
+   *
+   * Usage: GLenum attachments[] = { GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT };
+   *        DiscardFrameBufferEXT(GL_FRAMEBUFFER, 2, attachments);
+   *
+   * @param target is usually GL_FRAMEBUFFER
+   * @param numAttachments is the count of attachments
+   * @param attachments is a pointer to the attachments
+   */
+  void DiscardFrameBuffer (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+
+  /**
+   * GLES extension
+   * Returns the program object's executable bytecode.
+   * @param[in] program       The program object's name/id
+   * @param[in] bufSize       The maximum number of bytes that may be written into binary
+   * @param[out] length       The actual number of bytes written into binary
+   * @param[out] binaryFormat The format of the program binary
+   * @param[out] binary       The actual program bytecode
+   */
+  void GetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary);
+
+  /**
+   * GLES extension
+   * Loads a program object with a program binary previously returned from GetProgramBinaryOES
+   * @param[in] program       The program object's name/id
+   * @param[in] binaryFormat  The format of the program binary
+   * @param[in] binary        The program bytecode
+   * @param[in] length        The number of bytes in binary
+   */
+  void ProgramBinaryOES (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);
+
+private:
+
+  /**
+   * Lazy Initialize extensions on first use
+   */
+  void Initialize();
+
+#ifdef GL_EXT_discard_framebuffer
+  PFNGLDISCARDFRAMEBUFFEREXTPROC mGlDiscardFramebuffer;
+#endif
+
+#ifdef GL_OES_get_program_binary
+  PFNGLGETPROGRAMBINARYOESPROC mGlGetProgramBinaryOES;
+  PFNGLPROGRAMBINARYOESPROC mGlProgramBinaryOES;
+#endif
+
+  bool mInitialized;
+
+};
+
+} // namespace ECoreX
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif /* DALI_INTERNAL_GL_EXTENSION_H */
diff --git a/dali/internal/graphics/gles/gl-implementation.h b/dali/internal/graphics/gles/gl-implementation.h
new file mode 100644 (file)
index 0000000..9ccc015
--- /dev/null
@@ -0,0 +1,1379 @@
+#ifndef DALI_INTERNAL_GL_IMPLEMENTATION_H
+#define DALI_INTERNAL_GL_IMPLEMENTATION_H
+
+/*
+ * Copyright (c) 2019 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 <memory>
+#include <cstdlib>
+#include <GLES2/gl2.h>
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/devel-api/threading/conditional-wait.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/gles/gles-abstraction.h>
+#include <dali/internal/graphics/gles/gles2-implementation.h>
+#include <dali/internal/graphics/gles/gles3-implementation.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * GlImplementation is a concrete implementation for GlAbstraction.
+ * The class provides an OpenGL-ES 2.0 or 3.0 implementation.
+ * The class is provided when creating the Integration::Core object.
+ */
+class GlImplementation : public Dali::Integration::GlAbstraction
+{
+
+public:
+  GlImplementation()
+    : mGlesVersion( 30 ),
+      mIsSurfacelessContextSupported( false ),
+      mIsContextCreated( false ),
+      mContextCreatedWaitCondition(),
+      mMaxTextureSize( 0 )
+  {
+    mImpl.reset( new Gles3Implementation() );
+  }
+
+  virtual ~GlImplementation() {}
+
+  void PreRender()
+  {
+    /* Do nothing in main implementation */
+  }
+
+  void PostRender()
+  {
+    /* Do nothing in main implementation */
+  }
+
+  void ContextCreated()
+  {
+    glGetIntegerv( GL_MAX_TEXTURE_SIZE, &mMaxTextureSize );
+
+    if( !mIsContextCreated )
+    {
+      mContextCreatedWaitCondition.Notify();
+    }
+    mIsContextCreated = true;
+  }
+
+  void SetGlesVersion( const int32_t glesVersion )
+  {
+    if( mGlesVersion != glesVersion )
+    {
+      mGlesVersion = glesVersion;
+      if( mGlesVersion >= 30 )
+      {
+        mImpl.reset( new Gles3Implementation() );
+      }
+      else
+      {
+        mImpl.reset( new Gles2Implementation() );
+      }
+    }
+  }
+
+  void SetIsSurfacelessContextSupported( const bool isSupported )
+  {
+    mIsSurfacelessContextSupported = isSupported;
+  }
+
+  bool IsSurfacelessContextSupported() const
+  {
+    return mIsSurfacelessContextSupported;
+  }
+
+  bool TextureRequiresConverting( const GLenum imageGlFormat, const GLenum textureGlFormat, const bool isSubImage ) const
+  {
+    bool convert = ( ( imageGlFormat == GL_RGB ) && ( textureGlFormat == GL_RGBA ) );
+    if( mGlesVersion >= 30 )
+    {
+      // Don't convert manually from RGB to RGBA if GLES >= 3.0 and a sub-image is uploaded.
+      convert = ( convert && !isSubImage );
+    }
+    return convert;
+  }
+
+  int GetMaxTextureSize()
+  {
+    if( !mIsContextCreated )
+    {
+      mContextCreatedWaitCondition.Wait();
+    }
+    return mMaxTextureSize;
+  }
+
+  /* OpenGL ES 2.0 */
+
+  void ActiveTexture( GLenum texture )
+  {
+    glActiveTexture( texture );
+  }
+
+  void AttachShader( GLuint program, GLuint shader )
+  {
+    glAttachShader( program, shader );
+  }
+
+  void BindAttribLocation( GLuint program, GLuint index, const char* name )
+  {
+    glBindAttribLocation( program, index, name );
+  }
+
+  void BindBuffer( GLenum target, GLuint buffer )
+  {
+    glBindBuffer( target, buffer );
+  }
+
+  void BindFramebuffer( GLenum target, GLuint framebuffer )
+  {
+    glBindFramebuffer( target, framebuffer );
+  }
+
+  void BindRenderbuffer( GLenum target, GLuint renderbuffer )
+  {
+    glBindRenderbuffer( target, renderbuffer );
+  }
+
+  void BindTexture( GLenum target, GLuint texture )
+  {
+    glBindTexture( target, texture );
+  }
+
+  void BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
+  {
+    glBlendColor( red, green, blue, alpha );
+  }
+
+  void BlendEquation( GLenum mode )
+  {
+    glBlendEquation( mode );
+  }
+
+  void BlendEquationSeparate( GLenum modeRGB, GLenum modeAlpha )
+  {
+    glBlendEquationSeparate( modeRGB, modeAlpha );
+  }
+
+  void BlendFunc( GLenum sfactor, GLenum dfactor )
+  {
+    glBlendFunc( sfactor, dfactor );
+  }
+
+  void BlendFuncSeparate( GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha )
+  {
+    glBlendFuncSeparate( srcRGB, dstRGB, srcAlpha, dstAlpha );
+  }
+
+  void BufferData( GLenum target, GLsizeiptr size, const void* data, GLenum usage )
+  {
+    glBufferData( target, size, data, usage );
+  }
+
+  void BufferSubData( GLenum target, GLintptr offset, GLsizeiptr size, const void* data )
+  {
+    glBufferSubData( target, offset, size, data );
+  }
+
+  GLenum CheckFramebufferStatus( GLenum target )
+  {
+    return glCheckFramebufferStatus( target );
+  }
+
+  void Clear( GLbitfield mask )
+  {
+    glClear( mask );
+  }
+
+  void ClearColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
+  {
+    glClearColor( red, green, blue, alpha );
+  }
+
+  void ClearDepthf( GLclampf depth )
+  {
+    glClearDepthf( depth );
+  }
+
+  void ClearStencil( GLint s )
+  {
+    glClearStencil( s );
+  }
+
+  void ColorMask( GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha )
+  {
+    glColorMask( red, green, blue, alpha );
+  }
+
+  void CompileShader( GLuint shader )
+  {
+    glCompileShader( shader );
+  }
+
+  void CompressedTexImage2D( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data )
+  {
+    glCompressedTexImage2D( target, level, internalformat, width, height, border, imageSize, data );
+  }
+
+  void CompressedTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data )
+  {
+    glCompressedTexSubImage2D( target, level, xoffset, yoffset, width, height, format, imageSize, data );
+  }
+
+  void CopyTexImage2D( GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border )
+  {
+    glCopyTexImage2D( target, level, internalformat, x, y, width, height, border );
+  }
+
+  void CopyTexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height )
+  {
+    glCopyTexSubImage2D( target, level, xoffset, yoffset, x, y, width, height );
+  }
+
+  GLuint CreateProgram( void )
+  {
+    return glCreateProgram();
+  }
+
+  GLuint CreateShader( GLenum type )
+  {
+    return glCreateShader( type );
+  }
+
+  void CullFace( GLenum mode )
+  {
+    glCullFace( mode );
+  }
+
+  void DeleteBuffers( GLsizei n, const GLuint* buffers )
+  {
+    glDeleteBuffers( n, buffers );
+  }
+
+  void DeleteFramebuffers( GLsizei n, const GLuint* framebuffers )
+  {
+    glDeleteFramebuffers( n, framebuffers );
+  }
+
+  void DeleteProgram( GLuint program )
+  {
+    glDeleteProgram( program );
+  }
+
+  void DeleteRenderbuffers( GLsizei n, const GLuint* renderbuffers )
+  {
+    glDeleteRenderbuffers( n, renderbuffers );
+  }
+
+  void DeleteShader( GLuint shader )
+  {
+    glDeleteShader( shader );
+  }
+
+  void DeleteTextures( GLsizei n, const GLuint* textures )
+  {
+    glDeleteTextures( n, textures );
+  }
+
+  void DepthFunc( GLenum func )
+  {
+    glDepthFunc( func );
+  }
+
+  void DepthMask( GLboolean flag )
+  {
+    glDepthMask( flag );
+  }
+
+  void DepthRangef( GLclampf zNear, GLclampf zFar )
+  {
+    glDepthRangef( zNear, zFar );
+  }
+
+  void DetachShader( GLuint program, GLuint shader )
+  {
+    glDetachShader( program, shader );
+  }
+
+  void Disable( GLenum cap )
+  {
+    glDisable( cap );
+  }
+
+  void DisableVertexAttribArray( GLuint index )
+  {
+    glDisableVertexAttribArray( index );
+  }
+
+  void DrawArrays( GLenum mode, GLint first, GLsizei count )
+  {
+    glDrawArrays( mode, first, count );
+  }
+
+  void DrawElements( GLenum mode, GLsizei count, GLenum type, const void* indices )
+  {
+    glDrawElements( mode, count, type, indices );
+  }
+
+  void Enable( GLenum cap )
+  {
+    glEnable( cap );
+  }
+
+  void EnableVertexAttribArray( GLuint index )
+  {
+    glEnableVertexAttribArray( index );
+  }
+
+  void Finish( void )
+  {
+    glFinish();
+  }
+
+  void Flush( void )
+  {
+    glFlush();
+  }
+
+  void FramebufferRenderbuffer( GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer )
+  {
+    glFramebufferRenderbuffer( target, attachment, renderbuffertarget, renderbuffer );
+  }
+
+  void FramebufferTexture2D( GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level )
+  {
+    glFramebufferTexture2D( target, attachment, textarget, texture, level );
+  }
+
+  void FrontFace( GLenum mode )
+  {
+    glFrontFace( mode );
+  }
+
+  void GenBuffers( GLsizei n, GLuint* buffers )
+  {
+    glGenBuffers( n, buffers );
+  }
+
+  void GenerateMipmap( GLenum target )
+  {
+    glGenerateMipmap( target );
+  }
+
+  void GenFramebuffers( GLsizei n, GLuint* framebuffers )
+  {
+    glGenFramebuffers( n, framebuffers );
+  }
+
+  void GenRenderbuffers( GLsizei n, GLuint* renderbuffers )
+  {
+    glGenRenderbuffers( n, renderbuffers );
+  }
+
+  void GenTextures( GLsizei n, GLuint* textures )
+  {
+    glGenTextures( n, textures );
+  }
+
+  void GetActiveAttrib( GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name )
+  {
+    glGetActiveAttrib( program, index, bufsize, length, size, type, name );
+  }
+
+  void GetActiveUniform( GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name )
+  {
+    glGetActiveUniform( program, index, bufsize, length, size, type, name );
+  }
+
+  void GetAttachedShaders( GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders )
+  {
+    glGetAttachedShaders( program, maxcount, count, shaders );
+  }
+
+  int  GetAttribLocation( GLuint program, const char* name )
+  {
+    return glGetAttribLocation( program, name );
+  }
+
+  void GetBooleanv( GLenum pname, GLboolean* params )
+  {
+    glGetBooleanv( pname, params );
+  }
+
+  void GetBufferParameteriv( GLenum target, GLenum pname, GLint* params )
+  {
+    glGetBufferParameteriv( target, pname, params );
+  }
+
+  GLenum GetError( void )
+  {
+    return glGetError();
+  }
+
+  void GetFloatv( GLenum pname, GLfloat* params )
+  {
+    glGetFloatv( pname, params );
+  }
+
+  void GetFramebufferAttachmentParameteriv( GLenum target, GLenum attachment, GLenum pname, GLint* params )
+  {
+    glGetFramebufferAttachmentParameteriv( target, attachment, pname, params );
+  }
+
+  void GetIntegerv( GLenum pname, GLint* params )
+  {
+    glGetIntegerv( pname, params );
+  }
+
+  void GetProgramiv( GLuint program, GLenum pname, GLint* params )
+  {
+    glGetProgramiv( program, pname, params );
+  }
+
+  void GetProgramInfoLog( GLuint program, GLsizei bufsize, GLsizei* length, char* infolog )
+  {
+    glGetProgramInfoLog( program, bufsize, length, infolog );
+  }
+
+  void GetRenderbufferParameteriv( GLenum target, GLenum pname, GLint* params )
+  {
+    glGetRenderbufferParameteriv( target, pname, params );
+  }
+
+  void GetShaderiv( GLuint shader, GLenum pname, GLint* params )
+  {
+    glGetShaderiv( shader, pname, params );
+  }
+
+  void GetShaderInfoLog( GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog )
+  {
+    glGetShaderInfoLog( shader, bufsize, length, infolog );
+  }
+
+  void GetShaderPrecisionFormat( GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision )
+  {
+    glGetShaderPrecisionFormat( shadertype, precisiontype, range, precision );
+  }
+
+  void GetShaderSource( GLuint shader, GLsizei bufsize, GLsizei* length, char* source )
+  {
+    glGetShaderSource( shader, bufsize, length, source );
+  }
+
+  const GLubyte* GetString( GLenum name )
+  {
+    return glGetString( name );
+  }
+
+  void GetTexParameterfv( GLenum target, GLenum pname, GLfloat* params )
+  {
+    glGetTexParameterfv( target, pname, params );
+  }
+
+  void GetTexParameteriv( GLenum target, GLenum pname, GLint* params )
+  {
+    glGetTexParameteriv( target, pname, params );
+  }
+
+  void GetUniformfv( GLuint program, GLint location, GLfloat* params )
+  {
+    glGetUniformfv( program, location, params );
+  }
+
+  void GetUniformiv( GLuint program, GLint location, GLint* params )
+  {
+    glGetUniformiv( program, location, params );
+  }
+
+  int  GetUniformLocation( GLuint program, const char* name )
+  {
+    return glGetUniformLocation( program, name );
+  }
+
+  void GetVertexAttribfv( GLuint index, GLenum pname, GLfloat* params )
+  {
+    glGetVertexAttribfv( index, pname, params );
+  }
+
+  void GetVertexAttribiv( GLuint index, GLenum pname, GLint* params )
+  {
+    glGetVertexAttribiv( index, pname, params );
+  }
+
+  void GetVertexAttribPointerv( GLuint index, GLenum pname, void** pointer )
+  {
+    glGetVertexAttribPointerv( index, pname, pointer );
+  }
+
+  void Hint( GLenum target, GLenum mode )
+  {
+    glHint( target, mode );
+  }
+
+  GLboolean IsBuffer( GLuint buffer )
+  {
+    return glIsBuffer( buffer );
+  }
+
+  GLboolean IsEnabled( GLenum cap )
+  {
+    return glIsEnabled( cap );
+  }
+
+  GLboolean IsFramebuffer( GLuint framebuffer )
+  {
+    return glIsFramebuffer( framebuffer );
+  }
+
+  GLboolean IsProgram( GLuint program )
+  {
+    return glIsProgram( program );
+  }
+
+  GLboolean IsRenderbuffer( GLuint renderbuffer )
+  {
+    return glIsRenderbuffer( renderbuffer );
+  }
+
+  GLboolean IsShader( GLuint shader )
+  {
+    return glIsShader( shader );
+  }
+
+  GLboolean IsTexture( GLuint texture )
+  {
+    return glIsTexture( texture );
+  }
+
+  void LineWidth( GLfloat width )
+  {
+    glLineWidth( width );
+  }
+
+  void LinkProgram( GLuint program )
+  {
+    glLinkProgram( program );
+  }
+
+  void PixelStorei( GLenum pname, GLint param )
+  {
+    glPixelStorei( pname, param );
+  }
+
+  void PolygonOffset( GLfloat factor, GLfloat units )
+  {
+    glPolygonOffset( factor, units );
+  }
+
+  void ReadPixels( GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels )
+  {
+    glReadPixels( x, y, width, height, format, type, pixels );
+  }
+
+  void ReleaseShaderCompiler( void )
+  {
+    glReleaseShaderCompiler();
+  }
+
+  void RenderbufferStorage( GLenum target, GLenum internalformat, GLsizei width, GLsizei height )
+  {
+    glRenderbufferStorage( target, internalformat, width, height );
+  }
+
+  void SampleCoverage( GLclampf value, GLboolean invert )
+  {
+    glSampleCoverage( value, invert );
+  }
+
+  void Scissor( GLint x, GLint y, GLsizei width, GLsizei height )
+  {
+    glScissor( x, y, width, height );
+  }
+
+  void ShaderBinary( GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length )
+  {
+    glShaderBinary( n, shaders, binaryformat, binary, length );
+  }
+
+  void ShaderSource( GLuint shader, GLsizei count, const char** string, const GLint* length )
+  {
+    glShaderSource( shader, count, string, length );
+  }
+
+  void StencilFunc( GLenum func, GLint ref, GLuint mask )
+  {
+    glStencilFunc( func, ref, mask );
+  }
+
+  void StencilFuncSeparate( GLenum face, GLenum func, GLint ref, GLuint mask )
+  {
+    glStencilFuncSeparate( face, func, ref, mask );
+  }
+
+  void StencilMask( GLuint mask )
+  {
+    glStencilMask( mask );
+  }
+
+  void StencilMaskSeparate( GLenum face, GLuint mask )
+  {
+    glStencilMaskSeparate( face, mask );
+  }
+
+  void StencilOp( GLenum fail, GLenum zfail, GLenum zpass )
+  {
+    glStencilOp( fail, zfail, zpass );
+  }
+
+  void StencilOpSeparate( GLenum face, GLenum fail, GLenum zfail, GLenum zpass )
+  {
+    glStencilOpSeparate( face, fail, zfail, zpass );
+  }
+
+  void TexImage2D( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels )
+  {
+    glTexImage2D( target, level, internalformat, width, height, border, format, type, pixels );
+  }
+
+  void TexParameterf( GLenum target, GLenum pname, GLfloat param )
+  {
+    glTexParameterf( target, pname, param );
+  }
+
+  void TexParameterfv( GLenum target, GLenum pname, const GLfloat* params )
+  {
+    glTexParameterfv( target, pname, params );
+  }
+
+  void TexParameteri( GLenum target, GLenum pname, GLint param )
+  {
+    glTexParameteri( target, pname, param );
+  }
+
+  void TexParameteriv( GLenum target, GLenum pname, const GLint* params )
+  {
+    glTexParameteriv( target, pname, params );
+  }
+
+  void TexSubImage2D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels )
+  {
+    glTexSubImage2D( target, level, xoffset, yoffset, width, height, format, type, pixels );
+  }
+
+  void Uniform1f( GLint location, GLfloat x )
+  {
+    glUniform1f( location, x );
+  }
+
+  void Uniform1fv( GLint location, GLsizei count, const GLfloat* v )
+  {
+    glUniform1fv( location, count, v );
+  }
+
+  void Uniform1i( GLint location, GLint x )
+  {
+    glUniform1i( location, x );
+  }
+
+  void Uniform1iv( GLint location, GLsizei count, const GLint* v )
+  {
+    glUniform1iv( location, count, v );
+  }
+
+  void Uniform2f( GLint location, GLfloat x, GLfloat y )
+  {
+    glUniform2f( location, x, y );
+  }
+
+  void Uniform2fv( GLint location, GLsizei count, const GLfloat* v )
+  {
+    glUniform2fv( location, count, v );
+  }
+
+  void Uniform2i( GLint location, GLint x, GLint y )
+  {
+    glUniform2i( location, x, y );
+  }
+
+  void Uniform2iv( GLint location, GLsizei count, const GLint* v )
+  {
+    glUniform2iv( location, count, v );
+  }
+
+  void Uniform3f( GLint location, GLfloat x, GLfloat y, GLfloat z )
+  {
+    glUniform3f( location, x, y, z );
+  }
+
+  void Uniform3fv( GLint location, GLsizei count, const GLfloat* v )
+  {
+    glUniform3fv( location, count, v );
+  }
+
+  void Uniform3i( GLint location, GLint x, GLint y, GLint z )
+  {
+    glUniform3i( location, x, y, z );
+  }
+
+  void Uniform3iv( GLint location, GLsizei count, const GLint* v )
+  {
+    glUniform3iv( location, count, v );
+  }
+
+  void Uniform4f( GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+  {
+    glUniform4f( location, x, y, z, w );
+  }
+
+  void Uniform4fv( GLint location, GLsizei count, const GLfloat* v )
+  {
+    glUniform4fv( location, count, v );
+  }
+
+  void Uniform4i( GLint location, GLint x, GLint y, GLint z, GLint w )
+  {
+    glUniform4i( location, x, y, z, w );
+  }
+
+  void Uniform4iv( GLint location, GLsizei count, const GLint* v )
+  {
+    glUniform4iv( location, count, v );
+  }
+
+  void UniformMatrix2fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value )
+  {
+    glUniformMatrix2fv( location, count, transpose, value );
+  }
+
+  void UniformMatrix3fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value )
+  {
+    glUniformMatrix3fv( location, count, transpose, value );
+  }
+
+  void UniformMatrix4fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value )
+  {
+    glUniformMatrix4fv( location, count, transpose, value );
+  }
+
+  void UseProgram( GLuint program )
+  {
+    glUseProgram( program );
+  }
+
+  void ValidateProgram( GLuint program )
+  {
+    glValidateProgram( program );
+  }
+
+  void VertexAttrib1f( GLuint indx, GLfloat x )
+  {
+    glVertexAttrib1f( indx, x );
+  }
+
+  void VertexAttrib1fv( GLuint indx, const GLfloat* values )
+  {
+    glVertexAttrib1fv( indx, values );
+  }
+
+  void VertexAttrib2f( GLuint indx, GLfloat x, GLfloat y )
+  {
+    glVertexAttrib2f( indx, x, y );
+  }
+
+  void VertexAttrib2fv( GLuint indx, const GLfloat* values )
+  {
+    glVertexAttrib2fv( indx, values );
+  }
+
+  void VertexAttrib3f( GLuint indx, GLfloat x, GLfloat y, GLfloat z )
+  {
+    glVertexAttrib3f( indx, x, y, z );
+  }
+
+  void VertexAttrib3fv( GLuint indx, const GLfloat* values )
+  {
+    glVertexAttrib3fv( indx, values );
+  }
+
+  void VertexAttrib4f( GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+  {
+    glVertexAttrib4f( indx, x, y, z, w );
+  }
+
+  void VertexAttrib4fv( GLuint indx, const GLfloat* values )
+  {
+    glVertexAttrib4fv( indx, values );
+  }
+
+  void VertexAttribPointer( GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr )
+  {
+    glVertexAttribPointer( indx, size, type, normalized, stride, ptr );
+  }
+
+  void Viewport( GLint x, GLint y, GLsizei width, GLsizei height )
+  {
+    glViewport( x, y, width, height );
+  }
+
+  /* OpenGL ES 3.0 */
+
+  void ReadBuffer( GLenum mode )
+  {
+    mImpl->ReadBuffer( mode );
+  }
+
+  void DrawRangeElements( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices )
+  {
+    mImpl->DrawRangeElements( mode, start, end, count, type, indices );
+  }
+
+  void TexImage3D( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels )
+  {
+    mImpl->TexImage3D( target, level, internalformat, width, height, depth, border, format, type, pixels );
+  }
+
+  void TexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels )
+  {
+    mImpl->TexSubImage3D( target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels );
+  }
+
+  void CopyTexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height )
+  {
+    mImpl->CopyTexSubImage3D( target, level, xoffset, yoffset, zoffset, x, y, width, height );
+  }
+
+  void CompressedTexImage3D( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data )
+  {
+    mImpl->CompressedTexImage3D( target, level, internalformat, width, height, depth, border, imageSize, data );
+  }
+
+  void CompressedTexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data )
+  {
+    mImpl->CompressedTexSubImage3D( target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data );
+  }
+
+  void GenQueries( GLsizei n, GLuint* ids )
+  {
+    mImpl->GenQueries( n, ids );
+  }
+
+  void DeleteQueries( GLsizei n, const GLuint* ids )
+  {
+    mImpl->DeleteQueries( n, ids );
+  }
+
+  GLboolean IsQuery( GLuint id )
+  {
+    return mImpl->IsQuery( id );
+  }
+
+  void BeginQuery( GLenum target, GLuint id )
+  {
+    mImpl->BeginQuery( target, id );
+  }
+
+  void EndQuery( GLenum target )
+  {
+    mImpl->EndQuery( target );
+  }
+
+  void GetQueryiv( GLenum target, GLenum pname, GLint* params )
+  {
+    mImpl->GetQueryiv( target, pname, params );
+  }
+
+  void GetQueryObjectuiv( GLuint id, GLenum pname, GLuint* params )
+  {
+    mImpl->GetQueryObjectuiv( id, pname, params );
+  }
+
+  GLboolean UnmapBuffer( GLenum target )
+  {
+    return mImpl->UnmapBuffer( target );
+  }
+
+  void GetBufferPointerv( GLenum target, GLenum pname, GLvoid** params )
+  {
+    mImpl->GetBufferPointerv( target, pname, params );
+  }
+
+  void DrawBuffers( GLsizei n, const GLenum* bufs )
+  {
+    mImpl->DrawBuffers( n, bufs );
+  }
+
+  void UniformMatrix2x3fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value )
+  {
+    mImpl->UniformMatrix2x3fv( location, count, transpose, value );
+  }
+
+  void UniformMatrix3x2fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value )
+  {
+    mImpl->UniformMatrix3x2fv( location, count, transpose, value );
+  }
+
+  void UniformMatrix2x4fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value )
+  {
+    mImpl->UniformMatrix2x4fv( location, count, transpose, value );
+  }
+
+  void UniformMatrix4x2fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value )
+  {
+    mImpl->UniformMatrix4x2fv( location, count, transpose, value );
+  }
+
+  void UniformMatrix3x4fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value )
+  {
+    mImpl->UniformMatrix3x4fv( location, count, transpose, value );
+  }
+
+  void UniformMatrix4x3fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value )
+  {
+    mImpl->UniformMatrix4x3fv( location, count, transpose, value );
+  }
+
+  void BlitFramebuffer( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter )
+  {
+    mImpl->BlitFramebuffer( srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter );
+  }
+
+  void RenderbufferStorageMultisample( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height )
+  {
+    mImpl->RenderbufferStorageMultisample( target, samples, internalformat, width, height );
+  }
+
+  void FramebufferTextureLayer( GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer )
+  {
+    mImpl->FramebufferTextureLayer( target, attachment, texture, level, layer );
+  }
+
+  GLvoid* MapBufferRange( GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access )
+  {
+    return mImpl->MapBufferRange( target, offset, length, access );
+  }
+
+  void FlushMappedBufferRange( GLenum target, GLintptr offset, GLsizeiptr length )
+  {
+    mImpl->FlushMappedBufferRange( target, offset, length );
+  }
+
+  void BindVertexArray( GLuint array )
+  {
+    mImpl->BindVertexArray( array );
+  }
+
+  void DeleteVertexArrays( GLsizei n, const GLuint* arrays )
+  {
+    mImpl->DeleteVertexArrays( n, arrays );
+  }
+
+  void GenVertexArrays( GLsizei n, GLuint* arrays )
+  {
+    mImpl->GenVertexArrays( n, arrays );
+  }
+
+  GLboolean IsVertexArray( GLuint array )
+  {
+    return mImpl->IsVertexArray( array );
+  }
+
+  void GetIntegeri_v( GLenum target, GLuint index, GLint* data )
+  {
+    mImpl->GetIntegeri_v( target, index, data );
+  }
+
+  void BeginTransformFeedback( GLenum primitiveMode )
+  {
+    mImpl->BeginTransformFeedback( primitiveMode );
+  }
+
+  void EndTransformFeedback( void )
+  {
+    mImpl->EndTransformFeedback();
+  }
+
+  void BindBufferRange( GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size )
+  {
+    mImpl->BindBufferRange( target, index, buffer, offset, size );
+  }
+
+  void BindBufferBase( GLenum target, GLuint index, GLuint buffer )
+  {
+    mImpl->BindBufferBase( target, index, buffer );
+  }
+
+  void TransformFeedbackVaryings( GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode )
+  {
+    mImpl->TransformFeedbackVaryings( program, count, varyings, bufferMode );
+  }
+
+  void GetTransformFeedbackVarying( GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name )
+  {
+    mImpl->GetTransformFeedbackVarying( program, index, bufSize, length, size, type, name );
+  }
+
+  void VertexAttribIPointer( GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer )
+  {
+    mImpl->VertexAttribIPointer( index, size, type, stride, pointer );
+  }
+
+  void GetVertexAttribIiv( GLuint index, GLenum pname, GLint* params )
+  {
+    mImpl->GetVertexAttribIiv( index, pname, params );
+  }
+
+  void GetVertexAttribIuiv( GLuint index, GLenum pname, GLuint* params )
+  {
+    mImpl->GetVertexAttribIuiv( index, pname, params );
+  }
+
+  void VertexAttribI4i( GLuint index, GLint x, GLint y, GLint z, GLint w )
+  {
+    mImpl->VertexAttribI4i( index, x, y, z, w );
+  }
+
+  void VertexAttribI4ui( GLuint index, GLuint x, GLuint y, GLuint z, GLuint w )
+  {
+    mImpl->VertexAttribI4ui( index, x, y, z, w );
+  }
+
+  void VertexAttribI4iv( GLuint index, const GLint* v )
+  {
+    mImpl->VertexAttribI4iv( index, v );
+  }
+
+  void VertexAttribI4uiv( GLuint index, const GLuint* v )
+  {
+    mImpl->VertexAttribI4uiv( index, v );
+  }
+
+  void GetUniformuiv( GLuint program, GLint location, GLuint* params )
+  {
+    mImpl->GetUniformuiv( program, location, params );
+  }
+
+  GLint GetFragDataLocation( GLuint program, const GLchar *name )
+  {
+    return mImpl->GetFragDataLocation( program, name );
+  }
+
+  void Uniform1ui( GLint location, GLuint v0 )
+  {
+    mImpl->Uniform1ui( location, v0 );
+  }
+
+  void Uniform2ui( GLint location, GLuint v0, GLuint v1 )
+  {
+    mImpl->Uniform2ui( location, v0, v1 );
+  }
+
+  void Uniform3ui( GLint location, GLuint v0, GLuint v1, GLuint v2 )
+  {
+    mImpl->Uniform3ui( location, v0, v1, v2 );
+  }
+
+  void Uniform4ui( GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3 )
+  {
+    mImpl->Uniform4ui( location, v0, v1, v2, v3 );
+  }
+
+  void Uniform1uiv( GLint location, GLsizei count, const GLuint* value )
+  {
+    mImpl->Uniform1uiv( location, count, value );
+  }
+
+  void Uniform2uiv( GLint location, GLsizei count, const GLuint* value )
+  {
+    mImpl->Uniform2uiv( location, count, value );
+  }
+
+  void Uniform3uiv( GLint location, GLsizei count, const GLuint* value )
+  {
+    mImpl->Uniform3uiv( location, count, value );
+  }
+
+  void Uniform4uiv( GLint location, GLsizei count, const GLuint* value )
+  {
+    mImpl->Uniform4uiv( location, count, value );
+  }
+
+  void ClearBufferiv( GLenum buffer, GLint drawbuffer, const GLint* value )
+  {
+    mImpl->ClearBufferiv( buffer, drawbuffer, value );
+  }
+
+  void ClearBufferuiv( GLenum buffer, GLint drawbuffer, const GLuint* value )
+  {
+    mImpl->ClearBufferuiv( buffer, drawbuffer, value );
+  }
+
+  void ClearBufferfv( GLenum buffer, GLint drawbuffer, const GLfloat* value )
+  {
+    mImpl->ClearBufferfv( buffer, drawbuffer, value );
+  }
+
+  void ClearBufferfi( GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil )
+  {
+    mImpl->ClearBufferfi( buffer, drawbuffer, depth, stencil );
+  }
+
+  const GLubyte* GetStringi( GLenum name, GLuint index )
+  {
+    return mImpl->GetStringi( name, index );
+  }
+
+  void CopyBufferSubData( GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size )
+  {
+    mImpl->CopyBufferSubData( readTarget, writeTarget, readOffset, writeOffset, size );
+  }
+
+  void GetUniformIndices( GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices )
+  {
+    mImpl->GetUniformIndices( program, uniformCount, uniformNames, uniformIndices );
+  }
+
+  void GetActiveUniformsiv( GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params )
+  {
+    mImpl->GetActiveUniformsiv( program, uniformCount, uniformIndices, pname, params );
+  }
+
+  GLuint GetUniformBlockIndex( GLuint program, const GLchar* uniformBlockName )
+  {
+    return mImpl->GetUniformBlockIndex( program, uniformBlockName );
+  }
+
+  void GetActiveUniformBlockiv( GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params )
+  {
+    mImpl->GetActiveUniformBlockiv( program, uniformBlockIndex, pname, params );
+  }
+
+  void GetActiveUniformBlockName( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName )
+  {
+    mImpl->GetActiveUniformBlockName( program, uniformBlockIndex, bufSize, length, uniformBlockName );
+  }
+
+  void UniformBlockBinding( GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding )
+  {
+    mImpl->UniformBlockBinding( program, uniformBlockIndex, uniformBlockBinding );
+  }
+
+  void DrawArraysInstanced( GLenum mode, GLint first, GLsizei count, GLsizei instanceCount )
+  {
+    mImpl->DrawArraysInstanced( mode, first, count, instanceCount );
+  }
+
+  void DrawElementsInstanced( GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount )
+  {
+    mImpl->DrawElementsInstanced( mode, count, type, indices, instanceCount );
+  }
+
+  GLsync FenceSync( GLenum condition, GLbitfield flags )
+  {
+    return mImpl->FenceSync( condition, flags );
+  }
+
+  GLboolean IsSync( GLsync sync )
+  {
+    return mImpl->IsSync( sync );
+  }
+
+  void DeleteSync( GLsync sync )
+  {
+    mImpl->DeleteSync( sync );
+  }
+
+  GLenum ClientWaitSync( GLsync sync, GLbitfield flags, GLuint64 timeout )
+  {
+    return mImpl->ClientWaitSync( sync, flags, timeout );
+  }
+
+  void WaitSync( GLsync sync, GLbitfield flags, GLuint64 timeout )
+  {
+    mImpl->WaitSync( sync, flags, timeout );
+  }
+
+  void GetInteger64v( GLenum pname, GLint64* params )
+  {
+    mImpl->GetInteger64v( pname, params );
+  }
+
+  void GetSynciv( GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values )
+  {
+    mImpl->GetSynciv( sync, pname, bufSize, length, values );
+  }
+
+  void GetInteger64i_v( GLenum target, GLuint index, GLint64* data )
+  {
+    mImpl->GetInteger64i_v( target, index, data );
+  }
+
+  void GetBufferParameteri64v( GLenum target, GLenum pname, GLint64* params )
+  {
+    mImpl->GetBufferParameteri64v( target, pname, params );
+  }
+
+  void GenSamplers( GLsizei count, GLuint* samplers )
+  {
+    mImpl->GenSamplers( count, samplers );
+  }
+
+  void DeleteSamplers( GLsizei count, const GLuint* samplers )
+  {
+    mImpl->DeleteSamplers( count, samplers );
+  }
+
+  GLboolean IsSampler( GLuint sampler )
+  {
+    return mImpl->IsSampler( sampler );
+  }
+
+  void BindSampler( GLuint unit, GLuint sampler )
+  {
+    mImpl->BindSampler( unit, sampler );
+  }
+
+  void SamplerParameteri( GLuint sampler, GLenum pname, GLint param )
+  {
+    mImpl->SamplerParameteri( sampler, pname, param );
+  }
+
+  void SamplerParameteriv( GLuint sampler, GLenum pname, const GLint* param )
+  {
+    mImpl->SamplerParameteriv( sampler, pname, param );
+  }
+
+  void SamplerParameterf( GLuint sampler, GLenum pname, GLfloat param )
+  {
+    mImpl->SamplerParameterf( sampler, pname, param );
+  }
+
+  void SamplerParameterfv( GLuint sampler, GLenum pname, const GLfloat* param )
+  {
+    mImpl->SamplerParameterfv( sampler, pname, param );
+  }
+
+  void GetSamplerParameteriv( GLuint sampler, GLenum pname, GLint* params )
+  {
+    mImpl->GetSamplerParameteriv( sampler, pname, params );
+  }
+
+  void GetSamplerParameterfv( GLuint sampler, GLenum pname, GLfloat* params )
+  {
+    mImpl->GetSamplerParameterfv( sampler, pname, params );
+  }
+
+  void VertexAttribDivisor( GLuint index, GLuint divisor )
+  {
+    mImpl->VertexAttribDivisor( index, divisor );
+  }
+
+  void BindTransformFeedback( GLenum target, GLuint id )
+  {
+    mImpl->BindTransformFeedback( target, id );
+  }
+
+  void DeleteTransformFeedbacks( GLsizei n, const GLuint* ids )
+  {
+    mImpl->DeleteTransformFeedbacks( n, ids );
+  }
+
+  void GenTransformFeedbacks( GLsizei n, GLuint* ids )
+  {
+    mImpl->GenTransformFeedbacks( n, ids );
+  }
+
+  GLboolean IsTransformFeedback( GLuint id )
+  {
+    return mImpl->IsTransformFeedback( id );
+  }
+
+  void PauseTransformFeedback( void )
+  {
+    mImpl->PauseTransformFeedback();
+  }
+
+  void ResumeTransformFeedback( void )
+  {
+    mImpl->ResumeTransformFeedback();
+  }
+
+  void GetProgramBinary( GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary )
+  {
+    mImpl->GetProgramBinary( program, bufSize, length, binaryFormat, binary );
+  }
+
+  void ProgramBinary( GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length )
+  {
+    mImpl->ProgramBinary( program, binaryFormat, binary, length );
+  }
+
+  void ProgramParameteri( GLuint program, GLenum pname, GLint value )
+  {
+    mImpl->ProgramParameteri( program, pname, value );
+  }
+
+  void InvalidateFramebuffer( GLenum target, GLsizei numAttachments, const GLenum* attachments )
+  {
+    mImpl->InvalidateFramebuffer( target, numAttachments, attachments );
+  }
+
+  void InvalidateSubFramebuffer( GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height )
+  {
+    mImpl->InvalidateSubFramebuffer( target, numAttachments, attachments, x, y, width, height );
+  }
+
+  void TexStorage2D( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height )
+  {
+    mImpl->TexStorage2D( target, levels, internalformat, width, height );
+  }
+
+  void TexStorage3D( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth )
+  {
+    mImpl->TexStorage3D( target, levels, internalformat, width, height, depth );
+  }
+
+  void GetInternalformativ( GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params )
+  {
+    mImpl->GetInternalformativ( target, internalformat, pname, bufSize, params );
+  }
+
+private:
+  int32_t mGlesVersion;
+  bool mIsSurfacelessContextSupported;
+  bool mIsContextCreated;
+  ConditionalWait mContextCreatedWaitCondition;
+  GLint mMaxTextureSize;
+  std::unique_ptr<GlesAbstraction> mImpl;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_GL_IMPLEMENTATION_H
diff --git a/dali/internal/graphics/gles/gl-proxy-implementation.cpp b/dali/internal/graphics/gles/gl-proxy-implementation.cpp
new file mode 100644 (file)
index 0000000..ae87def
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/graphics/gles/gl-proxy-implementation.h>
+
+// EXTERNAL INCLUDES
+#include <math.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/environment-options.h>
+
+namespace
+{
+const int NUM_FRAMES_PER_SECOND( 60 );
+}
+
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+Sampler::Sampler( const char* description )
+: mDescription( description ),
+  mAccumulatedSquare( 0 ),
+  mAccumulated( 0 ),
+  mNumSamples( 0 ),
+  mMin( 0.0f ),
+  mMax( 0.0f ),
+  mCurrentFrameCount( 0 )
+{
+}
+
+void Sampler::Increment()
+{
+  mCurrentFrameCount++;
+}
+
+void Sampler::Reset()
+{
+  mAccumulatedSquare = 0;
+  mAccumulated = 0;
+  mNumSamples = 0;
+  mMin = 0.0f;
+  mMax = 0.0f;
+  mCurrentFrameCount = 0;
+}
+
+void Sampler::Accumulate()
+{
+  if( mNumSamples == 0 )
+  {
+    mMin = mCurrentFrameCount;
+    mMax = mCurrentFrameCount;
+  }
+  else
+  {
+    if( mCurrentFrameCount < mMin )
+    {
+      mMin = mCurrentFrameCount;
+    }
+    if( mCurrentFrameCount > mMax )
+    {
+      mMax = mCurrentFrameCount;
+    }
+  }
+
+  mNumSamples++;
+
+  mAccumulated += mCurrentFrameCount;
+  mAccumulatedSquare += ( mCurrentFrameCount * mCurrentFrameCount );
+  mCurrentFrameCount = 0;
+}
+const char* Sampler::GetDescription() const
+{
+  return mDescription;
+}
+
+float Sampler::GetMeanValue() const
+{
+  float meanValue = 0;
+  if( mNumSamples > 0 )
+  {
+    meanValue = static_cast<double>( mAccumulated ) / static_cast<double>( mNumSamples );
+  }
+  return meanValue;
+}
+
+float Sampler::GetStandardDeviation() const
+{
+  float standardDeviation = 0.0f;
+  if( mNumSamples > 0 )
+  {
+    standardDeviation = sqrtf( mNumSamples * mAccumulatedSquare - ( mAccumulated * mAccumulated ) ) / mNumSamples;
+  }
+  return standardDeviation;
+}
+
+float Sampler::GetMin() const
+{
+  return mMin;
+}
+
+float Sampler::GetMax() const
+{
+  return mMax;
+}
+
+uint64_t Sampler::GetCount() const
+{
+  return mAccumulated;
+}
+
+ObjectCounter::ObjectCounter( const char* description )
+: mDescription( description ),
+  mCount( 0 ),
+  mPeak( 0 )
+{}
+
+void ObjectCounter::Increment()
+{
+  ++mCount;
+  if( mCount > mPeak )
+  {
+    mPeak = mCount;
+  }
+}
+
+void ObjectCounter::Decrement()
+{
+  --mCount;
+}
+
+unsigned int ObjectCounter::GetCount() const
+{
+  return mCount;
+}
+unsigned int ObjectCounter::GetPeak() const
+{
+  return mPeak;
+}
+
+const char* ObjectCounter::GetDescription() const
+{
+  return mDescription;
+}
+
+GlProxyImplementation::GlProxyImplementation( EnvironmentOptions& environmentOptions )
+: mEnvironmentOptions( environmentOptions ),
+  mActiveTextureSampler( "ActiveTexture calls" ),
+  mClearSampler( "Clear calls" ),
+  mBindBufferSampler( "Bind buffers" ),
+  mBindTextureSampler( "Bind textures" ),
+  mDrawSampler( "Draw calls" ),
+  mUniformSampler( "Uniform sets" ),
+  mUseProgramSampler( "Used programs" ),
+  mBufferCount( "Buffer Count" ),
+  mTextureCount( "Texture Count" ),
+  mProgramCount( "Program Count" ),
+  mCurrentFrameCount( 0 ),
+  mTotalFrameCount( 0 )
+{
+}
+
+GlProxyImplementation::~GlProxyImplementation()
+{
+}
+
+void GlProxyImplementation::PreRender()
+{
+}
+
+void GlProxyImplementation::PostRender()
+{
+  // Accumulate counts in each sampler
+  AccumulateSamples();
+
+  // When we reach the desired frame count, output the averages from the samples
+  mTotalFrameCount++;
+  mCurrentFrameCount++;
+
+  if( mCurrentFrameCount >= mEnvironmentOptions.GetGlesCallTime() * NUM_FRAMES_PER_SECOND )
+  {
+    mCurrentFrameCount = 0;
+    LogResults();
+
+    if( !mEnvironmentOptions.GetGlesCallAccumulate() )
+    {
+      ResetSamplers();
+    }
+  }
+}
+
+void GlProxyImplementation::Clear( GLbitfield mask )
+{
+  mClearSampler.Increment();
+  GlImplementation::Clear(mask);
+}
+
+void GlProxyImplementation::GenBuffers(GLsizei n, GLuint* buffers)
+{
+  mBufferCount.Increment();
+  GlImplementation::GenBuffers( n, buffers );
+}
+
+void GlProxyImplementation::DeleteBuffers( GLsizei n, const GLuint* buffers )
+{
+  mBufferCount.Decrement();
+  GlImplementation::DeleteBuffers( n, buffers );
+}
+
+void GlProxyImplementation::BindBuffer( GLenum target, GLuint buffer )
+{
+  mBindBufferSampler.Increment();
+  GlImplementation::BindBuffer( target, buffer );
+}
+
+void GlProxyImplementation::GenTextures( GLsizei n, GLuint* textures )
+{
+  mTextureCount.Increment();
+  GlImplementation::GenTextures( n, textures );
+}
+
+void GlProxyImplementation::DeleteTextures( GLsizei n, const GLuint* textures )
+{
+  mTextureCount.Decrement();
+  GlImplementation::DeleteTextures( n, textures );
+}
+
+void GlProxyImplementation::ActiveTexture( GLenum texture )
+{
+  mActiveTextureSampler.Increment();
+  GlImplementation::ActiveTexture( texture );
+}
+
+void GlProxyImplementation::BindTexture( GLenum target, GLuint texture )
+{
+  mBindTextureSampler.Increment();
+  GlImplementation::BindTexture(target,texture);
+}
+
+void GlProxyImplementation::DrawArrays( GLenum mode, GLint first, GLsizei count )
+{
+  mDrawSampler.Increment();
+  GlImplementation::DrawArrays( mode, first, count );
+}
+
+void GlProxyImplementation::DrawElements( GLenum mode, GLsizei count, GLenum type, const void* indices )
+{
+  mDrawSampler.Increment();
+  GlImplementation::DrawElements( mode, count, type, indices );
+}
+
+void GlProxyImplementation::Uniform1f( GLint location, GLfloat x )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform1f( location, x );
+}
+
+void GlProxyImplementation::Uniform1fv( GLint location, GLsizei count, const GLfloat* v )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform1fv( location, count, v );
+}
+
+void GlProxyImplementation::Uniform1i( GLint location, GLint x )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform1i( location, x );
+}
+
+void GlProxyImplementation::Uniform1iv( GLint location, GLsizei count, const GLint* v )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform1iv( location, count, v );
+}
+
+void GlProxyImplementation::Uniform2f( GLint location, GLfloat x, GLfloat y)
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform2f( location, x, y );
+}
+
+void GlProxyImplementation::Uniform2fv( GLint location, GLsizei count, const GLfloat* v )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform2fv( location, count, v );
+}
+
+void GlProxyImplementation::Uniform2i( GLint location, GLint x, GLint y )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform2i( location, x, y );
+}
+
+void GlProxyImplementation::Uniform2iv( GLint location, GLsizei count, const GLint* v )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform2iv( location, count, v );
+}
+
+void GlProxyImplementation::Uniform3f( GLint location, GLfloat x, GLfloat y, GLfloat z )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform3f( location, x, y, z );
+}
+
+void GlProxyImplementation::Uniform3fv( GLint location, GLsizei count, const GLfloat* v )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform3fv( location, count, v );
+}
+
+void GlProxyImplementation::Uniform3i( GLint location, GLint x, GLint y, GLint z )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform3i( location, x, y, z );
+}
+
+void GlProxyImplementation::Uniform3iv( GLint location, GLsizei count, const GLint* v )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform3iv( location, count, v );
+}
+
+void GlProxyImplementation::Uniform4f( GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform4f( location, x, y, z, w );
+}
+
+void GlProxyImplementation::Uniform4fv( GLint location, GLsizei count, const GLfloat* v )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform4fv( location, count, v );
+}
+
+void GlProxyImplementation::Uniform4i( GLint location, GLint x, GLint y, GLint z, GLint w )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform4i( location, x, y, z, w );
+}
+
+void GlProxyImplementation::Uniform4iv( GLint location, GLsizei count, const GLint* v )
+{
+  mUniformSampler.Increment();
+  GlImplementation::Uniform4iv( location, count, v );
+}
+
+void GlProxyImplementation::UniformMatrix2fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value )
+{
+  mUniformSampler.Increment();
+  GlImplementation::UniformMatrix2fv( location, count, transpose, value );
+}
+
+void GlProxyImplementation::UniformMatrix3fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value )
+{
+  mUniformSampler.Increment();
+  GlImplementation::UniformMatrix3fv( location, count, transpose, value );
+}
+
+void GlProxyImplementation::UniformMatrix4fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value )
+{
+  mUniformSampler.Increment();
+  GlImplementation::UniformMatrix4fv( location, count, transpose, value);
+}
+
+GLuint GlProxyImplementation::CreateProgram( void )
+{
+  mProgramCount.Increment();
+  return GlImplementation::CreateProgram();
+}
+
+void GlProxyImplementation::DeleteProgram( GLuint program )
+{
+  mProgramCount.Decrement();
+  GlImplementation::DeleteProgram( program );
+}
+
+void GlProxyImplementation::UseProgram( GLuint program )
+{
+  mUseProgramSampler.Increment();
+  GlImplementation::UseProgram( program );
+}
+
+void GlProxyImplementation::AccumulateSamples()
+{
+  // Accumulate counts in each sampler
+  mActiveTextureSampler.Accumulate();
+  mClearSampler.Accumulate();
+  mBindBufferSampler.Accumulate();
+  mBindTextureSampler.Accumulate();
+  mDrawSampler.Accumulate();
+  mUniformSampler.Accumulate();
+  mUseProgramSampler.Accumulate();
+}
+
+void GlProxyImplementation::LogResults()
+{
+  Debug::LogMessage( Debug::DebugInfo, "OpenGL ES statistics sampled over %d frames) operations per frame:\n", mTotalFrameCount );
+  LogCalls( mActiveTextureSampler );
+  LogCalls( mClearSampler );
+  LogCalls( mBindBufferSampler );
+  LogCalls( mBindTextureSampler );
+  LogCalls( mDrawSampler );
+  LogCalls( mUniformSampler );
+  LogCalls( mUseProgramSampler );
+  Debug::LogMessage( Debug::DebugInfo, "OpenGL ES Object Count:\n" );
+  LogObjectCounter( mBufferCount );
+  LogObjectCounter( mTextureCount );
+  LogObjectCounter( mProgramCount );
+}
+
+void GlProxyImplementation::LogCalls( const Sampler& sampler )
+{
+  Debug::LogMessage( Debug::DebugInfo, "  %s : Mean %5.2f  (Min:%5.2f, Max:%5.2f, StdDev:%5.2f, Actual:%d)\n",
+                     sampler.GetDescription(),
+                     sampler.GetMeanValue(), sampler.GetMin(), sampler.GetMax(),
+                     sampler.GetStandardDeviation(),
+                     sampler.GetCount() );
+}
+
+void GlProxyImplementation::LogObjectCounter( const ObjectCounter& sampler )
+{
+  Debug::LogMessage( Debug::DebugInfo, "  %s : %u  (Peak:%u)\n",
+                     sampler.GetDescription(),
+                     sampler.GetCount(),
+                     sampler.GetPeak() );
+}
+
+void GlProxyImplementation::ResetSamplers()
+{
+  mActiveTextureSampler.Reset();
+  mClearSampler.Reset();
+  mBindBufferSampler.Reset();
+  mBindTextureSampler.Reset();
+  mDrawSampler.Reset();
+  mUniformSampler.Reset();
+  mUseProgramSampler.Reset();
+  mTotalFrameCount = 0;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/graphics/gles/gl-proxy-implementation.h b/dali/internal/graphics/gles/gl-proxy-implementation.h
new file mode 100644 (file)
index 0000000..638dcaa
--- /dev/null
@@ -0,0 +1,241 @@
+#ifndef DALI_INTERNAL_GL_PROXY_IMPLEMENTATION_H
+#define DALI_INTERNAL_GL_PROXY_IMPLEMENTATION_H
+
+/*
+ * Copyright (c) 2019 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 <dali/internal/graphics/gles/gl-implementation.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class EnvironmentOptions;
+
+/**
+ * Helper class to calculate the statistics for Open GLES calls
+ */
+class Sampler
+{
+public:
+
+  /**
+   * Constructor
+   * @param description to write to the log
+   */
+  Sampler( const char* description );
+
+  /**
+   * Increment the counter for this frame
+   */
+  void Increment();
+
+  /**
+   * Reset the counter
+   */
+  void Reset();
+
+  /**
+   * Accumulate the count onto statistics
+   */
+  void Accumulate();
+
+  /**
+   * @return the description of the sampler
+   */
+  const char* GetDescription() const;
+
+  /**
+   * @return the mean value
+   */
+  float GetMeanValue() const;
+
+  /**
+   * @return the standard deviation
+   */
+  float GetStandardDeviation() const;
+
+  /**
+   * @return the minimum value
+   */
+  float GetMin() const;
+
+  /**
+   * @return the maximum value
+   */
+  float GetMax() const;
+
+  /**
+   * @return the current count
+   */
+  uint64_t GetCount() const;
+
+private: // Data
+
+  const char* mDescription;
+
+  uint64_t mAccumulatedSquare;
+  uint64_t mAccumulated;
+  uint64_t mNumSamples;
+  float mMin;
+  float mMax;
+  unsigned int mCurrentFrameCount;
+};
+
+/**
+ * Helper class to calculate number of OpenGL objects
+ */
+class ObjectCounter
+{
+public:
+  ObjectCounter( const char* description );
+
+  /**
+   * Increment the counter
+   */
+  void Increment();
+
+  /**
+   * Decrement the counter
+   */
+  void Decrement();
+
+  /**
+   * @return The current number of objects
+   */
+  unsigned int GetCount() const;
+
+  /**
+   * @return The maximum number of objects created
+   */
+  unsigned int GetPeak() const;
+
+  /**
+   * @return the description of the sampler
+   */
+  const char* GetDescription() const;
+
+private:
+  const char* mDescription;
+  unsigned int mCount;
+  unsigned int mPeak;
+};
+
+/**
+ * GlProxyImplementation is a wrapper for the concrete implementation
+ * of GlAbstraction that also gathers statistical information.
+ */
+class GlProxyImplementation : public GlImplementation
+{
+public:
+
+  /**
+   * Constructor
+   * @param environmentOptions to check how often to log results
+   */
+  GlProxyImplementation( EnvironmentOptions& environmentOptions );
+
+  /**
+   * Virtual destructor
+   */
+  virtual ~GlProxyImplementation();
+
+  /**
+   * @copydoc GlAbstraction::PreRender();
+   */
+  virtual void PreRender();
+
+  /**
+   * @copydoc GlAbstraction::PostRender();
+   */
+  virtual void PostRender();
+
+  /* OpenGL ES 2.0 API */
+  virtual void Clear( GLbitfield mask );
+
+  virtual void GenBuffers( GLsizei n, GLuint* buffers );
+  virtual void DeleteBuffers( GLsizei n, const GLuint* buffers );
+  virtual void BindBuffer( GLenum target, GLuint buffer );
+
+  virtual void GenTextures( GLsizei n, GLuint* textures );
+  virtual void DeleteTextures( GLsizei n, const GLuint* textures );
+  virtual void ActiveTexture( GLenum texture );
+  virtual void BindTexture( GLenum target, GLuint texture );
+
+  virtual void DrawArrays( GLenum mode, GLint first, GLsizei count );
+  virtual void DrawElements( GLenum mode, GLsizei count, GLenum type, const void* indices );
+
+  virtual void Uniform1f ( GLint location, GLfloat x );
+  virtual void Uniform1fv( GLint location, GLsizei count, const GLfloat* v );
+  virtual void Uniform1i ( GLint location, GLint x );
+  virtual void Uniform1iv( GLint location, GLsizei count, const GLint* v );
+  virtual void Uniform2f ( GLint location, GLfloat x, GLfloat y );
+  virtual void Uniform2fv( GLint location, GLsizei count, const GLfloat* v );
+  virtual void Uniform2i ( GLint location, GLint x, GLint y );
+  virtual void Uniform2iv( GLint location, GLsizei count, const GLint* v );
+  virtual void Uniform3f ( GLint location, GLfloat x, GLfloat y, GLfloat z );
+  virtual void Uniform3fv( GLint location, GLsizei count, const GLfloat* v );
+  virtual void Uniform3i ( GLint location, GLint x, GLint y, GLint z );
+  virtual void Uniform3iv( GLint location, GLsizei count, const GLint* v );
+  virtual void Uniform4f ( GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w );
+  virtual void Uniform4fv( GLint location, GLsizei count, const GLfloat* v );
+  virtual void Uniform4i ( GLint location, GLint x, GLint y, GLint z, GLint w );
+  virtual void Uniform4iv( GLint location, GLsizei count, const GLint* v );
+  virtual void UniformMatrix2fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value );
+  virtual void UniformMatrix3fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value );
+  virtual void UniformMatrix4fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value );
+
+  virtual GLuint CreateProgram( void );
+  virtual void DeleteProgram( GLuint program );
+  virtual void UseProgram( GLuint program );
+
+private: // Helpers
+
+  void AccumulateSamples();
+  void LogResults();
+  void LogCalls( const Sampler& sampler );
+  void LogObjectCounter( const ObjectCounter& sampler );
+  void ResetSamplers();
+
+private: // Data
+
+  EnvironmentOptions& mEnvironmentOptions;
+  Sampler mActiveTextureSampler;
+  Sampler mClearSampler;
+  Sampler mBindBufferSampler;
+  Sampler mBindTextureSampler;
+  Sampler mDrawSampler;
+  Sampler mUniformSampler;
+  Sampler mUseProgramSampler;
+  ObjectCounter mBufferCount;
+  ObjectCounter mTextureCount;
+  ObjectCounter mProgramCount;
+
+  int mCurrentFrameCount;
+  int mTotalFrameCount;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_GL_PROXY_IMPLEMENTATION_H
diff --git a/dali/internal/graphics/gles/gles-abstraction.h b/dali/internal/graphics/gles/gles-abstraction.h
new file mode 100644 (file)
index 0000000..8dc63e6
--- /dev/null
@@ -0,0 +1,255 @@
+#ifndef DALI_INTERNAL_GLES_ABSTRACTION_H
+#define DALI_INTERNAL_GLES_ABSTRACTION_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class GlesAbstraction
+{
+
+public:
+
+  /**
+   * Destructor
+   */
+  virtual ~GlesAbstraction() {};
+
+  virtual void ReadBuffer( GLenum mode ) = 0;
+
+  virtual void DrawRangeElements( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices ) = 0;
+
+  virtual void TexImage3D( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels ) = 0;
+
+  virtual void TexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels ) = 0;
+
+  virtual void CopyTexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height ) = 0;
+
+  virtual void CompressedTexImage3D( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data ) = 0;
+
+  virtual void CompressedTexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data ) = 0;
+
+  virtual void GenQueries( GLsizei n, GLuint* ids ) = 0;
+
+  virtual void DeleteQueries( GLsizei n, const GLuint* ids ) = 0;
+
+  virtual GLboolean IsQuery( GLuint id ) = 0;
+
+  virtual void BeginQuery( GLenum target, GLuint id ) = 0;
+
+  virtual void EndQuery( GLenum target ) = 0;
+
+  virtual void GetQueryiv( GLenum target, GLenum pname, GLint* params ) = 0;
+
+  virtual void GetQueryObjectuiv( GLuint id, GLenum pname, GLuint* params ) = 0;
+
+  virtual GLboolean UnmapBuffer( GLenum target ) = 0;
+
+  virtual void GetBufferPointerv( GLenum target, GLenum pname, GLvoid** params ) = 0;
+
+  virtual void DrawBuffers( GLsizei n, const GLenum* bufs ) = 0;
+
+  virtual void UniformMatrix2x3fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) = 0;
+
+  virtual void UniformMatrix3x2fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) = 0;
+
+  virtual void UniformMatrix2x4fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) = 0;
+
+  virtual void UniformMatrix4x2fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) = 0;
+
+  virtual void UniformMatrix3x4fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) = 0;
+
+  virtual void UniformMatrix4x3fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) = 0;
+
+  virtual void BlitFramebuffer( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter ) = 0;
+
+  virtual void RenderbufferStorageMultisample( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height ) = 0;
+
+  virtual void FramebufferTextureLayer( GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer ) = 0;
+
+  virtual GLvoid* MapBufferRange( GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access ) = 0;
+
+  virtual void FlushMappedBufferRange( GLenum target, GLintptr offset, GLsizeiptr length ) = 0;
+
+  virtual void BindVertexArray( GLuint array ) = 0;
+
+  virtual void DeleteVertexArrays( GLsizei n, const GLuint* arrays ) = 0;
+
+  virtual void GenVertexArrays( GLsizei n, GLuint* arrays ) = 0;
+
+  virtual GLboolean IsVertexArray( GLuint array ) = 0;
+
+  virtual void GetIntegeri_v( GLenum target, GLuint index, GLint* data ) = 0;
+
+  virtual void BeginTransformFeedback( GLenum primitiveMode ) = 0;
+
+  virtual void EndTransformFeedback( void ) = 0;
+
+  virtual void BindBufferRange( GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size ) = 0;
+
+  virtual void BindBufferBase( GLenum target, GLuint index, GLuint buffer ) = 0;
+
+  virtual void TransformFeedbackVaryings( GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode ) = 0;
+
+  virtual void GetTransformFeedbackVarying( GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name ) = 0;
+
+  virtual void VertexAttribIPointer( GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer ) = 0;
+
+  virtual void GetVertexAttribIiv( GLuint index, GLenum pname, GLint* params ) = 0;
+
+  virtual void GetVertexAttribIuiv( GLuint index, GLenum pname, GLuint* params ) = 0;
+
+  virtual void VertexAttribI4i( GLuint index, GLint x, GLint y, GLint z, GLint w ) = 0;
+
+  virtual void VertexAttribI4ui( GLuint index, GLuint x, GLuint y, GLuint z, GLuint w ) = 0;
+
+  virtual void VertexAttribI4iv( GLuint index, const GLint* v ) = 0;
+
+  virtual void VertexAttribI4uiv( GLuint index, const GLuint* v ) = 0;
+
+  virtual void GetUniformuiv( GLuint program, GLint location, GLuint* params ) = 0;
+
+  virtual GLint GetFragDataLocation( GLuint program, const GLchar *name ) = 0;
+
+  virtual void Uniform1ui( GLint location, GLuint v0 ) = 0;
+
+  virtual void Uniform2ui( GLint location, GLuint v0, GLuint v1 ) = 0;
+
+  virtual void Uniform3ui( GLint location, GLuint v0, GLuint v1, GLuint v2 ) = 0;
+
+  virtual void Uniform4ui( GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3 ) = 0;
+
+  virtual void Uniform1uiv( GLint location, GLsizei count, const GLuint* value ) = 0;
+
+  virtual void Uniform2uiv( GLint location, GLsizei count, const GLuint* value ) = 0;
+
+  virtual void Uniform3uiv( GLint location, GLsizei count, const GLuint* value ) = 0;
+
+  virtual void Uniform4uiv( GLint location, GLsizei count, const GLuint* value ) = 0;
+
+  virtual void ClearBufferiv( GLenum buffer, GLint drawbuffer, const GLint* value ) = 0;
+
+  virtual void ClearBufferuiv( GLenum buffer, GLint drawbuffer, const GLuint* value ) = 0;
+
+  virtual void ClearBufferfv( GLenum buffer, GLint drawbuffer, const GLfloat* value ) = 0;
+
+  virtual void ClearBufferfi( GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil ) = 0;
+
+  virtual const GLubyte* GetStringi( GLenum name, GLuint index ) = 0;
+
+  virtual void CopyBufferSubData( GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size ) = 0;
+
+  virtual void GetUniformIndices( GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices ) = 0;
+
+  virtual void GetActiveUniformsiv( GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params ) = 0;
+
+  virtual GLuint GetUniformBlockIndex( GLuint program, const GLchar* uniformBlockName ) = 0;
+
+  virtual void GetActiveUniformBlockiv( GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params ) = 0;
+
+  virtual void GetActiveUniformBlockName( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName ) = 0;
+
+  virtual void UniformBlockBinding( GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding ) = 0;
+
+  virtual void DrawArraysInstanced( GLenum mode, GLint first, GLsizei count, GLsizei instanceCount ) = 0;
+
+  virtual void DrawElementsInstanced( GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount ) = 0;
+
+  virtual GLsync FenceSync( GLenum condition, GLbitfield flags ) = 0;
+
+  virtual GLboolean IsSync( GLsync sync ) = 0;
+
+  virtual void DeleteSync( GLsync sync ) = 0;
+
+  virtual GLenum ClientWaitSync( GLsync sync, GLbitfield flags, GLuint64 timeout ) = 0;
+
+  virtual void WaitSync( GLsync sync, GLbitfield flags, GLuint64 timeout ) = 0;
+
+  virtual void GetInteger64v( GLenum pname, GLint64* params ) = 0;
+
+  virtual void GetSynciv( GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values ) = 0;
+
+  virtual void GetInteger64i_v( GLenum target, GLuint index, GLint64* data ) = 0;
+
+  virtual void GetBufferParameteri64v( GLenum target, GLenum pname, GLint64* params ) = 0;
+
+  virtual void GenSamplers( GLsizei count, GLuint* samplers ) = 0;
+
+  virtual void DeleteSamplers( GLsizei count, const GLuint* samplers ) = 0;
+
+  virtual GLboolean IsSampler( GLuint sampler ) = 0;
+
+  virtual void BindSampler( GLuint unit, GLuint sampler ) = 0;
+
+  virtual void SamplerParameteri( GLuint sampler, GLenum pname, GLint param ) = 0;
+
+  virtual void SamplerParameteriv( GLuint sampler, GLenum pname, const GLint* param ) = 0;
+
+  virtual void SamplerParameterf( GLuint sampler, GLenum pname, GLfloat param ) = 0;
+
+  virtual void SamplerParameterfv( GLuint sampler, GLenum pname, const GLfloat* param ) = 0;
+
+  virtual void GetSamplerParameteriv( GLuint sampler, GLenum pname, GLint* params ) = 0;
+
+  virtual void GetSamplerParameterfv( GLuint sampler, GLenum pname, GLfloat* params ) = 0;
+
+  virtual void VertexAttribDivisor( GLuint index, GLuint divisor ) = 0;
+
+  virtual void BindTransformFeedback( GLenum target, GLuint id ) = 0;
+
+  virtual void DeleteTransformFeedbacks( GLsizei n, const GLuint* ids ) = 0;
+
+  virtual void GenTransformFeedbacks( GLsizei n, GLuint* ids ) = 0;
+
+  virtual GLboolean IsTransformFeedback( GLuint id ) = 0;
+
+  virtual void PauseTransformFeedback( void ) = 0;
+
+  virtual void ResumeTransformFeedback( void ) = 0;
+
+  virtual void GetProgramBinary( GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary ) = 0;
+
+  virtual void ProgramBinary( GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length ) = 0;
+
+  virtual void ProgramParameteri( GLuint program, GLenum pname, GLint value ) = 0;
+
+  virtual void InvalidateFramebuffer( GLenum target, GLsizei numAttachments, const GLenum* attachments ) = 0;
+
+  virtual void InvalidateSubFramebuffer( GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height ) = 0;
+
+  virtual void TexStorage2D( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height ) = 0;
+
+  virtual void TexStorage3D( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth ) = 0;
+
+  virtual void GetInternalformativ( GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params ) = 0;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_GLES_ABSTRACTION_H
diff --git a/dali/internal/graphics/gles/gles2-implementation.h b/dali/internal/graphics/gles/gles2-implementation.h
new file mode 100644 (file)
index 0000000..5bab59b
--- /dev/null
@@ -0,0 +1,587 @@
+#ifndef DALI_INTERNAL_GLES2_IMPLEMENTATION_H
+#define DALI_INTERNAL_GLES2_IMPLEMENTATION_H
+
+/*
+ * Copyright (c) 2019 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/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/gles/gl-extensions.h>
+#include <dali/internal/graphics/gles/gles-abstraction.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class Gles2Implementation : public GlesAbstraction
+{
+
+public:
+  Gles2Implementation() {}
+
+  ~Gles2Implementation() override {}
+
+  void ReadBuffer( GLenum mode ) override
+  {
+    DALI_LOG_ERROR( "glReadBuffer is not supported in OpenGL es 2.0\n" );
+  }
+
+  void DrawRangeElements( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices ) override
+  {
+    DALI_LOG_ERROR( "glDrawRangeElements is not supported in OpenGL es 2.0\n" );
+  }
+
+  void TexImage3D( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels ) override
+  {
+    DALI_LOG_ERROR( "glTexImage3D is not supported in OpenGL es 2.0\n" );
+  }
+
+  void TexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels ) override
+  {
+    DALI_LOG_ERROR( "glTexSubImage3D is not supported in OpenGL es 2.0\n" );
+  }
+
+  void CopyTexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height ) override
+  {
+    DALI_LOG_ERROR( "glCopyTexSubImage3D is not supported in OpenGL es 2.0\n" );
+  }
+
+  void CompressedTexImage3D( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data ) override
+  {
+    DALI_LOG_ERROR( "glCompressedTexImage3D is not supported in OpenGL es 2.0\n" );
+  }
+
+  void CompressedTexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data ) override
+  {
+    DALI_LOG_ERROR( "glCompressedTexSubImage3D is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GenQueries( GLsizei n, GLuint* ids ) override
+  {
+    DALI_LOG_ERROR( "glGenQueries is not supported in OpenGL es 2.0\n" );
+  }
+
+  void DeleteQueries( GLsizei n, const GLuint* ids ) override
+  {
+    DALI_LOG_ERROR( "glDeleteQueries is not supported in OpenGL es 2.0\n" );
+  }
+
+  GLboolean IsQuery( GLuint id ) override
+  {
+    DALI_LOG_ERROR( "glIsQuery is not supported in OpenGL es 2.0\n" );
+    return 0;
+  }
+
+  void BeginQuery( GLenum target, GLuint id ) override
+  {
+    DALI_LOG_ERROR( "glBeginQuery is not supported in OpenGL es 2.0\n" );
+  }
+
+  void EndQuery( GLenum target ) override
+  {
+    DALI_LOG_ERROR( "glEndQuery is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GetQueryiv( GLenum target, GLenum pname, GLint* params ) override
+  {
+    DALI_LOG_ERROR( "glGetQueryiv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GetQueryObjectuiv( GLuint id, GLenum pname, GLuint* params ) override
+  {
+    DALI_LOG_ERROR( "glGetQueryObjectuiv is not supported in OpenGL es 2.0\n" );
+  }
+
+  GLboolean UnmapBuffer( GLenum target ) override
+  {
+    DALI_LOG_ERROR( "glUnmapBuffer is not supported in OpenGL es 2.0\n" );
+    return 0;
+  }
+
+  void GetBufferPointerv( GLenum target, GLenum pname, GLvoid** params ) override
+  {
+    DALI_LOG_ERROR( "glGetBufferPointerv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void DrawBuffers( GLsizei n, const GLenum* bufs ) override
+  {
+    DALI_LOG_ERROR( "glDrawBuffers is not supported in OpenGL es 2.0\n" );
+  }
+
+  void UniformMatrix2x3fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) override
+  {
+    DALI_LOG_ERROR( "glUniformMatrix2x3fv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void UniformMatrix3x2fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) override
+  {
+    DALI_LOG_ERROR( "glUniformMatrix3x2fv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void UniformMatrix2x4fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) override
+  {
+    DALI_LOG_ERROR( "glUniformMatrix2x4fv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void UniformMatrix4x2fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) override
+  {
+    DALI_LOG_ERROR( "glUniformMatrix4x2fv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void UniformMatrix3x4fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) override
+  {
+    DALI_LOG_ERROR( "glUniformMatrix3x4fv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void UniformMatrix4x3fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) override
+  {
+    DALI_LOG_ERROR( "glUniformMatrix4x3fv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void BlitFramebuffer( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter ) override
+  {
+    DALI_LOG_ERROR( "glBlitFramebuffer is not supported in OpenGL es 2.0\n" );
+  }
+
+  void RenderbufferStorageMultisample( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height ) override
+  {
+    DALI_LOG_ERROR( "glRenderbufferStorageMultisample is not supported in OpenGL es 2.0\n" );
+  }
+
+  void FramebufferTextureLayer( GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer ) override
+  {
+    DALI_LOG_ERROR( "glFramebufferTextureLayer is not supported in OpenGL es 2.0\n" );
+  }
+
+  GLvoid* MapBufferRange( GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access ) override
+  {
+    DALI_LOG_ERROR( "glMapBufferRange is not supported in OpenGL es 2.0\n" );
+    return NULL;
+  }
+
+  void FlushMappedBufferRange( GLenum target, GLintptr offset, GLsizeiptr length ) override
+  {
+    DALI_LOG_ERROR( "glFlushMappedBufferRange is not supported in OpenGL es 2.0\n" );
+  }
+
+  void BindVertexArray( GLuint array ) override
+  {
+    DALI_LOG_ERROR( "glBindVertexArray is not supported in OpenGL es 2.0\n" );
+  }
+
+  void DeleteVertexArrays( GLsizei n, const GLuint* arrays ) override
+  {
+    DALI_LOG_ERROR( "glDeleteVertexArrays is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GenVertexArrays( GLsizei n, GLuint* arrays ) override
+  {
+    DALI_LOG_ERROR( "glGenVertexArrays is not supported in OpenGL es 2.0\n" );
+  }
+
+  GLboolean IsVertexArray( GLuint array ) override
+  {
+    DALI_LOG_ERROR( "glIsVertexArray is not supported in OpenGL es 2.0\n" );
+    return 0;
+  }
+
+  void GetIntegeri_v( GLenum target, GLuint index, GLint* data ) override
+  {
+    DALI_LOG_ERROR( "glGetIntegeri_v is not supported in OpenGL es 2.0\n" );
+  }
+
+  void BeginTransformFeedback( GLenum primitiveMode ) override
+  {
+    DALI_LOG_ERROR( "glBeginTransformFeedback is not supported in OpenGL es 2.0\n" );
+  }
+
+  void EndTransformFeedback( void ) override
+  {
+    DALI_LOG_ERROR( "glEndTransformFeedback is not supported in OpenGL es 2.0\n" );
+  }
+
+  void BindBufferRange( GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size ) override
+  {
+    DALI_LOG_ERROR( "glBindBufferRange is not supported in OpenGL es 2.0\n" );
+  }
+
+  void BindBufferBase( GLenum target, GLuint index, GLuint buffer ) override
+  {
+    DALI_LOG_ERROR( "glBindBufferBase is not supported in OpenGL es 2.0\n" );
+  }
+
+  void TransformFeedbackVaryings( GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode ) override
+  {
+    DALI_LOG_ERROR( "glTransformFeedbackVaryings is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GetTransformFeedbackVarying( GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name ) override
+  {
+    DALI_LOG_ERROR( "glGetTransformFeedbackVarying is not supported in OpenGL es 2.0\n" );
+  }
+
+  void VertexAttribIPointer( GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer ) override
+  {
+    DALI_LOG_ERROR( "glVertexAttribIPointer is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GetVertexAttribIiv( GLuint index, GLenum pname, GLint* params ) override
+  {
+    DALI_LOG_ERROR( "glGetVertexAttribIiv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GetVertexAttribIuiv( GLuint index, GLenum pname, GLuint* params ) override
+  {
+    DALI_LOG_ERROR( "glGetVertexAttribIuiv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void VertexAttribI4i( GLuint index, GLint x, GLint y, GLint z, GLint w ) override
+  {
+    DALI_LOG_ERROR( "glVertexAttribI4i is not supported in OpenGL es 2.0\n" );
+  }
+
+  void VertexAttribI4ui( GLuint index, GLuint x, GLuint y, GLuint z, GLuint w ) override
+  {
+    DALI_LOG_ERROR( "glVertexAttribI4ui is not supported in OpenGL es 2.0\n" );
+  }
+
+  void VertexAttribI4iv( GLuint index, const GLint* v ) override
+  {
+    DALI_LOG_ERROR( "glVertexAttribI4iv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void VertexAttribI4uiv( GLuint index, const GLuint* v ) override
+  {
+    DALI_LOG_ERROR( "glVertexAttribI4uiv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GetUniformuiv( GLuint program, GLint location, GLuint* params ) override
+  {
+    DALI_LOG_ERROR( "glGetUniformuiv is not supported in OpenGL es 2.0\n" );
+  }
+
+  GLint GetFragDataLocation( GLuint program, const GLchar *name ) override
+  {
+    DALI_LOG_ERROR( "glGetFragDataLocation is not supported in OpenGL es 2.0\n" );
+    return -1;
+  }
+
+  void Uniform1ui( GLint location, GLuint v0 ) override
+  {
+    DALI_LOG_ERROR( "glUniform1ui is not supported in OpenGL es 2.0\n" );
+  }
+
+  void Uniform2ui( GLint location, GLuint v0, GLuint v1 ) override
+  {
+    DALI_LOG_ERROR( "glUniform2ui is not supported in OpenGL es 2.0\n" );
+  }
+
+  void Uniform3ui( GLint location, GLuint v0, GLuint v1, GLuint v2 ) override
+  {
+    DALI_LOG_ERROR( "glUniform3ui is not supported in OpenGL es 2.0\n" );
+  }
+
+  void Uniform4ui( GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3 ) override
+  {
+    DALI_LOG_ERROR( "glUniform4ui is not supported in OpenGL es 2.0\n" );
+  }
+
+  void Uniform1uiv( GLint location, GLsizei count, const GLuint* value ) override
+  {
+    DALI_LOG_ERROR( "glUniform1uiv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void Uniform2uiv( GLint location, GLsizei count, const GLuint* value ) override
+  {
+    DALI_LOG_ERROR( "glUniform2uiv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void Uniform3uiv( GLint location, GLsizei count, const GLuint* value ) override
+  {
+    DALI_LOG_ERROR( "glUniform3uiv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void Uniform4uiv( GLint location, GLsizei count, const GLuint* value ) override
+  {
+    DALI_LOG_ERROR( "glUniform4uiv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void ClearBufferiv( GLenum buffer, GLint drawbuffer, const GLint* value ) override
+  {
+    DALI_LOG_ERROR( "glClearBufferiv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void ClearBufferuiv( GLenum buffer, GLint drawbuffer, const GLuint* value ) override
+  {
+    DALI_LOG_ERROR( "glClearBufferuiv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void ClearBufferfv( GLenum buffer, GLint drawbuffer, const GLfloat* value ) override
+  {
+    DALI_LOG_ERROR( "glClearBufferfv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void ClearBufferfi( GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil ) override
+  {
+    DALI_LOG_ERROR( "glClearBufferfi is not supported in OpenGL es 2.0\n" );
+  }
+
+  const GLubyte* GetStringi( GLenum name, GLuint index ) override
+  {
+    DALI_LOG_ERROR( "glGetStringi is not supported in OpenGL es 2.0\n" );
+    return NULL;
+  }
+
+  void CopyBufferSubData( GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size ) override
+  {
+    DALI_LOG_ERROR( "glCopyBufferSubData is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GetUniformIndices( GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices ) override
+  {
+    DALI_LOG_ERROR( "glGetUniformIndices is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GetActiveUniformsiv( GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params ) override
+  {
+    DALI_LOG_ERROR( "glGetActiveUniformsiv is not supported in OpenGL es 2.0\n" );
+  }
+
+  GLuint GetUniformBlockIndex( GLuint program, const GLchar* uniformBlockName ) override
+  {
+    DALI_LOG_ERROR( "glGetUniformBlockIndex is not supported in OpenGL es 2.0\n" );
+    return 0;
+  }
+
+  void GetActiveUniformBlockiv( GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params ) override
+  {
+    DALI_LOG_ERROR( "glGetActiveUniformBlockiv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GetActiveUniformBlockName( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName ) override
+  {
+    DALI_LOG_ERROR( "glGetActiveUniformBlockName is not supported in OpenGL es 2.0\n" );
+  }
+
+  void UniformBlockBinding( GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding ) override
+  {
+    DALI_LOG_ERROR( "glUniformBlockBinding is not supported in OpenGL es 2.0\n" );
+  }
+
+  void DrawArraysInstanced( GLenum mode, GLint first, GLsizei count, GLsizei instanceCount ) override
+  {
+    DALI_LOG_ERROR( "glDrawArraysInstanced is not supported in OpenGL es 2.0\n" );
+  }
+
+  void DrawElementsInstanced( GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount ) override
+  {
+    DALI_LOG_ERROR( "glDrawElementsInstanced is not supported in OpenGL es 2.0\n" );
+  }
+
+  GLsync FenceSync( GLenum condition, GLbitfield flags ) override
+  {
+    DALI_LOG_ERROR( "glFenceSync is not supported in OpenGL es 2.0\n" );
+    return NULL;
+  }
+
+  GLboolean IsSync( GLsync sync ) override
+  {
+    DALI_LOG_ERROR( "glIsSync is not supported in OpenGL es 2.0\n" );
+    return 0;
+  }
+
+  void DeleteSync( GLsync sync ) override
+  {
+    DALI_LOG_ERROR( "glDeleteSync is not supported in OpenGL es 2.0\n" );
+  }
+
+  GLenum ClientWaitSync( GLsync sync, GLbitfield flags, GLuint64 timeout ) override
+  {
+    DALI_LOG_ERROR( "glClientWaitSync is not supported in OpenGL es 2.0\n" );
+    return 0;
+  }
+
+  void WaitSync( GLsync sync, GLbitfield flags, GLuint64 timeout ) override
+  {
+    DALI_LOG_ERROR( "glWaitSync is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GetInteger64v( GLenum pname, GLint64* params ) override
+  {
+    DALI_LOG_ERROR( "glGetInteger64v is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GetSynciv( GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values ) override
+  {
+    DALI_LOG_ERROR( "glGetSynciv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GetInteger64i_v( GLenum target, GLuint index, GLint64* data ) override
+  {
+    DALI_LOG_ERROR( "glGetInteger64i_v is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GetBufferParameteri64v( GLenum target, GLenum pname, GLint64* params ) override
+  {
+    DALI_LOG_ERROR( "glGetBufferParameteri64v is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GenSamplers( GLsizei count, GLuint* samplers ) override
+  {
+    DALI_LOG_ERROR( "glGenSamplers is not supported in OpenGL es 2.0\n" );
+  }
+
+  void DeleteSamplers( GLsizei count, const GLuint* samplers ) override
+  {
+    DALI_LOG_ERROR( "glDeleteSamplers is not supported in OpenGL es 2.0\n" );
+  }
+
+  GLboolean IsSampler( GLuint sampler ) override
+  {
+    DALI_LOG_ERROR( "glIsSampler is not supported in OpenGL es 2.0\n" );
+    return 0;
+  }
+
+  void BindSampler( GLuint unit, GLuint sampler ) override
+  {
+    DALI_LOG_ERROR( "glBindSampler is not supported in OpenGL es 2.0\n" );
+  }
+
+  void SamplerParameteri( GLuint sampler, GLenum pname, GLint param ) override
+  {
+    DALI_LOG_ERROR( "glSamplerParameteri is not supported in OpenGL es 2.0\n" );
+  }
+
+  void SamplerParameteriv( GLuint sampler, GLenum pname, const GLint* param ) override
+  {
+    DALI_LOG_ERROR( "glSamplerParameteriv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void SamplerParameterf( GLuint sampler, GLenum pname, GLfloat param ) override
+  {
+    DALI_LOG_ERROR( "glSamplerParameterf is not supported in OpenGL es 2.0\n" );
+  }
+
+  void SamplerParameterfv( GLuint sampler, GLenum pname, const GLfloat* param ) override
+  {
+    DALI_LOG_ERROR( "glSamplerParameterfv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GetSamplerParameteriv( GLuint sampler, GLenum pname, GLint* params ) override
+  {
+    DALI_LOG_ERROR( "glGetSamplerParameteriv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GetSamplerParameterfv( GLuint sampler, GLenum pname, GLfloat* params ) override
+  {
+    DALI_LOG_ERROR( "glGetSamplerParameterfv is not supported in OpenGL es 2.0\n" );
+  }
+
+  void VertexAttribDivisor( GLuint index, GLuint divisor ) override
+  {
+    DALI_LOG_ERROR( "glVertexAttribDivisor is not supported in OpenGL es 2.0\n" );
+  }
+
+  void BindTransformFeedback( GLenum target, GLuint id ) override
+  {
+    DALI_LOG_ERROR( "glBindTransformFeedback is not supported in OpenGL es 2.0\n" );
+  }
+
+  void DeleteTransformFeedbacks( GLsizei n, const GLuint* ids ) override
+  {
+    DALI_LOG_ERROR( "glDeleteTransformFeedbacks is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GenTransformFeedbacks( GLsizei n, GLuint* ids ) override
+  {
+    DALI_LOG_ERROR( "glGenTransformFeedbacks is not supported in OpenGL es 2.0\n" );
+  }
+
+  GLboolean IsTransformFeedback( GLuint id ) override
+  {
+    DALI_LOG_ERROR( "glIsTransformFeedback is not supported in OpenGL es 2.0\n" );
+    return 0;
+  }
+
+  void PauseTransformFeedback( void ) override
+  {
+    DALI_LOG_ERROR( "glPauseTransformFeedback is not supported in OpenGL es 2.0\n" );
+  }
+
+  void ResumeTransformFeedback( void ) override
+  {
+    DALI_LOG_ERROR( "glResumeTransformFeedback is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GetProgramBinary( GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary ) override
+  {
+    mGlExtensions.GetProgramBinaryOES( program, bufSize, length, binaryFormat, binary );
+  }
+
+  void ProgramBinary( GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length ) override
+  {
+    mGlExtensions.ProgramBinaryOES( program, binaryFormat, binary, length );
+  }
+
+  void ProgramParameteri( GLuint program, GLenum pname, GLint value ) override
+  {
+    DALI_LOG_ERROR( "glProgramParameteri is not supported in OpenGL es 2.0\n" );
+  }
+
+  void InvalidateFramebuffer( GLenum target, GLsizei numAttachments, const GLenum* attachments ) override
+  {
+    mGlExtensions.DiscardFrameBuffer( target, numAttachments, attachments );
+  }
+
+  void InvalidateSubFramebuffer( GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height ) override
+  {
+    DALI_LOG_ERROR( "glInvalidateSubFramebuffer is not supported in OpenGL es 2.0\n" );
+  }
+
+  void TexStorage2D( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height ) override
+  {
+    DALI_LOG_ERROR( "glTexStorage2D is not supported in OpenGL es 2.0\n" );
+  }
+
+  void TexStorage3D( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth ) override
+  {
+    DALI_LOG_ERROR( "glTexStorage3D is not supported in OpenGL es 2.0\n" );
+  }
+
+  void GetInternalformativ( GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params ) override
+  {
+    DALI_LOG_ERROR( "glGetInternalformativ is not supported in OpenGL es 2.0\n" );
+  }
+
+private:
+  ECoreX::GlExtensions mGlExtensions;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_GLES2_IMPLEMENTATION_H
diff --git a/dali/internal/graphics/gles/gles3-implementation.h b/dali/internal/graphics/gles/gles3-implementation.h
new file mode 100644 (file)
index 0000000..ace3849
--- /dev/null
@@ -0,0 +1,571 @@
+#ifndef DALI_INTERNAL_GLES3_IMPLEMENTATION_H
+#define DALI_INTERNAL_GLES3_IMPLEMENTATION_H
+
+/*
+ * Copyright (c) 2019 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 <GLES3/gl3.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/gles/gles-abstraction.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class Gles3Implementation : public GlesAbstraction
+{
+
+public:
+  Gles3Implementation() {}
+
+  ~Gles3Implementation() override {}
+
+  void ReadBuffer( GLenum mode ) override
+  {
+    glReadBuffer( mode );
+  }
+
+  void DrawRangeElements( GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices ) override
+  {
+    glDrawRangeElements( mode, start, end, count, type, indices );
+  }
+
+  void TexImage3D( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels ) override
+  {
+    glTexImage3D( target, level, internalformat, width, height, depth, border, format, type, pixels );
+  }
+
+  void TexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels ) override
+  {
+    glTexSubImage3D( target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels );
+  }
+
+  void CopyTexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height ) override
+  {
+    glCopyTexSubImage3D( target, level, xoffset, yoffset, zoffset, x, y, width, height );
+  }
+
+  void CompressedTexImage3D( GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data ) override
+  {
+    glCompressedTexImage3D( target, level, internalformat, width, height, depth, border, imageSize, data );
+  }
+
+  void CompressedTexSubImage3D( GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data ) override
+  {
+    glCompressedTexSubImage3D( target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data );
+  }
+
+  void GenQueries( GLsizei n, GLuint* ids ) override
+  {
+    glGenQueries( n, ids );
+  }
+
+  void DeleteQueries( GLsizei n, const GLuint* ids ) override
+  {
+    glDeleteQueries( n, ids );
+  }
+
+  GLboolean IsQuery( GLuint id ) override
+  {
+    return glIsQuery( id );
+  }
+
+  void BeginQuery( GLenum target, GLuint id ) override
+  {
+    glBeginQuery( target, id );
+  }
+
+  void EndQuery( GLenum target ) override
+  {
+    glEndQuery( target );
+  }
+
+  void GetQueryiv( GLenum target, GLenum pname, GLint* params ) override
+  {
+    glGetQueryiv( target, pname, params );
+  }
+
+  void GetQueryObjectuiv( GLuint id, GLenum pname, GLuint* params ) override
+  {
+    glGetQueryObjectuiv( id, pname, params );
+  }
+
+  GLboolean UnmapBuffer( GLenum target ) override
+  {
+    return glUnmapBuffer( target );
+  }
+
+  void GetBufferPointerv( GLenum target, GLenum pname, GLvoid** params ) override
+  {
+    glGetBufferPointerv( target, pname, params );
+  }
+
+  void DrawBuffers( GLsizei n, const GLenum* bufs ) override
+  {
+    glDrawBuffers( n, bufs );
+  }
+
+  void UniformMatrix2x3fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) override
+  {
+    glUniformMatrix2x3fv( location, count, transpose, value );
+  }
+
+  void UniformMatrix3x2fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) override
+  {
+    glUniformMatrix3x2fv( location, count, transpose, value );
+  }
+
+  void UniformMatrix2x4fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) override
+  {
+    glUniformMatrix2x4fv( location, count, transpose, value );
+  }
+
+  void UniformMatrix4x2fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) override
+  {
+    glUniformMatrix4x2fv( location, count, transpose, value );
+  }
+
+  void UniformMatrix3x4fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) override
+  {
+    glUniformMatrix3x4fv( location, count, transpose, value );
+  }
+
+  void UniformMatrix4x3fv( GLint location, GLsizei count, GLboolean transpose, const GLfloat* value ) override
+  {
+    glUniformMatrix4x3fv( location, count, transpose, value );
+  }
+
+  void BlitFramebuffer( GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter ) override
+  {
+    glBlitFramebuffer( srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter );
+  }
+
+  void RenderbufferStorageMultisample( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height ) override
+  {
+    glRenderbufferStorageMultisample( target, samples, internalformat, width, height );
+  }
+
+  void FramebufferTextureLayer( GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer ) override
+  {
+    glFramebufferTextureLayer( target, attachment, texture, level, layer );
+  }
+
+  GLvoid* MapBufferRange( GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access ) override
+  {
+    return glMapBufferRange( target, offset, length, access );
+  }
+
+  void FlushMappedBufferRange( GLenum target, GLintptr offset, GLsizeiptr length ) override
+  {
+    glFlushMappedBufferRange( target, offset, length );
+  }
+
+  void BindVertexArray( GLuint array ) override
+  {
+    glBindVertexArray( array );
+  }
+
+  void DeleteVertexArrays( GLsizei n, const GLuint* arrays ) override
+  {
+    glDeleteVertexArrays( n, arrays );
+  }
+
+  void GenVertexArrays( GLsizei n, GLuint* arrays ) override
+  {
+    glGenVertexArrays( n, arrays );
+  }
+
+  GLboolean IsVertexArray( GLuint array ) override
+  {
+    return glIsVertexArray( array );
+  }
+
+  void GetIntegeri_v( GLenum target, GLuint index, GLint* data ) override
+  {
+    glGetIntegeri_v( target, index, data );
+  }
+
+  void BeginTransformFeedback( GLenum primitiveMode ) override
+  {
+    glBeginTransformFeedback( primitiveMode );
+  }
+
+  void EndTransformFeedback( void ) override
+  {
+    glEndTransformFeedback();
+  }
+
+  void BindBufferRange( GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size ) override
+  {
+    glBindBufferRange( target, index, buffer, offset, size );
+  }
+
+  void BindBufferBase( GLenum target, GLuint index, GLuint buffer ) override
+  {
+    glBindBufferBase( target, index, buffer );
+  }
+
+  void TransformFeedbackVaryings( GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode ) override
+  {
+    glTransformFeedbackVaryings( program, count, varyings, bufferMode );
+  }
+
+  void GetTransformFeedbackVarying( GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name ) override
+  {
+    glGetTransformFeedbackVarying( program, index, bufSize, length, size, type, name );
+  }
+
+  void VertexAttribIPointer( GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer ) override
+  {
+    glVertexAttribIPointer( index, size, type, stride, pointer );
+  }
+
+  void GetVertexAttribIiv( GLuint index, GLenum pname, GLint* params ) override
+  {
+    glGetVertexAttribIiv( index, pname, params );
+  }
+
+  void GetVertexAttribIuiv( GLuint index, GLenum pname, GLuint* params ) override
+  {
+    glGetVertexAttribIuiv( index, pname, params );
+  }
+
+  void VertexAttribI4i( GLuint index, GLint x, GLint y, GLint z, GLint w ) override
+  {
+    glVertexAttribI4i( index, x, y, z, w );
+  }
+
+  void VertexAttribI4ui( GLuint index, GLuint x, GLuint y, GLuint z, GLuint w ) override
+  {
+    glVertexAttribI4ui( index, x, y, z, w );
+  }
+
+  void VertexAttribI4iv( GLuint index, const GLint* v ) override
+  {
+    glVertexAttribI4iv( index, v );
+  }
+
+  void VertexAttribI4uiv( GLuint index, const GLuint* v ) override
+  {
+    glVertexAttribI4uiv( index, v );
+  }
+
+  void GetUniformuiv( GLuint program, GLint location, GLuint* params ) override
+  {
+    glGetUniformuiv( program, location, params );
+  }
+
+  GLint GetFragDataLocation( GLuint program, const GLchar *name ) override
+  {
+    return glGetFragDataLocation( program, name );
+  }
+
+  void Uniform1ui( GLint location, GLuint v0 ) override
+  {
+    glUniform1ui( location, v0 );
+  }
+
+  void Uniform2ui( GLint location, GLuint v0, GLuint v1 ) override
+  {
+    glUniform2ui( location, v0, v1 );
+  }
+
+  void Uniform3ui( GLint location, GLuint v0, GLuint v1, GLuint v2 ) override
+  {
+    glUniform3ui( location, v0, v1, v2 );
+  }
+
+  void Uniform4ui( GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3 ) override
+  {
+    glUniform4ui( location, v0, v1, v2, v3 );
+  }
+
+  void Uniform1uiv( GLint location, GLsizei count, const GLuint* value ) override
+  {
+    glUniform1uiv( location, count, value );
+  }
+
+  void Uniform2uiv( GLint location, GLsizei count, const GLuint* value ) override
+  {
+    glUniform2uiv( location, count, value );
+  }
+
+  void Uniform3uiv( GLint location, GLsizei count, const GLuint* value ) override
+  {
+    glUniform3uiv( location, count, value );
+  }
+
+  void Uniform4uiv( GLint location, GLsizei count, const GLuint* value ) override
+  {
+    glUniform4uiv( location, count, value );
+  }
+
+  void ClearBufferiv( GLenum buffer, GLint drawbuffer, const GLint* value ) override
+  {
+    glClearBufferiv( buffer, drawbuffer, value );
+  }
+
+  void ClearBufferuiv( GLenum buffer, GLint drawbuffer, const GLuint* value ) override
+  {
+    glClearBufferuiv( buffer, drawbuffer, value );
+  }
+
+  void ClearBufferfv( GLenum buffer, GLint drawbuffer, const GLfloat* value ) override
+  {
+    glClearBufferfv( buffer, drawbuffer, value );
+  }
+
+  void ClearBufferfi( GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil ) override
+  {
+    glClearBufferfi( buffer, drawbuffer, depth, stencil );
+  }
+
+  const GLubyte* GetStringi( GLenum name, GLuint index ) override
+  {
+    return glGetStringi( name, index );
+  }
+
+  void CopyBufferSubData( GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size ) override
+  {
+    glCopyBufferSubData( readTarget, writeTarget, readOffset, writeOffset, size );
+  }
+
+  void GetUniformIndices( GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices ) override
+  {
+    glGetUniformIndices( program, uniformCount, uniformNames, uniformIndices );
+  }
+
+  void GetActiveUniformsiv( GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params ) override
+  {
+    glGetActiveUniformsiv( program, uniformCount, uniformIndices, pname, params );
+  }
+
+  GLuint GetUniformBlockIndex( GLuint program, const GLchar* uniformBlockName ) override
+  {
+    return glGetUniformBlockIndex( program, uniformBlockName );
+  }
+
+  void GetActiveUniformBlockiv( GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params ) override
+  {
+    glGetActiveUniformBlockiv( program, uniformBlockIndex, pname, params );
+  }
+
+  void GetActiveUniformBlockName( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName ) override
+  {
+    glGetActiveUniformBlockName( program, uniformBlockIndex, bufSize, length, uniformBlockName );
+  }
+
+  void UniformBlockBinding( GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding ) override
+  {
+    glUniformBlockBinding( program, uniformBlockIndex, uniformBlockBinding );
+  }
+
+  void DrawArraysInstanced( GLenum mode, GLint first, GLsizei count, GLsizei instanceCount ) override
+  {
+    glDrawArraysInstanced( mode, first, count, instanceCount );
+  }
+
+  void DrawElementsInstanced( GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount ) override
+  {
+    glDrawElementsInstanced( mode, count, type, indices, instanceCount );
+  }
+
+  GLsync FenceSync( GLenum condition, GLbitfield flags ) override
+  {
+    return glFenceSync( condition, flags );
+  }
+
+  GLboolean IsSync( GLsync sync ) override
+  {
+    return glIsSync( sync );
+  }
+
+  void DeleteSync( GLsync sync ) override
+  {
+    glDeleteSync( sync );
+  }
+
+  GLenum ClientWaitSync( GLsync sync, GLbitfield flags, GLuint64 timeout ) override
+  {
+    return glClientWaitSync( sync, flags, timeout );
+  }
+
+  void WaitSync( GLsync sync, GLbitfield flags, GLuint64 timeout ) override
+  {
+    glWaitSync( sync, flags, timeout );
+  }
+
+  void GetInteger64v( GLenum pname, GLint64* params ) override
+  {
+    glGetInteger64v( pname, params );
+  }
+
+  void GetSynciv( GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values ) override
+  {
+    glGetSynciv( sync, pname, bufSize, length, values );
+  }
+
+  void GetInteger64i_v( GLenum target, GLuint index, GLint64* data ) override
+  {
+    glGetInteger64i_v( target, index, data );
+  }
+
+  void GetBufferParameteri64v( GLenum target, GLenum pname, GLint64* params ) override
+  {
+    glGetBufferParameteri64v( target, pname, params );
+  }
+
+  void GenSamplers( GLsizei count, GLuint* samplers ) override
+  {
+    glGenSamplers( count, samplers );
+  }
+
+  void DeleteSamplers( GLsizei count, const GLuint* samplers ) override
+  {
+    glDeleteSamplers( count, samplers );
+  }
+
+  GLboolean IsSampler( GLuint sampler ) override
+  {
+    return glIsSampler( sampler );
+  }
+
+  void BindSampler( GLuint unit, GLuint sampler ) override
+  {
+    glBindSampler( unit, sampler );
+  }
+
+  void SamplerParameteri( GLuint sampler, GLenum pname, GLint param ) override
+  {
+    glSamplerParameteri( sampler, pname, param );
+  }
+
+  void SamplerParameteriv( GLuint sampler, GLenum pname, const GLint* param ) override
+  {
+    glSamplerParameteriv( sampler, pname, param );
+  }
+
+  void SamplerParameterf( GLuint sampler, GLenum pname, GLfloat param ) override
+  {
+    glSamplerParameterf( sampler, pname, param );
+  }
+
+  void SamplerParameterfv( GLuint sampler, GLenum pname, const GLfloat* param ) override
+  {
+    glSamplerParameterfv( sampler, pname, param );
+  }
+
+  void GetSamplerParameteriv( GLuint sampler, GLenum pname, GLint* params ) override
+  {
+    glGetSamplerParameteriv( sampler, pname, params );
+  }
+
+  void GetSamplerParameterfv( GLuint sampler, GLenum pname, GLfloat* params ) override
+  {
+    glGetSamplerParameterfv( sampler, pname, params );
+  }
+
+  void VertexAttribDivisor( GLuint index, GLuint divisor ) override
+  {
+    glVertexAttribDivisor( index, divisor );
+  }
+
+  void BindTransformFeedback( GLenum target, GLuint id ) override
+  {
+    glBindTransformFeedback( target, id );
+  }
+
+  void DeleteTransformFeedbacks( GLsizei n, const GLuint* ids ) override
+  {
+    glDeleteTransformFeedbacks( n, ids );
+  }
+
+  void GenTransformFeedbacks( GLsizei n, GLuint* ids ) override
+  {
+    glGenTransformFeedbacks( n, ids );
+  }
+
+  GLboolean IsTransformFeedback( GLuint id ) override
+  {
+    return glIsTransformFeedback( id );
+  }
+
+  void PauseTransformFeedback( void ) override
+  {
+    glPauseTransformFeedback();
+  }
+
+  void ResumeTransformFeedback( void ) override
+  {
+    glResumeTransformFeedback();
+  }
+
+  void GetProgramBinary( GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary ) override
+  {
+    glGetProgramBinary( program, bufSize, length, binaryFormat, binary );
+  }
+
+  void ProgramBinary( GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length ) override
+  {
+    glProgramBinary( program, binaryFormat, binary, length );
+  }
+
+  void ProgramParameteri( GLuint program, GLenum pname, GLint value ) override
+  {
+    glProgramParameteri( program, pname, value );
+  }
+
+  void InvalidateFramebuffer( GLenum target, GLsizei numAttachments, const GLenum* attachments ) override
+  {
+    glInvalidateFramebuffer( target, numAttachments, attachments );
+  }
+
+  void InvalidateSubFramebuffer( GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height ) override
+  {
+    glInvalidateSubFramebuffer( target, numAttachments, attachments, x, y, width, height );
+  }
+
+  void TexStorage2D( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height ) override
+  {
+    glTexStorage2D( target, levels, internalformat, width, height );
+  }
+
+  void TexStorage3D( GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth ) override
+  {
+    glTexStorage3D( target, levels, internalformat, width, height, depth );
+  }
+
+  void GetInternalformativ( GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params ) override
+  {
+    glGetInternalformativ( target, internalformat, pname, bufSize, params );
+  }
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_GLES3_IMPLEMENTATION_H
diff --git a/dali/internal/graphics/tizen/egl-image-extensions-tizen.cpp b/dali/internal/graphics/tizen/egl-image-extensions-tizen.cpp
new file mode 100644 (file)
index 0000000..4d0bf18
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+// CLASS HEADER
+#include <dali/internal/graphics/common/egl-image-extensions.h>
+
+// EXTERNAL INCLUDES
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3.h>
+
+#include <EGL/eglext.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/gles/egl-implementation.h>
+
+// TBM surface support
+#ifndef EGL_NATIVE_SURFACE_TIZEN
+#define EGL_NATIVE_SURFACE_TIZEN 0x32A1
+#endif
+
+namespace
+{
+// function pointers assigned in InitializeEglImageKHR
+PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHRProc = 0;
+PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHRProc = 0;
+PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOESProc = 0;
+} // unnamed namespace
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+EglImageExtensions::EglImageExtensions(EglImplementation* eglImpl)
+: mEglImplementation(eglImpl),
+  mImageKHRInitialized(false),
+  mImageKHRInitializeFailed(false)
+{
+  DALI_ASSERT_ALWAYS( eglImpl && "EGL Implementation not instantiated" );
+}
+
+EglImageExtensions::~EglImageExtensions()
+{
+}
+
+void* EglImageExtensions::CreateImageKHR(EGLClientBuffer clientBuffer)
+{
+  if (mImageKHRInitialized == false)
+  {
+    InitializeEglImageKHR();
+  }
+
+  if (mImageKHRInitialized == false)
+  {
+    return NULL;
+  }
+
+  // Use the EGL image extension
+  const EGLint attribs[] =
+  {
+    EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+    EGL_NONE
+  };
+
+  EGLImageKHR eglImage  = eglCreateImageKHRProc( mEglImplementation->GetDisplay(),
+                                             EGL_NO_CONTEXT,
+                                             EGL_NATIVE_SURFACE_TIZEN,
+                                             clientBuffer,
+                                             attribs );
+
+  if( EGL_NO_IMAGE_KHR == eglImage )
+  {
+    switch( eglGetError() )
+    {
+      case EGL_SUCCESS :
+      {
+        break;
+      }
+      case EGL_BAD_DISPLAY:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_DISPLAY: Invalid EGLDisplay object\n" );
+        break;
+      }
+      case EGL_BAD_CONTEXT:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_CONTEXT: Invalid EGLContext object\n" );
+        break;
+      }
+      case EGL_BAD_PARAMETER:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_PARAMETER: Invalid target parameter or attribute in attrib_list\n" );
+        break;
+      }
+      case EGL_BAD_MATCH:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_MATCH: attrib_list does not match target\n" );
+        break;
+      }
+      case EGL_BAD_ACCESS:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_ACCESS: Previously bound off-screen, or EGLImage sibling error\n" );
+        break;
+      }
+      case EGL_BAD_ALLOC:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_ALLOC: Insufficient memory is available\n" );
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+  DALI_ASSERT_DEBUG( EGL_NO_IMAGE_KHR != eglImage && "EglImageExtensions::CreateImageKHR: eglCreateImageKHR failed!\n");
+
+  return eglImage;
+}
+
+void EglImageExtensions::DestroyImageKHR(void* eglImageKHR)
+{
+  DALI_ASSERT_DEBUG( mImageKHRInitialized );
+
+  if( ! mImageKHRInitialized )
+  {
+    return;
+  }
+
+  if( eglImageKHR == NULL )
+  {
+    return;
+  }
+
+  EGLImageKHR eglImage = static_cast<EGLImageKHR>(eglImageKHR);
+
+  EGLBoolean result = eglDestroyImageKHRProc(mEglImplementation->GetDisplay(), eglImage);
+
+  if( EGL_FALSE == result )
+  {
+    switch( eglGetError() )
+    {
+      case EGL_BAD_DISPLAY:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_DISPLAY: Invalid EGLDisplay object\n" );
+        break;
+      }
+      case EGL_BAD_PARAMETER:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_PARAMETER: eglImage is not a valid EGLImageKHR object created with respect to EGLDisplay\n" );
+        break;
+      }
+      case EGL_BAD_ACCESS:
+      {
+        DALI_LOG_ERROR( "EGL_BAD_ACCESS: EGLImage sibling error\n" );
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+}
+
+void EglImageExtensions::TargetTextureKHR(void* eglImageKHR)
+{
+  DALI_ASSERT_DEBUG( mImageKHRInitialized );
+
+  if( eglImageKHR != NULL )
+  {
+    EGLImageKHR eglImage = static_cast<EGLImageKHR>(eglImageKHR);
+
+#ifdef EGL_ERROR_CHECKING
+    GLint glError = glGetError();
+#endif
+
+    glEGLImageTargetTexture2DOESProc(GL_TEXTURE_EXTERNAL_OES, reinterpret_cast< GLeglImageOES >( eglImage ) );
+
+#ifdef EGL_ERROR_CHECKING
+    glError = glGetError();
+    if( GL_NO_ERROR != glError )
+    {
+      DALI_LOG_ERROR(" glEGLImageTargetTexture2DOES returned error %0x04x\n", glError );
+    }
+#endif
+  }
+}
+
+void EglImageExtensions::InitializeEglImageKHR()
+{
+  // avoid trying to reload extended KHR functions, if it fails the first time
+  if( ! mImageKHRInitializeFailed )
+  {
+    eglCreateImageKHRProc  = reinterpret_cast< PFNEGLCREATEIMAGEKHRPROC >( eglGetProcAddress("eglCreateImageKHR") );
+    eglDestroyImageKHRProc = reinterpret_cast< PFNEGLDESTROYIMAGEKHRPROC >( eglGetProcAddress("eglDestroyImageKHR") );
+    glEGLImageTargetTexture2DOESProc = reinterpret_cast< PFNGLEGLIMAGETARGETTEXTURE2DOESPROC >( eglGetProcAddress("glEGLImageTargetTexture2DOES") );
+  }
+
+  if (eglCreateImageKHRProc && eglDestroyImageKHRProc && glEGLImageTargetTexture2DOESProc)
+  {
+    mImageKHRInitialized = true;
+  }
+  else
+  {
+    mImageKHRInitializeFailed = true;
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/graphics/windows-gl/egl-image-extensions.cpp b/dali/internal/graphics/windows-gl/egl-image-extensions.cpp
new file mode 100755 (executable)
index 0000000..9b4ab64
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+
+// CLASS HEADER
+#include <dali/internal/graphics/common/egl-image-extensions.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/gles/egl-implementation.h>
+
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+EglImageExtensions::EglImageExtensions(EglImplementation* eglImpl)
+: mEglImplementation(eglImpl),
+  mImageKHRInitialized(false),
+  mImageKHRInitializeFailed(false)
+{
+  DALI_ASSERT_ALWAYS( eglImpl && "EGL Implementation not instantiated" );
+}
+
+EglImageExtensions::~EglImageExtensions()
+{
+}
+
+void* EglImageExtensions::CreateImageKHR(EGLClientBuffer clientBuffer)
+{
+  DALI_LOG_ERROR(" does not support CreateImageKHR\n");
+  return NULL;
+}
+
+void EglImageExtensions::DestroyImageKHR(void* eglImageKHR)
+{
+  DALI_LOG_ERROR(" does not support DestroyImageKHR\n");
+}
+
+void EglImageExtensions::TargetTextureKHR(void* eglImageKHR)
+{
+  DALI_LOG_ERROR(" does not support TargetTextureKHR\n");
+}
+
+void EglImageExtensions::InitializeEglImageKHR()
+{
+  DALI_LOG_ERROR(" does not support InitializeEglImageKHR\n");
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/haptics/common/feedback-player-impl.cpp b/dali/internal/haptics/common/feedback-player-impl.cpp
new file mode 100644 (file)
index 0000000..7468372
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/haptics/common/feedback-player-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/adaptor-framework/file-loader.h>
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // unnamed namespace
+{
+
+// Type Registration
+Dali::BaseHandle Create()
+{
+  return FeedbackPlayer::Get();
+}
+
+Dali::TypeRegistration FEEDBACK_PLAYER_TYPE( typeid(Dali::FeedbackPlayer), typeid(Dali::BaseHandle), Create );
+
+} // unnamed namespace
+
+Dali::FeedbackPlayer FeedbackPlayer::New()
+{
+  Dali::FeedbackPlayer player = Dali::FeedbackPlayer( new FeedbackPlayer() );
+  return player;
+}
+
+Dali::FeedbackPlayer FeedbackPlayer::Get()
+{
+  Dali::FeedbackPlayer player;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::FeedbackPlayer ) );
+    if ( handle )
+    {
+      // If so, downcast the handle
+      player = Dali::FeedbackPlayer( dynamic_cast< FeedbackPlayer* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      player = Dali::FeedbackPlayer( New() );
+      service.Register( typeid( player ), player );
+    }
+  }
+
+  return player;
+}
+
+void FeedbackPlayer::PlayMonotone( unsigned int duration )
+{
+  mPlugin.PlayHapticMonotone( duration );
+}
+
+void FeedbackPlayer::PlayFile( const std::string& filePath )
+{
+  mPlugin.PlayHaptic( filePath );
+}
+
+void FeedbackPlayer::Stop()
+{
+  mPlugin.StopHaptic();
+}
+
+int FeedbackPlayer::PlaySound( const std::string& filename )
+{
+  return mPlugin.PlaySound(filename);
+}
+
+void FeedbackPlayer::StopSound( int handle )
+{
+  mPlugin.StopSound(handle);
+}
+
+void FeedbackPlayer::PlayFeedbackPattern( int type, int pattern )
+{
+  mPlugin.PlayFeedbackPattern(type, pattern);
+}
+
+bool FeedbackPlayer::LoadFile(const std::string& filename, std::string& data)
+{
+  bool loaded = false;
+
+  std::streampos bufferSize = 0;
+  Dali::Vector<char> fileBuffer;
+  if( Dali::FileLoader::ReadFile( filename, bufferSize, fileBuffer, FileLoader::FileType::TEXT ) )
+  {
+    data.assign( &fileBuffer[0], bufferSize );
+    loaded = true;
+  }
+
+  return loaded;
+}
+
+FeedbackPlayer::FeedbackPlayer()
+: mPlugin( FeedbackPluginProxy::DEFAULT_OBJECT_NAME )
+{
+}
+
+FeedbackPlayer::~FeedbackPlayer()
+{
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/haptics/common/feedback-player-impl.h b/dali/internal/haptics/common/feedback-player-impl.h
new file mode 100644 (file)
index 0000000..1355e31
--- /dev/null
@@ -0,0 +1,145 @@
+#ifndef DALI_INTERNAL_FEEDBACK_PLAYER_H
+#define DALI_INTERNAL_FEEDBACK_PLAYER_H
+
+/*
+ * Copyright (c) 2019 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/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/feedback-player.h>
+#include <dali/internal/haptics/common/feedback-plugin-proxy.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class FeedbackPluginProxy;
+
+/**
+ * Plays haptic effects.
+ */
+class FeedbackPlayer : public Dali::BaseObject
+{
+
+public:
+
+  /**
+   * Create a FeedbackPlayer.
+   * This should only be called once by the Adaptor class.
+   * @return A newly created FeedbackPlayer.
+   */
+  static Dali::FeedbackPlayer New();
+
+  /**
+   * Retrieve a handle to the FeedbackPlayer. This creates an instance if none has been created.
+   * @return A handle to the FeedbackPlayer.
+   */
+  static Dali::FeedbackPlayer Get();
+
+  /**
+   * @copydoc Dali::FeedbackPlayer::PlayMonotone()
+   */
+  void PlayMonotone(unsigned int duration);
+
+  /**
+   * @copydoc Dali::FeedbackPlayer::PlayFile()
+   */
+  void PlayFile( const std::string& filePath );
+
+  /**
+   * @copydoc Dali::FeedbackPlayer::Stop()
+   */
+  void Stop();
+
+  /**
+   * @copydoc Dali::FeedbackPlayer::PlaySound()
+   */
+  int PlaySound( const std::string& fileName );
+
+  /**
+   * @copydoc Dali::FeedbackPlayer::StopSound()
+   */
+  void StopSound( int handle );
+
+  /**
+   * @copydoc Dali::FeedbackPlayer::PlayFeedbackPattern()
+   */
+  void PlayFeedbackPattern( int type, int pattern );
+
+  /**
+   * @copydoc Dali::FeedbackPlayer::LoadFile()
+   */
+  bool LoadFile(const std::string& filename, std::string& data);
+
+private:
+
+  /**
+   * Private Constructor; see also FeedbackPlayer::New()
+   */
+  FeedbackPlayer();
+
+  /**
+   * Virtual Destructor
+   */
+  virtual ~FeedbackPlayer();
+
+  // Undefined
+  FeedbackPlayer(const FeedbackPlayer&);
+
+  // Undefined
+  FeedbackPlayer& operator=(FeedbackPlayer&);
+
+private:
+
+  FeedbackPluginProxy mPlugin;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::FeedbackPlayer& GetImplementation(Dali::FeedbackPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "FeedbackPlayer handle is empty" );
+
+  BaseObject& handle = player.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::FeedbackPlayer&>(handle);
+}
+
+inline const Internal::Adaptor::FeedbackPlayer& GetImplementation(const Dali::FeedbackPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "FeedbackPlayer handle is empty" );
+
+  const BaseObject& handle = player.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::FeedbackPlayer&>(handle);
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_FEEDBACK_PLAYER_H
diff --git a/dali/internal/haptics/common/feedback-plugin-proxy.cpp b/dali/internal/haptics/common/feedback-plugin-proxy.cpp
new file mode 100644 (file)
index 0000000..f8d7ce7
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/haptics/common/feedback-plugin-proxy.h>
+
+// EXTERNAL INCLUDES
+#include <dlfcn.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+#if _GLIBCXX_USE_CXX11_ABI
+const char * const FeedbackPluginProxy::DEFAULT_OBJECT_NAME( "libdali-feedback-plugin.so" );
+#else
+const char * const FeedbackPluginProxy::DEFAULT_OBJECT_NAME( "libdali-feedback-plugin-cxx03.so" );
+#endif
+
+FeedbackPluginProxy::FeedbackPluginProxy( const std::string& sharedObjectName )
+: mInitializeAttempted( false ),
+  mLibHandle( NULL ),
+  mSharedObjectName( sharedObjectName ),
+  mCreatePluginFunctionPtr( NULL ),
+  mFeedbackPlugin( NULL )
+{
+  // Lazily initialize when sound/haptic is first played
+}
+
+FeedbackPluginProxy::~FeedbackPluginProxy()
+{
+  if( mFeedbackPlugin )
+  {
+    delete mFeedbackPlugin;
+    mFeedbackPlugin = NULL;
+
+    if( mLibHandle && dlclose( mLibHandle ) )
+    {
+      DALI_LOG_ERROR( "Error closing dali feedback plugin library: %s\n", dlerror() );
+    }
+  }
+}
+
+void FeedbackPluginProxy::PlayHaptic( const std::string& filePath )
+{
+  // Lazy initialization
+  Initialize();
+
+  if( mFeedbackPlugin )
+  {
+    mFeedbackPlugin->PlayHaptic( filePath );
+  }
+}
+
+void FeedbackPluginProxy::PlayHapticMonotone( unsigned int duration )
+{
+  // Lazy initialization
+  Initialize();
+
+  if( mFeedbackPlugin )
+  {
+    mFeedbackPlugin->PlayHapticMonotone( duration );
+  }
+}
+
+void FeedbackPluginProxy::StopHaptic()
+{
+  // Must already have been initialized to play haptic
+  if( mFeedbackPlugin )
+  {
+    mFeedbackPlugin->StopHaptic();
+  }
+}
+
+int FeedbackPluginProxy::PlaySound( const std::string& fileName )
+{
+  // Lazy initialization
+  Initialize();
+
+  if( mFeedbackPlugin )
+  {
+    return mFeedbackPlugin->PlaySound( fileName );
+  }
+
+  return 0;
+}
+
+void FeedbackPluginProxy::StopSound( int handle )
+{
+  // Must already have been initialized to play sound
+  if ( mFeedbackPlugin )
+  {
+    mFeedbackPlugin->StopSound( handle );
+  }
+}
+
+void FeedbackPluginProxy::PlayFeedbackPattern( int type, int pattern )
+{
+  // Lazy initialization
+  Initialize();
+
+  if( mFeedbackPlugin )
+  {
+    mFeedbackPlugin->PlayFeedbackPattern( type, pattern );
+  }
+}
+
+void FeedbackPluginProxy::Initialize()
+{
+  // Only attempt to load dll once
+  if ( !mInitializeAttempted )
+  {
+    mInitializeAttempted = true;
+
+    mLibHandle = dlopen( mSharedObjectName.c_str(), RTLD_NOW | RTLD_GLOBAL );
+    if( !mLibHandle )
+    {
+      DALI_LOG_ERROR( "Cannot load dali feedback plugin library error: %s\n", dlerror() );
+      return;
+    }
+
+    // reset errors
+    dlerror();
+
+    // load plugin
+    mCreatePluginFunctionPtr = reinterpret_cast<CreateFeedbackPlugin*>(dlsym(mLibHandle, "CreateFeedbackPlugin"));
+    if(!mCreatePluginFunctionPtr)
+    {
+      DALI_LOG_ERROR("Cannot load symbol CreateFeedbackPlugin(): %s\n", dlerror());
+      return;
+    }
+
+    // reset errors
+    dlerror();
+
+    mFeedbackPlugin = mCreatePluginFunctionPtr();
+
+    if(!mFeedbackPlugin)
+    {
+      DALI_LOG_ERROR("Call to function CreateFeedbackPlugin() failed\n");
+    }
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/haptics/common/feedback-plugin-proxy.h b/dali/internal/haptics/common/feedback-plugin-proxy.h
new file mode 100644 (file)
index 0000000..fb17ad9
--- /dev/null
@@ -0,0 +1,115 @@
+#ifndef DALI_INTERNAL_FEEDBACK_PLUGIN_PROXY_H
+#define DALI_INTERNAL_FEEDBACK_PLUGIN_PROXY_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/adaptor-framework/feedback-plugin.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+typedef Dali::FeedbackPlugin::SoundStopCallBack SoundStopCallBack;
+typedef Dali::FeedbackPlugin::CreateFeedbackPlugin CreateFeedbackPlugin;
+
+/**
+ * Proxy class to dynamically load, use and unload feedback plugin.
+ */
+class FeedbackPluginProxy
+{
+public:
+
+  /**
+   * The default feedback plugin proxy.
+   */
+  static const char * const DEFAULT_OBJECT_NAME;
+
+public:
+
+  /**
+   * Constructor.
+   */
+  FeedbackPluginProxy( const std::string& sharedObjectName );
+
+  /**
+   * The destructor
+   */
+  ~FeedbackPluginProxy();
+
+  /**
+   * @copydoc Dali::Integration::FeedbackPlugin::PlayHaptic()
+   */
+  void PlayHaptic( const std::string& filePath );
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::PlayHapticMonotone()
+   */
+  void PlayHapticMonotone( unsigned int duration );
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::StopHaptic()
+   */
+  void StopHaptic();
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::PlaySound()
+   */
+  int PlaySound( const std::string& fileName );
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::StopSound()
+   */
+  void StopSound( int handle );
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::PlayFeedbackPattern()
+   */
+  void PlayFeedbackPattern( int type, int pattern );
+
+private:
+
+  /**
+   * Dynamically loads the feedback plugin.
+   */
+  void Initialize();
+
+private:
+
+  bool mInitializeAttempted;
+  void* mLibHandle;
+  std::string mSharedObjectName;
+  CreateFeedbackPlugin* mCreatePluginFunctionPtr;
+  Dali::FeedbackPlugin* mFeedbackPlugin;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_FEEDBACK_PLUGIN_PROXY_H
diff --git a/dali/internal/haptics/file.list b/dali/internal/haptics/file.list
new file mode 100644 (file)
index 0000000..20a8a60
--- /dev/null
@@ -0,0 +1,7 @@
+
+# module: haptics, backend: common
+SET( adaptor_haptics_common_src_files 
+    ${adaptor_haptics_dir}/common/feedback-player-impl.cpp 
+    ${adaptor_haptics_dir}/common/feedback-plugin-proxy.cpp
+)
+
diff --git a/dali/internal/imaging/android/native-image-source-factory-android.cpp b/dali/internal/imaging/android/native-image-source-factory-android.cpp
new file mode 100644 (file)
index 0000000..b37c532
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/imaging/android/native-image-source-factory-android.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/imaging/android/native-image-source-impl-android.h>
+#include <dali/internal/imaging/android/native-image-source-queue-impl-android.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+std::unique_ptr< NativeImageSource > NativeImageSourceFactoryAndroid::CreateNativeImageSource( uint32_t width, uint32_t height,
+                                                                                         Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
+{
+  return std::unique_ptr< NativeImageSource >( NativeImageSourceAndroid::New( width, height, depth, nativeImageSource ) );
+}
+
+std::unique_ptr< NativeImageSourceQueue > NativeImageSourceFactoryAndroid::CreateNativeImageSourceQueue( uint32_t width, uint32_t height,
+                                                                                                   Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue )
+{
+  return std::unique_ptr< NativeImageSourceQueue >( NativeImageSourceQueueAndroid::New( width, height, depth, nativeImageSourceQueue ) );
+}
+
+// this should be created from somewhere
+std::unique_ptr< NativeImageSourceFactory > GetNativeImageSourceFactory()
+{
+  // returns native image source factory
+  return std::unique_ptr< NativeImageSourceFactoryAndroid >( new NativeImageSourceFactoryAndroid() );
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/dali/internal/imaging/android/native-image-source-factory-android.h b/dali/internal/imaging/android/native-image-source-factory-android.h
new file mode 100644 (file)
index 0000000..45bfe6d
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef DALI_INTERNAL_NATIVE_IMAGE_SOURCE_FACTORY_ANDROID_H
+#define DALI_INTERNAL_NATIVE_IMAGE_SOURCE_FACTORY_ANDROID_H
+
+/*
+ * Copyright (c) 2019 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 <dali/internal/imaging/common/native-image-source-factory.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class NativeImageSourceFactoryAndroid : public NativeImageSourceFactory
+{
+public:
+
+  std::unique_ptr< NativeImageSource > CreateNativeImageSource( uint32_t width, uint32_t height,
+                                                                Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource ) override;
+
+  std::unique_ptr< NativeImageSourceQueue > CreateNativeImageSourceQueue( uint32_t width, uint32_t height,
+                                                                          Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue ) override;
+
+};
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // DALI_INTERNAL_NATIVE_IMAGE_SOURCE_FACTORY_ANDROID_H
diff --git a/dali/internal/imaging/android/native-image-source-impl-android.cpp b/dali/internal/imaging/android/native-image-source-impl-android.cpp
new file mode 100755 (executable)
index 0000000..53fdc8c
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#define EGL_EGLEXT_PROTOTYPES
+#if __ANDROID_API__ < 26
+#error "Unsupported Android API version, must be >= 26"
+#endif
+
+// CLASS HEADER
+#include <dali/internal/imaging/android/native-image-source-impl-android.h>
+
+// EXTERNAL INCLUDES
+#include <EGL/egl.h>
+#include <include/EGL/eglext.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/bitmap-saver.h>
+#include <dali/integration-api/adaptor-framework/render-surface-interface.h>
+#include <dali/internal/graphics/common/egl-image-extensions.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+using Dali::Integration::PixelBuffer;
+
+NativeImageSourceAndroid* NativeImageSourceAndroid::New( uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
+{
+  NativeImageSourceAndroid* image = new NativeImageSourceAndroid( width, height, depth, nativeImageSource );
+  DALI_ASSERT_DEBUG( image && "NativeImageSource allocation failed." );
+
+  // 2nd phase construction
+  if( image ) //< Defensive in case we ever compile without exceptions.
+  {
+    image->Initialize();
+  }
+
+  return image;
+}
+
+NativeImageSourceAndroid::NativeImageSourceAndroid( uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
+: mWidth( width ),
+  mHeight( height ),
+  mOwnPixmap( true ),
+  mPixmap( NULL ),
+  mBlendingRequired( false ),
+  mColorDepth( depth ),
+  mEglImageKHR( NULL ),
+  mEglImageExtensions( NULL )
+{
+  DALI_ASSERT_ALWAYS( Adaptor::IsAvailable() );
+
+  GraphicsInterface* graphics = &( Adaptor::GetImplementation( Adaptor::Get() ).GetGraphicsInterface() );
+  auto eglGraphics = static_cast<EglGraphics*>( graphics );
+
+  mEglImageExtensions = eglGraphics->GetImageExtensions();
+
+  DALI_ASSERT_DEBUG( mEglImageExtensions );
+
+  // assign the pixmap
+  mPixmap = static_cast<AHardwareBuffer*>( GetPixmapFromAny( nativeImageSource ) );
+  if( !mPixmap )
+  {
+    AHardwareBuffer_Desc bufferDescription;
+    memset( &bufferDescription, 0, sizeof( AHardwareBuffer_Desc ) );
+    bufferDescription.width = width;
+    bufferDescription.height = height;
+    bufferDescription.layers = 1;
+    bufferDescription.usage = AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN | AHARDWAREBUFFER_USAGE_CPU_READ_RARELY | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+    switch( mColorDepth )
+    {
+      case Dali::NativeImageSource::COLOR_DEPTH_32:
+      case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
+        bufferDescription.format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM;
+        break;
+      case Dali::NativeImageSource::COLOR_DEPTH_24:
+        bufferDescription.format = AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM;
+        break;
+      case Dali::NativeImageSource::COLOR_DEPTH_16:
+        bufferDescription.format = AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM;
+        break;
+      case Dali::NativeImageSource::COLOR_DEPTH_8:
+        bufferDescription.format = AHARDWAREBUFFER_FORMAT_BLOB;
+        break;
+    }
+
+    int ret = AHardwareBuffer_allocate( &bufferDescription, &mPixmap );
+    if( ret )
+    {
+      DALI_LOG_ERROR("Failed to allocate AHardwareBuffer %d", ret);
+    }
+
+    mOwnPixmap = true;
+  }
+}
+
+void NativeImageSourceAndroid::Initialize()
+{
+  if( mPixmap && !mOwnPixmap )
+  {
+    AHardwareBuffer_acquire( mPixmap ) ;
+
+    // find out the pixmap width / height and color depth
+    GetPixmapDetails();
+  }
+}
+
+NativeImageSourceAndroid::~NativeImageSourceAndroid()
+{
+  AHardwareBuffer_release( mPixmap );
+  mPixmap = NULL;
+}
+
+Any NativeImageSourceAndroid::GetNativeImageSource() const
+{
+  return Any( mPixmap );
+}
+
+bool NativeImageSourceAndroid::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
+{
+  DALI_ASSERT_DEBUG( sizeof(unsigned) == 4 );
+  bool success = false;
+
+  width  = mWidth;
+  height = mHeight;
+
+  AHardwareBuffer_Desc bufferDescription;
+  memset( &bufferDescription, 0, sizeof( AHardwareBuffer_Desc ) );
+  AHardwareBuffer_describe( mPixmap, &bufferDescription );
+  switch( bufferDescription.format )
+  {
+    case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
+      pixelFormat = Pixel::Format::RGBA8888;
+      break;
+    case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
+      pixelFormat = Pixel::Format::RGB8888;
+      break;
+    case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
+      pixelFormat = Pixel::Format::RGB888;
+      break;
+    case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
+      pixelFormat = Pixel::Format::RGB565;
+      break;
+    case AHARDWAREBUFFER_FORMAT_BLOB:
+    default:
+      pixelFormat = Pixel::Format::A8;
+      break;
+  }
+
+  void* buffer = NULL;
+  int ret = AHardwareBuffer_lock( mPixmap, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, -1, NULL, &buffer );
+  if( ret != 0 )
+  {
+    DALI_LOG_ERROR("Failed to AHardwareBuffer_lock %d", ret);
+    return success;
+  }
+
+  uint32_t size = bufferDescription.stride * bufferDescription.height;
+  pixbuf.resize( size );
+  memcpy( pixbuf.data(), buffer, size );
+
+  ret = AHardwareBuffer_unlock( mPixmap, NULL );
+  if( ret != 0 )
+  {
+    DALI_LOG_ERROR("failed to AHardwareBuffer_unlock %d", ret);
+    return success;
+  }
+  success = true;
+
+  return success;
+}
+
+bool NativeImageSourceAndroid::EncodeToFile(const std::string& filename) const
+{
+  std::vector< unsigned char > pixbuf;
+  unsigned int width(0), height(0);
+  Pixel::Format pixelFormat;
+
+  if( GetPixels( pixbuf, width, height, pixelFormat ) )
+  {
+    return Dali::EncodeToFile( &pixbuf[0], filename, pixelFormat, width, height );
+  }
+  return false;
+}
+
+void NativeImageSourceAndroid::SetSource( Any source )
+{
+  if( mPixmap )
+  {
+    mOwnPixmap = false;
+
+    AHardwareBuffer_release( mPixmap );
+    mPixmap = NULL;
+  }
+
+  mPixmap = static_cast<AHardwareBuffer*>( GetPixmapFromAny( source ) );
+
+  if( mPixmap )
+  {
+    // we don't own the pixmap
+    mOwnPixmap = false;
+
+    // find out the pixmap width / height and color depth
+    GetPixmapDetails();
+  }
+}
+
+bool NativeImageSourceAndroid::IsColorDepthSupported( Dali::NativeImageSource::ColorDepth colorDepth )
+{
+  return true;
+}
+
+bool NativeImageSourceAndroid::GlExtensionCreate()
+{
+  // if the image existed previously delete it.
+  if( mEglImageKHR != NULL )
+  {
+    GlExtensionDestroy();
+  }
+
+  DALI_ASSERT_ALWAYS( mPixmap );
+  EGLClientBuffer eglBuffer = eglGetNativeClientBufferANDROID( mPixmap );
+  switch( eglGetError() )
+  {
+    case EGL_SUCCESS :
+    {
+      break;
+    }
+    case EGL_BAD_PARAMETER:
+    {
+      DALI_LOG_ERROR( "EGL_BAD_PARAMETER: bad pixmap parameter\n" );
+      break;
+    }
+    case EGL_BAD_ACCESS:
+    {
+      DALI_LOG_ERROR( "EGL_BAD_ACCESS: bad access to pixmap\n" );
+      break;
+    }
+    case EGL_BAD_ALLOC:
+    {
+      DALI_LOG_ERROR( "EGL_BAD_ALLOC: Insufficient memory is available\n" );
+      break;
+    }
+    default:
+    {
+      DALI_LOG_ERROR( "eglGetNativeClientBufferANDROID error\n" );
+      break;
+    }
+  }
+
+  DALI_ASSERT_ALWAYS( eglBuffer );
+  mEglImageKHR = mEglImageExtensions->CreateImageKHR( eglBuffer );
+
+  return mEglImageKHR != NULL;
+}
+
+void NativeImageSourceAndroid::GlExtensionDestroy()
+{
+  mEglImageExtensions->DestroyImageKHR( mEglImageKHR );
+
+  mEglImageKHR = NULL;
+}
+
+uint32_t NativeImageSourceAndroid::TargetTexture()
+{
+  mEglImageExtensions->TargetTextureKHR( mEglImageKHR );
+
+  return 0;
+}
+
+void NativeImageSourceAndroid::PrepareTexture()
+{
+}
+
+void* NativeImageSourceAndroid::GetPixmapFromAny(Any pixmap) const
+{
+  if( pixmap.Empty() )
+  {
+    return 0;
+  }
+
+  return AnyCast<void*>( pixmap );
+}
+
+void NativeImageSourceAndroid::GetPixmapDetails()
+{
+  // get the width, height and depth
+  mBlendingRequired = false;
+
+  AHardwareBuffer_Desc bufferDescription;
+  memset( &bufferDescription, 0, sizeof( AHardwareBuffer_Desc ) );
+  AHardwareBuffer_describe( mPixmap, &bufferDescription );
+
+  mWidth = bufferDescription.width;
+  mHeight = bufferDescription.height;
+  switch (bufferDescription.format)
+  {
+  case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
+    mColorDepth = Dali::NativeImageSource::COLOR_DEPTH_32;
+    break;
+  case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
+    mColorDepth = Dali::NativeImageSource::COLOR_DEPTH_24;
+    break;
+  case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
+    mColorDepth = Dali::NativeImageSource::COLOR_DEPTH_16;
+    break;
+  case AHARDWAREBUFFER_FORMAT_BLOB:
+  default:
+    mColorDepth = Dali::NativeImageSource::COLOR_DEPTH_8;
+  }
+}
+
+uint8_t* NativeImageSourceAndroid::AcquireBuffer( uint16_t& width, uint16_t& height, uint16_t& stride )
+{
+  if( mPixmap )
+  {
+    AHardwareBuffer_Desc bufferDescription;
+    memset( &bufferDescription, 0, sizeof( AHardwareBuffer_Desc ) );
+    AHardwareBuffer_describe( mPixmap, &bufferDescription );
+
+    void* buffer = NULL;
+    if( AHardwareBuffer_lock( mPixmap, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY, -1, NULL, &buffer ) != 0 )
+    {
+      DALI_LOG_ERROR( "Failed to AHardwareBuffer_lock\n" );
+      return NULL;
+    }
+
+    stride = bufferDescription.stride;
+    width  = bufferDescription.width;
+    height = bufferDescription.height;
+
+    return static_cast< uint8_t* >( buffer );
+  }
+
+  return NULL;
+}
+
+
+bool NativeImageSourceAndroid::ReleaseBuffer()
+{
+  if( mPixmap )
+  {
+    if( AHardwareBuffer_unlock( mPixmap, NULL ) != 0 )
+    {
+      DALI_LOG_ERROR( "failed to AHardwareBuffer_unlock\n" );
+      return false;
+    }
+    return true;
+  }
+  return false;
+}
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
diff --git a/dali/internal/imaging/android/native-image-source-impl-android.h b/dali/internal/imaging/android/native-image-source-impl-android.h
new file mode 100755 (executable)
index 0000000..7d941ca
--- /dev/null
@@ -0,0 +1,203 @@
+#ifndef DALI_INTERNAL_NATIVE_IMAGE_SOURCE_H
+#define DALI_INTERNAL_NATIVE_IMAGE_SOURCE_H
+
+/*
+ * Copyright (c) 2019 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 <hardware_buffer.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/common/graphics-interface.h>
+
+#include <dali/public-api/adaptor-framework/native-image-source.h>
+
+#include <dali/internal/imaging/common/native-image-source-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class EglImageExtensions;
+
+/**
+ * Dali internal NativeImageSource.
+ */
+class NativeImageSourceAndroid : public Internal::Adaptor::NativeImageSource
+{
+public:
+
+  /**
+   * Create a new NativeImageSource internally.
+   * Depending on hardware the width and height may have to be a power of two.
+   * @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: Android hardware buffer or is empty
+   * @return A smart-pointer to a newly allocated image.
+   */
+  static NativeImageSourceAndroid* New( uint32_t width,
+                          uint32_t height,
+                          Dali::NativeImageSource::ColorDepth depth,
+                          Any nativeImageSource);
+  /**
+   * @copydoc Dali::NativeImageSource::GetNativeImageSource()
+   */
+  Any GetNativeImageSource() const override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetPixels()
+   */
+  bool GetPixels(std::vector<unsigned char> &pixbuf, uint32_t &width, uint32_t &height, Pixel::Format& pixelFormat ) const override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::EncodeToFile(const std::string& )
+   */
+  bool EncodeToFile(const std::string& filename) const override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::SetSource( Any source )
+   */
+  void SetSource( Any source ) override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::IsColorDepthSupported( ColorDepth colorDepth )
+   */
+  bool IsColorDepthSupported( Dali::NativeImageSource::ColorDepth colorDepth ) override;
+
+  /**
+   * destructor
+   */
+  ~NativeImageSourceAndroid() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GlExtensionCreate()
+   */
+  bool GlExtensionCreate() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GlExtensionDestroy()
+   */
+  void GlExtensionDestroy() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::TargetTexture()
+   */
+  uint32_t TargetTexture() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::PrepareTexture()
+   */
+  void PrepareTexture() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetWidth()
+   */
+  uint32_t GetWidth() const override
+  {
+    return mWidth;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetHeight()
+   */
+  uint32_t GetHeight() const override
+  {
+    return mHeight;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageSource::RequiresBlending()
+   */
+  bool RequiresBlending() const override
+  {
+    return mBlendingRequired;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetExtension()
+   */
+  NativeImageInterface::Extension* GetNativeImageInterfaceExtension() override
+  {
+    return nullptr;
+  }
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::NativeImageSource::AcquireBuffer()
+   */
+  uint8_t* AcquireBuffer( uint16_t& width, uint16_t& height, uint16_t& stride ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::NativeImageSource::ReleaseBuffer()
+   */
+  bool ReleaseBuffer() override;
+
+private:
+
+  /**
+   * Private constructor; @see NativeImageSource::New()
+   * @param[in] width The width of the image.
+   * @param[in] height The height of the image.
+   * @param[in] colour depth of the image.
+   * @param[in] nativeImageSource contains either: pixmap of type X11 Pixmap , a Ecore_X_Pixmap or is empty
+   */
+  NativeImageSourceAndroid( uint32_t width,
+              uint32_t height,
+              Dali::NativeImageSource::ColorDepth depth,
+              Any nativeImageSource);
+
+  /**
+   * 2nd phase construction.
+   */
+  void Initialize();
+
+  /**
+   * Gets the pixmap from the Any parameter
+   * @param pixmap contains either: pixmap of type Android hardware buffer or empty
+   * @return pixmap pixmap
+   */
+  void* GetPixmapFromAny(Any pixmap) const;
+
+  /**
+   * Given an existing pixmap, the function uses Android hardware buffer API to find
+   * the width, heigth and depth of that pixmap.
+   */
+  void GetPixmapDetails();
+
+private:
+
+  uint32_t mWidth;                            ///< image width
+  uint32_t mHeight;                           ///< image heights
+  bool mOwnPixmap;                            ///< Whether we created pixmap or not
+  AHardwareBuffer* mPixmap;                   ///<
+  bool mBlendingRequired;                     ///< Whether blending is required
+  Dali::NativeImageSource::ColorDepth mColorDepth;  ///< color depth of image
+  void* mEglImageKHR;                         ///< From EGL extension
+  EglImageExtensions* mEglImageExtensions;    ///< The EGL Image Extensions
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_NATIVE_IMAGE_SOURCE_H
diff --git a/dali/internal/imaging/android/native-image-source-queue-impl-android.cpp b/dali/internal/imaging/android/native-image-source-queue-impl-android.cpp
new file mode 100644 (file)
index 0000000..7043979
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/imaging/android/native-image-source-queue-impl-android.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/gl-defines.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/common/egl-image-extensions.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+const char* FRAGMENT_PREFIX = "\n";
+const char* SAMPLER_TYPE = "sampler2D";
+
+}
+
+NativeImageSourceQueueAndroid* NativeImageSourceQueueAndroid::New( uint32_t width, uint32_t height, Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue )
+{
+  NativeImageSourceQueueAndroid* image = new NativeImageSourceQueueAndroid( width, height, depth, nativeImageSourceQueue );
+  return image;
+}
+
+NativeImageSourceQueueAndroid::NativeImageSourceQueueAndroid( uint32_t width, uint32_t height, Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue )
+: mWidth( width ),
+  mHeight( height )
+{
+  DALI_LOG_ERROR( "NativeImageSourceQueueAndroid::NativeImageSourceQueueAndroid: Not supported\n" );
+}
+
+NativeImageSourceQueueAndroid::~NativeImageSourceQueueAndroid()
+{
+}
+
+Any NativeImageSourceQueueAndroid::GetNativeImageSourceQueue() const
+{
+  return Any();
+}
+
+void NativeImageSourceQueueAndroid::SetSize( uint32_t width, uint32_t height )
+{
+  mWidth = width;
+  mHeight = height;
+}
+
+bool NativeImageSourceQueueAndroid::GlExtensionCreate()
+{
+  return true;
+}
+
+void NativeImageSourceQueueAndroid::GlExtensionDestroy()
+{
+}
+
+uint32_t NativeImageSourceQueueAndroid::TargetTexture()
+{
+  return 0;
+}
+
+void NativeImageSourceQueueAndroid::PrepareTexture()
+{
+}
+
+const char* NativeImageSourceQueueAndroid::GetCustomFragmentPreFix()
+{
+  return FRAGMENT_PREFIX;
+}
+
+const char* NativeImageSourceQueueAndroid::GetCustomSamplerTypename()
+{
+  return SAMPLER_TYPE;
+}
+
+int NativeImageSourceQueueAndroid::GetEglImageTextureTarget()
+{
+  return 0;
+}
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
diff --git a/dali/internal/imaging/android/native-image-source-queue-impl-android.h b/dali/internal/imaging/android/native-image-source-queue-impl-android.h
new file mode 100644 (file)
index 0000000..e1cb045
--- /dev/null
@@ -0,0 +1,163 @@
+#ifndef DALI_INTERNAL_NATIVE_IMAGE_SOURCE_QUEUE_IMPL_ANDROID_H
+#define DALI_INTERNAL_NATIVE_IMAGE_SOURCE_QUEUE_IMPL_ANDROID_H
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/images/native-image-interface-extension.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/imaging/common/native-image-source-queue-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class EglGraphics;
+class EglImageExtensions;
+
+/**
+ * Dali internal NativeImageSourceQueue.
+ */
+class NativeImageSourceQueueAndroid: public Internal::Adaptor::NativeImageSourceQueue, public NativeImageInterface::Extension
+{
+public:
+
+  /**
+   * Create a new NativeImageSourceQueueAndroid internally.
+   * Depending on hardware the width and height may have to be a power of two.
+   * @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] nativeImageSourceQueue contains tbm_surface_queue_h or is empty
+   * @return A smart-pointer to a newly allocated image.
+   */
+  static NativeImageSourceQueueAndroid* New( uint32_t width, uint32_t height, Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue );
+
+  /**
+   * @copydoc Dali::NativeImageSourceQueue::GetNativeImageSourceQueue()
+   */
+  Any GetNativeImageSourceQueue() const override;
+
+  /**
+   * @copydoc Dali::NativeImageSourceQueue::SetSize
+   */
+  void SetSize( uint32_t width, uint32_t height ) override;
+
+  /**
+   * destructor
+   */
+  ~NativeImageSourceQueueAndroid() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionCreate()
+   */
+  bool GlExtensionCreate() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionDestroy()
+   */
+  void GlExtensionDestroy() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::TargetTexture()
+   */
+  uint32_t TargetTexture() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::PrepareTexture()
+   */
+  void PrepareTexture() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetWidth()
+   */
+  uint32_t GetWidth() const override
+  {
+    return mWidth;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetHeight()
+   */
+  uint32_t GetHeight() const override
+  {
+    return mHeight;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageInterface::RequiresBlending()
+   */
+  bool RequiresBlending() const override
+  {
+    return true;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetExtension()
+   */
+  NativeImageInterface::Extension* GetNativeImageInterfaceExtension() override
+  {
+    return this;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageInterface::Extension::GetCustomFragmentPreFix()
+   */
+  const char* GetCustomFragmentPreFix() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::Extension::GetCustomSamplerTypename()
+   */
+  const char* GetCustomSamplerTypename() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::Extension::GetEglImageTextureTarget()
+   */
+  int GetEglImageTextureTarget() override;
+
+private:
+
+  /**
+   * Private constructor; @see NativeImageSourceQueue::New()
+   * @param[in] width The width of the image.
+   * @param[in] height The height of the image.
+   * @param[in] colour depth of the image.
+   * @param[in] nativeImageSourceQueue contains tbm_surface_queue_h or is empty
+   */
+  NativeImageSourceQueueAndroid( uint32_t width, uint32_t height, Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue );
+
+private:
+
+  uint32_t    mWidth;                ///< image width
+  uint32_t    mHeight;               ///< image height
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_NATIVE_IMAGE_SOURCE_QUEUE_IMPL_ANDROID_H
diff --git a/dali/internal/imaging/common/alpha-mask.cpp b/dali/internal/imaging/common/alpha-mask.cpp
new file mode 100644 (file)
index 0000000..e2e0b25
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * 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/internal/imaging/common/pixel-manipulation.h>
+#include <dali/internal/imaging/common/alpha-mask.h>
+#include <dali/internal/imaging/common/pixel-buffer-impl.h>
+#include <dali/public-api/images/image-operations.h> // For ImageDimensions
+#include <dali/internal/imaging/common/image-operations.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+void ApplyMaskToAlphaChannel( PixelBuffer& buffer, const PixelBuffer& mask )
+{
+  int srcAlphaByteOffset=0;
+  int srcAlphaMask=0;
+  Dali::Pixel::Format srcPixelFormat = mask.GetPixelFormat();
+
+  if( Pixel::HasAlpha(srcPixelFormat) )
+  {
+    Dali::Pixel::GetAlphaOffsetAndMask( srcPixelFormat, srcAlphaByteOffset, srcAlphaMask );
+  }
+  else if( srcPixelFormat == Pixel::L8 )
+  {
+    srcAlphaMask=0xFF;
+  }
+
+  int destAlphaByteOffset=0;
+  int destAlphaMask=0;
+  Dali::Pixel::Format destPixelFormat = buffer.GetPixelFormat();
+  Dali::Pixel::GetAlphaOffsetAndMask( destPixelFormat, destAlphaByteOffset, destAlphaMask );
+
+  unsigned int srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel( srcPixelFormat );
+  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;
+
+  // if image is premultiplied, the other channels of the image need to multiply by alpha.
+  if( buffer.IsAlphaPreMultiplied() )
+  {
+    for( unsigned int row = 0; row < buffer.GetHeight(); ++row )
+    {
+      for( unsigned int col = 0; col < buffer.GetWidth(); ++col )
+      {
+        auto srcAlpha      = ReadChannel( srcBuffer + srcOffset, srcPixelFormat, Adaptor::ALPHA);
+        auto destRed       = ReadChannel( destBuffer + destOffset, destPixelFormat, Adaptor::RED);
+        auto destGreen     = ReadChannel( destBuffer + destOffset, destPixelFormat, Adaptor::GREEN);
+        auto destBlue      = ReadChannel( destBuffer + destOffset, destPixelFormat, Adaptor::BLUE);
+        auto destLuminance = ReadChannel( destBuffer + destOffset, destPixelFormat, Adaptor::LUMINANCE);
+        auto destAlpha     = ReadChannel( destBuffer + destOffset, destPixelFormat, Adaptor::ALPHA);
+
+        WriteChannel( destBuffer + destOffset, destPixelFormat, Adaptor::RED, destRed*srcAlpha / 255 );
+        WriteChannel( destBuffer + destOffset, destPixelFormat, Adaptor::GREEN, destGreen*srcAlpha/255 );
+        WriteChannel( destBuffer + destOffset, destPixelFormat, Adaptor::BLUE, destBlue*srcAlpha/255 );
+        WriteChannel( destBuffer + destOffset, destPixelFormat, Adaptor::LUMINANCE, destLuminance*srcAlpha/255 );
+        WriteChannel( destBuffer + destOffset, destPixelFormat, Adaptor::ALPHA, destAlpha*srcAlpha/255 );
+
+        srcOffset  += srcBytesPerPixel;
+        destOffset += destBytesPerPixel;
+      }
+    }
+  }
+  else
+  {
+    for( unsigned int row = 0; row < buffer.GetHeight(); ++row )
+    {
+      for( unsigned int col = 0; col < buffer.GetWidth(); ++col )
+      {
+        unsigned char alpha = srcBuffer[srcOffset + srcAlphaByteOffset] & srcAlphaMask;
+        srcAlphaValue = float(alpha)/255.0f;
+
+        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 );
+
+        srcOffset  += srcBytesPerPixel;
+        destOffset += destBytesPerPixel;
+      }
+    }
+  }
+}
+
+PixelBufferPtr CreateNewMaskedBuffer( const PixelBuffer& buffer, const PixelBuffer& mask )
+{
+  // Set up source alpha offsets
+  int srcAlphaByteOffset=0;
+  int srcAlphaMask=0;
+  Dali::Pixel::Format srcPixelFormat = mask.GetPixelFormat();
+
+  if( Pixel::HasAlpha(srcPixelFormat) )
+  {
+    Dali::Pixel::GetAlphaOffsetAndMask( srcPixelFormat, srcAlphaByteOffset, srcAlphaMask );
+  }
+  else if( srcPixelFormat == Pixel::L8 )
+  {
+    srcAlphaMask=0xFF;
+  }
+
+  unsigned int srcBytesPerPixel = Dali::Pixel::GetBytesPerPixel( srcPixelFormat );
+  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 )
+    {
+      unsigned char alpha = srcBuffer[srcAlphaOffset + srcAlphaByteOffset] & srcAlphaMask;
+      srcAlphaValue = float(alpha)/255.0f;
+
+      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;
+      srcAlphaOffset += srcBytesPerPixel;
+      destOffset += destBytesPerPixel;
+    }
+  }
+
+  return newPixelBuffer;
+}
+
+} //namespace Adaptor
+
+}// namespace Internal
+
+}// namespace Dali
diff --git a/dali/internal/imaging/common/alpha-mask.h b/dali/internal/imaging/common/alpha-mask.h
new file mode 100644 (file)
index 0000000..4d01466
--- /dev/null
@@ -0,0 +1,51 @@
+#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 <dali/internal/imaging/common/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 );
+
+} //namespace Adaptor
+} //namespace Internal
+} //namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_ALPHA_MASK_H
diff --git a/dali/internal/imaging/common/file-download.cpp b/dali/internal/imaging/common/file-download.cpp
new file mode 100755 (executable)
index 0000000..6930618
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * 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.
+ *
+ */
+
+// HEADER
+#include <dali/internal/imaging/common/file-download.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <pthread.h>
+#include <curl/curl.h>
+#include <cstring>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/file-writer.h>
+
+using namespace Dali::Integration;
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace // unnamed namespace
+{
+
+const int CONNECTION_TIMEOUT_SECONDS( 30L );
+const int TIMEOUT_SECONDS( 120L );
+const long VERBOSE_MODE = 0L;                // 0 == off, 1 == on
+const long CLOSE_CONNECTION_ON_ERROR = 1L;   // 0 == off, 1 == on
+const long EXCLUDE_HEADER = 0L;
+const long INCLUDE_HEADER = 1L;
+const long INCLUDE_BODY = 0L;
+const long EXCLUDE_BODY = 1L;
+
+/**
+ * Curl library environment. Direct initialize ensures it's constructed before adaptor
+ * or application creates any threads.
+ */
+static Dali::TizenPlatform::Network::CurlEnvironment gCurlEnvironment;
+
+void ConfigureCurlOptions( CURL* curlHandle, const std::string& url )
+{
+  curl_easy_setopt( curlHandle, CURLOPT_URL, url.c_str() );
+  curl_easy_setopt( curlHandle, CURLOPT_VERBOSE, VERBOSE_MODE );
+
+  // CURLOPT_FAILONERROR is not fail-safe especially when authentication is involved ( see manual )
+  // Removed CURLOPT_FAILONERROR option
+  curl_easy_setopt( curlHandle, CURLOPT_CONNECTTIMEOUT, CONNECTION_TIMEOUT_SECONDS );
+  curl_easy_setopt( curlHandle, CURLOPT_TIMEOUT, TIMEOUT_SECONDS );
+  curl_easy_setopt( curlHandle, CURLOPT_HEADER, INCLUDE_HEADER );
+  curl_easy_setopt( curlHandle, CURLOPT_NOBODY, EXCLUDE_BODY );
+}
+
+// Without a write function or a buffer (file descriptor) to write to, curl will pump out
+// header/body contents to stdout
+size_t DummyWrite(char *ptr, size_t size, size_t nmemb, void *userdata)
+{
+  return size * nmemb;
+}
+
+struct ChunkData
+{
+  std::vector< uint8_t > data;
+};
+
+size_t ChunkLoader(char *ptr, size_t size, size_t nmemb, void *userdata)
+{
+  std::vector<ChunkData>* chunks = static_cast<std::vector<ChunkData>*>( userdata );
+  int numBytes = size*nmemb;
+  chunks->push_back( ChunkData() );
+  ChunkData& chunkData = (*chunks)[chunks->size()-1];
+  chunkData.data.reserve( numBytes );
+  memcpy( &chunkData.data[0], ptr, numBytes );
+  return numBytes;
+}
+
+
+CURLcode DownloadFileDataWithSize( CURL* curlHandle, Dali::Vector<uint8_t>& dataBuffer, size_t dataSize )
+{
+  CURLcode result( CURLE_OK );
+
+  // create
+  Dali::Internal::Platform::FileWriter fileWriter( dataBuffer, dataSize );
+  FILE* dataBufferFilePointer = fileWriter.GetFile();
+  if( NULL != dataBufferFilePointer )
+  {
+    // we only want the body which contains the file data
+    curl_easy_setopt( curlHandle, CURLOPT_HEADER, EXCLUDE_HEADER );
+    curl_easy_setopt( curlHandle, CURLOPT_NOBODY, INCLUDE_BODY );
+
+    // disable the write callback, and get curl to write directly into our data buffer
+    curl_easy_setopt( curlHandle, CURLOPT_WRITEFUNCTION, NULL );
+    curl_easy_setopt( curlHandle, CURLOPT_WRITEDATA, dataBufferFilePointer );
+
+    // synchronous request of the body data
+    result = curl_easy_perform( curlHandle );
+  }
+  return result;
+}
+
+CURLcode DownloadFileDataByChunk( CURL* curlHandle, Dali::Vector<uint8_t>& dataBuffer, size_t& dataSize )
+{
+  // create
+  std::vector< ChunkData > chunks;
+
+  // we only want the body which contains the file data
+  curl_easy_setopt( curlHandle, CURLOPT_HEADER, EXCLUDE_HEADER );
+  curl_easy_setopt( curlHandle, CURLOPT_NOBODY, INCLUDE_BODY );
+
+  // Enable the write callback.
+  curl_easy_setopt( curlHandle, CURLOPT_WRITEFUNCTION, ChunkLoader );
+  curl_easy_setopt( curlHandle, CURLOPT_WRITEDATA, &chunks );
+
+  // synchronous request of the body data
+  CURLcode result = curl_easy_perform( curlHandle );
+
+  // chunks should now contain all of the chunked data. Reassemble into a single vector
+  dataSize = 0;
+  for( size_t i=0; i<chunks.size() ; ++i )
+  {
+    dataSize += chunks[i].data.capacity();
+  }
+  dataBuffer.Resize(dataSize);
+
+  size_t offset = 0;
+  for( size_t i=0; i<chunks.size() ; ++i )
+  {
+    memcpy( &dataBuffer[offset], &chunks[i].data[0], chunks[i].data.capacity() );
+    offset += chunks[i].data.capacity();
+  }
+
+  return result;
+}
+
+bool DownloadFile( CURL* curlHandle,
+                   const std::string& url,
+                   Dali::Vector<uint8_t>& dataBuffer,
+                   size_t& dataSize,
+                   size_t maximumAllowedSizeBytes )
+{
+  CURLcode result( CURLE_OK );
+  double size(0);
+
+  // setup curl to download just the header so we can extract the content length
+  ConfigureCurlOptions( curlHandle, url );
+
+  curl_easy_setopt( curlHandle, CURLOPT_WRITEFUNCTION, DummyWrite);
+
+  // perform the request to get the header
+  result = curl_easy_perform( curlHandle );
+
+  if( result != CURLE_OK)
+  {
+    DALI_LOG_ERROR( "Failed to download http header for \"%s\" with error code %d\n", url.c_str(), result );
+    return false;
+  }
+
+  // get the content length, -1 == size is not known
+  curl_easy_getinfo( curlHandle,CURLINFO_CONTENT_LENGTH_DOWNLOAD , &size );
+
+
+  if( size >= maximumAllowedSizeBytes )
+  {
+    DALI_LOG_ERROR( "File content length %f > max allowed %zu \"%s\" \n", size, maximumAllowedSizeBytes, url.c_str() );
+    return false;
+  }
+  else if( size > 0 )
+  {
+    // If we know the size up front, allocate once and avoid chunk copies.
+    dataSize = static_cast<size_t>( size );
+    result = DownloadFileDataWithSize( curlHandle, dataBuffer, dataSize );
+  }
+  else
+  {
+    result = DownloadFileDataByChunk( curlHandle, dataBuffer, dataSize );
+  }
+
+  if( result != CURLE_OK )
+  {
+    DALI_LOG_ERROR( "Failed to download image file \"%s\" with error code %d\n", url.c_str(), result );
+    return false;
+  }
+  return true;
+}
+
+
+} // unnamed namespace
+
+
+namespace Network
+{
+
+CurlEnvironment::CurlEnvironment()
+{
+  // Must be called before we attempt any loads. e.g. by using curl_easy_init()
+  // and before we start any threads.
+  curl_global_init(CURL_GLOBAL_ALL);
+}
+
+CurlEnvironment::~CurlEnvironment()
+{
+  curl_global_cleanup();
+}
+
+bool DownloadRemoteFileIntoMemory( const std::string& url,
+                                   Dali::Vector<uint8_t>& dataBuffer,
+                                   size_t& dataSize,
+                                   size_t maximumAllowedSizeBytes )
+{
+  bool result = false;
+
+  if( url.empty() )
+  {
+    DALI_LOG_WARNING("empty url requested \n");
+    return false;
+  }
+
+  // start a libcurl easy session, this internally calls curl_global_init, if we ever have more than one download
+  // thread we need to explicity call curl_global_init() on startup from a single thread.
+
+  CURL* curlHandle = curl_easy_init();
+  if ( curlHandle )
+  {
+    result = DownloadFile( curlHandle, url, dataBuffer,  dataSize, maximumAllowedSizeBytes);
+
+    // clean up session
+    curl_easy_cleanup( curlHandle );
+  }
+  return result;
+}
+
+} // namespace Network
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/dali/internal/imaging/common/file-download.h b/dali/internal/imaging/common/file-download.h
new file mode 100755 (executable)
index 0000000..d53438c
--- /dev/null
@@ -0,0 +1,89 @@
+#ifndef DALI_TIZEN_PLATFORM_NETWORK_FILE_DOWNLOAD_H
+#define DALI_TIZEN_PLATFORM_NETWORK_FILE_DOWNLOAD_H
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <string>
+#include <mutex> //c++11
+#include <stdint.h> // uint8
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace Network
+{
+
+/**
+ * Set up the cURL environment - this will ensure curl_global_init is called on startup
+ * and curl_global_cleanup is called on shutdown.
+ * Having this environment enables curl to be used in a single or multi-threaded
+ * program safely.
+ */
+class CurlEnvironment
+{
+public:
+  /**
+   * Constructor calls curl_global_init()
+   */
+  CurlEnvironment();
+
+  /**
+   * Destructor calls curl_global_cleanup()
+   */
+  ~CurlEnvironment();
+
+  // Moveable but not copyable
+
+  CurlEnvironment( const CurlEnvironment& ) = delete;
+  CurlEnvironment& operator=( const CurlEnvironment& ) = delete;
+  CurlEnvironment( CurlEnvironment&& ) = default;
+  CurlEnvironment& operator=( CurlEnvironment&& ) = default;
+};
+
+
+/**
+ * Download a requested file into a memory buffer.
+ *
+ * @note Threading notes: This function can be called from multiple threads, however
+ * we must explicitly call curl_global_init() from a single thread before using curl
+ * as the global function calls are not thread safe.
+ *
+ * @param[in] url The requested file url
+ * @param[out] dataBuffer  A memory buffer object to be written with downloaded file data.
+ * @param[out] dataSize  The size of the memory buffer.
+ * @param[in] maximumAllowedSize The maxmimum allowed file size in bytes to download. E.g. for an Image file this may be 50 MB
+ * @return true on success, false on failure
+ *
+ */
+bool DownloadRemoteFileIntoMemory( const std::string& url,
+                                   Dali::Vector<uint8_t>& dataBuffer,
+                                   size_t& dataSize,
+                                   size_t maximumAllowedSizeBytes );
+
+} // namespace Network
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // DALI_TIZEN_PLATFORM_RESOURCE_THREAD_IMAGE_H
diff --git a/dali/internal/imaging/common/gaussian-blur.cpp b/dali/internal/imaging/common/gaussian-blur.cpp
new file mode 100644 (file)
index 0000000..73eda57
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+
+// EXTERNAL INCLUDES
+#include <memory.h>
+#include <cmath>
+
+// INTERNAL INCLUDES
+#include <dali/internal/imaging/common/gaussian-blur.h>
+#include <dali/internal/imaging/common/pixel-buffer-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+
+
+void ConvoluteAndTranspose( unsigned char* inBuffer,
+                            unsigned char* outBuffer,
+                            const unsigned int bufferWidth,
+                            const unsigned int bufferHeight,
+                            const float blurRadius )
+{
+  // Calculate the weights for gaussian blur
+  int radius = static_cast<int>( std::ceil( blurRadius ) );
+  int rows = radius * 2 + 1;
+
+  float sigma = ( blurRadius < Math::MACHINE_EPSILON_1 ) ? 0.0f : blurRadius * 0.4f + 0.6f; // The same equation used by Android
+  float sigma22 = 2.0f * sigma * sigma;
+  float sqrtSigmaPi2 = std::sqrt( 2.0f * Math::PI ) * sigma;
+  float radius2 = radius * radius;
+  float normalizeFactor = 0.0f;
+
+  float* weightMatrix = new float[rows];
+  int index = 0;
+
+  for ( int row = -radius; row <= radius; row++ )
+  {
+    float distance = row * row;
+    if ( distance > radius2 )
+    {
+      weightMatrix[index] = 0.0f;
+    }
+    else
+    {
+      weightMatrix[index] = static_cast<float>( std::exp( -( distance ) / sigma22 ) / sqrtSigmaPi2 );
+    }
+    normalizeFactor += weightMatrix[index];
+    index++;
+  }
+
+  for ( int i = 0; i < rows; i++ )
+  {
+    weightMatrix[i] /= normalizeFactor;
+  }
+
+  // Perform the convolution and transposition using the weights
+  int columns = rows;
+  int columns2 = columns / 2;
+  for ( unsigned int y = 0; y < bufferHeight; y++ )
+  {
+    unsigned int targetPixelIndex = y;
+    unsigned int ioffset = y * bufferWidth;
+    for ( unsigned int x = 0; x < bufferWidth; x++ )
+    {
+      float r = 0.0f, g = 0.0f, b = 0.0f, a = 0.0f;
+      int weightColumnOffset = columns2;
+      for ( int column = -columns2; column <= columns2; column++ )
+      {
+        float weight = weightMatrix[weightColumnOffset + column];
+        if ( fabsf( weight ) > Math::MACHINE_EPSILON_1 )
+        {
+          int ix = x + column;
+          ix = std::max( 0, std::min( ix, static_cast<int>( bufferWidth - 1 ) ) );
+          unsigned int sourcePixelIndex = ioffset + ix;
+          r += weight * inBuffer[sourcePixelIndex*4];
+          g += weight * inBuffer[sourcePixelIndex*4+1];
+          b += weight * inBuffer[sourcePixelIndex*4+2];
+          a += weight * inBuffer[sourcePixelIndex*4+3];
+        }
+      }
+
+      outBuffer[targetPixelIndex*4] = std::max( 0, std::min( static_cast<int>( r + 0.5f ), 255 ) );
+      outBuffer[targetPixelIndex*4+1] = std::max( 0, std::min( static_cast<int>( g + 0.5f ), 255 ) );
+      outBuffer[targetPixelIndex*4+2] = std::max( 0, std::min( static_cast<int>( b + 0.5f ), 255 ) );
+      outBuffer[targetPixelIndex*4+3] = std::max( 0, std::min( static_cast<int>( a + 0.5f ), 255 ) );
+
+      targetPixelIndex += bufferHeight;
+    }
+  }
+
+  delete [] weightMatrix;
+}
+
+void PerformGaussianBlurRGBA( PixelBuffer& buffer, const float blurRadius )
+{
+  unsigned int bufferWidth = buffer.GetWidth();
+  unsigned int bufferHeight = buffer.GetHeight();
+
+  // Create a temporary buffer for the two-pass blur
+  PixelBufferPtr softShadowImageBuffer = PixelBuffer::New( bufferWidth, bufferHeight, Pixel::RGBA8888 );
+  memcpy( softShadowImageBuffer->GetBuffer(), buffer.GetBuffer(), 4u * bufferWidth * bufferHeight );
+
+  // We perform the blur first but write its output image buffer transposed, so that we
+  // can just do it in two passes. The first pass blurs horizontally and transposes, the
+  // second pass does the same, but as the image is now transposed, it's really doing a
+  // vertical blur. The second transposition makes the image the right way up again. This
+  // is much faster than doing a 2D convolution.
+  ConvoluteAndTranspose( buffer.GetBuffer(), softShadowImageBuffer->GetBuffer(), bufferWidth, bufferHeight, blurRadius );
+  ConvoluteAndTranspose( softShadowImageBuffer->GetBuffer(), buffer.GetBuffer(), bufferHeight, bufferWidth, blurRadius );
+
+  // On leaving scope, softShadowImageBuffer will get destroyed.
+}
+
+} //namespace Adaptor
+
+}// namespace Internal
+
+}// namespace Dali
diff --git a/dali/internal/imaging/common/gaussian-blur.h b/dali/internal/imaging/common/gaussian-blur.h
new file mode 100644 (file)
index 0000000..28b4342
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef DALI_INTERNAL_ADAPTOR_GAUSSIAN_BLUR_H
+#define DALI_INTERNAL_ADAPTOR_GAUSSIAN_BLUR_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/internal/imaging/common/pixel-buffer-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Perform a one dimension Gaussian blur convolution and write its output buffer transposed.
+ *
+ * @param[in] inBuffer The input buffer with the source image
+ * @param[in] outBuffer The output buffer with the Gaussian blur applied and transposed
+ * @param[in] bufferWidth The width of the buffer
+ * @param[in] bufferHeight The height of the buffer
+ * @param[in] blurRadius The radius for Gaussian blur
+ */
+void ConvoluteAndTranspose( unsigned char* inBuffer, unsigned char* outBuffer, const unsigned int bufferWidth, const unsigned int bufferHeight, const float blurRadius );
+
+/**
+ * Perform Gaussian blur on a buffer.
+ *
+ * A Gaussian blur is generated by replacing each pixel’s color values with the average of the surrounding pixels’
+ * colors. This region is a circle with the given radius. Thus, a bigger radius yields a blurrier image.
+ *
+ * @note The pixel format of the buffer must be RGBA8888
+ *
+ * @param[in] buffer The buffer to apply the Gaussian blur to
+ * @param[in] blurRadius The radius for Gaussian blur
+ */
+void PerformGaussianBlurRGBA( PixelBuffer& buffer, const float blurRadius );
+
+} //namespace Adaptor
+
+} //namespace Internal
+
+} //namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_GAUSSIAN_BLUR_H
diff --git a/dali/internal/imaging/common/http-utils.cpp b/dali/internal/imaging/common/http-utils.cpp
new file mode 100644 (file)
index 0000000..97d5e19
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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 <dali/internal/imaging/common/http-utils.h>
+
+// EXTERNAL INCLUDES
+#include <cstring>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace
+{
+const unsigned int MIN_HTTP_URL_LENGTH = 12; // assume we have a least http://xx/yy
+const char HTTP_URL[] = "http://";
+const char HTTPS_URL[] = "https://";
+}
+
+bool Network::IsHttpUrl( const std::string& path )
+{
+ if( path.size() <= MIN_HTTP_URL_LENGTH )
+ {
+   return false;
+ }
+
+ if( ( strncasecmp( path.c_str(), HTTP_URL,  sizeof(HTTP_URL)  -1 ) == 0 )  ||
+     ( strncasecmp( path.c_str(), HTTPS_URL, sizeof(HTTPS_URL) -1 ) == 0 ) )
+ {
+   return true;
+ }
+
+ return false;
+}
+
+} // TizenPlatform
+
+} // Dali
diff --git a/dali/internal/imaging/common/http-utils.h b/dali/internal/imaging/common/http-utils.h
new file mode 100644 (file)
index 0000000..01de460
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef DALI_TIZEN_PLATFORM_NETWORK_UTILS_H
+#define DALI_TIZEN_PLATFORM_NETWORK_UTILS_H
+
+/*
+ * Copyright (c) 2019 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 <string>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace Network
+{
+
+/**
+ * @brief Tests if a string starts with either http:// or https://
+ * @param[in] path string
+ * @return true if the path is a http url
+ */
+bool IsHttpUrl( const std::string& path );
+
+} // Network
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // DALI_TIZEN_PLATFORM_NETWORK_UTILS_H
diff --git a/dali/internal/imaging/common/image-loader-plugin-proxy.cpp b/dali/internal/imaging/common/image-loader-plugin-proxy.cpp
new file mode 100755 (executable)
index 0000000..1c61731
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/imaging/common/image-loader-plugin-proxy.h>
+
+// EXTERNAL INCLUDES
+#include <dlfcn.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace ImageLoaderPluginProxy
+{
+
+
+static const char * DEFAULT_OBJECT_NAME( "libdali-image-loader-plugin.so" );
+
+static bool mInitializeAttempted = false;
+static void* mLibHandle = NULL;
+static CreateImageLoaderPlugin* mCreatePluginFunctionPtr = NULL;
+static DestroyImageLoaderPlugin* mDestroyImageLoaderPluginPtr = NULL;
+static Dali::ImageLoaderPlugin* mImageLoaderPlugin = NULL;
+
+#if defined(DEBUG_ENABLED)
+/**
+ * Disable logging of image loader plugin proxy or make it verbose from the commandline
+ * as follows (e.g., for dali demo app):
+ * <code>
+ * LOG_IMAGE_LOADER_PLUGIN=0 dali-demo #< off
+ * LOG_IMAGE_LOADER_PLUGIN=3 dali-demo #< on, verbose
+ * </code>
+ */
+Debug::Filter* gImageLoaderPluginLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_IMAGE_LOADER_PLUGIN" );
+#endif
+
+void Initialize()
+{
+  // Only attempt to load dll once
+  char* error = NULL;
+  if ( !mInitializeAttempted )
+  {
+    mInitializeAttempted = true;
+    mLibHandle = dlopen( DEFAULT_OBJECT_NAME, RTLD_LAZY );
+    error = dlerror();
+    if( !mLibHandle )
+    {
+      DALI_LOG_INFO( gImageLoaderPluginLogFilter, Dali::Integration::Log::Verbose, "Cannot load dali image loading plugin library error: %s\n", error );
+      return;
+    }
+
+    // load plugin
+    mCreatePluginFunctionPtr = reinterpret_cast<CreateImageLoaderPlugin*>( dlsym( mLibHandle, "CreateImageLoaderPlugin" ) );
+    error = dlerror();
+    if( !mCreatePluginFunctionPtr )
+    {
+      DALI_LOG_ERROR("Cannot load symbol CreateImageLoaderPlugin(): %s\n", error );
+      return;
+    }
+
+    mDestroyImageLoaderPluginPtr = reinterpret_cast<DestroyImageLoaderPlugin*>( dlsym( mLibHandle, "DestroyImageLoaderPlugin" ) );
+    error = dlerror();
+    if( !mDestroyImageLoaderPluginPtr )
+    {
+      DALI_LOG_ERROR("Cannot load symbol DestroyImageLoaderPlugin(): %s\n", error );
+      return;
+    }
+
+
+    mImageLoaderPlugin = mCreatePluginFunctionPtr();
+    error = dlerror();
+    if( !mImageLoaderPlugin )
+    {
+      DALI_LOG_ERROR("Call to function CreateImageLoaderPlugin() failed : %s\n", error );
+      return;
+    }
+  }
+}
+
+void Destroy()
+{
+  if( mImageLoaderPlugin && mDestroyImageLoaderPluginPtr )
+  {
+    mDestroyImageLoaderPluginPtr( mImageLoaderPlugin );
+    mImageLoaderPlugin = NULL;
+  }
+}
+
+const ImageLoader::BitmapLoader* BitmapLoaderLookup( const std::string& filename )
+{
+  if( mImageLoaderPlugin )
+  {
+    const ImageLoader::BitmapLoader* data = mImageLoaderPlugin->BitmapLoaderLookup( filename );
+    return data;
+  }
+  return NULL;
+}
+
+} // namespace ImageLoaderPluginProxy
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/imaging/common/image-loader-plugin-proxy.h b/dali/internal/imaging/common/image-loader-plugin-proxy.h
new file mode 100755 (executable)
index 0000000..53d36d8
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef DALI_INTERNAL_IMAGE_LOADING_PLUGIN_PROXY_H
+#define DALI_INTERNAL_IMAGE_LOADING_PLUGIN_PROXY_H
+
+/*
+ * Copyright (c) 2018 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 <dali/devel-api/adaptor-framework/image-loader-plugin.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace ImageLoaderPluginProxy
+{
+
+ using CreateImageLoaderPlugin = Dali::ImageLoaderPlugin::CreateImageLoaderPlugin;
+ using DestroyImageLoaderPlugin = Dali::ImageLoaderPlugin::DestroyImageLoaderPlugin;
+
+
+ /**
+  * @brief Initialize
+  */
+ void Initialize();
+
+
+ /**
+  * @brief Destroy
+  */
+ void Destroy();
+
+ /**
+  * @brief BitmapLoaderLookup
+  */
+ const ImageLoader::BitmapLoader* BitmapLoaderLookup( const std::string& filename );
+
+
+} // namespace ImageLoaderPluginProxy
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_IMAGE_LOADING_PLUGIN_PROXY_H
diff --git a/dali/internal/imaging/common/image-loader.cpp b/dali/internal/imaging/common/image-loader.cpp
new file mode 100755 (executable)
index 0000000..5980796
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * 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/internal/imaging/common/image-loader.h>
+
+#include <dali/devel-api/common/ref-counted-dali-vector.h>
+#include <dali/internal/imaging/common/pixel-buffer-impl.h>
+
+#include <dali/internal/imaging/common/loader-astc.h>
+#include <dali/internal/imaging/common/loader-bmp.h>
+#include <dali/internal/imaging/common/loader-gif.h>
+#include <dali/internal/imaging/common/loader-ico.h>
+#include <dali/internal/imaging/common/loader-jpeg.h>
+#include <dali/internal/imaging/common/loader-ktx.h>
+#include <dali/internal/imaging/common/loader-png.h>
+#include <dali/internal/imaging/common/loader-wbmp.h>
+#include <dali/internal/imaging/common/image-operations.h>
+#include <dali/devel-api/adaptor-framework/image-loader-input.h>
+#include <dali/internal/imaging/common/image-loader-plugin-proxy.h>
+#include <dali/internal/system/common/file-reader.h>
+
+using namespace Dali::Integration;
+
+namespace Dali
+{
+namespace TizenPlatform
+{
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Integration::Log::Filter* gLogFilter = Debug::Filter::New( Debug::Concise, false, "LOG_IMAGE_LOADING" );
+#endif
+
+static unsigned int gMaxTextureSize = 4096;
+
+static bool gMaxTextureSizeUpdated = false;
+
+/**
+ * Enum for file formats, has to be in sync with BITMAP_LOADER_LOOKUP_TABLE
+ */
+enum FileFormats
+{
+  // Unknown file format
+  FORMAT_UNKNOWN = -1,
+
+  // formats that use magic bytes
+  FORMAT_PNG = 0,
+  FORMAT_JPEG,
+  FORMAT_BMP,
+  FORMAT_GIF,
+  FORMAT_KTX,
+  FORMAT_ASTC,
+  FORMAT_ICO,
+  FORMAT_MAGIC_BYTE_COUNT,
+
+  // formats after this one do not use magic bytes
+  FORMAT_WBMP = FORMAT_MAGIC_BYTE_COUNT,
+  FORMAT_TOTAL_COUNT
+};
+
+/**
+ * A lookup table containing all the bitmap loaders with the appropriate information.
+ * Has to be in sync with enum FileFormats
+ */
+const Dali::ImageLoader::BitmapLoader BITMAP_LOADER_LOOKUP_TABLE[FORMAT_TOTAL_COUNT] =
+{
+  { Png::MAGIC_BYTE_1,  Png::MAGIC_BYTE_2,  LoadBitmapFromPng,  LoadPngHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS },
+  { Jpeg::MAGIC_BYTE_1, Jpeg::MAGIC_BYTE_2, LoadBitmapFromJpeg, LoadJpegHeader, Bitmap::BITMAP_2D_PACKED_PIXELS },
+  { Bmp::MAGIC_BYTE_1,  Bmp::MAGIC_BYTE_2,  LoadBitmapFromBmp,  LoadBmpHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS },
+  { Gif::MAGIC_BYTE_1,  Gif::MAGIC_BYTE_2,  LoadBitmapFromGif,  LoadGifHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS },
+  { Ktx::MAGIC_BYTE_1,  Ktx::MAGIC_BYTE_2,  LoadBitmapFromKtx,  LoadKtxHeader,  Bitmap::BITMAP_COMPRESSED       },
+  { Astc::MAGIC_BYTE_1, Astc::MAGIC_BYTE_2, LoadBitmapFromAstc, LoadAstcHeader, Bitmap::BITMAP_COMPRESSED       },
+  { Ico::MAGIC_BYTE_1,  Ico::MAGIC_BYTE_2,  LoadBitmapFromIco,  LoadIcoHeader,  Bitmap::BITMAP_2D_PACKED_PIXELS },
+  { 0x0,                0x0,                LoadBitmapFromWbmp, LoadWbmpHeader, Bitmap::BITMAP_2D_PACKED_PIXELS },
+};
+
+const unsigned int MAGIC_LENGTH = 2;
+
+/**
+ * This code tries to predict the file format from the filename to help with format picking.
+ */
+struct FormatExtension
+{
+  const std::string extension;
+  FileFormats format;
+};
+
+const FormatExtension FORMAT_EXTENSIONS[] =
+{
+ { ".png",  FORMAT_PNG  },
+ { ".jpg",  FORMAT_JPEG },
+ { ".bmp",  FORMAT_BMP  },
+ { ".gif",  FORMAT_GIF  },
+ { ".ktx",  FORMAT_KTX  },
+ { ".astc", FORMAT_ASTC },
+ { ".ico",  FORMAT_ICO  },
+ { ".wbmp", FORMAT_WBMP }
+};
+
+const unsigned int FORMAT_EXTENSIONS_COUNT = sizeof(FORMAT_EXTENSIONS) / sizeof(FormatExtension);
+
+FileFormats GetFormatHint( const std::string& filename )
+{
+  FileFormats format = FORMAT_UNKNOWN;
+
+  for ( unsigned int i = 0; i < FORMAT_EXTENSIONS_COUNT; ++i )
+  {
+    unsigned int length = FORMAT_EXTENSIONS[i].extension.size();
+    if ( ( filename.size() > length ) &&
+         ( 0 == filename.compare( filename.size() - length, length, FORMAT_EXTENSIONS[i].extension ) ) )
+    {
+      format = FORMAT_EXTENSIONS[i].format;
+      break;
+    }
+  }
+
+  return format;
+}
+
+/**
+ * Checks the magic bytes of the file first to determine which Image decoder to use to decode the
+ * bitmap.
+ * @param[in]   fp      The file to decode
+ * @param[in]   format  Hint about what format to try first
+ * @param[out]  loader  Set with the function to use to decode the image
+ * @param[out]  header  Set with the function to use to decode the header
+ * @param[out]  profile The kind of bitmap to hold the bits loaded for the bitmap.
+ * @return true, if we can decode the image, false otherwise
+ */
+bool GetBitmapLoaderFunctions( FILE *fp,
+                               FileFormats format,
+                               Dali::ImageLoader::LoadBitmapFunction& loader,
+                               Dali::ImageLoader::LoadBitmapHeaderFunction& header,
+                               Bitmap::Profile& profile,
+                               const std::string& filename )
+{
+  unsigned char magic[MAGIC_LENGTH];
+  size_t read = fread(magic, sizeof(unsigned char), MAGIC_LENGTH, fp);
+
+  // Reset to the start of the file.
+  if( fseek(fp, 0, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking to start of file\n");
+  }
+
+  if (read != MAGIC_LENGTH)
+  {
+    return false;
+  }
+
+  bool loaderFound = false;
+  const Dali::ImageLoader::BitmapLoader *lookupPtr = BITMAP_LOADER_LOOKUP_TABLE;
+  Dali::ImageLoader::Input defaultInput( fp );
+
+  // try plugin image loader
+  const Dali::ImageLoader::BitmapLoader* data = Internal::Adaptor::ImageLoaderPluginProxy::BitmapLoaderLookup( filename );
+  if( data != NULL )
+  {
+    lookupPtr = data;
+    unsigned int width = 0;
+    unsigned int height = 0;
+    loaderFound = lookupPtr->header( fp, width, height );
+  }
+
+  // try hinted format
+  if ( false == loaderFound && format != FORMAT_UNKNOWN )
+  {
+    lookupPtr = BITMAP_LOADER_LOOKUP_TABLE + format;
+    if ( format >= FORMAT_MAGIC_BYTE_COUNT ||
+         ( lookupPtr->magicByte1 == magic[0] && lookupPtr->magicByte2 == magic[1] ) )
+    {
+      unsigned int width = 0;
+      unsigned int height = 0;
+      loaderFound = lookupPtr->header( fp, width, height );
+    }
+  }
+
+  // then try to get a match with formats that have magic bytes
+  if ( false == loaderFound )
+  {
+    for ( lookupPtr = BITMAP_LOADER_LOOKUP_TABLE;
+          lookupPtr < BITMAP_LOADER_LOOKUP_TABLE + FORMAT_MAGIC_BYTE_COUNT;
+          ++lookupPtr )
+    {
+      if ( lookupPtr->magicByte1 == magic[0] && lookupPtr->magicByte2 == magic[1] )
+      {
+        // to seperate ico file format and wbmp file format
+        unsigned int width = 0;
+        unsigned int height = 0;
+        loaderFound = lookupPtr->header(fp, width, height);
+      }
+      if (loaderFound)
+      {
+        break;
+      }
+    }
+  }
+
+  // finally try formats that do not use magic bytes
+  if ( false == loaderFound )
+  {
+    for ( lookupPtr = BITMAP_LOADER_LOOKUP_TABLE + FORMAT_MAGIC_BYTE_COUNT;
+          lookupPtr < BITMAP_LOADER_LOOKUP_TABLE + FORMAT_TOTAL_COUNT;
+          ++lookupPtr )
+    {
+      // to seperate ico file format and wbmp file format
+      unsigned int width = 0;
+      unsigned int height = 0;
+      loaderFound = lookupPtr->header(fp, width, height);
+      if (loaderFound)
+      {
+        break;
+      }
+    }
+  }
+
+  // if a loader was found set the outputs
+  if ( loaderFound )
+  {
+    loader  = lookupPtr->loader;
+    header  = lookupPtr->header;
+    profile = lookupPtr->profile;
+  }
+
+  // Reset to the start of the file.
+  if( fseek(fp, 0, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking to start of file\n");
+  }
+
+  return loaderFound;
+}
+
+} // anonymous namespace
+
+
+namespace ImageLoader
+{
+
+bool ConvertStreamToBitmap( const BitmapResourceType& resource, std::string path, FILE * const fp, Dali::Devel::PixelBuffer& pixelBuffer )
+{
+  DALI_LOG_TRACE_METHOD( gLogFilter );
+
+  bool result = false;
+
+  if (fp != NULL)
+  {
+    Dali::ImageLoader::LoadBitmapFunction function;
+    Dali::ImageLoader::LoadBitmapHeaderFunction header;
+
+    Bitmap::Profile profile;
+
+    if ( GetBitmapLoaderFunctions( fp,
+                                   GetFormatHint( path ),
+                                   function,
+                                   header,
+                                   profile,
+                                   path ) )
+    {
+      const Dali::ImageLoader::ScalingParameters scalingParameters( resource.size, resource.scalingMode, resource.samplingMode );
+      const Dali::ImageLoader::Input input( fp, scalingParameters, resource.orientationCorrection );
+
+      // Run the image type decoder:
+      result = function( input, pixelBuffer );
+
+      if (!result)
+      {
+        DALI_LOG_WARNING( "Unable to convert %s\n", path.c_str() );
+        pixelBuffer.Reset();
+      }
+
+      pixelBuffer = Internal::Platform::ApplyAttributesToBitmap( pixelBuffer, resource.size, resource.scalingMode, resource.samplingMode );
+    }
+    else
+    {
+      DALI_LOG_WARNING( "Image Decoder for %s unavailable\n", path.c_str() );
+    }
+  }
+
+  return result;
+}
+
+ResourcePointer LoadImageSynchronously( const Integration::BitmapResourceType& resource, const std::string& path )
+{
+  ResourcePointer result;
+  Dali::Devel::PixelBuffer bitmap;
+
+  Internal::Platform::FileReader fileReader( path );
+  FILE * const fp = fileReader.GetFile();
+  if( fp != NULL )
+  {
+    bool success = ConvertStreamToBitmap(resource, path, fp, bitmap);
+    if (success && bitmap)
+    {
+      Bitmap::Profile profile{Bitmap::Profile::BITMAP_2D_PACKED_PIXELS};
+
+      // For backward compatibility the Bitmap must be created
+      auto retval = Bitmap::New(profile, Dali::ResourcePolicy::OWNED_DISCARD);
+
+      DALI_LOG_SET_OBJECT_STRING( retval, path );
+
+      retval->GetPackedPixelsProfile()->ReserveBuffer(
+              bitmap.GetPixelFormat(),
+              bitmap.GetWidth(),
+              bitmap.GetHeight(),
+              bitmap.GetWidth(),
+              bitmap.GetHeight()
+            );
+
+      auto& impl = Dali::GetImplementation(bitmap);
+
+      std::copy( impl.GetBuffer(), impl.GetBuffer()+impl.GetBufferSize(), retval->GetBuffer());
+      result.Reset(retval);
+    }
+  }
+  return result;
+}
+
+///@ToDo: Rename GetClosestImageSize() functions. Make them use the orientation correction and scaling information. Requires jpeg loader to tell us about reorientation. [Is there still a requirement for this functionality at all?]
+ImageDimensions  GetClosestImageSize( const std::string& filename,
+                                      ImageDimensions size,
+                                      FittingMode::Type fittingMode,
+                                      SamplingMode::Type samplingMode,
+                                      bool orientationCorrection )
+{
+  unsigned int width = 0;
+  unsigned int height = 0;
+
+  Internal::Platform::FileReader fileReader( filename );
+  FILE *fp = fileReader.GetFile();
+  if (fp != NULL)
+  {
+    Dali::ImageLoader::LoadBitmapFunction loaderFunction;
+    Dali::ImageLoader::LoadBitmapHeaderFunction headerFunction;
+    Bitmap::Profile profile;
+
+    if ( GetBitmapLoaderFunctions( fp,
+                                   GetFormatHint(filename),
+                                   loaderFunction,
+                                   headerFunction,
+                                   profile,
+                                   filename ) )
+    {
+      const Dali::ImageLoader::Input input( fp, Dali::ImageLoader::ScalingParameters( size, fittingMode, samplingMode ), orientationCorrection );
+
+      const bool read_res = headerFunction( input, width, height );
+      if(!read_res)
+      {
+        DALI_LOG_WARNING("Image Decoder failed to read header for %s\n", filename.c_str());
+      }
+    }
+    else
+    {
+      DALI_LOG_WARNING("Image Decoder for %s unavailable\n", filename.c_str());
+    }
+  }
+  return ImageDimensions( width, height );
+}
+
+ImageDimensions GetClosestImageSize( Integration::ResourcePointer resourceBuffer,
+                                     ImageDimensions size,
+                                     FittingMode::Type fittingMode,
+                                     SamplingMode::Type samplingMode,
+                                     bool orientationCorrection )
+{
+  unsigned int width = 0;
+  unsigned int height = 0;
+
+  // Get the blob of binary data that we need to decode:
+  DALI_ASSERT_DEBUG( resourceBuffer );
+  Dali::RefCountedVector<uint8_t>* const encodedBlob = reinterpret_cast<Dali::RefCountedVector<uint8_t>*>( resourceBuffer.Get() );
+
+  if( encodedBlob != 0 )
+  {
+    if( encodedBlob->GetVector().Size() )
+    {
+      // Open a file handle on the memory buffer:
+      Internal::Platform::FileReader fileReader( encodedBlob->GetVector() );
+      FILE *fp = fileReader.GetFile();
+      if ( fp != NULL )
+      {
+        Dali::ImageLoader::LoadBitmapFunction loaderFunction;
+        Dali::ImageLoader::LoadBitmapHeaderFunction headerFunction;
+        Bitmap::Profile profile;
+
+        if ( GetBitmapLoaderFunctions( fp,
+                                       FORMAT_UNKNOWN,
+                                       loaderFunction,
+                                       headerFunction,
+                                       profile,
+                                       "" ) )
+        {
+          const Dali::ImageLoader::Input input( fp, Dali::ImageLoader::ScalingParameters( size, fittingMode, samplingMode ), orientationCorrection );
+          const bool read_res = headerFunction( input, width, height );
+          if( !read_res )
+          {
+            DALI_LOG_WARNING( "Image Decoder failed to read header for resourceBuffer\n" );
+          }
+        }
+      }
+    }
+  }
+  return ImageDimensions( width, height );
+}
+
+void SetMaxTextureSize( unsigned int size )
+{
+  gMaxTextureSize = size;
+  gMaxTextureSizeUpdated = true;
+}
+
+unsigned int GetMaxTextureSize()
+{
+  return gMaxTextureSize;
+}
+
+bool MaxTextureSizeUpdated()
+{
+  return gMaxTextureSizeUpdated;
+}
+
+} // ImageLoader
+} // TizenPlatform
+} // Dali
diff --git a/dali/internal/imaging/common/image-loader.h b/dali/internal/imaging/common/image-loader.h
new file mode 100644 (file)
index 0000000..a7c42a0
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef DALI_TIZEN_PLATFORM_IMAGE_LOADER_H
+#define DALI_TIZEN_PLATFORM_IMAGE_LOADER_H
+
+/*
+ * Copyright (c) 2019 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/images/image-operations.h>
+#include <dali/integration-api/resource-types.h>
+#include <dali/integration-api/bitmap.h>
+#include <dali/public-api/images/pixel-data.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <string>
+
+namespace Dali
+{
+namespace Integration
+{
+typedef IntrusivePtr<Dali::RefObject> ResourcePointer;
+} // Integration
+
+namespace TizenPlatform
+{
+namespace ImageLoader
+{
+/**
+ * Convert a file stream into a bitmap.
+ * @param[in] resource The resource to convert.
+ * @param[in] path The path to the resource.
+ * @param[in] fp File Pointer. Closed on exit.
+ * @param[out] bitmap Pointer to write bitmap to
+ * @return true on success, false on failure
+ */
+bool ConvertStreamToBitmap( const Integration::BitmapResourceType& resource, std::string path, FILE * const fp, Dali::Devel::PixelBuffer& pixelBuffer );
+
+/**
+ * Convert a bitmap and write to a file stream.
+ * @param[in] path The path to the resource.
+ * @param[in] fp File Pointer. Closed on exit.
+ * @param[out] pixelData Reference to PixelData object.
+ * @return true on success, false on failure
+ */
+bool ConvertBitmapToStream( std::string path, FILE * const fp, Dali::Devel::PixelBuffer& pixelBuffer );
+
+/**
+ * Loads an image synchronously
+ * @param resource details of the image
+ * @param path to the image
+ * @return bitmap
+ */
+Integration::ResourcePointer LoadImageSynchronously( const Integration::BitmapResourceType& resource, const std::string& path );
+
+/**
+ * @returns the closest image size
+ */
+ImageDimensions  GetClosestImageSize( const std::string& filename,
+                          ImageDimensions size,
+                          FittingMode::Type fittingMode,
+                          SamplingMode::Type samplingMode,
+                          bool orientationCorrection );
+
+/**
+ * @returns the closest image size
+ */
+ImageDimensions GetClosestImageSize( Integration::ResourcePointer resourceBuffer,
+                          ImageDimensions size,
+                          FittingMode::Type fittingMode,
+                          SamplingMode::Type samplingMode,
+                          bool orientationCorrection );
+
+/**
+ * @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();
+
+/**
+ * @brief Check the gMaxTextureSize is updated or not.
+ *
+ * @return Whether the gMaxTextureSize is updated or not.
+ */
+bool MaxTextureSizeUpdated();
+
+} // ImageLoader
+} // TizenPlatform
+} // Dali
+
+#endif // DALI_TIZEN_PLATFORM_IMAGE_LOADER_H
diff --git a/dali/internal/imaging/common/image-operations.cpp b/dali/internal/imaging/common/image-operations.cpp
new file mode 100755 (executable)
index 0000000..d75e027
--- /dev/null
@@ -0,0 +1,2413 @@
+/*
+ * Copyright (c) 2019 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/internal/imaging/common/image-operations.h>
+
+// EXTERNAL INCLUDES
+#include <cstring>
+#include <stddef.h>
+#include <cmath>
+#include <limits>
+#include <memory>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/math/vector2.h>
+#include <third-party/resampler/resampler.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Platform
+{
+
+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 );
+
+// 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 float RAD_135 = Math::PI_2 + Math::PI_4; ///< 135 degrees in radians;
+const float RAD_225 = RAD_135    + Math::PI_2; ///< 225 degrees in radians;
+const float RAD_270 = 3.f * Math::PI_2;        ///< 270 degrees in radians;
+const float RAD_315 = RAD_225    + Math::PI_2; ///< 315 degrees in radians;
+
+using Integration::Bitmap;
+using Integration::BitmapPtr;
+typedef unsigned char PixelBuffer;
+
+/**
+ * @brief 4 byte pixel structure.
+ */
+struct Pixel4Bytes
+{
+  uint8_t r;
+  uint8_t g;
+  uint8_t b;
+  uint8_t a;
+} __attribute__((packed, aligned(4))); //< Tell the compiler it is okay to use a single 32 bit load.
+
+/**
+ * @brief RGB888 pixel structure.
+ */
+struct Pixel3Bytes
+{
+  uint8_t r;
+  uint8_t g;
+  uint8_t b;
+} __attribute__((packed, aligned(1)));
+
+/**
+ * @brief RGB565 pixel typedefed from a short.
+ *
+ * Access fields by manual shifting and masking.
+ */
+typedef uint16_t PixelRGB565;
+
+/**
+ * @brief a Pixel composed of two independent byte components.
+ */
+struct Pixel2Bytes
+{
+  uint8_t l;
+  uint8_t a;
+} __attribute__((packed, aligned(2))); //< Tell the compiler it is okay to use a single 16 bit load.
+
+
+#if defined(DEBUG_ENABLED)
+/**
+ * Disable logging of image operations or make it verbose from the commandline
+ * as follows (e.g., for dali demo app):
+ * <code>
+ * LOG_IMAGE_OPERATIONS=0 dali-demo #< off
+ * LOG_IMAGE_OPERATIONS=3 dali-demo #< on, verbose
+ * </code>
+ */
+Debug::Filter* gImageOpsLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_IMAGE_OPERATIONS" );
+#endif
+
+/** @return The greatest even number less than or equal to the argument. */
+inline unsigned int EvenDown( const unsigned int a )
+{
+  const unsigned int evened = a & ~1u;
+  return evened;
+}
+
+/**
+ * @brief Log bad parameters.
+ */
+void ValidateScalingParameters( const unsigned int inputWidth,
+                                const unsigned int inputHeight,
+                                const unsigned int desiredWidth,
+                                const unsigned int desiredHeight )
+{
+  if( desiredWidth > inputWidth || desiredHeight > inputHeight )
+  {
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Upscaling not supported (%u, %u -> %u, %u).\n", inputWidth, inputHeight, desiredWidth, desiredHeight );
+  }
+
+  if( desiredWidth == 0u || desiredHeight == 0u )
+  {
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Downscaling to a zero-area target is pointless.\n" );
+  }
+
+  if( inputWidth == 0u || inputHeight == 0u )
+  {
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Zero area images cannot be scaled\n" );
+  }
+}
+
+/**
+ * @brief Do debug assertions common to all scanline halving functions.
+ * @note Inline and in anon namespace so should boil away in release builds.
+ */
+inline void DebugAssertScanlineParameters( const uint8_t * const pixels, const unsigned int width )
+{
+  DALI_ASSERT_DEBUG( pixels && "Null pointer." );
+  DALI_ASSERT_DEBUG( width > 1u && "Can't average fewer than two pixels." );
+  DALI_ASSERT_DEBUG( width < 131072u && "Unusually wide image: are you sure you meant to pass that value in?" );
+}
+
+/**
+ * @brief Assertions on params to functions averaging pairs of scanlines.
+ * @note Inline as intended to boil away in release.
+ */
+inline void DebugAssertDualScanlineParameters( const uint8_t * const scanline1,
+                                               const uint8_t * const scanline2,
+                                               uint8_t* const outputScanline,
+                                               const size_t widthInComponents )
+{
+  DALI_ASSERT_DEBUG( scanline1 && "Null pointer." );
+  DALI_ASSERT_DEBUG( scanline2 && "Null pointer." );
+  DALI_ASSERT_DEBUG( outputScanline && "Null pointer." );
+  DALI_ASSERT_DEBUG( ((scanline1 >= scanline2 + widthInComponents) || (scanline2 >= scanline1 + widthInComponents )) && "Scanlines alias." );
+  DALI_ASSERT_DEBUG( ((outputScanline >= (scanline2 + widthInComponents)) || (scanline2 >= (scanline1 + widthInComponents))) && "Scanline 2 aliases output." );
+}
+
+/**
+ * @brief Converts a scaling mode to the definition of which dimensions matter when box filtering as a part of that mode.
+ */
+BoxDimensionTest DimensionTestForScalingMode( FittingMode::Type fittingMode )
+{
+  BoxDimensionTest dimensionTest;
+  dimensionTest = BoxDimensionTestEither;
+
+  switch( fittingMode )
+  {
+    // Shrink to fit attempts to make one or zero dimensions smaller than the
+    // desired dimensions and one or two dimensions exactly the same as the desired
+    // ones, so as long as one dimension is larger than the desired size, box
+    // filtering can continue even if the second dimension is smaller than the
+    // desired dimensions:
+    case FittingMode::SHRINK_TO_FIT:
+    {
+      dimensionTest = BoxDimensionTestEither;
+      break;
+    }
+    // Scale to fill mode keeps both dimensions at least as large as desired:
+    case FittingMode::SCALE_TO_FILL:
+    {
+      dimensionTest = BoxDimensionTestBoth;
+      break;
+    }
+    // Y dimension is irrelevant when downscaling in FIT_WIDTH mode:
+    case FittingMode::FIT_WIDTH:
+    {
+      dimensionTest = BoxDimensionTestX;
+      break;
+    }
+    // X Dimension is ignored by definition in FIT_HEIGHT mode:
+    case FittingMode::FIT_HEIGHT:
+    {
+      dimensionTest = BoxDimensionTestY;
+      break;
+    }
+  }
+
+  return dimensionTest;
+}
+
+/**
+ * @brief Work out the dimensions for a uniform scaling of the input to map it
+ * into the target while effecting ShinkToFit scaling mode.
+ */
+ImageDimensions FitForShrinkToFit( ImageDimensions target, ImageDimensions source )
+{
+  // Scale the input by the least extreme of the two dimensions:
+  const float widthScale  = target.GetX() / float(source.GetX());
+  const float heightScale = target.GetY() / float(source.GetY());
+  const float scale = widthScale < heightScale ? widthScale : heightScale;
+
+  // Do no scaling at all if the result would increase area:
+  if( scale >= 1.0f )
+  {
+    return source;
+  }
+
+  return ImageDimensions( source.GetX() * scale + 0.5f, source.GetY() * scale + 0.5f );
+}
+
+/**
+ * @brief Work out the dimensions for a uniform scaling of the input to map it
+ * into the target while effecting SCALE_TO_FILL scaling mode.
+ * @note An image scaled into the output dimensions will need either top and
+ * bottom or left and right to be cropped away unless the source was pre-cropped
+ * to match the destination aspect ratio.
+ */
+ImageDimensions FitForScaleToFill( ImageDimensions target, ImageDimensions source )
+{
+  DALI_ASSERT_DEBUG( source.GetX() > 0 && source.GetY() > 0  && "Zero-area rectangles should not be passed-in" );
+  // Scale the input by the least extreme of the two dimensions:
+  const float widthScale  = target.GetX() / float(source.GetX());
+  const float heightScale = target.GetY() / float(source.GetY());
+  const float scale = widthScale > heightScale ? widthScale : heightScale;
+
+  // Do no scaling at all if the result would increase area:
+  if( scale >= 1.0f )
+  {
+    return source;
+  }
+
+  return ImageDimensions( source.GetX() * scale + 0.5f, source.GetY() * scale + 0.5f );
+}
+
+/**
+ * @brief Work out the dimensions for a uniform scaling of the input to map it
+ * into the target while effecting FIT_WIDTH scaling mode.
+ */
+ImageDimensions FitForFitWidth( ImageDimensions target, ImageDimensions source )
+{
+  DALI_ASSERT_DEBUG( source.GetX() > 0 && "Cant fit a zero-dimension rectangle." );
+  const float scale  = target.GetX() / float(source.GetX());
+
+  // Do no scaling at all if the result would increase area:
+  if( scale >= 1.0f )
+  {
+   return source;
+  }
+  return ImageDimensions( source.GetX() * scale + 0.5f, source.GetY() * scale + 0.5f );
+}
+
+/**
+ * @brief Work out the dimensions for a uniform scaling of the input to map it
+ * into the target while effecting FIT_HEIGHT scaling mode.
+ */
+ImageDimensions FitForFitHeight( ImageDimensions target, ImageDimensions source )
+{
+  DALI_ASSERT_DEBUG( source.GetY() > 0 && "Cant fit a zero-dimension rectangle." );
+  const float scale = target.GetY() / float(source.GetY());
+
+  // Do no scaling at all if the result would increase area:
+  if( scale >= 1.0f )
+  {
+    return source;
+  }
+
+  return ImageDimensions( source.GetX() * scale + 0.5f, source.GetY() * scale + 0.5f );
+}
+
+/**
+ * @brief Generate the rectangle to use as the target of a pixel sampling pass
+ * (e.g., nearest or linear).
+ */
+ImageDimensions FitToScalingMode( ImageDimensions requestedSize, ImageDimensions sourceSize, FittingMode::Type fittingMode )
+{
+  ImageDimensions fitDimensions;
+  switch( fittingMode )
+  {
+    case FittingMode::SHRINK_TO_FIT:
+    {
+      fitDimensions = FitForShrinkToFit( requestedSize, sourceSize );
+      break;
+    }
+    case FittingMode::SCALE_TO_FILL:
+    {
+      fitDimensions = FitForScaleToFill( requestedSize, sourceSize );
+      break;
+    }
+    case FittingMode::FIT_WIDTH:
+    {
+      fitDimensions = FitForFitWidth( requestedSize, sourceSize );
+      break;
+    }
+    case FittingMode::FIT_HEIGHT:
+    {
+      fitDimensions = FitForFitHeight( requestedSize, sourceSize );
+      break;
+    }
+  }
+
+  return fitDimensions;
+}
+
+/**
+ * @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 int sourceWidth( static_cast<int>( sourceSize.GetWidth() ) );
+  const int sourceHeight( static_cast<int>(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;
+    }
+  }
+
+  requestedSize.SetWidth( finalWidth );
+  requestedSize.SetHeight( finalHeight );
+}
+
+/**
+ * @brief Construct a pixel buffer object from a copy of the pixel array passed in.
+ */
+Dali::Devel::PixelBuffer MakePixelBuffer( const uint8_t * const pixels, Pixel::Format pixelFormat, unsigned int width, unsigned int height )
+{
+  DALI_ASSERT_DEBUG( pixels && "Null bitmap buffer to copy." );
+
+  // Allocate a pixel buffer to hold the image passed in:
+  auto newBitmap = Dali::Devel::PixelBuffer::New( width, height, pixelFormat );
+
+  // Copy over the pixels from the downscaled image that was generated in-place in the pixel buffer of the input bitmap:
+  memcpy( newBitmap.GetBuffer(), pixels, width * height * Pixel::GetBytesPerPixel( pixelFormat ) );
+  return newBitmap;
+}
+
+/**
+ * @brief Work out the desired width and height, accounting for zeros.
+ *
+ * @param[in] bitmapWidth Width of image before processing.
+ * @param[in] bitmapHeight Height of image before processing.
+ * @param[in] requestedWidth Width of area to scale image into. Can be zero.
+ * @param[in] requestedHeight Height of area to scale image into. Can be zero.
+ * @return Dimensions of area to scale image into after special rules are applied.
+ */
+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 )
+  {
+    if( bitmapWidth <= maxSize && bitmapHeight <= maxSize )
+    {
+      return ImageDimensions( bitmapWidth, bitmapHeight );
+    }
+    else
+    {
+      // Calculate the size from the max texture size and the source image aspect ratio
+      if( bitmapWidth > bitmapHeight )
+      {
+        return ImageDimensions( maxSize, bitmapHeight * maxSize / static_cast< float >( bitmapWidth ) + 0.5f );
+      }
+      else
+      {
+        return ImageDimensions( bitmapWidth * maxSize / static_cast< float >( bitmapHeight ) + 0.5f, maxSize );
+      }
+    }
+  }
+
+  // If both dimensions have values requested, use them both:
+  if( requestedWidth != 0 && requestedHeight != 0 )
+  {
+    if( requestedWidth <= maxSize && requestedHeight <= maxSize )
+    {
+      return ImageDimensions( requestedWidth, requestedHeight );
+    }
+    else
+    {
+      // Calculate the size from the max texture size and the source image aspect ratio
+      if( requestedWidth > requestedHeight )
+      {
+        return ImageDimensions( maxSize, requestedHeight * maxSize / static_cast< float >( requestedWidth ) + 0.5f );
+      }
+      else
+      {
+        return ImageDimensions( requestedWidth * maxSize / static_cast< float >( requestedHeight ) + 0.5f, 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 );
+}
+
+/**
+ * @brief Rotates the given buffer @p pixelsIn 90 degrees counter clockwise.
+ *
+ * @note It allocates memory for the returned @p pixelsOut buffer.
+ * @note Code got from https://www.codeproject.com/Articles/202/High-quality-image-rotation-rotate-by-shear by Eran Yariv.
+ * @note It may fail if malloc() fails to allocate memory.
+ *
+ * @param[in] pixelsIn The input buffer.
+ * @param[in] widthIn The width of the input buffer.
+ * @param[in] heightIn The height of the input buffer.
+ * @param[in] pixelSize The size of the pixel.
+ * @param[out] pixelsOut The rotated output buffer.
+ * @param[out] widthOut The width of the output buffer.
+ * @param[out] heightOut The height of the output buffer.
+ *
+ * @return Whether the rotation succeded.
+ */
+bool Rotate90( const uint8_t* const pixelsIn,
+               unsigned int widthIn,
+               unsigned int heightIn,
+               unsigned int pixelSize,
+               uint8_t*& pixelsOut,
+               unsigned int& widthOut,
+               unsigned int& heightOut )
+{
+  // The new size of the image.
+  widthOut = heightIn;
+  heightOut = widthIn;
+
+  // Allocate memory for the rotated buffer.
+  pixelsOut = static_cast<uint8_t*>( malloc ( widthOut * heightOut * pixelSize ) );
+  if( nullptr == pixelsOut )
+  {
+    widthOut = 0u;
+    heightOut = 0u;
+
+    // Return if the memory allocations fails.
+    return false;
+  }
+
+  // Rotate the buffer.
+  for( unsigned int y = 0u; y < heightIn; ++y )
+  {
+    const unsigned int srcLineIndex = y * widthIn;
+    const unsigned int dstX = y;
+    for( unsigned int x = 0u; x < widthIn; ++x )
+    {
+      const unsigned int dstY = heightOut - x - 1u;
+      const unsigned int dstIndex = pixelSize * ( dstY * widthOut + dstX );
+      const unsigned int srcIndex = pixelSize * ( srcLineIndex + x );
+
+      for( unsigned int channel = 0u; channel < pixelSize; ++channel )
+      {
+        *( pixelsOut + dstIndex + channel ) = *( pixelsIn + srcIndex + channel );
+      }
+    }
+  }
+
+  return true;
+}
+
+/**
+ * @brief Rotates the given buffer @p pixelsIn 180 degrees counter clockwise.
+ *
+ * @note It allocates memory for the returned @p pixelsOut buffer.
+ * @note Code got from https://www.codeproject.com/Articles/202/High-quality-image-rotation-rotate-by-shear by Eran Yariv.
+ * @note It may fail if malloc() fails to allocate memory.
+ *
+ * @param[in] pixelsIn The input buffer.
+ * @param[in] widthIn The width of the input buffer.
+ * @param[in] heightIn The height of the input buffer.
+ * @param[in] pixelSize The size of the pixel.
+ * @param[out] pixelsOut The rotated output buffer.
+ *
+ * @return Whether the rotation succeded.
+ */
+bool Rotate180( const uint8_t* const pixelsIn,
+                unsigned int widthIn,
+                unsigned int heightIn,
+                unsigned int pixelSize,
+                uint8_t*& pixelsOut )
+{
+  // Allocate memory for the rotated buffer.
+  pixelsOut = static_cast<uint8_t*>( malloc ( widthIn * heightIn * pixelSize ) );
+  if( nullptr == pixelsOut )
+  {
+    // Return if the memory allocations fails.
+    return false;
+  }
+
+  // Rotate the buffer.
+  for( unsigned int y = 0u; y < heightIn; ++y )
+  {
+    const unsigned int srcLineIndex = y * widthIn;
+    const unsigned int dstY = heightIn - y - 1u;
+    for( unsigned int x = 0u; x < widthIn; ++x )
+    {
+      const unsigned int dstX = widthIn - x - 1u;
+      const unsigned int dstIndex = pixelSize * ( dstY * widthIn + dstX );
+      const unsigned int srcIndex = pixelSize * ( srcLineIndex + x );
+
+      for( unsigned int channel = 0u; channel < pixelSize; ++channel )
+      {
+        *( pixelsOut + dstIndex + channel ) = *( pixelsIn + srcIndex + channel );
+      }
+    }
+  }
+
+  return true;
+}
+
+/**
+ * @brief Rotates the given buffer @p pixelsIn 270 degrees counter clockwise.
+ *
+ * @note It allocates memory for the returned @p pixelsOut buffer.
+ * @note Code got from https://www.codeproject.com/Articles/202/High-quality-image-rotation-rotate-by-shear by Eran Yariv.
+ * @note It may fail if malloc() fails to allocate memory.
+ *
+ * @param[in] pixelsIn The input buffer.
+ * @param[in] widthIn The width of the input buffer.
+ * @param[in] heightIn The height of the input buffer.
+ * @param[in] pixelSize The size of the pixel.
+ * @param[out] pixelsOut The rotated output buffer.
+ * @param[out] widthOut The width of the output buffer.
+ * @param[out] heightOut The height of the output buffer.
+ *
+ * @return Whether the rotation succeded.
+ */
+bool Rotate270( const uint8_t* const pixelsIn,
+                unsigned int widthIn,
+                unsigned int heightIn,
+                unsigned int pixelSize,
+                uint8_t*& pixelsOut,
+                unsigned int& widthOut,
+                unsigned int& heightOut )
+{
+  // The new size of the image.
+  widthOut = heightIn;
+  heightOut = widthIn;
+
+  // Allocate memory for the rotated buffer.
+  pixelsOut = static_cast<uint8_t*>( malloc ( widthOut * heightOut * pixelSize ) );
+  if( nullptr == pixelsOut )
+  {
+    widthOut = 0u;
+    heightOut = 0u;
+
+    // Return if the memory allocations fails.
+    return false;
+  }
+
+  // Rotate the buffer.
+  for( unsigned int y = 0u; y < heightIn; ++y )
+  {
+    const unsigned int srcLineIndex = y * widthIn;
+    const unsigned int dstX = widthOut - y - 1u;
+    for( unsigned int x = 0u; x < widthIn; ++x )
+    {
+      const unsigned int dstY = x;
+      const unsigned int dstIndex = pixelSize * ( dstY * widthOut + dstX );
+      const unsigned int srcIndex = pixelSize * ( srcLineIndex + x );
+
+      for( unsigned int channel = 0u; channel < pixelSize; ++channel )
+      {
+        *( pixelsOut + dstIndex + channel ) = *( pixelsIn + srcIndex + channel );
+      }
+    }
+  }
+
+  return true;
+}
+
+/**
+ * @brief Skews a row horizontally (with filtered weights)
+ *
+ * @note Limited to 45 degree skewing only.
+ * @note Code got from https://www.codeproject.com/Articles/202/High-quality-image-rotation-rotate-by-shear by Eran Yariv.
+ *
+ * @param[in] srcBufferPtr Pointer to the input pixel buffer.
+ * @param[in] srcWidth The width of the input pixel buffer.
+ * @param[in] pixelSize The size of the pixel.
+ * @param[in,out] dstPixelBuffer Pointer to the output pixel buffer.
+ * @param[in] dstWidth The width of the output pixel buffer.
+ * @param[in] row The row index.
+ * @param[in] offset The skew offset.
+ * @param[in] weight The relative weight of right pixel.
+ */
+void HorizontalSkew( const uint8_t* const srcBufferPtr,
+                     int srcWidth,
+                     unsigned int pixelSize,
+                     uint8_t*& dstBufferPtr,
+                     int dstWidth,
+                     unsigned int row,
+                     int offset,
+                     float weight )
+{
+  if( offset > 0 )
+  {
+    // Fill gap left of skew with background.
+    memset( dstBufferPtr + row * pixelSize * dstWidth, 0u, pixelSize * offset );
+  }
+
+  unsigned char oldLeft[4u] = { 0u, 0u, 0u, 0u };
+
+  int i = 0;
+  for( i = 0u; i < srcWidth; ++i )
+  {
+    // Loop through row pixels
+    const unsigned int srcIndex = pixelSize * ( row * srcWidth + i );
+
+    unsigned char src[4u] = { 0u, 0u, 0u, 0u };
+    for( unsigned int channel = 0u; channel < pixelSize; ++channel )
+    {
+      src[channel] = *( srcBufferPtr + srcIndex + channel );
+    }
+
+    // Calculate weights
+    unsigned char left[4u] = { 0u, 0u, 0u, 0u };
+    for( unsigned int channel = 0u; channel < pixelSize; ++channel )
+    {
+      left[channel] = static_cast<unsigned char>( static_cast<float>( src[channel] ) * weight );
+
+      // Update left over on source
+      src[channel] -= ( left[channel] - oldLeft[channel] );
+    }
+
+    // Check boundaries
+    if( ( i + offset >= 0 ) && ( i + offset < dstWidth ) )
+    {
+      const unsigned int dstIndex = pixelSize * ( row * dstWidth + i + offset );
+
+      for( unsigned int channel = 0u; channel < pixelSize; ++channel )
+      {
+        *( dstBufferPtr + dstIndex + channel ) = src[channel];
+      }
+    }
+
+    // Save leftover for next pixel in scan
+    for( unsigned int channel = 0u; channel < pixelSize; ++channel )
+    {
+      oldLeft[channel] = left[channel];
+    }
+  }
+
+  // Go to rightmost point of skew
+  i += offset;
+  if( i < dstWidth )
+  {
+    // If still in image bounds, put leftovers there
+    const unsigned int dstIndex = pixelSize * ( row * dstWidth + i );
+
+    for( unsigned int channel = 0u; channel < pixelSize; ++channel )
+    {
+      *( dstBufferPtr + dstIndex + channel ) = oldLeft[channel];
+    }
+
+    // Clear to the right of the skewed line with background
+    ++i;
+    memset( dstBufferPtr + pixelSize * ( row * dstWidth + i ), 0u, pixelSize * ( dstWidth - i ) );
+  }
+}
+
+/**
+ * @brief Skews a column vertically (with filtered weights)
+ *
+ * @note Limited to 45 degree skewing only.
+ * @note Code got from https://www.codeproject.com/Articles/202/High-quality-image-rotation-rotate-by-shear by Eran Yariv.
+ *
+ * @param[in] srcBufferPtr Pointer to the input pixel buffer.
+ * @param[in] srcWidth The width of the input pixel buffer.
+ * @param[in] srcHeight The height of the input pixel buffer.
+ * @param[in] pixelSize The size of the pixel.
+ * @param[in,out] dstPixelBuffer Pointer to the output pixel buffer.
+ * @param[in] dstWidth The width of the output pixel buffer.
+ * @param[in] dstHeight The height of the output pixel buffer.
+ * @param[in] column The column index.
+ * @param[in] offset The skew offset.
+ * @param[in] weight The relative weight of uppeer pixel.
+ */
+void VerticalSkew( const uint8_t* const srcBufferPtr,
+                   int srcWidth,
+                   int srcHeight,
+                   unsigned int pixelSize,
+                   uint8_t*& dstBufferPtr,
+                   int dstWidth,
+                   int dstHeight,
+                   unsigned int column,
+                   int offset,
+                   float weight )
+{
+  for( int i = 0; i < offset; ++i )
+  {
+    // Fill gap above skew with background
+    const unsigned int dstIndex = pixelSize * ( i * dstWidth + column );
+
+    for( unsigned int channel = 0u; channel < pixelSize; ++channel )
+    {
+      *( dstBufferPtr + dstIndex + channel ) = 0u;
+    }
+  }
+
+  unsigned char oldLeft[4u] = { 0u, 0u, 0u, 0u };
+
+  int yPos = 0;
+  int i = 0;
+  for( i = 0; i < srcHeight; ++i )
+  {
+    // Loop through column pixels
+    const unsigned int srcIndex = pixelSize * ( i * srcWidth + column );
+
+    unsigned char src[4u] = { 0u, 0u, 0u, 0u };
+    for( unsigned int channel = 0u; channel < pixelSize; ++channel )
+    {
+      src[channel] = *( srcBufferPtr + srcIndex + channel );
+    }
+
+    yPos = i + offset;
+
+    // Calculate weights
+    unsigned char left[4u] = { 0u, 0u, 0u, 0u };
+    for( unsigned int channel = 0u; channel < pixelSize; ++channel )
+    {
+      left[channel] = static_cast<unsigned char>( static_cast<float>( src[channel] ) * weight );
+      // Update left over on source
+      src[channel] -= ( left[channel] - oldLeft[channel] );
+    }
+
+    // Check boundaries
+    if( ( yPos >= 0 ) && ( yPos < dstHeight ) )
+    {
+      const unsigned int dstIndex = pixelSize * ( yPos * dstWidth + column );
+
+      for( unsigned int channel = 0u; channel < pixelSize; ++channel )
+      {
+        *( dstBufferPtr + dstIndex + channel ) = src[channel];
+      }
+    }
+
+    // Save leftover for next pixel in scan
+    for( unsigned int channel = 0u; channel < pixelSize; ++channel )
+    {
+      oldLeft[channel] = left[channel];
+    }
+  }
+
+  // Go to bottom point of skew
+  i = yPos;
+  if( i < dstHeight )
+  {
+    // If still in image bounds, put leftovers there
+    const unsigned int dstIndex = pixelSize * ( i * dstWidth + column );
+
+    for( unsigned int channel = 0u; channel < pixelSize; ++channel )
+    {
+      *( dstBufferPtr + dstIndex + channel ) = oldLeft[channel];
+    }
+  }
+
+  while( ++i < dstHeight )
+  {
+    // Clear below skewed line with background
+    const unsigned int dstIndex = pixelSize * ( i * dstWidth + column );
+
+    for( unsigned int channel = 0u; channel < pixelSize; ++channel )
+    {
+      *( dstBufferPtr + dstIndex + channel ) = 0u;
+    }
+  }
+}
+
+} // namespace - unnamed
+
+ImageDimensions CalculateDesiredDimensions( ImageDimensions rawDimensions, ImageDimensions requestedDimensions )
+{
+  return CalculateDesiredDimensions( rawDimensions.GetWidth(), rawDimensions.GetHeight(), requestedDimensions.GetWidth(), requestedDimensions.GetHeight() ) ;
+}
+
+/**
+ * @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.
+ *
+ * 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.
+ *
+ * @param[in] bitmap            The source pixel buffer 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                      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.
+ */
+Dali::Devel::PixelBuffer CropAndPadForFittingMode( Dali::Devel::PixelBuffer& 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 );
+
+Dali::Devel::PixelBuffer ApplyAttributesToBitmap( Dali::Devel::PixelBuffer bitmap, ImageDimensions dimensions, FittingMode::Type fittingMode, SamplingMode::Type samplingMode )
+{
+  if( bitmap )
+  {
+    // Calculate the desired box, accounting for a possible zero component:
+    const ImageDimensions desiredDimensions  = CalculateDesiredDimensions( bitmap.GetWidth(), bitmap.GetHeight(), dimensions.GetWidth(), dimensions.GetHeight() );
+
+    // If a different size than the raw one has been requested, resize the image
+    // maximally using a repeated box filter without making it smaller than the
+    // requested size in either dimension:
+    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.
+    // Add crop and add borders if necessary depending on fitting mode.
+    if( bitmap )
+    {
+      bitmap = CropAndPadForFittingMode( bitmap, desiredDimensions, fittingMode );
+    }
+  }
+
+  return bitmap;
+}
+
+Dali::Devel::PixelBuffer CropAndPadForFittingMode( Dali::Devel::PixelBuffer& bitmap, ImageDimensions desiredDimensions, FittingMode::Type fittingMode )
+{
+  const unsigned int inputWidth = bitmap.GetWidth();
+  const unsigned int inputHeight = bitmap.GetHeight();
+
+  if( desiredDimensions.GetWidth() < 1u || desiredDimensions.GetHeight() < 1u )
+  {
+    DALI_LOG_WARNING( "Image scaling aborted as desired dimensions too small (%u, %u).\n", desiredDimensions.GetWidth(), desiredDimensions.GetHeight() );
+  }
+  else if( inputWidth != desiredDimensions.GetWidth() || inputHeight != desiredDimensions.GetHeight() )
+  {
+    // 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 )
+    {
+      // 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 new PixelBuffer with the desired size.
+      const auto pixelFormat = bitmap.GetPixelFormat();
+
+      auto croppedBitmap = Devel::PixelBuffer::New( desiredWidth, desiredHeight, pixelFormat );
+
+      // 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 auto 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( targetPixelsActive, sourcePixels, ( desiredHeight - scanlinesToPad ) * outputSpan );
+      }
+      else
+      {
+        // 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( &targetPixelsActive[ y * outputSpan ], &sourcePixels[ y * inputSpan ], copySpan );
+        }
+      }
+
+      // Add vertical or horizontal borders to the final image (if required).
+      desiredDimensions.SetWidth( desiredWidth );
+      desiredDimensions.SetHeight( desiredHeight );
+      AddBorders( croppedBitmap.GetBuffer(), bytesPerPixel, desiredDimensions, 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 );
+    }
+  }
+}
+
+Dali::Devel::PixelBuffer DownscaleBitmap( Dali::Devel::PixelBuffer bitmap,
+                                        ImageDimensions desired,
+                                        FittingMode::Type fittingMode,
+                                        SamplingMode::Type samplingMode )
+{
+  // Source dimensions as loaded from resources (e.g. filesystem):
+  auto bitmapWidth  = bitmap.GetWidth();
+  auto bitmapHeight = bitmap.GetHeight();
+  // Desired dimensions (the rectangle to fit the source image to):
+  auto desiredWidth = desired.GetWidth();
+  auto desiredHeight = desired.GetHeight();
+
+  Dali::Devel::PixelBuffer outputBitmap { bitmap };
+
+  // If a different size than the raw one has been requested, resize the image:
+  if(
+      (desiredWidth > 0.0f) && (desiredHeight > 0.0f) &&
+      ((desiredWidth < bitmapWidth) || (desiredHeight < bitmapHeight)) )
+  {
+    auto pixelFormat = bitmap.GetPixelFormat();
+
+    // Do the fast power of 2 iterated box filter to get to roughly the right side if the filter mode requests that:
+    unsigned int shrunkWidth = -1, shrunkHeight = -1;
+    DownscaleInPlacePow2( bitmap.GetBuffer(), pixelFormat, bitmapWidth, bitmapHeight, desiredWidth, desiredHeight, fittingMode, samplingMode, shrunkWidth, shrunkHeight );
+
+    // Work out the dimensions of the downscaled bitmap, given the scaling mode and desired dimensions:
+    const ImageDimensions filteredDimensions = FitToScalingMode( ImageDimensions( desiredWidth, desiredHeight ), ImageDimensions( shrunkWidth, shrunkHeight ), fittingMode );
+    const unsigned int filteredWidth = filteredDimensions.GetWidth();
+    const unsigned int filteredHeight = filteredDimensions.GetHeight();
+
+    // Run a filter to scale down the bitmap if it needs it:
+    bool filtered = false;
+    if( filteredWidth < shrunkWidth || filteredHeight < shrunkHeight )
+    {
+      if( samplingMode == SamplingMode::LINEAR || samplingMode == SamplingMode::BOX_THEN_LINEAR ||
+          samplingMode == SamplingMode::NEAREST || samplingMode == SamplingMode::BOX_THEN_NEAREST )
+      {
+        outputBitmap = Dali::Devel::PixelBuffer::New( filteredWidth, filteredHeight, pixelFormat );
+
+        if( outputBitmap )
+        {
+          if( samplingMode == SamplingMode::LINEAR || samplingMode == SamplingMode::BOX_THEN_LINEAR )
+          {
+            LinearSample( bitmap.GetBuffer(), ImageDimensions(shrunkWidth, shrunkHeight), pixelFormat, outputBitmap.GetBuffer(), filteredDimensions );
+          }
+          else
+          {
+            PointSample( bitmap.GetBuffer(), shrunkWidth, shrunkHeight, pixelFormat, outputBitmap.GetBuffer(), filteredWidth, filteredHeight );
+          }
+          filtered = true;
+        }
+      }
+    }
+    // Copy out the 2^x downscaled, box-filtered pixels if no secondary filter (point or linear) was applied:
+    if( filtered == false && ( shrunkWidth < bitmapWidth || shrunkHeight < bitmapHeight ) )
+    {
+      outputBitmap = MakePixelBuffer( bitmap.GetBuffer(), pixelFormat, shrunkWidth, shrunkHeight );
+    }
+  }
+
+  return outputBitmap;
+}
+
+namespace
+{
+/**
+ * @brief Returns whether to keep box filtering based on whether downscaled dimensions will overshoot the desired ones aty the next step.
+ * @param test Which combination of the two dimensions matter for terminating the filtering.
+ * @param scaledWidth The width of the current downscaled image.
+ * @param scaledHeight The height of the current downscaled image.
+ * @param desiredWidth The target width for the downscaling.
+ * @param desiredHeight The target height for the downscaling.
+ */
+bool ContinueScaling( BoxDimensionTest test, unsigned int scaledWidth, unsigned int scaledHeight, unsigned int desiredWidth, unsigned int desiredHeight )
+{
+  bool keepScaling = false;
+  const unsigned int nextWidth = scaledWidth >> 1u;
+  const unsigned int nextHeight = scaledHeight >> 1u;
+
+  if( nextWidth >= 1u && nextHeight >= 1u )
+  {
+    switch( test )
+    {
+      case BoxDimensionTestEither:
+      {
+        keepScaling = nextWidth >= desiredWidth || nextHeight >= desiredHeight;
+        break;
+      }
+      case BoxDimensionTestBoth:
+      {
+        keepScaling = nextWidth >= desiredWidth && nextHeight >= desiredHeight;
+        break;
+      }
+      case BoxDimensionTestX:
+      {
+        keepScaling = nextWidth >= desiredWidth;
+        break;
+      }
+      case BoxDimensionTestY:
+      {
+        keepScaling = nextHeight >= desiredHeight;
+        break;
+      }
+    }
+  }
+
+  return keepScaling;
+}
+
+/**
+ * @brief A shared implementation of the overall iterative box filter
+ * downscaling algorithm.
+ *
+ * Specialise this for particular pixel formats by supplying the number of bytes
+ * per pixel and two functions: one for averaging pairs of neighbouring pixels
+ * on a single scanline, and a second for averaging pixels at corresponding
+ * positions on different scanlines.
+ **/
+template<
+  int BYTES_PER_PIXEL,
+  void (*HalveScanlineInPlace)( unsigned char * const pixels, const unsigned int width ),
+  void (*AverageScanlines) ( const unsigned char * const scanline1, const unsigned char * const __restrict__ scanline2, unsigned char* const outputScanline, const unsigned int width )
+>
+void DownscaleInPlacePow2Generic( unsigned char * const pixels,
+                                  const unsigned int inputWidth,
+                                  const unsigned int inputHeight,
+                                  const unsigned int desiredWidth,
+                                  const unsigned int desiredHeight,
+                                  BoxDimensionTest dimensionTest,
+                                  unsigned& outWidth,
+                                  unsigned& outHeight )
+{
+  if( pixels == 0 )
+  {
+    return;
+  }
+  ValidateScalingParameters( inputWidth, inputHeight, desiredWidth, desiredHeight );
+
+  // Scale the image until it would be smaller than desired, stopping if the
+  // resulting height or width would be less than 1:
+  unsigned int scaledWidth = inputWidth, scaledHeight = inputHeight;
+  while( ContinueScaling( dimensionTest, scaledWidth, scaledHeight, desiredWidth, desiredHeight ) )
+  {
+    const unsigned int lastWidth = scaledWidth;
+    scaledWidth  >>= 1u;
+    scaledHeight >>= 1u;
+
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Scaling to %u\t%u.\n", scaledWidth, scaledHeight );
+
+    const unsigned int lastScanlinePair = scaledHeight - 1;
+
+    // Scale pairs of scanlines until any spare one at the end is dropped:
+    for( unsigned int y = 0; y <= lastScanlinePair; ++y )
+    {
+      // Scale two scanlines horizontally:
+      HalveScanlineInPlace( &pixels[y * 2 * lastWidth * BYTES_PER_PIXEL], lastWidth );
+      HalveScanlineInPlace( &pixels[(y * 2 + 1) * lastWidth * BYTES_PER_PIXEL], lastWidth );
+
+      // Scale vertical pairs of pixels while the last two scanlines are still warm in
+      // the CPU cache(s):
+      // Note, better access patterns for cache-coherence are possible for very large
+      // images but even a 4k wide RGB888 image will use just 24kB of cache (4k pixels
+      // * 3 Bpp * 2 scanlines) for two scanlines on the first iteration.
+      AverageScanlines(
+          &pixels[y * 2 * lastWidth * BYTES_PER_PIXEL],
+          &pixels[(y * 2 + 1) * lastWidth * BYTES_PER_PIXEL],
+          &pixels[y * scaledWidth * BYTES_PER_PIXEL],
+          scaledWidth );
+    }
+  }
+
+  ///@note: we could finish off with one of two mutually exclusive passes, one squashing horizontally as far as possible, and the other vertically, if we knew a following cpu point or bilinear filter would restore the desired aspect ratio.
+  outWidth = scaledWidth;
+  outHeight = scaledHeight;
+}
+
+}
+
+void HalveScanlineInPlaceRGB888( unsigned char * const pixels, const unsigned int width )
+{
+  DebugAssertScanlineParameters( pixels, width );
+
+  const unsigned int lastPair = EvenDown( width - 2 );
+
+  for( unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel )
+  {
+    // Load all the byte pixel components we need:
+    const unsigned int c11 = pixels[pixel * 3];
+    const unsigned int c12 = pixels[pixel * 3 + 1];
+    const unsigned int c13 = pixels[pixel * 3 + 2];
+    const unsigned int c21 = pixels[pixel * 3 + 3];
+    const unsigned int c22 = pixels[pixel * 3 + 4];
+    const unsigned int c23 = pixels[pixel * 3 + 5];
+
+    // Save the averaged byte pixel components:
+    pixels[outPixel * 3]     = static_cast<unsigned char>( AverageComponent( c11, c21 ) );
+    pixels[outPixel * 3 + 1] = static_cast<unsigned char>( AverageComponent( c12, c22 ) );
+    pixels[outPixel * 3 + 2] = static_cast<unsigned char>( AverageComponent( c13, c23 ) );
+  }
+}
+
+void HalveScanlineInPlaceRGBA8888( unsigned char * const pixels, const unsigned int width )
+{
+  DebugAssertScanlineParameters( pixels, width );
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(pixels) & 3u) == 0u) && "Pointer should be 4-byte aligned for performance on some platforms." );
+
+  uint32_t* const alignedPixels = reinterpret_cast<uint32_t*>(pixels);
+
+  const unsigned int lastPair = EvenDown( width - 2 );
+
+  for( unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel )
+  {
+    const uint32_t averaged = AveragePixelRGBA8888( alignedPixels[pixel], alignedPixels[pixel + 1] );
+    alignedPixels[outPixel] = averaged;
+  }
+}
+
+void HalveScanlineInPlaceRGB565( unsigned char * pixels, unsigned int width )
+{
+  DebugAssertScanlineParameters( pixels, width );
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(pixels) & 1u) == 0u) && "Pointer should be 2-byte aligned for performance on some platforms." );
+
+  uint16_t* const alignedPixels = reinterpret_cast<uint16_t*>(pixels);
+
+  const unsigned int lastPair = EvenDown( width - 2 );
+
+  for( unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel )
+  {
+    const uint32_t averaged = AveragePixelRGB565( alignedPixels[pixel], alignedPixels[pixel + 1] );
+    alignedPixels[outPixel] = averaged;
+  }
+}
+
+void HalveScanlineInPlace2Bytes( unsigned char * const pixels, const unsigned int width )
+{
+  DebugAssertScanlineParameters( pixels, width );
+
+  const unsigned int lastPair = EvenDown( width - 2 );
+
+  for( unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel )
+  {
+    // Load all the byte pixel components we need:
+    const unsigned int c11 = pixels[pixel * 2];
+    const unsigned int c12 = pixels[pixel * 2 + 1];
+    const unsigned int c21 = pixels[pixel * 2 + 2];
+    const unsigned int c22 = pixels[pixel * 2 + 3];
+
+    // Save the averaged byte pixel components:
+    pixels[outPixel * 2]     = static_cast<unsigned char>( AverageComponent( c11, c21 ) );
+    pixels[outPixel * 2 + 1] = static_cast<unsigned char>( AverageComponent( c12, c22 ) );
+  }
+}
+
+void HalveScanlineInPlace1Byte( unsigned char * const pixels, const unsigned int width )
+{
+  DebugAssertScanlineParameters( pixels, width );
+
+  const unsigned int lastPair = EvenDown( width - 2 );
+
+  for( unsigned int pixel = 0, outPixel = 0; pixel <= lastPair; pixel += 2, ++outPixel )
+  {
+    // Load all the byte pixel components we need:
+    const unsigned int c1 = pixels[pixel];
+    const unsigned int c2 = pixels[pixel + 1];
+
+    // Save the averaged byte pixel component:
+    pixels[outPixel] = static_cast<unsigned char>( AverageComponent( c1, c2 ) );
+  }
+}
+
+/**
+ * @ToDo: Optimise for ARM using a 4 bytes at a time loop wrapped around the single ARMV6 instruction: UHADD8  R4, R0, R5. Note, this is not neon. It runs in the normal integer pipeline so there is no downside like a stall moving between integer and copro, or extra power for clocking-up the idle copro.
+ * if (widthInComponents >= 7) { word32* aligned1 = scanline1 + 3 & 3; word32* aligned1_end = scanline1 + widthInPixels & 3; while(aligned1 < aligned1_end) { UHADD8  *aligned1++, *aligned2++, *alignedoutput++ } .. + 0 to 3 spare pixels at each end.
+ */
+void AverageScanlines1( const unsigned char * const scanline1,
+                        const unsigned char * const __restrict__ scanline2,
+                        unsigned char* const outputScanline,
+                        const unsigned int width )
+{
+  DebugAssertDualScanlineParameters( scanline1, scanline2, outputScanline, width );
+
+  for( unsigned int component = 0; component < width; ++component )
+  {
+    outputScanline[component] = static_cast<unsigned char>( AverageComponent( scanline1[component], scanline2[component] ) );
+  }
+}
+
+void AverageScanlines2( const unsigned char * const scanline1,
+                        const unsigned char * const __restrict__ scanline2,
+                        unsigned char* const outputScanline,
+                        const unsigned int width )
+{
+  DebugAssertDualScanlineParameters( scanline1, scanline2, outputScanline, width * 2 );
+
+  for( unsigned int component = 0; component < width * 2; ++component )
+  {
+    outputScanline[component] = static_cast<unsigned char>( AverageComponent( scanline1[component], scanline2[component] ) );
+  }
+}
+
+void AverageScanlines3( const unsigned char * const scanline1,
+                        const unsigned char * const __restrict__ scanline2,
+                        unsigned char* const outputScanline,
+                        const unsigned int width )
+{
+  DebugAssertDualScanlineParameters( scanline1, scanline2, outputScanline, width * 3 );
+
+  for( unsigned int component = 0; component < width * 3; ++component )
+  {
+    outputScanline[component] = static_cast<unsigned char>( AverageComponent( scanline1[component], scanline2[component] ) );
+  }
+}
+
+void AverageScanlinesRGBA8888( const unsigned char * const scanline1,
+                               const unsigned char * const __restrict__ scanline2,
+                               unsigned char * const outputScanline,
+                               const unsigned int width )
+{
+  DebugAssertDualScanlineParameters( scanline1, scanline2, outputScanline, width * 4 );
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(scanline1) & 3u) == 0u) && "Pointer should be 4-byte aligned for performance on some platforms." );
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(scanline2) & 3u) == 0u) && "Pointer should be 4-byte aligned for performance on some platforms." );
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(outputScanline) & 3u) == 0u) && "Pointer should be 4-byte aligned for performance on some platforms." );
+
+  const uint32_t* const alignedScanline1 = reinterpret_cast<const uint32_t*>(scanline1);
+  const uint32_t* const alignedScanline2 = reinterpret_cast<const uint32_t*>(scanline2);
+  uint32_t* const alignedOutput = reinterpret_cast<uint32_t*>(outputScanline);
+
+  for( unsigned int pixel = 0; pixel < width; ++pixel )
+  {
+    alignedOutput[pixel] = AveragePixelRGBA8888( alignedScanline1[pixel], alignedScanline2[pixel] );
+  }
+}
+
+void AverageScanlinesRGB565( const unsigned char * const scanline1,
+                             const unsigned char * const __restrict__ scanline2,
+                             unsigned char * const outputScanline,
+                             const unsigned int width )
+{
+  DebugAssertDualScanlineParameters( scanline1, scanline2, outputScanline, width * 2 );
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(scanline1) & 1u) == 0u) && "Pointer should be 2-byte aligned for performance on some platforms." );
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(scanline2) & 1u) == 0u) && "Pointer should be 2-byte aligned for performance on some platforms." );
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(outputScanline) & 1u) == 0u) && "Pointer should be 2-byte aligned for performance on some platforms." );
+
+  const uint16_t* const alignedScanline1 = reinterpret_cast<const uint16_t*>(scanline1);
+  const uint16_t* const alignedScanline2 = reinterpret_cast<const uint16_t*>(scanline2);
+  uint16_t* const alignedOutput = reinterpret_cast<uint16_t*>(outputScanline);
+
+  for( unsigned int pixel = 0; pixel < width; ++pixel )
+  {
+    alignedOutput[pixel] = AveragePixelRGB565( alignedScanline1[pixel], alignedScanline2[pixel] );
+  }
+}
+
+/// Dispatch to pixel format appropriate box filter downscaling functions.
+void DownscaleInPlacePow2( unsigned char * const pixels,
+                           Pixel::Format pixelFormat,
+                           unsigned int inputWidth,
+                           unsigned int inputHeight,
+                           unsigned int desiredWidth,
+                           unsigned int desiredHeight,
+                           FittingMode::Type fittingMode,
+                           SamplingMode::Type samplingMode,
+                           unsigned& outWidth,
+                           unsigned& outHeight )
+{
+  outWidth = inputWidth;
+  outHeight = inputHeight;
+  // Perform power of 2 iterated 4:1 box filtering if the requested filter mode requires it:
+  if( samplingMode == SamplingMode::BOX || samplingMode == SamplingMode::BOX_THEN_NEAREST || samplingMode == SamplingMode::BOX_THEN_LINEAR )
+  {
+    // Check the pixel format is one that is supported:
+    if( pixelFormat == Pixel::RGBA8888 || pixelFormat == Pixel::RGB888 || pixelFormat == Pixel::RGB565 || pixelFormat == Pixel::LA88 || pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8 )
+    {
+      const BoxDimensionTest dimensionTest = DimensionTestForScalingMode( fittingMode );
+
+      if( pixelFormat == Pixel::RGBA8888 )
+      {
+        Internal::Platform::DownscaleInPlacePow2RGBA8888( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+      }
+      else if( pixelFormat == Pixel::RGB888 )
+      {
+        Internal::Platform::DownscaleInPlacePow2RGB888( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+      }
+      else if( pixelFormat == Pixel::RGB565 )
+      {
+        Internal::Platform::DownscaleInPlacePow2RGB565( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+      }
+      else if( pixelFormat == Pixel::LA88 )
+      {
+        Internal::Platform::DownscaleInPlacePow2ComponentPair( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+      }
+      else if( pixelFormat == Pixel::L8  || pixelFormat == Pixel::A8 )
+      {
+        Internal::Platform::DownscaleInPlacePow2SingleBytePerPixel( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+      }
+      else
+      {
+        DALI_ASSERT_DEBUG( false && "Inner branch conditions don't match outer branch." );
+      }
+    }
+  }
+  else
+  {
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Bitmap was not shrunk: unsupported pixel format: %u.\n", unsigned(pixelFormat) );
+  }
+}
+
+void DownscaleInPlacePow2RGB888( unsigned char *pixels,
+                                 unsigned int inputWidth,
+                                 unsigned int inputHeight,
+                                 unsigned int desiredWidth,
+                                 unsigned int desiredHeight,
+                                 BoxDimensionTest dimensionTest,
+                                 unsigned& outWidth,
+                                 unsigned& outHeight )
+{
+  DownscaleInPlacePow2Generic<3, HalveScanlineInPlaceRGB888, AverageScanlines3>( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+}
+
+void DownscaleInPlacePow2RGBA8888( unsigned char * pixels,
+                                   unsigned int inputWidth,
+                                   unsigned int inputHeight,
+                                   unsigned int desiredWidth,
+                                   unsigned int desiredHeight,
+                                   BoxDimensionTest dimensionTest,
+                                   unsigned& outWidth,
+                                   unsigned& outHeight )
+{
+  DALI_ASSERT_DEBUG( ((reinterpret_cast<ptrdiff_t>(pixels) & 3u) == 0u) && "Pointer should be 4-byte aligned for performance on some platforms." );
+  DownscaleInPlacePow2Generic<4, HalveScanlineInPlaceRGBA8888, AverageScanlinesRGBA8888>( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+}
+
+void DownscaleInPlacePow2RGB565( unsigned char * pixels,
+                                 unsigned int inputWidth,
+                                 unsigned int inputHeight,
+                                 unsigned int desiredWidth,
+                                 unsigned int desiredHeight,
+                                 BoxDimensionTest dimensionTest,
+                                 unsigned int& outWidth,
+                                 unsigned int& outHeight )
+{
+  DownscaleInPlacePow2Generic<2, HalveScanlineInPlaceRGB565, AverageScanlinesRGB565>( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+}
+
+/**
+ * @copydoc DownscaleInPlacePow2RGB888
+ *
+ * For 2-byte formats such as lum8alpha8, but not packed 16 bit formats like RGB565.
+ */
+void DownscaleInPlacePow2ComponentPair( unsigned char *pixels,
+                                        unsigned int inputWidth,
+                                        unsigned int inputHeight,
+                                        unsigned int desiredWidth,
+                                        unsigned int desiredHeight,
+                                        BoxDimensionTest dimensionTest,
+                                        unsigned& outWidth,
+                                        unsigned& outHeight )
+{
+  DownscaleInPlacePow2Generic<2, HalveScanlineInPlace2Bytes, AverageScanlines2>( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+}
+
+void DownscaleInPlacePow2SingleBytePerPixel( unsigned char * pixels,
+                                             unsigned int inputWidth,
+                                             unsigned int inputHeight,
+                                             unsigned int desiredWidth,
+                                             unsigned int desiredHeight,
+                                             BoxDimensionTest dimensionTest,
+                                             unsigned int& outWidth,
+                                             unsigned int& outHeight )
+{
+  DownscaleInPlacePow2Generic<1, HalveScanlineInPlace1Byte, AverageScanlines1>( pixels, inputWidth, inputHeight, desiredWidth, desiredHeight, dimensionTest, outWidth, outHeight );
+}
+
+namespace
+{
+
+/**
+ * @brief Point sample an image to a new resolution (like GL_NEAREST).
+ *
+ * Template is used purely as a type-safe code generator in this one
+ * compilation unit. Generated code is inlined into type-specific wrapper
+ * functions below which are exported to rest of module.
+ */
+template<typename PIXEL>
+inline void PointSampleAddressablePixels( const uint8_t * inPixels,
+                                   unsigned int inputWidth,
+                                   unsigned int inputHeight,
+                                   uint8_t * outPixels,
+                                   unsigned int desiredWidth,
+                                   unsigned int desiredHeight )
+{
+  DALI_ASSERT_DEBUG( ((desiredWidth <= inputWidth && desiredHeight <= inputHeight) ||
+      outPixels >= inPixels + inputWidth * inputHeight * sizeof(PIXEL) || outPixels <= inPixels - desiredWidth * desiredHeight * sizeof(PIXEL)) &&
+      "The input and output buffers must not overlap for an upscaling.");
+  DALI_ASSERT_DEBUG( reinterpret_cast< uint64_t >( inPixels )  % sizeof(PIXEL) == 0 && "Pixel pointers need to be aligned to the size of the pixels (E.g., 4 bytes for RGBA, 2 bytes for RGB565, ...)." );
+  DALI_ASSERT_DEBUG( reinterpret_cast< uint64_t >( outPixels ) % sizeof(PIXEL) == 0 && "Pixel pointers need to be aligned to the size of the pixels (E.g., 4 bytes for RGBA, 2 bytes for RGB565, ...)." );
+
+  if( inputWidth < 1u || inputHeight < 1u || desiredWidth < 1u || desiredHeight < 1u )
+  {
+    return;
+  }
+  const PIXEL* const inAligned = reinterpret_cast<const PIXEL*>(inPixels);
+  PIXEL* const       outAligned = reinterpret_cast<PIXEL*>(outPixels);
+  const unsigned int deltaX = (inputWidth  << 16u) / desiredWidth;
+  const unsigned int deltaY = (inputHeight << 16u) / desiredHeight;
+
+  unsigned int inY = 0;
+  for( unsigned int outY = 0; outY < desiredHeight; ++outY )
+  {
+    // Round fixed point y coordinate to nearest integer:
+    const unsigned int integerY = (inY + (1u << 15u)) >> 16u;
+    const PIXEL* const inScanline = &inAligned[inputWidth * integerY];
+    PIXEL* const outScanline = &outAligned[desiredWidth * outY];
+
+    DALI_ASSERT_DEBUG( integerY < inputHeight );
+    DALI_ASSERT_DEBUG( reinterpret_cast<const uint8_t*>(inScanline) < ( inPixels + inputWidth * inputHeight * sizeof(PIXEL) ) );
+    DALI_ASSERT_DEBUG( reinterpret_cast<uint8_t*>(outScanline) < ( outPixels + desiredWidth * desiredHeight * sizeof(PIXEL) ) );
+
+    unsigned int inX = 0;
+    for( unsigned int outX = 0; outX < desiredWidth; ++outX )
+    {
+      // Round the fixed-point x coordinate to an integer:
+      const unsigned int integerX = (inX + (1u << 15u)) >> 16u;
+      const PIXEL* const inPixelAddress = &inScanline[integerX];
+      const PIXEL pixel = *inPixelAddress;
+      outScanline[outX] = pixel;
+      inX += deltaX;
+    }
+    inY += deltaY;
+  }
+}
+
+}
+
+// RGBA8888
+void PointSample4BPP( const unsigned char * inPixels,
+                      unsigned int inputWidth,
+                      unsigned int inputHeight,
+                      unsigned char * outPixels,
+                      unsigned int desiredWidth,
+                      unsigned int desiredHeight )
+{
+  PointSampleAddressablePixels<uint32_t>( inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight );
+}
+
+// RGB565, LA88
+void PointSample2BPP( const unsigned char * inPixels,
+                      unsigned int inputWidth,
+                      unsigned int inputHeight,
+                      unsigned char * outPixels,
+                      unsigned int desiredWidth,
+                      unsigned int desiredHeight )
+{
+  PointSampleAddressablePixels<uint16_t>( inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight );
+}
+
+// L8, A8
+void PointSample1BPP( const unsigned char * inPixels,
+                      unsigned int inputWidth,
+                      unsigned int inputHeight,
+                      unsigned char * outPixels,
+                      unsigned int desiredWidth,
+                      unsigned int desiredHeight )
+{
+  PointSampleAddressablePixels<uint8_t>( inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight );
+}
+
+/* RGB888
+ * RGB888 is a special case as its pixels are not aligned addressable units.
+ */
+void PointSample3BPP( const uint8_t * inPixels,
+                      unsigned int inputWidth,
+                      unsigned int inputHeight,
+                      uint8_t * outPixels,
+                      unsigned int desiredWidth,
+                      unsigned int desiredHeight )
+{
+  if( inputWidth < 1u || inputHeight < 1u || desiredWidth < 1u || desiredHeight < 1u )
+  {
+    return;
+  }
+  const unsigned int BYTES_PER_PIXEL = 3;
+
+  // Generate fixed-point 16.16 deltas in input image coordinates:
+  const unsigned int deltaX = (inputWidth  << 16u) / desiredWidth;
+  const unsigned int deltaY = (inputHeight << 16u) / desiredHeight;
+
+  // Step through output image in whole integer pixel steps while tracking the
+  // corresponding locations in the input image using 16.16 fixed-point
+  // coordinates:
+  unsigned int inY = 0; //< 16.16 fixed-point input image y-coord.
+  for( unsigned int outY = 0; outY < desiredHeight; ++outY )
+  {
+    const unsigned int integerY = (inY + (1u << 15u)) >> 16u;
+    const uint8_t* const inScanline = &inPixels[inputWidth * integerY * BYTES_PER_PIXEL];
+    uint8_t* const outScanline = &outPixels[desiredWidth * outY * BYTES_PER_PIXEL];
+    unsigned int inX = 0; //< 16.16 fixed-point input image x-coord.
+
+    for( unsigned int outX = 0; outX < desiredWidth * BYTES_PER_PIXEL; outX += BYTES_PER_PIXEL )
+    {
+      // Round the fixed-point input coordinate to the address of the input pixel to sample:
+      const unsigned int integerX = (inX + (1u << 15u)) >> 16u;
+      const uint8_t* const inPixelAddress = &inScanline[integerX * BYTES_PER_PIXEL];
+
+      // Issue loads for all pixel color components up-front:
+      const unsigned int c0 = inPixelAddress[0];
+      const unsigned int c1 = inPixelAddress[1];
+      const unsigned int c2 = inPixelAddress[2];
+      ///@ToDo: Optimise - Benchmark one 32bit load that will be unaligned 2/3 of the time + 3 rotate and masks, versus these three aligned byte loads, versus using an RGB packed, aligned(1) struct and letting compiler pick a strategy.
+
+      // Output the pixel components:
+      outScanline[outX]     = static_cast<uint8_t>( c0 );
+      outScanline[outX + 1] = static_cast<uint8_t>( c1 );
+      outScanline[outX + 2] = static_cast<uint8_t>( c2 );
+
+      // Increment the fixed-point input coordinate:
+      inX += deltaX;
+    }
+
+    inY += deltaY;
+  }
+}
+
+// Dispatch to a format-appropriate point sampling function:
+void PointSample( const unsigned char * inPixels,
+                  unsigned int inputWidth,
+                  unsigned int inputHeight,
+                  Pixel::Format pixelFormat,
+                  unsigned char * outPixels,
+                  unsigned int desiredWidth,
+                  unsigned int desiredHeight )
+{
+  // Check the pixel format is one that is supported:
+  if( pixelFormat == Pixel::RGBA8888 || pixelFormat == Pixel::RGB888 || pixelFormat == Pixel::RGB565 || pixelFormat == Pixel::LA88 || pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8 )
+  {
+    if( pixelFormat == Pixel::RGB888 )
+    {
+      PointSample3BPP( inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight );
+    }
+    else if( pixelFormat == Pixel::RGBA8888 )
+    {
+      PointSample4BPP( inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight );
+    }
+    else if( pixelFormat == Pixel::RGB565 || pixelFormat == Pixel::LA88 )
+    {
+      PointSample2BPP( inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight );
+    }
+    else if( pixelFormat == Pixel::L8  || pixelFormat == Pixel::A8 )
+    {
+      PointSample1BPP( inPixels, inputWidth, inputHeight, outPixels, desiredWidth, desiredHeight );
+    }
+    else
+    {
+      DALI_ASSERT_DEBUG( 0 == "Inner branch conditions don't match outer branch." );
+    }
+  }
+  else
+  {
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Bitmap was not point sampled: unsupported pixel format: %u.\n", unsigned(pixelFormat) );
+  }
+}
+
+// Linear sampling group below
+
+namespace
+{
+
+/** @brief Blend 4 pixels together using horizontal and vertical weights. */
+inline uint8_t BilinearFilter1BPPByte( uint8_t tl, uint8_t tr, uint8_t bl, uint8_t br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
+{
+  return static_cast<uint8_t>( BilinearFilter1Component( tl, tr, bl, br, fractBlendHorizontal, fractBlendVertical ) );
+}
+
+/** @copydoc BilinearFilter1BPPByte */
+inline Pixel2Bytes BilinearFilter2Bytes( Pixel2Bytes tl, Pixel2Bytes tr, Pixel2Bytes bl, Pixel2Bytes br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
+{
+  Pixel2Bytes pixel;
+  pixel.l = static_cast<uint8_t>( BilinearFilter1Component( tl.l, tr.l, bl.l, br.l, fractBlendHorizontal, fractBlendVertical ) );
+  pixel.a = static_cast<uint8_t>( BilinearFilter1Component( tl.a, tr.a, bl.a, br.a, fractBlendHorizontal, fractBlendVertical ) );
+  return pixel;
+}
+
+/** @copydoc BilinearFilter1BPPByte */
+inline Pixel3Bytes BilinearFilterRGB888( Pixel3Bytes tl, Pixel3Bytes tr, Pixel3Bytes bl, Pixel3Bytes br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
+{
+  Pixel3Bytes pixel;
+  pixel.r = static_cast<uint8_t>( BilinearFilter1Component( tl.r, tr.r, bl.r, br.r, fractBlendHorizontal, fractBlendVertical ) );
+  pixel.g = static_cast<uint8_t>( BilinearFilter1Component( tl.g, tr.g, bl.g, br.g, fractBlendHorizontal, fractBlendVertical ) );
+  pixel.b = static_cast<uint8_t>( BilinearFilter1Component( tl.b, tr.b, bl.b, br.b, fractBlendHorizontal, fractBlendVertical ) );
+  return pixel;
+}
+
+/** @copydoc BilinearFilter1BPPByte */
+inline PixelRGB565 BilinearFilterRGB565( PixelRGB565 tl, PixelRGB565 tr, PixelRGB565 bl, PixelRGB565 br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
+{
+  const PixelRGB565 pixel = static_cast<PixelRGB565>( (BilinearFilter1Component( tl >> 11u, tr >> 11u, bl >> 11u, br >> 11u, fractBlendHorizontal, fractBlendVertical ) << 11u) +
+                            (BilinearFilter1Component( (tl >> 5u) & 63u, (tr >> 5u) & 63u, (bl >> 5u) & 63u, (br >> 5u) & 63u, fractBlendHorizontal, fractBlendVertical ) << 5u) +
+                             BilinearFilter1Component( tl & 31u, tr & 31u, bl & 31u, br & 31u, fractBlendHorizontal, fractBlendVertical ) );
+  return pixel;
+}
+
+/** @copydoc BilinearFilter1BPPByte */
+inline Pixel4Bytes BilinearFilter4Bytes( Pixel4Bytes tl, Pixel4Bytes tr, Pixel4Bytes bl, Pixel4Bytes br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
+{
+  Pixel4Bytes pixel;
+  pixel.r = static_cast<uint8_t>( BilinearFilter1Component( tl.r, tr.r, bl.r, br.r, fractBlendHorizontal, fractBlendVertical ) );
+  pixel.g = static_cast<uint8_t>( BilinearFilter1Component( tl.g, tr.g, bl.g, br.g, fractBlendHorizontal, fractBlendVertical ) );
+  pixel.b = static_cast<uint8_t>( BilinearFilter1Component( tl.b, tr.b, bl.b, br.b, fractBlendHorizontal, fractBlendVertical ) );
+  pixel.a = static_cast<uint8_t>( BilinearFilter1Component( tl.a, tr.a, bl.a, br.a, fractBlendHorizontal, fractBlendVertical ) );
+  return pixel;
+}
+
+/**
+ * @brief Generic version of bilinear sampling image resize function.
+ * @note Limited to one compilation unit and exposed through type-specific
+ * wrapper functions below.
+ */
+template<
+  typename PIXEL,
+  PIXEL (*BilinearFilter) ( PIXEL tl, PIXEL tr, PIXEL bl, PIXEL br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical ),
+  bool DEBUG_ASSERT_ALIGNMENT
+>
+inline void LinearSampleGeneric( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions )
+{
+  const unsigned int inputWidth = inputDimensions.GetWidth();
+  const unsigned int inputHeight = inputDimensions.GetHeight();
+  const unsigned int desiredWidth = desiredDimensions.GetWidth();
+  const unsigned int desiredHeight = desiredDimensions.GetHeight();
+
+  DALI_ASSERT_DEBUG( ((outPixels >= inPixels + inputWidth   * inputHeight   * sizeof(PIXEL)) ||
+                      (inPixels >= outPixels + desiredWidth * desiredHeight * sizeof(PIXEL))) &&
+                     "Input and output buffers cannot overlap.");
+  if( DEBUG_ASSERT_ALIGNMENT )
+  {
+    DALI_ASSERT_DEBUG( reinterpret_cast< uint64_t >( inPixels )  % sizeof(PIXEL) == 0 && "Pixel pointers need to be aligned to the size of the pixels (E.g., 4 bytes for RGBA, 2 bytes for RGB565, ...)." );
+    DALI_ASSERT_DEBUG( reinterpret_cast< uint64_t >( outPixels) % sizeof(PIXEL) == 0 && "Pixel pointers need to be aligned to the size of the pixels (E.g., 4 bytes for RGBA, 2 bytes for RGB565, ...)." );
+  }
+
+  if( inputWidth < 1u || inputHeight < 1u || desiredWidth < 1u || desiredHeight < 1u )
+  {
+    return;
+  }
+  const PIXEL* const inAligned = reinterpret_cast<const PIXEL*>(inPixels);
+  PIXEL* const       outAligned = reinterpret_cast<PIXEL*>(outPixels);
+  const unsigned int deltaX = (inputWidth  << 16u) / desiredWidth;
+  const unsigned int deltaY = (inputHeight << 16u) / desiredHeight;
+
+  unsigned int inY = 0;
+  for( unsigned int outY = 0; outY < desiredHeight; ++outY )
+  {
+    PIXEL* const outScanline = &outAligned[desiredWidth * outY];
+
+    // Find the two scanlines to blend and the weight to blend with:
+    const unsigned int integerY1 = inY >> 16u;
+    const unsigned int integerY2 = integerY1 >= inputHeight ? integerY1 : integerY1 + 1;
+    const unsigned int inputYWeight = inY & 65535u;
+
+    DALI_ASSERT_DEBUG( integerY1 < inputHeight );
+    DALI_ASSERT_DEBUG( integerY2 < inputHeight );
+
+    const PIXEL* const inScanline1 = &inAligned[inputWidth * integerY1];
+    const PIXEL* const inScanline2 = &inAligned[inputWidth * integerY2];
+
+    unsigned int inX = 0;
+    for( unsigned int outX = 0; outX < desiredWidth; ++outX )
+    {
+      // Work out the two pixel scanline offsets for this cluster of four samples:
+      const unsigned int integerX1 = inX >> 16u;
+      const unsigned int integerX2 = integerX1 >= inputWidth ? integerX1 : integerX1 + 1;
+
+      // Execute the loads:
+      const PIXEL pixel1 = inScanline1[integerX1];
+      const PIXEL pixel2 = inScanline2[integerX1];
+      const PIXEL pixel3 = inScanline1[integerX2];
+      const PIXEL pixel4 = inScanline2[integerX2];
+      ///@ToDo Optimise - for 1 and 2  and 4 byte types to execute a single 2, 4, or 8 byte load per pair (caveat clamping) and let half of them be unaligned.
+
+      // Weighted bilinear filter:
+      const unsigned int inputXWeight = inX & 65535u;
+      outScanline[outX] = BilinearFilter( pixel1, pixel3, pixel2, pixel4, inputXWeight, inputYWeight );
+
+      inX += deltaX;
+    }
+    inY += deltaY;
+  }
+}
+
+}
+
+// Format-specific linear scaling instantiations:
+
+void LinearSample1BPP( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions )
+{
+  LinearSampleGeneric<uint8_t, BilinearFilter1BPPByte, false>( inPixels, inputDimensions, outPixels, desiredDimensions );
+}
+
+void LinearSample2BPP( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions )
+{
+  LinearSampleGeneric<Pixel2Bytes, BilinearFilter2Bytes, true>( inPixels, inputDimensions, outPixels, desiredDimensions );
+}
+
+void LinearSampleRGB565( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions )
+{
+  LinearSampleGeneric<PixelRGB565, BilinearFilterRGB565, true>( inPixels, inputDimensions, outPixels, desiredDimensions );
+}
+
+void LinearSample3BPP( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions )
+{
+  LinearSampleGeneric<Pixel3Bytes, BilinearFilterRGB888, false>( inPixels, inputDimensions, outPixels, desiredDimensions );
+}
+
+void LinearSample4BPP( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions )
+{
+  LinearSampleGeneric<Pixel4Bytes, BilinearFilter4Bytes, true>( inPixels, inputDimensions, outPixels, desiredDimensions );
+}
+
+
+void Resample( const unsigned char * __restrict__ inPixels,
+               ImageDimensions inputDimensions,
+               unsigned char * __restrict__ outPixels,
+               ImageDimensions desiredDimensions,
+               Resampler::Filter filterType,
+               int numChannels, bool hasAlpha )
+{
+  // Got from the test.cpp of the ImageResampler lib.
+  const float ONE_DIV_255 = 1.0f / 255.0f;
+  const int MAX_UNSIGNED_CHAR = std::numeric_limits<uint8_t>::max();
+  const int LINEAR_TO_SRGB_TABLE_SIZE = 4096;
+  const int ALPHA_CHANNEL = hasAlpha ? (numChannels-1) : 0;
+
+  static bool loadColorSpaces = true;
+  static float srgbToLinear[MAX_UNSIGNED_CHAR + 1];
+  static unsigned char linearToSrgb[LINEAR_TO_SRGB_TABLE_SIZE];
+
+  if( loadColorSpaces ) // Only create the color space conversions on the first execution
+  {
+    loadColorSpaces = false;
+
+    for( int i = 0; i <= MAX_UNSIGNED_CHAR; ++i )
+    {
+      srgbToLinear[i] = pow( static_cast<float>( i ) * ONE_DIV_255, DEFAULT_SOURCE_GAMMA );
+    }
+
+    const float invLinearToSrgbTableSize = 1.0f / static_cast<float>( LINEAR_TO_SRGB_TABLE_SIZE );
+    const float invSourceGamma = 1.0f / DEFAULT_SOURCE_GAMMA;
+
+    for( int i = 0; i < LINEAR_TO_SRGB_TABLE_SIZE; ++i )
+    {
+      int k = static_cast<int>( 255.0f * pow( static_cast<float>( i ) * invLinearToSrgbTableSize, invSourceGamma ) + 0.5f );
+      if( k < 0 )
+      {
+        k = 0;
+      }
+      else if( k > MAX_UNSIGNED_CHAR )
+      {
+        k = MAX_UNSIGNED_CHAR;
+      }
+      linearToSrgb[i] = static_cast<unsigned char>( k );
+    }
+  }
+
+  std::vector<Resampler*> resamplers( numChannels );
+  std::vector<Vector<float>> samples(numChannels);
+
+  const int srcWidth = inputDimensions.GetWidth();
+  const int srcHeight = inputDimensions.GetHeight();
+  const int dstWidth = desiredDimensions.GetWidth();
+  const int dstHeight = desiredDimensions.GetHeight();
+
+  // Now create a Resampler instance for each component to process. The first instance will create new contributor tables, which are shared by the resamplers
+  // used for the other components (a memory and slight cache efficiency optimization).
+  resamplers[0] = new Resampler( srcWidth,
+                                 srcHeight,
+                                 dstWidth,
+                                 dstHeight,
+                                 Resampler::BOUNDARY_CLAMP,
+                                 0.0f,           // sample_low,
+                                 1.0f,           // sample_high. Clamp output samples to specified range, or disable clamping if sample_low >= sample_high.
+                                 filterType,    // The type of filter.
+                                 NULL,           // Pclist_x,
+                                 NULL,           // Pclist_y. Optional pointers to contributor lists from another instance of a Resampler.
+                                 FILTER_SCALE,   // src_x_ofs,
+                                 FILTER_SCALE ); // src_y_ofs. Offset input image by specified amount (fractional values okay).
+  samples[0].Resize( srcWidth );
+  for( int i = 1; i < numChannels; ++i )
+  {
+    resamplers[i] = new Resampler( srcWidth,
+                                   srcHeight,
+                                   dstWidth,
+                                   dstHeight,
+                                   Resampler::BOUNDARY_CLAMP,
+                                   0.0f,
+                                   1.0f,
+                                   filterType,
+                                   resamplers[0]->get_clist_x(),
+                                   resamplers[0]->get_clist_y(),
+                                   FILTER_SCALE,
+                                   FILTER_SCALE );
+    samples[i].Resize( srcWidth );
+  }
+
+  const int srcPitch = srcWidth * numChannels;
+  const int dstPitch = dstWidth * numChannels;
+  int dstY = 0;
+
+  for( int srcY = 0; srcY < srcHeight; ++srcY )
+  {
+    const unsigned char* pSrc = &inPixels[srcY * srcPitch];
+
+    for( int x = 0; x < srcWidth; ++x )
+    {
+      for( int c = 0; c < numChannels; ++c )
+      {
+        if( c == ALPHA_CHANNEL && hasAlpha )
+        {
+          samples[c][x] = *pSrc++ * ONE_DIV_255;
+        }
+        else
+        {
+          samples[c][x] = srgbToLinear[*pSrc++];
+        }
+      }
+    }
+
+    for( int c = 0; c < numChannels; ++c )
+    {
+      if( !resamplers[c]->put_line( &samples[c][0] ) )
+      {
+        DALI_ASSERT_DEBUG( !"Out of memory" );
+      }
+    }
+
+    for(;;)
+    {
+      int compIndex;
+      for( compIndex = 0; compIndex < numChannels; ++compIndex )
+      {
+        const float* pOutputSamples = resamplers[compIndex]->get_line();
+        if( !pOutputSamples )
+        {
+          break;
+        }
+
+        const bool isAlphaChannel = ( compIndex == ALPHA_CHANNEL && hasAlpha );
+        DALI_ASSERT_DEBUG( dstY < dstHeight );
+        unsigned char* pDst = &outPixels[dstY * dstPitch + compIndex];
+
+        for( int x = 0; x < dstWidth; ++x )
+        {
+          if( isAlphaChannel )
+          {
+            int c = static_cast<int>( 255.0f * pOutputSamples[x] + 0.5f );
+            if( c < 0 )
+            {
+              c = 0;
+            }
+            else if( c > MAX_UNSIGNED_CHAR )
+            {
+              c = MAX_UNSIGNED_CHAR;
+            }
+            *pDst = static_cast<unsigned char>( c );
+          }
+          else
+          {
+            int j = static_cast<int>( LINEAR_TO_SRGB_TABLE_SIZE * pOutputSamples[x] + 0.5f );
+            if( j < 0 )
+            {
+              j = 0;
+            }
+            else if( j >= LINEAR_TO_SRGB_TABLE_SIZE )
+            {
+              j = LINEAR_TO_SRGB_TABLE_SIZE - 1;
+            }
+            *pDst = linearToSrgb[j];
+          }
+
+          pDst += numChannels;
+        }
+      }
+      if( compIndex < numChannels )
+      {
+        break;
+      }
+
+      ++dstY;
+    }
+  }
+
+  // Delete the resamplers.
+  for( int i = 0; i < numChannels; ++i )
+  {
+    delete resamplers[i];
+  }
+}
+
+void LanczosSample4BPP( const unsigned char * __restrict__ inPixels,
+                        ImageDimensions inputDimensions,
+                        unsigned char * __restrict__ outPixels,
+                        ImageDimensions desiredDimensions )
+{
+  Resample( inPixels, inputDimensions, outPixels, desiredDimensions, Resampler::LANCZOS4, 4, true );
+}
+
+void LanczosSample1BPP( const unsigned char * __restrict__ inPixels,
+                        ImageDimensions inputDimensions,
+                        unsigned char * __restrict__ outPixels,
+                        ImageDimensions desiredDimensions )
+{
+  // For L8 images
+  Resample( inPixels, inputDimensions, outPixels, desiredDimensions, Resampler::LANCZOS4, 1, false );
+}
+
+// Dispatch to a format-appropriate linear sampling function:
+void LinearSample( const unsigned char * __restrict__ inPixels,
+                   ImageDimensions inDimensions,
+                   Pixel::Format pixelFormat,
+                   unsigned char * __restrict__ outPixels,
+                   ImageDimensions outDimensions )
+{
+  // Check the pixel format is one that is supported:
+  if( pixelFormat == Pixel::RGB888 || pixelFormat == Pixel::RGBA8888 || pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8 || pixelFormat == Pixel::LA88 || pixelFormat == Pixel::RGB565 )
+  {
+    if( pixelFormat == Pixel::RGB888 )
+    {
+      LinearSample3BPP( inPixels, inDimensions, outPixels, outDimensions );
+    }
+    else if( pixelFormat == Pixel::RGBA8888 )
+    {
+      LinearSample4BPP( inPixels, inDimensions, outPixels, outDimensions );
+    }
+    else if( pixelFormat == Pixel::L8 || pixelFormat == Pixel::A8 )
+    {
+      LinearSample1BPP( inPixels, inDimensions, outPixels, outDimensions );
+    }
+    else if( pixelFormat == Pixel::LA88 )
+    {
+      LinearSample2BPP( inPixels, inDimensions, outPixels, outDimensions );
+    }
+    else if ( pixelFormat == Pixel::RGB565 )
+    {
+      LinearSampleRGB565( inPixels, inDimensions, outPixels, outDimensions );
+    }
+    else
+    {
+      DALI_ASSERT_DEBUG( 0 == "Inner branch conditions don't match outer branch." );
+    }
+  }
+  else
+  {
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Bitmap was not linear sampled: unsupported pixel format: %u.\n", unsigned(pixelFormat) );
+  }
+}
+
+void RotateByShear( const uint8_t* const pixelsIn,
+                    unsigned int widthIn,
+                    unsigned int heightIn,
+                    unsigned int pixelSize,
+                    float radians,
+                    uint8_t*& pixelsOut,
+                    unsigned int& widthOut,
+                    unsigned int& heightOut )
+{
+  // @note Code got from https://www.codeproject.com/Articles/202/High-quality-image-rotation-rotate-by-shear by Eran Yariv.
+
+  // Do first the fast rotations to transform the angle into a (-45..45] range.
+
+  float fastRotationPerformed = false;
+  if( ( radians > Math::PI_4 ) && ( radians <= RAD_135 ) )
+  {
+    // Angle in (45.0 .. 135.0]
+    // Rotate image by 90 degrees into temporary image,
+    // so it requires only an extra rotation angle
+    // of -45.0 .. +45.0 to complete rotation.
+    fastRotationPerformed = Rotate90( pixelsIn,
+                                      widthIn,
+                                      heightIn,
+                                      pixelSize,
+                                      pixelsOut,
+                                      widthOut,
+                                      heightOut );
+
+    if( !fastRotationPerformed )
+    {
+      DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "fast rotation failed\n");
+      // The fast rotation failed.
+      return;
+    }
+
+    radians -= Math::PI_2;
+  }
+  else if( ( radians > RAD_135 ) && ( radians <= RAD_225 ) )
+  {
+    // Angle in (135.0 .. 225.0]
+    // Rotate image by 180 degrees into temporary image,
+    // so it requires only an extra rotation angle
+    // of -45.0 .. +45.0 to complete rotation.
+
+    fastRotationPerformed = Rotate180( pixelsIn,
+                                       widthIn,
+                                       heightIn,
+                                       pixelSize,
+                                       pixelsOut );
+
+    if( !fastRotationPerformed )
+    {
+      DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "fast rotation failed\n");
+      // The fast rotation failed.
+      return;
+    }
+
+    radians -= Math::PI;
+    widthOut = widthIn;
+    heightOut = heightIn;
+  }
+  else if( ( radians > RAD_225 ) && ( radians <= RAD_315 ) )
+  {
+    // Angle in (225.0 .. 315.0]
+    // Rotate image by 270 degrees into temporary image,
+    // so it requires only an extra rotation angle
+    // of -45.0 .. +45.0 to complete rotation.
+
+    fastRotationPerformed = Rotate270( pixelsIn,
+                                       widthIn,
+                                       heightIn,
+                                       pixelSize,
+                                       pixelsOut,
+                                       widthOut,
+                                       heightOut );
+
+    if( !fastRotationPerformed )
+    {
+      DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "fast rotation failed\n");
+      // The fast rotation failed.
+      return;
+    }
+
+    radians -= RAD_270;
+  }
+
+  if( fabs( radians ) < Dali::Math::MACHINE_EPSILON_10 )
+  {
+    // Nothing else to do if the angle is zero.
+    // The rotation angle was 90, 180 or 270.
+
+    // @note Allocated memory by 'Fast Rotations', if any, has to be freed by the called to this function.
+    return;
+  }
+
+  const uint8_t* const firstHorizontalSkewPixelsIn = fastRotationPerformed ? pixelsOut : pixelsIn;
+  std::unique_ptr<uint8_t, void(*)(void*)> tmpPixelsInPtr( ( fastRotationPerformed ? pixelsOut : nullptr ), free );
+
+  // Reset the input/output
+  widthIn = widthOut;
+  heightIn = heightOut;
+  pixelsOut = nullptr;
+
+  const float angleSinus = sin( radians );
+  const float angleCosinus = cos( radians );
+  const float angleTangent = tan( 0.5f * radians );
+
+  ///////////////////////////////////////
+  // Perform 1st shear (horizontal)
+  ///////////////////////////////////////
+
+  // Calculate first shear (horizontal) destination image dimensions
+
+  widthOut = widthIn + static_cast<unsigned int>( fabs( angleTangent ) * static_cast<float>( heightIn ) );
+  heightOut = heightIn;
+
+  // Allocate the buffer for the 1st shear
+  pixelsOut = static_cast<uint8_t*>( malloc( widthOut * heightOut * pixelSize ) );
+
+  if( nullptr == pixelsOut )
+  {
+    widthOut = 0u;
+    heightOut = 0u;
+
+    DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "malloc failed to allocate memory\n");
+
+    // The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'Fast rotations'.
+    // Nothing else to do if the memory allocation fails.
+    return;
+  }
+
+  for( unsigned int y = 0u; y < heightOut; ++y )
+  {
+    const float shear = angleTangent * ( ( angleTangent >= 0.f ) ? ( 0.5f + static_cast<float>( y ) ) : ( 0.5f + static_cast<float>( y ) - static_cast<float>( heightOut ) ) );
+
+    const int intShear = static_cast<int>( floor( shear ) );
+    HorizontalSkew( firstHorizontalSkewPixelsIn, widthIn, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast<float>( intShear ) );
+  }
+
+  // Reset the 'pixel in' pointer with the output of the 'First Horizontal Skew' and free the memory allocated by the 'Fast Rotations'.
+  tmpPixelsInPtr.reset( pixelsOut );
+  unsigned int tmpWidthIn = widthOut;
+  unsigned int tmpHeightIn = heightOut;
+
+  // Reset the input/output
+  pixelsOut = nullptr;
+
+  ///////////////////////////////////////
+  // Perform 2nd shear (vertical)
+  ///////////////////////////////////////
+
+  // Calc 2nd shear (vertical) destination image dimensions
+  heightOut = static_cast<unsigned int>( static_cast<float>( widthIn ) * fabs( angleSinus ) + static_cast<float>( heightIn ) * angleCosinus );
+
+  // Allocate the buffer for the 2nd shear
+  pixelsOut = static_cast<uint8_t*>( malloc( widthOut * heightOut * pixelSize ) );
+
+  if( nullptr == pixelsOut )
+  {
+    widthOut = 0u;
+    heightOut = 0u;
+
+    DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "malloc failed to allocate memory\n");
+    // The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'First Horizontal Skew'.
+    // Nothing else to do if the memory allocation fails.
+    return;
+  }
+
+  // Variable skew offset
+  float offset = angleSinus * ( ( angleSinus > 0.f ) ? static_cast<float>( widthIn - 1u ) : -( static_cast<float>( widthIn ) - static_cast<float>( widthOut ) ) );
+
+  unsigned int column = 0u;
+  for( column = 0u; column < widthOut; ++column, offset -= angleSinus )
+  {
+    const int shear = static_cast<int>( floor( offset ) );
+    VerticalSkew( tmpPixelsInPtr.get(), tmpWidthIn, tmpHeightIn, pixelSize, pixelsOut, widthOut, heightOut, column, shear, offset - static_cast<float>( shear ) );
+  }
+  // Reset the 'pixel in' pointer with the output of the 'Vertical Skew' and free the memory allocated by the 'First Horizontal Skew'.
+  // Reset the input/output
+  tmpPixelsInPtr.reset( pixelsOut );
+  tmpWidthIn = widthOut;
+  tmpHeightIn = heightOut;
+  pixelsOut = nullptr;
+
+  ///////////////////////////////////////
+  // Perform 3rd shear (horizontal)
+  ///////////////////////////////////////
+
+  // Calc 3rd shear (horizontal) destination image dimensions
+  widthOut = static_cast<unsigned int>( static_cast<float>( heightIn ) * fabs( angleSinus ) + static_cast<float>( widthIn ) * angleCosinus ) + 1u;
+
+  // Allocate the buffer for the 3rd shear
+  pixelsOut = static_cast<uint8_t*>( malloc( widthOut * heightOut * pixelSize ) );
+
+  if( nullptr == pixelsOut )
+  {
+    widthOut = 0u;
+    heightOut = 0u;
+
+    DALI_LOG_INFO(gImageOpsLogFilter, Dali::Integration::Log::Verbose, "malloc failed to allocate memory\n");
+    // The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'Vertical Skew'.
+    // Nothing else to do if the memory allocation fails.
+    return;
+  }
+
+  offset =  ( angleSinus >= 0.f ) ? -angleSinus * angleTangent * static_cast<float>( widthIn - 1u ) : angleTangent * ( static_cast<float>( widthIn - 1u ) * -angleSinus + ( 1.f - static_cast<float>( heightOut ) ) );
+
+  for( unsigned int y = 0u; y < heightOut; ++y, offset += angleTangent )
+  {
+    const int shear = static_cast<int>( floor( offset ) );
+    HorizontalSkew( tmpPixelsInPtr.get(), tmpWidthIn, pixelSize, pixelsOut, widthOut, y, shear, offset - static_cast<float>( shear ) );
+  }
+
+  // The deleter of the tmpPixelsInPtr unique pointer is called freeing the memory allocated by the 'Vertical Skew'.
+  // @note Allocated memory by the last 'Horizontal Skew' has to be freed by the caller to this function.
+}
+
+void HorizontalShear( const uint8_t* const pixelsIn,
+                      unsigned int widthIn,
+                      unsigned int heightIn,
+                      unsigned int pixelSize,
+                      float radians,
+                      uint8_t*& pixelsOut,
+                      unsigned int& widthOut,
+                      unsigned int& heightOut )
+{
+  // Calculate the destination image dimensions.
+
+  const float absRadians = fabs( radians );
+
+  if( absRadians > Math::PI_4 )
+  {
+    // Can't shear more than 45 degrees.
+    widthOut = 0u;
+    heightOut = 0u;
+
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "Can't shear more than 45 degrees (PI/4 radians). radians : %f\n", radians );
+    return;
+  }
+
+  widthOut = widthIn + static_cast<unsigned int>( ceil ( absRadians * static_cast<float>( heightIn ) ) );
+  heightOut = heightIn;
+
+  // Allocate the buffer for the shear.
+  pixelsOut = static_cast<uint8_t*>( malloc( widthOut * heightOut * pixelSize ) );
+
+  if( nullptr == pixelsOut )
+  {
+    widthOut = 0u;
+    heightOut = 0u;
+
+    DALI_LOG_INFO( gImageOpsLogFilter, Dali::Integration::Log::Verbose, "malloc failed to allocate memory\n" );
+    return;
+  }
+
+  for( unsigned int y = 0u; y < heightOut; ++y )
+  {
+    const float shear = radians * ( ( radians >= 0.f ) ? ( 0.5f + static_cast<float>( y ) ) : ( 0.5f + static_cast<float>( y ) - static_cast<float>( heightOut ) ) );
+
+    const int intShear = static_cast<int>( floor( shear ) );
+    HorizontalSkew( pixelsIn, widthIn, pixelSize, pixelsOut, widthOut, y, intShear, shear - static_cast<float>( intShear ) );
+  }
+}
+
+} /* namespace Platform */
+} /* namespace Internal */
+} /* namespace Dali */
diff --git a/dali/internal/imaging/common/image-operations.h b/dali/internal/imaging/common/image-operations.h
new file mode 100755 (executable)
index 0000000..6ae9ba1
--- /dev/null
@@ -0,0 +1,613 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#ifndef DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H
+#define DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H
+
+// EXTERNAL INCLUDES
+#include <stdint.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/bitmap.h>
+#include <dali/public-api/images/image-operations.h>
+#include <third-party/resampler/resampler.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Platform
+{
+
+/**
+ * @brief Identify which combination of x and y dimensions matter in terminating iterative box filtering.
+ */
+enum BoxDimensionTest
+{
+  BoxDimensionTestEither,
+  BoxDimensionTestBoth,
+  BoxDimensionTestX,
+  BoxDimensionTestY
+};
+
+/**
+ * @brief The integer dimensions of an image or a region of an image packed into
+ *        16 bits per component.
+ * @note  This can only be used for images of up to 65535 x 65535 pixels.
+  */
+typedef Uint16Pair ImageDimensions;
+
+/**
+ * @brief Work out the true desired width and height, accounting for special
+ * rules for zeros in either or both input requested dimensions.
+ *
+ * @param[in] rawDimensions Width and height of image before processing.
+ * @param[in] requestedDimensions Width and height of area to scale image into. Can be zero.
+ * @return Dimensions of area to scale image into after special rules are applied.
+ */
+ImageDimensions CalculateDesiredDimensions( ImageDimensions rawDimensions, ImageDimensions requestedDimensions );
+
+/**
+ * @defgroup BitmapOperations Bitmap-to-Bitmap Image operations.
+ * @{
+ */
+
+/**
+ * @brief Apply requested attributes to bitmap.
+ *
+ * This is the top-level function which runs the on-load image post-processing
+ * pipeline. Bitmaps enter here as loaded from the file system by the file
+ * loaders and leave downscaled and filtered as requested by the application,
+ * ready for use.
+ *
+ * @param[in] bitmap The input bitmap.
+ * @param[in] requestedAttributes Attributes which should be applied to bitmap.
+ * @return A bitmap which results from applying the requested attributes to the
+ *         bitmap passed-in, or the original bitmap passed in if the attributes
+ *         have no effect.
+ */
+Dali::Devel::PixelBuffer ApplyAttributesToBitmap( Dali::Devel::PixelBuffer bitmap, ImageDimensions dimensions, FittingMode::Type fittingMode = FittingMode::DEFAULT, SamplingMode::Type samplingMode = SamplingMode::DEFAULT );
+
+/**
+ * @brief Apply downscaling to a bitmap according to requested attributes.
+ * @note The input bitmap pixel buffer may be modified and used as scratch working space for efficiency, so it must be discarded.
+ **/
+Dali::Devel::PixelBuffer DownscaleBitmap( Dali::Devel::PixelBuffer bitmap,
+                                          ImageDimensions desired,
+                                          FittingMode::Type fittingMode,
+                                          SamplingMode::Type samplingMode );
+/**@}*/
+
+/**
+ * @defgroup ImageBufferScalingAlgorithms Pixel buffer-level scaling algorithms.
+ * @{
+ */
+
+/**
+ * @brief Destructive in-place downscaling by a power of 2 factor.
+ *
+ * A box filter with a 2x2 kernel is repeatedly applied as long as the result
+ * of the next downscaling step would not be smaller than the desired
+ * dimensions.
+ * @param[in,out] pixels The buffer both to read from and write the result to.
+ * @param[in]     pixelFormat The format of the image pointed at by pixels.
+ * @param[in]     inputWidth The width of the input image.
+ * @param[in]     inputHeight The height of the input image.
+ * @param[in]     desiredWidth The width the client is requesting.
+ * @param[in]     desiredHeight The height the client is requesting.
+ * @param[out]    outWidth  The resulting width after downscaling.
+ * @param[out]    outHeight The resulting height after downscaling.
+ */
+void DownscaleInPlacePow2( unsigned char * const pixels,
+                           Pixel::Format pixelFormat,
+                           unsigned int inputWidth,
+                           unsigned int inputHeight,
+                           unsigned int desiredWidth,
+                           unsigned int desiredHeight,
+                           FittingMode::Type fittingMode,
+                           SamplingMode::Type samplingMode,
+                           unsigned& outWidth,
+                           unsigned& outHeight );
+
+/**
+ * @brief Destructive in-place downscaling by a power of 2 factor.
+ *
+ * A box filter with a 2x2 kernel is repeatedly applied as long as the result
+ * of the next downscaling step would not be smaller than the desired
+ * dimensions.
+ * @param[in,out] pixels The buffer both to read from and write the result to.
+ * @param[in]     inputWidth The width of the input image.
+ * @param[in]     inputHeight The height of the input image.
+ * @param[in]     desiredWidth The width the client is requesting.
+ * @param[in]     desiredHeight The height the client is requesting.
+ * @param[out]    outWidth  The resulting width after downscaling.
+ * @param[out]    outHeight The resulting height after downscaling.
+ */
+void DownscaleInPlacePow2RGB888( unsigned char * pixels,
+                                 unsigned int inputWidth,
+                                 unsigned int inputHeight,
+                                 unsigned int desiredWidth,
+                                 unsigned int desiredHeight,
+                                 BoxDimensionTest dimensionTest,
+                                 unsigned int& outWidth,
+                                 unsigned int& outHeight );
+
+/**
+ * @copydoc DownscaleInPlacePow2RGB888
+ */
+void DownscaleInPlacePow2RGBA8888( unsigned char * pixels,
+                                   unsigned int inputWidth,
+                                   unsigned int inputHeight,
+                                   unsigned int desiredWidth,
+                                   unsigned int desiredHeight,
+                                   BoxDimensionTest dimensionTest,
+                                   unsigned int& outWidth,
+                                   unsigned int& outHeight );
+
+/**
+ * @copydoc DownscaleInPlacePow2RGB888
+ *
+ * For the 2-byte packed 16 bit format RGB565.
+ */
+void DownscaleInPlacePow2RGB565( unsigned char * pixels,
+                                 unsigned int inputWidth,
+                                 unsigned int inputHeight,
+                                 unsigned int desiredWidth,
+                                 unsigned int desiredHeight,
+                                 BoxDimensionTest dimensionTest,
+                                 unsigned int& outWidth,
+                                 unsigned int& outHeight );
+
+/**
+ * @copydoc DownscaleInPlacePow2RGB888
+ *
+ * For 2-byte formats such as lum8alpha8, but not packed 16 bit formats like RGB565.
+ */
+void DownscaleInPlacePow2ComponentPair( unsigned char * pixels,
+                                        unsigned int inputWidth,
+                                        unsigned int inputHeight,
+                                        unsigned int desiredWidth,
+                                        unsigned int desiredHeight,
+                                        BoxDimensionTest dimensionTest,
+                                        unsigned int& outWidth,
+                                        unsigned int& outHeight );
+
+/**
+ * @copydoc DownscaleInPlacePow2RGB888
+ *
+ * For single-byte formats such as lum8 or alpha8.
+ */
+void DownscaleInPlacePow2SingleBytePerPixel( unsigned char * pixels,
+                                             unsigned int inputWidth,
+                                             unsigned int inputHeight,
+                                             unsigned int desiredWidth,
+                                             unsigned int desiredHeight,
+                                             BoxDimensionTest dimensionTest,
+                                             unsigned int& outWidth,
+                                             unsigned int& outHeight );
+
+/**
+ * @brief Rescales an input image into the exact output dimensions passed-in.
+ *
+ * Uses point sampling, equivalent to GL_NEAREST texture filter mode, for the
+ * fastest results, at the expense of aliasing (noisy images) when downscaling.
+ * @note inPixels is allowed to alias outPixels if this is a downscaling,
+ * but not for upscaling.
+ */
+void PointSample( const unsigned char * inPixels,
+                  unsigned int inputWidth,
+                  unsigned int inputHeight,
+                  Pixel::Format pixelFormat,
+                  unsigned char * outPixels,
+                  unsigned int desiredWidth,
+                  unsigned int desiredHeight );
+
+/**
+ * @copydoc PointSample
+ *
+ * Specialised for 4-byte formats like RGBA8888 and BGRA8888.
+ */
+void PointSample4BPP( const unsigned char * inPixels,
+                      unsigned int inputWidth,
+                      unsigned int inputHeight,
+                      unsigned char * outPixels,
+                      unsigned int desiredWidth,
+                      unsigned int desiredHeight );
+
+/**
+ * @copydoc PointSample
+ *
+ * Specialised for 3-byte formats like RGB888 and BGR888.
+ */
+void PointSample3BPP( const unsigned char * inPixels,
+                      unsigned int inputWidth,
+                      unsigned int inputHeight,
+                      unsigned char * outPixels,
+                      unsigned int desiredWidth,
+                      unsigned int desiredHeight );
+
+/**
+ * @copydoc PointSample
+ *
+ * Specialised for 2-byte formats like LA88.
+ */
+void PointSample2BPP( const unsigned char * inPixels,
+                      unsigned int inputWidth,
+                      unsigned int inputHeight,
+                      unsigned char * outPixels,
+                      unsigned int desiredWidth,
+                      unsigned int desiredHeight );
+
+/**
+ * @copydoc PointSample
+ *
+ * Specialised for 1-byte formats like L8 and A8.
+ */
+void PointSample1BPP( const unsigned char * inPixels,
+                      unsigned int inputWidth,
+                      unsigned int inputHeight,
+                      unsigned char * outPixels,
+                      unsigned int desiredWidth,
+                      unsigned int desiredHeight );
+
+/**
+ * @brief Resample input image to output image using a bilinear filter.
+ *
+ * Each output pixel is formed of a weighted sum of a 2x2 block of four input
+ * pixels
+ * @pre inPixels must not alias outPixels. The input image should be a totally
+ * separate buffer from the input one.
+ */
+void LinearSample( const unsigned char * __restrict__ inPixels,
+                   ImageDimensions inDimensions,
+                   Pixel::Format pixelFormat,
+                   unsigned char * __restrict__ outPixels,
+                   ImageDimensions outDimensions );
+
+/**
+ * @copydoc LinearSample
+ *
+ * Specialised for one byte per pixel formats.
+ */
+void LinearSample1BPP( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions );
+
+/**
+ * @copydoc LinearSample
+ *
+ * Specialised for two byte per pixel formats.
+ */
+void LinearSample2BPP( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions );
+
+/**
+ * @copydoc LinearSample
+ *
+ * Specialised for RGB565 16 bit pixel format.
+ */
+void LinearSampleRGB565( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions );
+
+/**
+ * @copydoc LinearSample
+ *
+ * Specialised for three byte per pixel formats like RGB888.
+ */
+void LinearSample3BPP( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions );
+
+/**
+ * @copydoc LinearSample
+ *
+ * Specialised for four byte per pixel formats like RGBA8888.
+ * @note, If used on RGBA8888, the A component will be blended independently.
+ */
+void LinearSample4BPP( const unsigned char * __restrict__ inPixels,
+                       ImageDimensions inputDimensions,
+                       unsigned char * __restrict__ outPixels,
+                       ImageDimensions desiredDimensions );
+
+/**
+ * @brief Resamples the input image with the Lanczos algorithm.
+ *
+ * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
+ * separate buffer from the output buffer.
+ *
+ * @param[in] inPixels Pointer to the input image buffer.
+ * @param[in] inputDimensions The input dimensions of the image.
+ * @param[out] outPixels Pointer to the output image buffer.
+ * @param[in] desiredDimensions The output dimensions of the image.
+ */
+void LanczosSample4BPP( const unsigned char * __restrict__ inPixels,
+                        ImageDimensions inputDimensions,
+                        unsigned char * __restrict__ outPixels,
+                        ImageDimensions desiredDimensions );
+
+/**
+ * @brief Resamples the input image with the Lanczos algorithm.
+ *
+ * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
+ * separate buffer from the output buffer.
+ *
+ * @param[in] inPixels Pointer to the input image buffer.
+ * @param[in] inputDimensions The input dimensions of the image.
+ * @param[out] outPixels Pointer to the output image buffer.
+ * @param[in] desiredDimensions The output dimensions of the image.
+ */
+void LanczosSample1BPP( const unsigned char * __restrict__ inPixels,
+                        ImageDimensions inputDimensions,
+                        unsigned char * __restrict__ outPixels,
+                        ImageDimensions desiredDimensions );
+
+/**
+ * @brief Resamples the input image with the Lanczos algorithm.
+ *
+ * @pre @p inPixels must not alias @p outPixels. The input image should be a totally
+ * separate buffer from the output buffer.
+ *
+ * @param[in] inPixels Pointer to the input image buffer.
+ * @param[in] inputDimensions The input dimensions of the image.
+ * @param[out] outPixels Pointer to the output image buffer.
+ * @param[in] desiredDimensions The output dimensions of the image.
+ */
+void Resample( const unsigned char * __restrict__ inPixels,
+               ImageDimensions inputDimensions,
+               unsigned char * __restrict__ outPixels,
+               ImageDimensions desiredDimensions,
+               Resampler::Filter filterType,
+               int numChannels, bool hasAlpha );
+
+
+/**
+ * @brief Rotates the input image with an implementation of the 'Rotate by Shear' algorithm.
+ *
+ * @pre @p pixelsIn must not alias @p pixelsOut. The input image should be a totally
+ * separate buffer from the output buffer.
+ *
+ * @note This function allocates memory in @p pixelsOut which has to be released by calling @e free()
+ *
+ * @param[in] pixelsIn The input buffer.
+ * @param[in] widthIn The width of the input buffer.
+ * @param[in] heightIn The height of the input buffer.
+ * @param[in] pixelSize The size of the pixel.
+ * @param[in] radians The rotation angle in radians.
+ * @param[out] pixelsOut The rotated output buffer.
+ * @param[out] widthOut The width of the output buffer.
+ * @param[out] heightOut The height of the output buffer.
+ */
+void RotateByShear( const uint8_t* const pixelsIn,
+                    unsigned int widthIn,
+                    unsigned int heightIn,
+                    unsigned int pixelSize,
+                    float radians,
+                    uint8_t*& pixelsOut,
+                    unsigned int& widthOut,
+                    unsigned int& heightOut );
+
+/**
+ * @brief Applies to the input image a horizontal shear transformation.
+ *
+ * @pre @p pixelsIn must not alias @p pixelsOut. The input image should be a totally
+ * separate buffer from the output buffer.
+ * @pre The maximun/minimum shear angle is +/-45 degrees (PI/4 around 0.79 radians).
+ *
+ * @note This function allocates memory in @p pixelsOut which has to be released by calling @e free()
+ *
+ * @param[in] pixelsIn The input buffer.
+ * @param[in] widthIn The width of the input buffer.
+ * @param[in] heightIn The height of the input buffer.
+ * @param[in] pixelSize The size of the pixel.
+ * @param[in] radians The shear angle in radians.
+ * @param[out] pixelsOut The rotated output buffer.
+ * @param[out] widthOut The width of the output buffer.
+ * @param[out] heightOut The height of the output buffer.
+ */
+void HorizontalShear( const uint8_t* const pixelsIn,
+                      unsigned int widthIn,
+                      unsigned int heightIn,
+                      unsigned int pixelSize,
+                      float radians,
+                      uint8_t*& pixelsOut,
+                      unsigned int& widthOut,
+                      unsigned int& heightOut );
+
+/**@}*/
+
+/**
+ * @defgroup ScalingAlgorithmFragments Composable subunits of the scaling algorithms.
+ * @{
+ */
+
+/**
+ * @brief Average adjacent pairs of pixels, overwriting the input array.
+ * @param[in,out] pixels The array of pixels to work on.
+ * @param[i]      width  The number of pixels in the array passed-in.
+ */
+void HalveScanlineInPlaceRGB888( unsigned char * pixels, unsigned int width );
+
+/**
+ * @copydoc HalveScanlineInPlaceRGB888
+ */
+void HalveScanlineInPlaceRGBA8888( unsigned char * pixels, unsigned int width );
+
+/**
+ * @copydoc HalveScanlineInPlaceRGB888
+ */
+void HalveScanlineInPlaceRGB565( unsigned char * pixels, unsigned int width );
+
+/**
+ * @copydoc HalveScanlineInPlaceRGB888
+ */
+void HalveScanlineInPlace2Bytes( unsigned char * pixels, unsigned int width );
+
+/**
+ * @copydoc HalveScanlineInPlaceRGB888
+ */
+void HalveScanlineInPlace1Byte( unsigned char * pixels, unsigned int width );
+
+/**
+ * @brief Average pixels at corresponding offsets in two scanlines.
+ *
+ * outputScanline is allowed to alias scanline1.
+ * @param[in] scanline1 First scanline of pixels to average.
+ * @param[in] scanline2 Second scanline of pixels to average.
+ * @param[out] outputScanline Destination for the averaged pixels.
+ * @param[in] width The widths of all the scanlines passed-in.
+ */
+void AverageScanlines1( const unsigned char * scanline1,
+                        const unsigned char * scanline2,
+                        unsigned char* outputScanline,
+                        /** Image width in pixels (1 byte == 1 pixel: e.g. lum8 or alpha8).*/
+                        unsigned int width );
+
+/**
+ * @copydoc AverageScanlines1
+ */
+void AverageScanlines2( const unsigned char * scanline1,
+                        const unsigned char * scanline2,
+                        unsigned char* outputScanline,
+                        /** Image width in pixels (2 bytes == 1 pixel: e.g. lum8alpha8).*/
+                        unsigned int width );
+
+/**
+ * @copydoc AverageScanlines1
+ */
+void AverageScanlines3( const unsigned char * scanline1,
+                        const unsigned char * scanline2,
+                        unsigned char* outputScanline,
+                        /** Image width in pixels (3 bytes == 1 pixel: e.g. RGB888).*/
+                        unsigned int width );
+
+/**
+ * @copydoc AverageScanlines1
+ */
+void AverageScanlinesRGBA8888( const unsigned char * scanline1,
+                               const unsigned char * scanline2,
+                               unsigned char * outputScanline,
+                               unsigned int width );
+
+/**
+ * @copydoc AverageScanlines1
+ */
+void AverageScanlinesRGB565( const unsigned char * scanline1,
+                             const unsigned char * scanline2,
+                             unsigned char* outputScanline,
+                             unsigned int width );
+/**@}*/
+
+/**
+ * @defgroup TestableInlines Inline functions exposed in header to allow unit testing.
+ * @{
+ */
+
+/**
+ * @brief Average two integer arguments.
+ * @return The average of two uint arguments.
+ * @param[in] a First component to average.
+ * @param[in] b Second component to average.
+ **/
+inline unsigned int AverageComponent( unsigned int a, unsigned int b )
+{
+  unsigned int avg = (a + b) >> 1u;
+  return avg;
+}
+
+/**
+ * @brief Average a pair of RGBA8888 pixels.
+ * @return The average of two RGBA8888 pixels.
+ * @param[in] a First pixel to average.
+ * @param[in] b Second pixel to average
+ **/
+inline uint32_t AveragePixelRGBA8888( uint32_t a, uint32_t b )
+{
+  const unsigned int avg =
+    ((AverageComponent( (a & 0xff000000) >> 1u, (b & 0xff000000) >> 1u ) << 1u) & 0xff000000 ) +
+    (AverageComponent( a & 0x00ff0000, b & 0x00ff0000 ) & 0x00ff0000 ) +
+    (AverageComponent( a & 0x0000ff00, b & 0x0000ff00 ) & 0x0000ff00 ) +
+    (AverageComponent( a & 0x000000ff, b & 0x000000ff ) );
+  return avg;
+  ///@ToDo: Optimise by trying return (((a ^ b) & 0xfefefefeUL) >> 1) + (a & b);
+  ///@ToDo: Optimise for ARM using the single ARMV6 instruction: UHADD8  R4, R0, R5. This is not Neon. It runs in the normal integer pipeline so there is no downside like a stall moving between integer and copro.
+}
+
+/**
+ * @brief Average a pair of RGB565 pixels.
+ * @param a[in] Low 16 bits hold a color value as RGB565 to average with parameter b.
+ * @param b[in] Low 16 bits hold a color value as RGB565 to average with parameter a.
+ * @return The average color of the two RGB565 pixels passed in, in the low 16 bits of the returned value.
+ **/
+inline uint32_t AveragePixelRGB565( uint32_t a, uint32_t b )
+{
+  const unsigned int avg =
+    (AverageComponent( a & 0xf800, b & 0xf800 ) & 0xf800 ) +
+    (AverageComponent( a & 0x7e0,  b & 0x7e0 )  & 0x7e0 ) +
+    (AverageComponent( a & 0x1f,   b & 0x1f ) );
+  return avg;
+}
+
+/** @return The weighted blend of two integers as a 16.16 fixed-point number, given a 0.16 fixed-point blending factor. */
+inline unsigned int WeightedBlendIntToFixed1616(unsigned int a, unsigned int b, unsigned int fractBlend )
+{
+  DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
+  const unsigned int weightedAFixed = a * (65535u - fractBlend);
+  const unsigned int weightedBFixed = b * fractBlend;
+  const unsigned blended = (weightedAFixed + weightedBFixed);
+  return blended;
+}
+
+/** @brief Blend two 16.16 inputs to give a 16.32 output. */
+inline uint64_t WeightedBlendFixed1616ToFixed1632(unsigned int a, unsigned int b, unsigned int fractBlend )
+{
+  DALI_ASSERT_DEBUG( fractBlend <= 65535u && "Factor should be in 0.16 fixed-point." );
+  // Blend while promoting intermediates to 16.32 fixed point:
+  const uint64_t weightedAFixed = uint64_t(a) * (65535u - fractBlend);
+  const uint64_t weightedBFixed = uint64_t(b) * fractBlend;
+  const uint64_t blended = (weightedAFixed + weightedBFixed);
+  return blended;
+}
+
+/**
+ * @brief Blend 4 taps into one value using horizontal and vertical weights.
+ */
+inline unsigned int BilinearFilter1Component(unsigned int tl, unsigned int tr, unsigned int bl, unsigned int br, unsigned int fractBlendHorizontal, unsigned int fractBlendVertical )
+{
+  DALI_ASSERT_DEBUG( fractBlendHorizontal <= 65535u && "Factor should be in 0.16 fixed-point." );
+  DALI_ASSERT_DEBUG( fractBlendVertical   <= 65535u && "Factor should be in 0.16 fixed-point." );
+
+  const unsigned int topBlend = WeightedBlendIntToFixed1616( tl, tr, fractBlendHorizontal );
+  const unsigned int botBlend = WeightedBlendIntToFixed1616( bl, br, fractBlendHorizontal );
+  const uint64_t blended2x2 = WeightedBlendFixed1616ToFixed1632( topBlend, botBlend, fractBlendVertical );
+  const unsigned int rounded = (blended2x2 + (1u << 31u) ) >> 32u;
+  return rounded;
+}
+
+/**@}*/
+
+} /* namespace Platform */
+} /* namespace Internal */
+} /* namespace Dali */
+
+#endif /* DALI_INTERNAL_PLATFORM_IMAGE_OPERATIONS_H */
diff --git a/dali/internal/imaging/common/loader-astc.cpp b/dali/internal/imaging/common/loader-astc.cpp
new file mode 100755 (executable)
index 0000000..1371a65
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * 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 <dali/internal/imaging/common/loader-astc.h>
+
+// EXTERNAL INCLUDES
+#include <cstring>
+#include <dali/public-api/common/compile-time-assert.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/images/pixel.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/internal/imaging/common/pixel-buffer-impl.h>
+
+namespace Dali
+{
+namespace TizenPlatform
+{
+namespace
+{
+
+// Max width or height of an image.
+const unsigned MAX_TEXTURE_DIMENSION = 4096;
+// Max bytes of image data allowed. Not a precise number, just a sanity check.
+const unsigned MAX_IMAGE_DATA_SIZE = MAX_TEXTURE_DIMENSION * MAX_TEXTURE_DIMENSION;
+
+// Minimum and maximum possible sizes for ASTC blocks.
+const unsigned int MINIMUM_ASTC_BLOCK_SIZE = 4;
+const unsigned int MAXIMUM_ASTC_BLOCK_SIZE = 12;
+
+typedef uint8_t Byte;
+
+// This bytes identify an ASTC native file.
+const Byte FileIdentifier[] = {
+   0x13, 0xAB, 0xA1, 0x5C
+};
+
+
+/**
+ * @brief This struct defines the ASTC file header values. From ASTC specifications.
+ * Packed attribute stops the structure from being aligned to compiler defaults
+ * so we can be sure of reading the whole header from file in one call to fread().
+ * Note: members to not conform to coding standards in order to be consistent with ASTC spec.
+ */
+struct AstcFileHeader
+{
+  unsigned char magic[ 4 ];
+  unsigned char blockdim_x;
+  unsigned char blockdim_y;
+  unsigned char blockdim_z;
+  unsigned char xsize[ 3 ];
+  unsigned char ysize[ 3 ];
+  unsigned char zsize[ 3 ];
+} __attribute__ ( (__packed__));
+
+using namespace Pixel;
+
+/**
+ * @brief This table allows fast conversion from an ASTC block size ([height][width]) to a pixel format.
+ * This could be done within a switch, but this way we have a constant time function.
+ * Note: As 4 is the minimum block size, 4 is subtracted from both the width and height to optimise size.
+ * IE. Table format is: Increasing order of block width from left-to-right:  4 -> 12
+ *                      Increasing order of block height from top-to-bottom: 4 -> 12
+ */
+Pixel::Format AstcLinearBlockSizeToPixelFormatTable[][( MAXIMUM_ASTC_BLOCK_SIZE - MINIMUM_ASTC_BLOCK_SIZE ) + 1] = {
+    { COMPRESSED_RGBA_ASTC_4x4_KHR, COMPRESSED_RGBA_ASTC_5x4_KHR, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID },
+    { INVALID, COMPRESSED_RGBA_ASTC_5x5_KHR, COMPRESSED_RGBA_ASTC_6x5_KHR, INVALID, COMPRESSED_RGBA_ASTC_8x5_KHR, INVALID, COMPRESSED_RGBA_ASTC_10x5_KHR, INVALID, INVALID },
+    { INVALID, INVALID, COMPRESSED_RGBA_ASTC_6x6_KHR, INVALID, COMPRESSED_RGBA_ASTC_8x6_KHR, INVALID, COMPRESSED_RGBA_ASTC_10x6_KHR, INVALID, INVALID },
+    { INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID },
+    { INVALID, INVALID, INVALID, INVALID, COMPRESSED_RGBA_ASTC_8x8_KHR, INVALID, COMPRESSED_RGBA_ASTC_10x8_KHR, INVALID, INVALID },
+    { INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID },
+    { INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, COMPRESSED_RGBA_ASTC_10x10_KHR, INVALID, COMPRESSED_RGBA_ASTC_12x10_KHR },
+    { INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID },
+    { INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, COMPRESSED_RGBA_ASTC_12x12_KHR }
+};
+
+/**
+ * @brief Uses header information to return the respective ASTC pixel format.
+ *
+ * @param[in] header A populated AstcFileHeader struct
+ * @return    The pixel format, or INVALID if the block size was invalid
+ */
+Pixel::Format GetAstcPixelFormat( AstcFileHeader& header )
+{
+  // Check the block size is valid. This will also prevent an invalid read from the conversion table.
+  if( ( header.blockdim_x < MINIMUM_ASTC_BLOCK_SIZE ) || ( header.blockdim_x > MAXIMUM_ASTC_BLOCK_SIZE ) ||
+      ( header.blockdim_y < MINIMUM_ASTC_BLOCK_SIZE ) || ( header.blockdim_y > MAXIMUM_ASTC_BLOCK_SIZE ) )
+  {
+    return Pixel::INVALID;
+  }
+
+  // Read the equivalent pixel format from the conversion table.
+  return AstcLinearBlockSizeToPixelFormatTable[ header.blockdim_y - MINIMUM_ASTC_BLOCK_SIZE ][ header.blockdim_x - MINIMUM_ASTC_BLOCK_SIZE ];
+}
+
+/**
+ * @brief Internal method to load ASTC header info from a file.
+ *
+ * @param[in]  filePointer The file pointer to the ASTC file to read
+ * @param[out] width       The width is output to this value
+ * @param[out] height      The height is output to this value
+ * @param[out] fileHeader  This will be populated with the header data
+ * @return                 True if the file is valid, false otherwise
+ */
+bool LoadAstcHeader( FILE * const filePointer, unsigned int& width, unsigned int& height, AstcFileHeader& fileHeader )
+{
+  // Pull the bytes of the file header in as a block:
+  const unsigned int readLength = sizeof( AstcFileHeader );
+  if( fread( &fileHeader, 1, readLength, filePointer ) != readLength )
+  {
+    return false;
+  }
+
+  // Check the header contains the ASTC native file identifier.
+  bool headerIsValid = memcmp( fileHeader.magic, FileIdentifier, sizeof( fileHeader.magic ) ) == 0;
+  if( !headerIsValid )
+  {
+    DALI_LOG_ERROR( "File is not a valid ASTC native file\n" );
+    // Return here as otherwise, if not a valid ASTC file, we are likely to pick up other header errors spuriously.
+    return false;
+  }
+
+  // Convert the 3-byte values for width and height to a single resultant value.
+  width = fileHeader.xsize[0] | ( fileHeader.xsize[1] << 8 ) | ( fileHeader.xsize[2] << 16 );
+  height = fileHeader.ysize[0] | ( fileHeader.ysize[1] << 8 ) | ( fileHeader.ysize[2] << 16 );
+
+  const unsigned int zDepth = static_cast<unsigned int>( fileHeader.zsize[0] )
+                              + ( static_cast<unsigned int>( fileHeader.zsize[1] ) << 8 )
+                              + ( static_cast<unsigned int>( fileHeader.zsize[2] ) << 16 );
+
+  // Check image dimensions are within limits.
+  if( ( width > MAX_TEXTURE_DIMENSION ) || ( height > MAX_TEXTURE_DIMENSION ) )
+  {
+    DALI_LOG_ERROR( "ASTC file has larger than supported dimensions: %d,%d\n", width, height );
+    headerIsValid = false;
+  }
+
+  // Confirm the ASTC block does not have any Z depth.
+  if( zDepth != 1 )
+  {
+    DALI_LOG_ERROR( "ASTC files with z size other than 1 are not supported. Z size is: %d\n", zDepth );
+    headerIsValid = false;
+  }
+
+  return headerIsValid;
+}
+
+} // Unnamed namespace.
+
+
+// File loading API entry-point:
+bool LoadAstcHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height )
+{
+  AstcFileHeader fileHeader;
+  return LoadAstcHeader( input.file, width, height, fileHeader );
+}
+
+// File loading API entry-point:
+bool LoadBitmapFromAstc( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap )
+{
+  FILE* const filePointer = input.file;
+  if( !filePointer )
+  {
+    DALI_LOG_ERROR( "Null file handle passed to ASTC compressed bitmap file loader.\n" );
+    return false;
+  }
+
+  // Load the header info.
+  AstcFileHeader fileHeader;
+  unsigned int width, height;
+
+  if( !LoadAstcHeader( filePointer, width, height, fileHeader ) )
+  {
+    DALI_LOG_ERROR( "Could not load ASTC Header from file.\n" );
+    return false;
+  }
+
+  // Retrieve the pixel format from the ASTC block size.
+  Pixel::Format pixelFormat = GetAstcPixelFormat( fileHeader );
+  if( pixelFormat == Pixel::INVALID )
+  {
+    DALI_LOG_ERROR( "No internal pixel format supported for ASTC file pixel format.\n" );
+    return false;
+  }
+
+  // Retrieve the file size.
+  if( fseek( filePointer, 0L, SEEK_END ) )
+  {
+    DALI_LOG_ERROR( "Could not seek through file.\n" );
+    return false;
+  }
+
+  off_t fileSize = ftell( filePointer );
+  if( fileSize == -1L )
+  {
+    DALI_LOG_ERROR( "Could not determine ASTC file size.\n" );
+    return false;
+  }
+
+  if( fseek( filePointer, sizeof( AstcFileHeader ), SEEK_SET ) )
+  {
+    DALI_LOG_ERROR( "Could not seek through file.\n" );
+    return false;
+  }
+
+  // Data size is file size - header size.
+  size_t imageByteCount = fileSize - sizeof( AstcFileHeader );
+
+  // Sanity-check the image data is not too large and that it is at less than 2 bytes per texel:
+  if( ( imageByteCount > MAX_IMAGE_DATA_SIZE ) || ( imageByteCount > ( ( static_cast< size_t >( width ) * height ) << 1 ) ) )
+  {
+    DALI_LOG_ERROR( "ASTC file has too large image-data field.\n" );
+    return false;
+  }
+
+  // allocate pixel data
+  bitmap = Dali::Devel::PixelBuffer::New(width, height, pixelFormat);
+
+  // Compressed format won't allocate the buffer
+  auto pixels = bitmap.GetBuffer();
+  if( !pixels )
+  {
+    // allocate buffer manually
+    auto& impl = GetImplementation( bitmap );
+    impl.AllocateFixedSize( imageByteCount );
+    pixels = bitmap.GetBuffer();
+  }
+
+  // Load the image data.
+  const size_t bytesRead = fread( pixels, 1, imageByteCount, filePointer );
+
+  // Check the size of loaded data is what we expected.
+  if( bytesRead != imageByteCount )
+  {
+    DALI_LOG_ERROR( "Read of image pixel data failed.\n" );
+    return false;
+  }
+
+  return true;
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/dali/internal/imaging/common/loader-astc.h b/dali/internal/imaging/common/loader-astc.h
new file mode 100755 (executable)
index 0000000..ed78a7d
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef DALI_TIZEN_PLATFORM_LOADER_ASTC_H
+#define DALI_TIZEN_PLATFORM_LOADER_ASTC_H
+
+/*
+ * Copyright (c) 2019 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 <cstdio>
+#include <dali/devel-api/adaptor-framework/image-loader-input.h>
+
+namespace Dali
+{
+namespace Devel
+{
+class PixelBuffer;
+}
+
+
+namespace TizenPlatform
+{
+
+class ResourceLoadingClient;
+
+namespace Astc
+{
+const unsigned char MAGIC_BYTE_1 = 0x13;
+const unsigned char MAGIC_BYTE_2 = 0xAB;
+} // namespace Astc
+
+
+/**
+ * Loads a compressed bitmap image from a ASTC file without decoding it.
+ * This function checks the header first
+ * and if it is not a ASTC file, or the header contents are invalid, it will return a failure.
+ * @param[in]  input  Information about the input image (including file pointer)
+ * @param[out] bitmap The bitmap class where the decoded image will be stored
+ * @return True if file loaded successfully, false otherwise
+ */
+bool LoadBitmapFromAstc( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap );
+
+/**
+ * Loads the header of a ASTC file and fills in the width and height appropriately.
+ * @param[in]  input  Information about the input image (including file pointer)
+ * @param[out] width  Is set with the width of the image
+ * @param[out] height Is set with the height of the image
+ * @return            True if the header was read successfully, false otherwise
+ */
+bool LoadAstcHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // DALI_TIZEN_PLATFORM_LOADER_ASTC_H
diff --git a/dali/internal/imaging/common/loader-bmp.cpp b/dali/internal/imaging/common/loader-bmp.cpp
new file mode 100755 (executable)
index 0000000..65120f2
--- /dev/null
@@ -0,0 +1,1375 @@
+/*
+ * 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/internal/imaging/common/loader-bmp.h>
+
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace
+{
+const unsigned int FileHeaderOffsetOfBF32V4 = 0x7A;
+const unsigned int MaskForBFRGB565 = 0x80;
+const unsigned int FileHeaderOffsetOfRGB24V5 = 0x8A;
+
+enum BmpFormat
+{
+  BMP_RGB1 = 14,    //BI_RGB & bpp =1
+  BMP_RGB4,         //BI_RGB & bpp = 4
+  BMP_RGB8,         //BI_RGB & bpp = 8
+  BMP_RGB555,       //BI_RGB & bpp = 16
+  BMP_BITFIELDS555, //BI_BITFIELDS & 16bit & R:G:B = 5:5:5
+  BMP_BITFIELDS32,  //BI_BITFIELDS & 32bit & R:G:B:A = 8:8:8:8
+  BMP_RLE8,         //BI_RLE8
+  BMP_RLE4,         //BI_RLE4
+  BMP_BITFIELDS32V4,//BI_BITFIELDS & 32bit
+  BMP_RGB24V5,      //BI_RGB & bpp = 24 & bmp version5
+  BMP_NOTEXIST
+};
+
+struct BmpFileHeader
+{
+  unsigned short signature; // Bitmap file signature
+  unsigned int   fileSize;  // Bitmap file size in bytes
+  unsigned short reserved1; // Reserved bits
+  unsigned short reserved2; // Reserved bits
+  unsigned int   offset;    // Offset from BMP file header to BMP bits
+} __attribute__ ( (__packed__)); // Stops the structure from being aligned to every 4 bytes
+
+struct BmpInfoHeader
+{
+  unsigned int   infoHeaderSize;  // Specifies the number of bytes required by the info header
+  unsigned int   width;           // The Image Width
+  int            height;          // The Image Height (negative value represents image data is flipped)
+  unsigned short planes;          // The number of color planes, must be 1
+  unsigned short bitsPerPixel;    // The bits per pixel
+  unsigned int   compression;     // The type of compression used by the image
+  unsigned int   imageSize;       // The size of the image in bytes
+  unsigned int   xPixelsPerMeter; // The number of pixels per meter in x axis
+  unsigned int   yPixelsPerMeter; // The number of pixels per meter in y axis
+  unsigned int   numberOfColors;  // The number of colors in the color table
+  unsigned int   importantColors; // The important color count
+} __attribute__ ( (__packed__)); // Stops the structure from being aligned to every 4 bytes
+
+/**
+ * Template function to read from the file directly into our structure.
+ * @param[in]  fp     The file to read from
+ * @param[out] header The structure we want to store our information in
+ * @return true, if read successful, false otherwise
+ */
+template<typename T>
+inline bool ReadHeader(FILE* fp, T& header)
+{
+  const unsigned int readLength = sizeof(T);
+
+  // Load the information directly into our structure
+  if ( fread( &header, 1, readLength, fp ) != readLength )
+  {
+    return false;
+  }
+
+  return true;
+}
+
+bool LoadBmpHeader(FILE *fp, unsigned int &width, unsigned int &height, BmpFileHeader &fileHeader, BmpInfoHeader &infoHeader)
+{
+  if (!ReadHeader(fp, fileHeader))
+  {
+    return false;
+  }
+
+  if (!ReadHeader(fp, infoHeader))
+  {
+    return false;
+  }
+
+  width = infoHeader.width;
+  height = abs(infoHeader.height);
+
+  if( infoHeader.width == 0 )
+  {
+    return false;
+  }
+
+  return true;
+}
+
+/**
+ * function to decode format BI_RGB & bpp = 24 & bmp version5.
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp image data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @param[in]  padding padded to a u_int32 boundary for each line
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeRGB24V5(FILE *fp,
+                   unsigned char* pixels,
+                   unsigned int width,
+                   unsigned int height,
+                   unsigned int offset,
+                   bool topDown,
+                   unsigned int rowStride,
+                   unsigned int padding)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_RGB24V5 format\n");
+    return false;
+  }
+  if ( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_RGB24V5 data\n");
+    return false;
+  }
+
+  for(unsigned int yPos = 0; yPos < height; yPos ++)
+  {
+    unsigned char* pixelsPtr = NULL;
+    if(topDown)
+    {
+      pixelsPtr = pixels + ( yPos * rowStride);
+    }
+    else
+    {
+      pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
+    }
+    if (fread(pixelsPtr, 1, rowStride, fp) != rowStride)
+    {
+      DALI_LOG_ERROR("Error reading the BMP image\n");
+      return false;
+    }
+    for(unsigned int i = 0; i < rowStride; i += 3)
+    {
+      unsigned char temp = pixelsPtr[i];
+      pixelsPtr[i] = pixelsPtr[i + 2];
+      pixelsPtr[i + 2] = temp;
+    }
+
+    if (padding)
+    {
+      // move past the padding.
+      if( fseek(fp, padding, SEEK_CUR) )
+      {
+        DALI_LOG_ERROR("Error moving past BMP_RGB24V5 padding\n");
+      }
+    }
+  }
+  return true;
+}
+
+/**
+ * function to decode format BI_BITFIELDS & bpp = 32 & bmp version4.
+ * @param[in]  fp        The file to read from
+ * @param[out] pixels    The pointer that  we want to store bmp data  in
+ * @param[in]  width     bmp width
+ * @param[in]  height    bmp height
+ * @param[in]  offset    offset from bmp header to bmp image data
+ * @param[in]  topDown   indicate image data is read from bottom or from top
+ * @param[in]  rowStride bits span for each line
+ * @param[in]  padding   padded to a u_int32 boundary for each line
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeBF32V4(FILE *fp,
+                  unsigned char* pixels,
+                  unsigned int width,
+                  unsigned int height,
+                  unsigned int offset,
+                  bool topDown,
+                  unsigned int rowStride,
+                  unsigned int padding)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32V4 format\n");
+    return false;
+  }
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32V4 data\n");
+    return false;
+  }
+
+  for(unsigned int yPos = 0; yPos < height; yPos ++)
+  {
+    unsigned char* pixelsPtr = NULL;
+    if(topDown)
+    {
+      pixelsPtr = pixels + ( yPos * rowStride);
+    }
+    else
+    {
+      pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
+    }
+    if (fread(pixelsPtr, 1, rowStride, fp) != rowStride)
+    {
+      DALI_LOG_ERROR("Error reading the BMP image\n");
+      return false;
+    }
+    for(unsigned int i = 0; i < rowStride; i += 4)
+    {
+      unsigned char temp = pixelsPtr[i];
+      pixelsPtr[i] = pixelsPtr[i + 2];
+      pixelsPtr[i + 2] = temp;
+    }
+    if (padding)
+    {
+      // move past the padding.
+      if( fseek(fp, padding, SEEK_CUR) )
+      {
+        DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32V4 padding\n");
+      }
+    }
+
+  }
+  return true;
+}
+
+/**
+ * function to decode format BI_BITFIELDS & bpp = 32
+ * @param[in]  fp        The file to read from
+ * @param[out] pixels    The pointer that  we want to store bmp data  in
+ * @param[in]  width     bmp width
+ * @param[in]  height    bmp height
+ * @param[in]  offset    offset from bmp header to bmp image data
+ * @param[in]  topDown   indicate image data is read from bottom or from top
+ * @param[in]  rowStride bits span for each line
+ * @param[in]  padding   padded to a u_int32 boundary for each line
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeBF32(FILE *fp,
+                unsigned char* pixels,
+                unsigned int width,
+                unsigned int height,
+                unsigned int offset,
+                bool topDown,
+                unsigned int rowStride,
+                unsigned int padding)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_BITFIELDS32 format\n");
+    return false;
+  }
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_BITFIELDS32 data\n");
+    return false;
+  }
+
+  for (unsigned int yPos = 0; yPos < height; yPos++)
+  {
+    unsigned char* pixelsPtr;
+    if (topDown)
+    {
+      // the data in the file is top down, and we store the data top down
+      pixelsPtr = pixels + ( yPos * rowStride);
+    }
+    else
+    {
+      // the data in the file is bottom up, and we store the data top down
+      pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
+    }
+
+    if (fread(pixelsPtr, 1, rowStride, fp) != rowStride)
+    {
+      DALI_LOG_ERROR("Error reading the BMP image\n");
+      return false;
+    }
+    for(unsigned int i = 0; i < rowStride; i += 4)
+    {
+      unsigned char temp = pixelsPtr[i];
+      pixelsPtr[i] = pixelsPtr[i + 2];
+      pixelsPtr[i + 2] = temp;
+    }
+
+    if (padding)
+    {
+      // move past the padding.
+      if( fseek(fp, padding, SEEK_CUR) )
+      {
+        DALI_LOG_ERROR("Error moving past BMP_BITFIELDS32 padding\n");
+      }
+    }
+  }
+  return true;
+}
+
+/**
+ * function to decode format BI_BITFIELDS & bpp = 16 & R:G:B = 5:6:5
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp image data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeBF565(FILE *fp,
+                 unsigned char* pixels,
+                 unsigned int width,
+                 unsigned int height,
+                 unsigned int offset,
+                 bool topDown)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding RGB565 format\n");
+    return false;
+  }
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking RGB565 data\n");
+    return false;
+  }
+
+  width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
+  unsigned int rowStride = width * 2;
+
+  for(unsigned int i = 0; i < height; i++)
+  {
+    unsigned char* pixelsPtr = NULL;
+    if (topDown)
+    {
+      // the data in the file is top down, and we store the data top down
+      pixelsPtr = pixels + ( i * rowStride);
+    }
+    else
+    {
+      // the data in the file is bottom up, and we store the data top down
+      pixelsPtr = pixels + (((height - 1) - i) * rowStride);
+    }
+    if(fread(pixelsPtr, 1, rowStride, fp) != rowStride)
+    {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+/**
+ * function to decode format BI_BITFIELDS & bpp = 16 & R:G:B = 5:5:5
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp image data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeBF555(FILE *fp,
+                 unsigned char* pixels,
+                 unsigned int width,
+                 unsigned int height,
+                 unsigned int offset,
+                 bool topDown)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_BITFIELDS555 format\n");
+    return false;
+  }
+
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_BITFIELDS555 data\n");
+    return false;
+  }
+
+  width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
+
+  std::vector<char> raw(width * height * 2);
+  unsigned int rawStride = width * 2;
+  unsigned int rowStride = width * 3;
+
+  char *rawPtr = NULL;
+  for(unsigned int j = 0; j <  height; j ++)
+  {
+    rawPtr = &raw[0] + ( j * rawStride);
+    if(fread(rawPtr, 1, rawStride, fp) != rawStride)
+    {
+      return false;
+    }
+  }
+
+  for (unsigned int yPos = 0; yPos < height; yPos++)
+  {
+    unsigned char* pixelsPtr = NULL;
+    if (topDown)
+    {
+      // the data in the file is top down, and we store the data top down
+      pixelsPtr = pixels + ( yPos * rowStride);
+    }
+    else
+    {
+      // the data in the file is bottom up, and we store the data top down
+      pixelsPtr = pixels + (((height-1)-yPos) * rowStride);
+    }
+
+    for(unsigned int k = 0; k < width; k ++)
+    {
+      int index = yPos * rawStride + 2 * k;
+      pixelsPtr[3 * k] = ((raw[ index + 1] >> 2) & 0x1F) * 0xFF / 0x1F;
+      pixelsPtr[3 * k + 1] = (((raw[index + 1] & 0x03) << 3) | (raw[ index] >> 5))  * 0xFF/ 0x1F;
+      pixelsPtr[3 * k + 2] = (raw[ index] & 0x1F) * 0xFF / 0x1F;
+    }
+  }
+  return true;
+}
+
+/**
+ * function to decode format BI_RGB & bpp = 16 & R:G:B = 5:5:5
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp image data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeRGB555(FILE *fp,
+                  unsigned char* pixels,
+                  unsigned int width,
+                  unsigned int height,
+                  unsigned int offset,
+                  bool topDown)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_RGB555 format\n");
+    return false;
+  }
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_RGB555 data\n");
+    return false;
+  }
+
+  width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
+  std::vector<char> raw(width * height * 2);
+  unsigned int rawStride = width * 2;
+  unsigned int rowStride = width * 3;
+
+  char *rawPtr = NULL;
+  for(unsigned int j = 0; j <  height; j ++)
+  {
+    rawPtr = &raw[0] + ( j * rawStride);
+    if(fread(rawPtr, 1, rawStride, fp) != rawStride)
+    {
+      return false;
+    }
+  }
+  for(unsigned int i = 0; i < height; i++)
+  {
+    unsigned char* pixelsPtr = NULL;
+    if (topDown)
+    {
+      // the data in the file is top down, and we store the data top down
+      pixelsPtr = pixels + ( i * rowStride);
+    }
+    else
+    {
+      // the data in the file is bottom up, and we store the data top down
+      pixelsPtr = pixels + (((height - 1) - i) * rowStride);
+    }
+    for(unsigned int k = 0; k < width; k ++)
+    {
+      int index = i * rawStride + 2 * k;
+      pixelsPtr[3 * k] = ((raw[ index + 1] >> 2) & 0x1F) * 0xFF / 0x1F;
+      pixelsPtr[3 * k + 1] = (((raw[index + 1] & 0x03) << 3) | (raw[ index] >> 5))  * 0xFF/ 0x1F;
+      pixelsPtr[3 * k + 2] = (raw[ index] & 0x1F) * 0xFF / 0x1F;
+    }
+
+  }
+  return true;
+}
+
+/**
+ * function to decode format BI_RGB & bpp = 1
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp palette data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeRGB1(FILE *fp,
+                unsigned char* pixels,
+                unsigned int width,
+                unsigned int height,
+                unsigned int offset,
+                bool topDown)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_RGB1 format\n");
+    return false;
+  }
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_RGB1 data\n");
+    return false;
+  }
+
+  unsigned char colorTable[8] = {0};
+  char cmd;
+  unsigned int fillw = ((width & 63) != 0) ? width + 64 - (width & 63) : width;
+  std::vector<char> colorIndex(fillw * height);
+  unsigned int rowStride = fillw * 3; // RGB
+
+
+  if(fread(colorTable, 1, 8, fp) != 8)
+  {
+    return false;
+  }
+
+  for(unsigned int i = 0; i < fillw * height; i += 8)
+  {
+    if(fread(&cmd, 1, 1, fp) != 1)
+    {
+      return false;
+    }
+
+    colorIndex[i]     = (cmd >> 7) & 0x01;
+    colorIndex[i + 1] = (cmd >> 6) & 0x01;
+    colorIndex[i + 2] = (cmd >> 5) & 0x01;
+    colorIndex[i + 3] = (cmd >> 4) & 0x01;
+    colorIndex[i + 4] = (cmd >> 3) & 0x01;
+    colorIndex[i + 5] = (cmd >> 2) & 0x01;
+    colorIndex[i + 6] = (cmd >> 1) & 0x01;
+    colorIndex[i + 7] = (cmd & 0x01);
+  }
+
+  for(unsigned int index = 0; index < height; index = index + 1)
+  {
+    unsigned char* pixelsPtr = NULL;
+    if (topDown)
+    {
+      // the data in the file is top down, and we store the data top down
+      pixelsPtr = pixels + ( index * rowStride);
+    }
+    else
+    {
+      // the data in the file is bottom up, and we store the data top down
+      pixelsPtr = pixels + (((height - 1) - index) * rowStride);
+    }
+    for(unsigned int j = 0; j < fillw; j ++)
+    {
+      unsigned int ctIndex = 0;
+      if((fillw * index + j ) < (fillw * height))
+      {
+        ctIndex = colorIndex[ fillw * index + j ];
+      }
+      else
+      {
+        break;
+      }
+      // temp solution for PLM bug P130411-5268, there is one mono bmp that cause DecodeRGB1 API crash.
+      if( ((3 * j + 2) < height * fillw * 3) && (ctIndex < 2))
+      {
+        pixelsPtr[ 3 * j ] = colorTable[4 * ctIndex + 2];
+        pixelsPtr[3 * j + 1] = colorTable[4 * ctIndex + 1];
+        pixelsPtr[3 * j + 2] = colorTable[4 * ctIndex ];
+      }
+    }
+  }
+  return true;
+}
+
+/**
+ * function to decode format BI_RGB & bpp = 4
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp palette data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeRGB4(FILE *fp,
+                unsigned char* pixels,
+                unsigned int width,
+                unsigned int height,
+                unsigned int offset,
+                bool topDown)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_RGB4 format\n");
+    return false;
+  }
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_RGB4 data\n");
+    return false;
+  }
+
+  char colorTable[64];
+  char cmd;
+  unsigned int fillw = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
+  std::vector<char> colorIndex(fillw * height);
+  unsigned int rowStride = fillw  * 3;
+
+  if(fread(colorTable, 1, 64, fp) != 64)
+  {
+    return false;
+  }
+
+  for(unsigned int i = 0; i < fillw * height; i += 2)
+  {
+    if (fread(&cmd, 1, 1, fp) != 1)
+    {
+      return false;
+    }
+
+    colorIndex[i] = cmd >> 4;
+    colorIndex[i + 1] = cmd & (0x0F);
+  }
+  unsigned int ctIndex = 0;
+
+  for(unsigned int index = 0; index < height; index = index + 1)
+  {
+    unsigned char* pixelsPtr = NULL;
+    if (topDown)
+    {
+      // the data in the file is top down, and we store the data top down
+      pixelsPtr = pixels + ( index * rowStride);
+    }
+    else
+    {
+      // the data in the file is bottom up, and we store the data top down
+      pixelsPtr = pixels + (((height - 1) - index) * rowStride);
+    }
+    for(unsigned int j = 0; j < fillw; j ++)
+    {
+      ctIndex = colorIndex[ fillw * index + j ];
+      pixelsPtr[ 3 * j ] = colorTable[4 * ctIndex + 2];
+      pixelsPtr[(3 * j + 1)] = colorTable[4 * ctIndex + 1];
+      pixelsPtr[(3 * j + 2)] = colorTable[4 * ctIndex ];
+    }
+  }
+
+  return true;
+}
+
+/**
+ * function to decode format BI_RGB & bpp = 8
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp palette data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeRGB8(FILE *fp,
+                unsigned char* pixels,
+                unsigned int width,
+                unsigned int height,
+                unsigned int offset,
+                bool topDown)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_RGB8 format\n");
+    return false;
+  }
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_RGB8 data\n");
+    return false;
+  }
+
+  std::vector<char> colorTable(1024);
+  width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
+  char cmd;
+  std::vector<char> colorIndex(width * height);
+  unsigned int rowStride = width * 3;//RGB8->RGB24
+
+  if(fread(&colorTable[0], 1, 1024, fp) != 1024)
+  {
+    return false;
+  }
+  for(unsigned int i = 0; i < width * height; i ++)
+  {
+    if (fread(&cmd, 1, 1, fp) != 1)
+    {
+      return false;
+    }
+
+    colorIndex[i] = cmd;
+  }
+  unsigned int ctIndex = 0;
+  for(unsigned int index = 0; index < height; index = index + 1)
+  {
+    unsigned char* pixelsPtr = NULL;
+    if (topDown)
+    {
+      // the data in the file is top down, and we store the data top down
+      pixelsPtr = pixels + ( index * rowStride);
+    }
+    else
+    {
+      // the data in the file is bottom up, and we store the data top down
+      pixelsPtr = pixels + (((height - 1) - index) * rowStride);
+    }
+    for(unsigned int j = 0; j < width; j ++)
+    {
+      ctIndex = colorIndex[ width * index + j ];
+      pixelsPtr[ 3 * j ] = colorTable[4 * ctIndex + 2];
+      pixelsPtr[(3 * j + 1)] = colorTable[4 * ctIndex + 1];
+      pixelsPtr[(3 * j + 2)] = colorTable[4 * ctIndex ];
+    }
+  }
+  return true;
+}
+
+/**
+ * function to decode format BI_RLE4 & bpp = 4
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp palette data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeRLE4(FILE *fp,
+                unsigned char* pixels,
+                unsigned int width,
+                unsigned int height,
+                unsigned int offset,
+                bool topDown)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_RLE4 format\n");
+    return false;
+  }
+  unsigned char* pixelsPtr = pixels;
+  width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
+  char cmd[2];
+  unsigned int cmdStride = 2;
+  char colorTable[64];
+  std::vector<char> colorIndex(width * height >> 1);
+  std::vector<char> run;
+  unsigned int x = 0;
+  unsigned int y = 0;
+  unsigned int dx = 0;
+  unsigned int dy = 0;
+  width += (width & 1);
+  width = width >> 1;
+
+  bool finish = false;
+
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_RLE4 data\n");
+    return false;
+  }
+
+  if (fread(colorTable, 1, 64, fp) != 64)
+  {
+    return false;
+  }
+
+  while((x >> 1) + y * width < width * height)
+  {
+    if (finish)
+    {
+      break;
+    }
+    if (fread(cmd, 1, cmdStride, fp) != cmdStride)
+    {
+      return false;
+    }
+    if(cmd[0] == 0) // ESCAPE
+    {
+      switch(cmd[1])
+      {
+        case 1: //end of bitmap
+          finish = true;
+          break;
+        case 0: // end of line
+          x = 0;
+          y ++;
+          break;
+        case 2: // delta
+          if (fread(cmd, 1, cmdStride, fp) != cmdStride)
+          {
+            DALI_LOG_ERROR("Error reading the BMP image\n");
+            return false;
+          }
+          dx = cmd[0] & (0xFF);
+          dy = cmd[1] & (0xFF);
+          x += dx;
+          y += dy;
+          break;
+        default:
+          // decode a literal run
+          unsigned int length = cmd[1] & (0xFF);
+          //size of run, which is word aligned
+          unsigned int bytesize = length;
+          bytesize += (bytesize & 1);
+          bytesize >>= 1;
+          bytesize += (bytesize & 1);
+          run.resize(bytesize);
+          if(fread(&run[0], 1, bytesize, fp) != bytesize)
+          {
+            DALI_LOG_ERROR("Error reading the BMP image\n");
+            return false;
+          }
+          if((x & 1) == 0)
+          {
+            length += (length & 1);
+            length >>= 1;
+            for(unsigned int i = 0; i < length; i += 1)
+            {
+              colorIndex[(x >> 1) + width * (height - y - 1) + i] = run[i];
+            }
+          }
+          else
+          {
+            for(unsigned int i = 0; i < length; i ++)
+            {
+              if((i & 1) == 0)//copy high to low
+              {
+                colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((run[i >> 1] & 0xF0) >> 4);
+              }
+              else //copy low to high
+              {
+                colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((run[i >> 1] & 0x0F) << 4);
+              }
+            }
+          }
+          x += cmd[1] & (0xFF);
+          break;
+      }
+    }
+    else
+    {
+      unsigned int length = cmd[0] & (0xFF);
+      if((x & 1) == 0)
+      {
+        length += (length & 1);
+        length >>= 1;
+        for(unsigned int i = 0; i < length; i ++)
+        {
+          colorIndex[(height-y-1)*width + i + (x >> 1)] = cmd[1];
+        }
+      }
+      else
+      {
+        for(unsigned int i = 0; i < length; i ++)
+        {
+          if((i & 1) == 0)
+          {
+            colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((cmd[1] & 0xF0) >> 4);
+          }
+          else
+          {
+            colorIndex[((x + i) >> 1) + width * (height - y - 1)] |= ((cmd[1] & 0x0F) << 4);
+          }
+        }
+      }
+      x += cmd[0] & (0xFF);
+    }
+  }
+
+  int ctIndexHigh = 0;
+  int ctIndexLow = 0;
+  for(unsigned int index = 0; index < (width * height ); index = index + 1)
+  {
+    ctIndexHigh = colorIndex[ index] >> 4;
+    ctIndexLow = colorIndex[index] & (0x0F);
+    pixelsPtr[6 * index ] = colorTable[4 * ctIndexHigh + 2];
+    pixelsPtr[6 * index + 1] = colorTable[4 * ctIndexHigh + 1];
+    pixelsPtr[6 * index + 2] = colorTable[4 * ctIndexHigh ];
+    pixelsPtr[6 * index + 3] = colorTable[4 * ctIndexLow + 2];
+    pixelsPtr[6 * index + 4] = colorTable[4 * ctIndexLow + 1];
+    pixelsPtr[6 * index + 5] = colorTable[4 * ctIndexLow ];
+  }
+  return true;
+}
+
+/**
+ * function to decode format BI_RLE8 & bpp = 8
+ * @param[in]  fp      The file to read from
+ * @param[out] pixels  The pointer that  we want to store bmp data  in
+ * @param[in]  width   bmp width
+ * @param[in]  height  bmp height
+ * @param[in]  offset  offset from bmp header to bmp palette data
+ * @param[in]  topDown indicate image data is read from bottom or from top
+ * @return true, if decode successful, false otherwise
+ */
+bool DecodeRLE8(FILE *fp,
+                unsigned char* pixels,
+                unsigned int width,
+                unsigned int height,
+                unsigned int offset,
+                bool topDown)
+{
+  if(fp == NULL || pixels == NULL)
+  {
+    DALI_LOG_ERROR("Error decoding BMP_RLE8 format\n");
+    return false;
+  }
+  unsigned char* pixelsPtr = pixels;
+  unsigned int x = 0;
+  unsigned int y = 0;
+  unsigned int cmdStride = 2;
+
+  width = ((width & 3) != 0) ? width + 4 - (width & 3) : width;
+  std::vector<char> colorTable(1024);
+  char cmd[2];
+  std::vector<char> colorIndex(width * height);
+
+  if( fseek(fp, offset, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking BMP_RLE8 data\n");
+    return false;
+  }
+
+  if (fread(&colorTable[0], 1, 1024, fp) != 1024)
+  {
+    return false;
+  }
+
+  unsigned int dx = 0;
+  unsigned int dy = 0;
+  bool finish = false;
+  unsigned int length = 0;
+  unsigned int copylength = 0;
+  std::vector<char> run;
+  while((x + y * width) < width * height )
+  {
+    if (finish)
+    {
+      break;
+    }
+    if (fread(cmd, 1, cmdStride, fp) != cmdStride)
+    {
+      return false;
+    }
+
+    if(cmd[0] == 0)//ESCAPE
+    {
+      switch(cmd[1])
+      {
+        case 1: // end of bitmap
+          finish = true;
+          break;
+        case 0: // end of line
+          x = 0;
+          y ++;
+          break;
+        case 2: // delta
+          if (fread(cmd, 1, cmdStride, fp) != cmdStride)
+          {
+            DALI_LOG_ERROR("Error reading the BMP image\n");
+            return false;
+          }
+          dx = cmd[0] & (0xFF);
+          dy = cmd[1] & (0xFF);
+          x += dx;
+          y += dy;
+          break;
+        default:
+          //decode a literal run
+          length = cmd[1] & (0xFF);
+          copylength = length;
+          //absolute mode must be word-aligned
+          length += (length & 1);
+          run.resize(length);
+          if(fread(&run[0], 1, length, fp) != length)
+          {
+            DALI_LOG_ERROR("Error reading the BMP image\n");
+            return false;
+          }
+
+          for(unsigned int i = 0; i < length; i += 1)
+          {
+            colorIndex[x + width * (height - y - 1) + i] = run[i];
+          }
+          x += copylength;
+          break;
+      }
+    }// end if cmd[0] ==
+    else
+    {
+      length = cmd[0] & (0xFF);
+      for(unsigned int i = 0; i < length; i ++)
+      {
+        colorIndex[(height - y - 1) * width + x] = cmd[1];
+        x++;
+      }
+    }
+  }
+  int ctIndex = 0;
+  for(unsigned int index = 0; index < width * height; index = index + 1)
+  {
+    ctIndex = colorIndex[ index];
+    pixelsPtr[3 * index ] = colorTable[4 * ctIndex + 2];
+    pixelsPtr[3 * index + 1] = colorTable[4 * ctIndex + 1];
+    pixelsPtr[3 * index + 2] = colorTable[4 * ctIndex ];
+  }
+  return true;
+}
+
+} // unnamed namespace
+
+bool LoadBmpHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height )
+{
+  BmpFileHeader fileHeader;
+  BmpInfoHeader infoHeader;
+
+  bool ret = LoadBmpHeader( input.file, width, height, fileHeader, infoHeader );
+
+  return ret;
+}
+
+bool LoadBitmapFromBmp( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap )
+{
+  //DALI_ASSERT_DEBUG( bitmap.GetPackedPixelsProfile() != 0 && "Need a packed pixel bitmap to load into." );
+  FILE* const fp = input.file;
+  if(fp == NULL)
+  {
+    DALI_LOG_ERROR("Error loading bitmap\n");
+    return false;
+  }
+  BmpFormat customizedFormat = BMP_NOTEXIST;
+  BmpFileHeader fileHeader;
+  BmpInfoHeader infoHeader;
+
+  // Load the header info
+  unsigned int width, height;
+
+  if (!LoadBmpHeader(fp, width, height, fileHeader, infoHeader))
+  {
+      return false;
+  }
+
+  Pixel::Format pixelFormat = Pixel::RGB888;
+  switch(infoHeader.compression)
+  {
+    case 0:
+      switch (infoHeader.bitsPerPixel)
+      {
+        case 32:
+          pixelFormat = Pixel::BGR8888;
+          break;
+
+        case 24:
+          if(fileHeader.offset == FileHeaderOffsetOfRGB24V5)//0x8A
+          {
+            customizedFormat = BMP_RGB24V5;
+          }
+          else
+          {
+            pixelFormat = Pixel::RGB888;
+          }
+          break;
+
+        case 16:
+          customizedFormat = BMP_RGB555;
+          break;
+
+        case 8:
+          customizedFormat = BMP_RGB8;
+          break;
+
+        case 4: // RGB4
+          customizedFormat = BMP_RGB4;
+          break;
+
+        case 1: //RGB1
+          customizedFormat = BMP_RGB1;
+          break;
+        default:
+          DALI_LOG_WARNING("%d bits per pixel not supported for BMP files\n", infoHeader.bitsPerPixel);
+          return false;
+      }
+    break;
+    case 1: //// RLE8
+    {
+      if(infoHeader.bitsPerPixel == 8)
+      {
+        customizedFormat = BMP_RLE8;
+      }
+      break;
+    }
+    case 2: // RLE4
+    {
+      if(infoHeader.bitsPerPixel == 4)
+      {
+        customizedFormat = BMP_RLE4;
+      }
+      break;
+    }
+    case 3: // // BI_BITFIELDS
+    {
+      if(infoHeader.bitsPerPixel == 16)
+      {
+        if( fseek(fp, 14 + infoHeader.infoHeaderSize + 1, SEEK_SET) )
+        {
+          return false;
+        }
+
+        char mask;
+        if(fread(&mask, 1, 1, fp) != 1)
+        {
+          return false;
+        }
+
+        if((mask & 0x80) == MaskForBFRGB565) // mask is 0xF8
+        {
+          pixelFormat = Pixel::RGB565;
+        }
+        else if((mask & 0x80) == 0)// mask is 0x 7C
+        {
+          customizedFormat = BMP_BITFIELDS555;
+        }
+        else
+        {
+          return false;
+        }
+      }
+      else if(infoHeader.bitsPerPixel == 32)
+      {
+        if(fileHeader.offset == FileHeaderOffsetOfBF32V4)// 0x7A
+        {
+          customizedFormat = BMP_BITFIELDS32V4;
+        }
+        else
+        {
+          customizedFormat = BMP_BITFIELDS32;
+        }
+      }
+      break;
+    }
+    default:
+      DALI_LOG_WARNING("Compression not supported for BMP files\n");
+      return false;
+  }
+
+  bool topDown = false;
+
+  // if height is negative, bitmap data is top down
+  if (infoHeader.height<0)
+  {
+    infoHeader.height =  abs(infoHeader.height);
+    height = infoHeader.height;
+    topDown = true;
+  }
+
+  unsigned int rowStride = infoHeader.width * (infoHeader.bitsPerPixel >>3);
+
+  // bitmaps row stride is padded to 4 bytes
+  unsigned int padding = (rowStride % 4);
+  if (padding)
+  {
+    padding = 4 - padding;
+  }
+
+  int imageW = infoHeader.width;
+  int pixelBufferW = infoHeader.width;
+  int pixelBufferH = infoHeader.height;
+  auto newPixelFormat = Pixel::Format::INVALID;
+
+  switch(customizedFormat)
+  {
+  case BMP_RLE8:
+  case BMP_RGB8:
+  case BMP_RGB4:
+  case BMP_RLE4:
+  case BMP_RGB555:
+  case BMP_BITFIELDS555:
+  {
+    pixelBufferW = ((imageW & 3) != 0) ? imageW + 4 - (imageW & 3) : imageW;
+    pixelBufferH = abs(infoHeader.height);
+    newPixelFormat = Pixel::RGB888;
+    break;
+  }
+  case BMP_RGB1:
+  {
+    pixelBufferW = ((imageW & 63) != 0) ? imageW + 64 - (imageW & 63) : imageW;
+    pixelBufferH = abs(infoHeader.height);
+    newPixelFormat = Pixel::RGB888;
+    break;
+  }
+  case BMP_BITFIELDS32:
+  case BMP_BITFIELDS32V4:
+  {
+    pixelBufferH = abs(infoHeader.height);
+    newPixelFormat = Pixel::RGB8888;
+    break;
+  }
+  case BMP_RGB24V5:
+  {
+    newPixelFormat = Pixel::RGB888;
+    break;
+  }
+  default:
+    if(pixelFormat == Pixel::RGB565 )
+    {
+      pixelBufferW = ((imageW & 3) != 0) ? imageW + 4 - (imageW & 3) : imageW;
+      pixelBufferH = abs(infoHeader.height);
+      newPixelFormat = Pixel::RGB565;
+    }
+    else
+    {
+      pixelBufferW = infoHeader.width;
+      pixelBufferH = infoHeader.height;
+      newPixelFormat = pixelFormat;
+    }
+    break;
+  }
+
+  bitmap = Dali::Devel::PixelBuffer::New(pixelBufferW, pixelBufferH, newPixelFormat);
+  auto pixels = bitmap.GetBuffer();
+
+  // Read the raw bitmap data
+  decltype(pixels) pixelsIterator = nullptr;
+
+  bool decodeResult(false);
+  switch(customizedFormat)
+  {
+    case BMP_RGB1:
+    {
+      decodeResult = DecodeRGB1( fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
+      break;
+    }
+    case BMP_RGB4:
+    {
+      decodeResult = DecodeRGB4(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
+      break;
+    }
+    case BMP_RLE4:
+    {
+      decodeResult = DecodeRLE4( fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
+      break;
+    }
+    case BMP_BITFIELDS32:
+    {
+      decodeResult = DecodeBF32(fp, pixels, infoHeader.width,  abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
+      break;
+    }
+    case BMP_BITFIELDS555:
+    {
+      decodeResult = DecodeBF555(fp, pixels,infoHeader.width,  abs(infoHeader.height), fileHeader.offset, topDown);
+      break;
+    }
+    case BMP_RGB555:
+    {
+      decodeResult = DecodeRGB555(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown);
+      break;
+    }
+    case BMP_RGB8:
+    {
+      decodeResult = DecodeRGB8(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
+      break;
+    }
+    case BMP_RLE8:
+    {
+      decodeResult = DecodeRLE8(fp, pixels, infoHeader.width, abs(infoHeader.height), 14 + infoHeader.infoHeaderSize, topDown);
+      break;
+    }
+    case BMP_RGB24V5:
+    {
+      decodeResult = DecodeRGB24V5(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
+      break;
+    }
+    case BMP_BITFIELDS32V4:
+    {
+      decodeResult = DecodeBF32V4(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset, topDown, rowStride, padding);
+      break;
+    }
+    default:
+    {
+      if(pixelFormat == Pixel::RGB565)
+      {
+        decodeResult = DecodeBF565(fp, pixels, infoHeader.width, abs(infoHeader.height), fileHeader.offset,  topDown);
+      }
+      else
+      {
+        for (unsigned int yPos = 0; yPos < height; yPos++)
+        {
+          if (topDown)
+          {
+            // the data in the file is top down, and we store the data top down
+            pixelsIterator = pixels + ( yPos * rowStride);
+          }
+          else
+          {
+            // the data in the file is bottom up, and we store the data top down
+            pixelsIterator = pixels + (((height-1)-yPos) * rowStride);
+          }
+
+          if (fread(pixelsIterator, 1, rowStride, fp) != rowStride)
+          {
+            DALI_LOG_ERROR("Error reading the BMP image\n");
+            break;
+          }
+
+          // If 24 bit mode then swap Blue and Red pixels
+          // BGR888 doesn't seem to be supported by dali-core
+          if (infoHeader.bitsPerPixel == 24 )
+          {
+            for(unsigned int i = 0; i < rowStride; i += 3)
+            {
+              unsigned char temp = pixelsIterator[i];
+              pixelsIterator[i] = pixelsIterator[i+2];
+              pixelsIterator[i+2] = temp;
+            }
+          }
+
+          if (padding)
+          {
+            if( fseek(fp, padding, SEEK_CUR) )  // move past the padding.
+            {
+              DALI_LOG_ERROR("Error moving past BMP padding\n");
+            }
+          }
+        }
+        decodeResult = true;
+      }
+      break;
+    }
+  } // switch
+
+  if( !decodeResult )
+  {
+    return false;
+  }
+
+  return true;
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/dali/internal/imaging/common/loader-bmp.h b/dali/internal/imaging/common/loader-bmp.h
new file mode 100755 (executable)
index 0000000..2e95efb
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef DALI_TIZEN_PLATFORM_LOADER_BMP_H
+#define DALI_TIZEN_PLATFORM_LOADER_BMP_H
+
+/*
+ * Copyright (c) 2019 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 <cstdio>
+#include <dali/devel-api/adaptor-framework/image-loader-input.h>
+
+namespace Dali
+{
+namespace Devel
+{
+class PixelBuffer;
+}
+
+
+namespace TizenPlatform
+{
+
+class ResourceLoadingClient;
+
+namespace Bmp
+{
+const unsigned char MAGIC_BYTE_1 = 0x42;
+const unsigned char MAGIC_BYTE_2 = 0x4D;
+} // namespace Bmp
+
+/**
+ * Loads the bitmap from an BMP file.  This function checks the header first
+ * and if it is not a BMP file, then it returns straight away.
+ * @param[in]  input  Information about the input image (including file pointer)
+ * @param[out] bitmap The bitmap class where the decoded image will be stored
+ * @return  true if file decoded successfully, false otherwise
+ */
+bool LoadBitmapFromBmp( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap );
+
+/**
+ * Loads the header of a BMP file and fills in the width and height appropriately.
+ * @param[in]   fp      Pointer to the Image file
+ * @param[in]   attributes  Describes the dimensions, pixel format and other details for loading the image data
+ * @param[out]  width   Is set with the width of the image
+ * @param[out]  height  Is set with the height of the image
+ * @return true if the file's header was read successully, false otherwise
+ */
+bool LoadBmpHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // DALI_TIZEN_PLATFORM_LOADER_BMP_H
diff --git a/dali/internal/imaging/common/loader-gif.cpp b/dali/internal/imaging/common/loader-gif.cpp
new file mode 100755 (executable)
index 0000000..cf9b010
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * 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/internal/imaging/common/loader-gif.h>
+
+#include <gif_lib.h>
+
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <memory>
+
+// We need to check if giflib has the new open and close API (including error parameter).
+#ifdef GIFLIB_MAJOR
+#define LIBGIF_VERSION_5_1_OR_ABOVE
+#endif
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace
+{
+
+// simple class to enforce clean-up of GIF structures
+struct AutoCleanupGif
+{
+  AutoCleanupGif(GifFileType*& _gifInfo)
+  : gifInfo(_gifInfo)
+  {
+  }
+
+  ~AutoCleanupGif()
+  {
+    if(NULL != gifInfo)
+    {
+      // clean up GIF resources
+#ifdef LIBGIF_VERSION_5_1_OR_ABOVE
+      int errorCode = 0; //D_GIF_SUCCEEDED is 0
+      DGifCloseFile( gifInfo, &errorCode );
+
+      if( errorCode )
+      {
+        DALI_LOG_ERROR( "GIF Loader: DGifCloseFile Error. Code: %d\n", errorCode );
+      }
+#else
+      DGifCloseFile( gifInfo );
+#endif
+    }
+  }
+
+  GifFileType*& gifInfo;
+};
+
+// Used in the GIF interlace algorithm to determine the starting byte and the increment required
+// for each pass.
+struct InterlacePair
+{
+  unsigned int startingByte;
+  unsigned int incrementalByte;
+};
+
+// Used in the GIF interlace algorithm to determine the order and which location to read data from
+// the file.
+const InterlacePair INTERLACE_PAIR_TABLE [] = {
+  { 0, 8 }, // Starting at 0, read every 8 bytes.
+  { 4, 8 }, // Starting at 4, read every 8 bytes.
+  { 2, 4 }, // Starting at 2, read every 4 bytes.
+  { 1, 2 }, // Starting at 1, read every 2 bytes.
+};
+const unsigned int INTERLACE_PAIR_TABLE_SIZE( sizeof( INTERLACE_PAIR_TABLE ) / sizeof( InterlacePair ) );
+
+/// Function used by Gif_Lib to read from the image file.
+int ReadDataFromGif(GifFileType *gifInfo, GifByteType *data, int length)
+{
+  FILE *fp = reinterpret_cast<FILE*>(gifInfo->UserData);
+  return fread( data, sizeof( GifByteType ), length, fp);
+}
+
+/// Loads the GIF Header.
+bool LoadGifHeader(FILE *fp, unsigned int &width, unsigned int &height, GifFileType** gifInfo)
+{
+  int errorCode = 0; //D_GIF_SUCCEEDED is 0
+
+#ifdef LIBGIF_VERSION_5_1_OR_ABOVE
+  *gifInfo = DGifOpen( reinterpret_cast<void*>(fp), ReadDataFromGif, &errorCode );
+#else
+  *gifInfo = DGifOpen( reinterpret_cast<void*>(fp), ReadDataFromGif );
+#endif
+
+  if ( !(*gifInfo) || errorCode )
+  {
+    DALI_LOG_ERROR( "GIF Loader: DGifOpen Error. Code: %d\n", errorCode );
+    return false;
+  }
+
+  width  = (*gifInfo)->SWidth;
+  height = (*gifInfo)->SHeight;
+
+  // No proper size in GIF.
+  if ( width <= 0 || height <= 0 )
+  {
+    return false;
+  }
+
+  return true;
+}
+
+/// Decode the GIF image.
+bool DecodeImage( GifFileType* gifInfo, unsigned char* decodedData, const unsigned int width, const unsigned int height, const unsigned int bytesPerRow )
+{
+  if ( gifInfo->Image.Interlace )
+  {
+    // If the image is interlaced, then use the GIF interlace algorithm to read the file appropriately.
+
+    const InterlacePair* interlacePairPtr( INTERLACE_PAIR_TABLE );
+    for ( unsigned int interlacePair = 0; interlacePair < INTERLACE_PAIR_TABLE_SIZE; ++interlacePair, ++interlacePairPtr )
+    {
+      for( unsigned int currentByte = interlacePairPtr->startingByte; currentByte < height; currentByte += interlacePairPtr->incrementalByte )
+      {
+        unsigned char* row = decodedData + currentByte * bytesPerRow;
+        if ( DGifGetLine( gifInfo, row, width ) == GIF_ERROR )
+        {
+          DALI_LOG_ERROR( "GIF Loader: Error reading Interlaced GIF\n" );
+          return false;
+        }
+      }
+    }
+  }
+  else
+  {
+    // Non-interlace does not require any erratic reading / jumping.
+    unsigned char* decodedDataPtr( decodedData );
+
+    for ( unsigned int row = 0; row < height; ++row )
+    {
+      if ( DGifGetLine( gifInfo, decodedDataPtr, width ) == GIF_ERROR)
+      {
+        DALI_LOG_ERROR( "GIF Loader: Error reading non-interlaced GIF\n" );
+        return false;
+      }
+      decodedDataPtr += bytesPerRow;
+    }
+  }
+  return true;
+}
+
+// Retrieves the colors used in the GIF image.
+GifColorType* GetImageColors( SavedImage* image, GifFileType* gifInfo )
+{
+  GifColorType* color( NULL );
+  if ( image->ImageDesc.ColorMap )
+  {
+    color = image->ImageDesc.ColorMap->Colors;
+  }
+  else
+  {
+    // if there is no color map for this image use the default one
+    color = gifInfo->SColorMap->Colors;
+  }
+  return color;
+}
+
+/// Called when we want to handle IMAGE_DESC_RECORD_TYPE
+bool HandleImageDescriptionRecordType( Dali::Devel::PixelBuffer& bitmap, GifFileType* gifInfo, unsigned int width, unsigned int height, bool& finished )
+{
+  if ( DGifGetImageDesc( gifInfo ) == GIF_ERROR )
+  {
+    DALI_LOG_ERROR( "GIF Loader: Error getting Image Description\n" );
+    return false;
+  }
+
+  // Ensure there is at least 1 image in the GIF.
+  if ( gifInfo->ImageCount < 1 )
+  {
+    DALI_LOG_ERROR( "GIF Loader: No Images\n" );
+    return false;
+  }
+
+  Pixel::Format pixelFormat( Pixel::RGB888 );
+
+  SavedImage* image( &gifInfo->SavedImages[ gifInfo->ImageCount - 1 ] );
+  const GifImageDesc& desc( image->ImageDesc );
+
+  auto decodedData = new unsigned char[ width * height * sizeof( GifPixelType ) ];
+
+  std::unique_ptr<unsigned char[]> ptr{ decodedData };
+
+  const unsigned int bytesPerRow( width * sizeof( GifPixelType ) );
+  const unsigned int actualWidth( desc.Width );
+  const unsigned int actualHeight( desc.Height );
+
+  // Create a buffer to store the decoded data.
+  bitmap = Dali::Devel::PixelBuffer::New( actualWidth, actualHeight, pixelFormat );
+
+  // Decode the GIF Image
+  if ( !DecodeImage( gifInfo, decodedData, actualWidth, actualHeight, bytesPerRow ) )
+  {
+    return false;
+  }
+
+  // Get the colormap for the GIF
+  GifColorType* color( GetImageColors( image, gifInfo ) );
+
+  // If it's an animated GIF, we still only read the first image
+
+  // Create and populate pixel buffer.
+  auto pixels = bitmap.GetBuffer();
+  for (unsigned int row = 0; row < actualHeight; ++row)
+  {
+    for (unsigned int column = 0; column < actualWidth; ++column)
+    {
+      unsigned char index = decodedData[row * width + column];
+
+      pixels[0] = color[index].Red;
+      pixels[1] = color[index].Green;
+      pixels[2] = color[index].Blue;
+      pixels += 3;
+    }
+  }
+  finished = true;
+  return true;
+}
+
+/// Called when we want to handle EXTENSION_RECORD_TYPE
+bool HandleExtensionRecordType( GifFileType* gifInfo )
+{
+  SavedImage image;
+  GifByteType *extensionByte( NULL );
+
+#ifdef LIBGIF_VERSION_5_1_OR_ABOVE
+  ExtensionBlock extensionBlocks;
+  image.ExtensionBlocks          = &extensionBlocks;
+  image.ExtensionBlockCount      = 1;
+  int *extensionBlockTypePointer = &image.ExtensionBlocks->Function;
+#else
+  image.ExtensionBlocks     = NULL;
+  image.ExtensionBlockCount = 0;
+  int *extensionBlockTypePointer = &image.Function;
+#endif
+
+  // Not really interested in the extensions so just skip them unless there is an error.
+  for ( int extRetCode = DGifGetExtension( gifInfo, extensionBlockTypePointer, &extensionByte );
+        extensionByte != NULL;
+        extRetCode = DGifGetExtensionNext( gifInfo, &extensionByte ) )
+  {
+    if ( extRetCode == GIF_ERROR )
+    {
+      DALI_LOG_ERROR( "GIF Loader: Error reading GIF Extension record.\n" );
+      return false;
+    }
+  }
+
+  return true;
+}
+
+} // unnamed namespace
+
+bool LoadGifHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height )
+{
+  GifFileType* gifInfo = NULL;
+  AutoCleanupGif autoCleanupGif(gifInfo);
+  FILE* const fp = input.file;
+
+  return LoadGifHeader(fp, width, height, &gifInfo);
+}
+
+bool LoadBitmapFromGif( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap )
+{
+  FILE* const fp = input.file;
+  // Load the GIF Header file.
+
+  GifFileType* gifInfo( NULL );
+  unsigned int width( 0 );
+  unsigned int height( 0 );
+  if ( !LoadGifHeader( fp, width, height, &gifInfo ) )
+  {
+    return false;
+  }
+  AutoCleanupGif autoGif( gifInfo );
+
+  // Check each record in the GIF file.
+
+  bool finished( false );
+  GifRecordType recordType( UNDEFINED_RECORD_TYPE );
+  for ( int returnCode = DGifGetRecordType( gifInfo, &recordType );
+        !finished && recordType != TERMINATE_RECORD_TYPE;
+        returnCode = DGifGetRecordType( gifInfo, &recordType ) )
+  {
+    if ( returnCode == GIF_ERROR )
+    {
+      DALI_LOG_ERROR( "GIF Loader: Error getting Record Type\n" );
+      return false;
+    }
+
+    if( IMAGE_DESC_RECORD_TYPE == recordType )
+    {
+      if ( !HandleImageDescriptionRecordType( bitmap, gifInfo, width, height, finished ) )
+      {
+        return false;
+      }
+    }
+    else if ( EXTENSION_RECORD_TYPE == recordType )
+    {
+      if ( !HandleExtensionRecordType( gifInfo ))
+      {
+        return false;
+      }
+    }
+  }
+
+  return true;
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/dali/internal/imaging/common/loader-gif.h b/dali/internal/imaging/common/loader-gif.h
new file mode 100755 (executable)
index 0000000..a215ae5
--- /dev/null
@@ -0,0 +1,67 @@
+#ifndef DALI_TIZEN_PLATFORM_LOADER_GIF_H
+#define DALI_TIZEN_PLATFORM_LOADER_GIF_H
+
+/*
+ * Copyright (c) 2019 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 <cstdio>
+#include <dali/devel-api/adaptor-framework/image-loader-input.h>
+
+namespace Dali
+{
+namespace Devel
+{
+class PixelBuffer;
+}
+
+
+namespace TizenPlatform
+{
+
+class ResourceLoadingClient;
+
+namespace Gif
+{
+const unsigned char MAGIC_BYTE_1 = 0x47;
+const unsigned char MAGIC_BYTE_2 = 0x49;
+} // namespace Gif
+
+/**
+ * Loads the bitmap from a GIF file.  This function checks the header first
+ * and if it is not a GIF file, then it returns straight away.
+ * @note For animated GIFs, only the first image is displayed
+ * @param[in]  input  Information about the input image (including file pointer)
+ * @param[out] bitmap The bitmap class where the decoded image will be stored
+ * @return  true if file decoded successfully, false otherwise
+ */
+bool LoadBitmapFromGif( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap );
+
+/**
+ * Loads the header of a GIF file and fills in the width and height appropriately.
+ * @param[in]   fp      Pointer to the Image file
+ * @param[in]  attributes  Describes the dimensions, pixel format and other details for loading the image data
+ * @param[in/out]  width   Is set with the width of the image
+ * @param[in/out]  height  Is set with the height of the image
+ * @return true if the file's header was read successully, false otherwise
+ */
+bool LoadGifHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // DALI_TIZEN_PLATFORM_LOADER_GIF_H
diff --git a/dali/internal/imaging/common/loader-ico.cpp b/dali/internal/imaging/common/loader-ico.cpp
new file mode 100755 (executable)
index 0000000..dc99750
--- /dev/null
@@ -0,0 +1,673 @@
+/*
+ * 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.
+ */
+
+/*
+ * Derived from Enlightenment file evas_image_load_ico.c[1]  which is licensed
+ * under the BSD 2-clause license[2] reproduced below.
+ *
+ * [1][http://web.archive.org/web/20141201151111/http://git.enlightenment.org/core/efl.git/tree/src/modules/evas/loaders/ico/evas_image_load_ico.c]
+ * [2][http://web.archive.org/web/20140717012400/https://git.enlightenment.org/core/efl.git/about/]
+ *
+ * Copyright (C) 2002-2012 Carsten Haitzler, Dan Sinclair, Mike Blumenkrantz,
+ * Samsung Electronics and various contributors (see AUTHORS)
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    1. Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *    2. Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// HEADER
+#include <dali/internal/imaging/common/loader-ico.h>
+
+// EXTERNAL INCLUDES
+#include <cstring>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace
+{
+// Reserved 2 bytes + type 2 bytes + count 2 bytes + count * 16 bytes
+const unsigned char ICO_FILE_HEADER = 22;
+// Info header 40 bytes = size 4 bytes + width 4 bytes + height 4 bytes + planes 2 bytes + bitcount 2 bytes
+// + compression 4 bytes + imagesize 4 bytes + xpixelsPerM 4 bytes + ypixelsPerM 4 bytes + colorsUsed 4 bytes + colorImportant 4 bytes
+// besides, there are rgba color data = numberOfColors * 4 bytes
+const unsigned char ICO_IMAGE_INFO_HEADER = 40;
+
+typedef unsigned char  DATA8;
+#define A_VAL(p) (reinterpret_cast< DATA8 * >( p )[3])
+
+#define RGB_JOIN(r,g,b) \
+                (((r) << 16) + ((g) << 8) + (b))
+
+#define ARGB_JOIN(a,r,g,b) \
+                (((a) << 24) + ((r) << 16) + ((g) << 8) + (b))
+
+bool read_ushort(unsigned char *map, size_t length, size_t *position, unsigned short *ret)
+{
+  unsigned char b[2];
+
+  if (*position + 2 > length)
+  {
+    return false;
+  }
+  b[0] = map[(*position)++];
+  b[1] = map[(*position)++];
+  *ret = (b[1] << 8) | b[0];
+  return true;
+}
+
+bool read_uint(unsigned char *map, size_t length, size_t *position, unsigned int *ret)
+{
+  unsigned char b[4];
+  unsigned int i;
+
+  if (*position + 4 > length)
+  {
+    return false;
+  }
+  for (i = 0; i < 4; i++)
+  {
+    b[i] = map[(*position)++];
+  }
+  *ret = ARGB_JOIN(b[3], b[2], b[1], b[0]);
+  return true;
+}
+
+bool read_uchar(unsigned char *map, size_t length, size_t *position, unsigned char *ret)
+{
+  if (*position + 1 > length)
+  {
+    return false;
+  }
+  *ret = map[(*position)++];
+  return true;
+}
+
+bool read_mem(unsigned char *map, size_t length, size_t *position, void *buffer, int size)
+{
+  if (*position + size > length)
+  {
+    return false;
+  }
+  memcpy(buffer, map + *position, size);
+  *position += size;
+  return true;
+}
+
+enum
+{
+  SMALLEST,
+  BIGGEST,
+  SMALLER,
+  BIGGER
+};
+
+enum
+{
+  ICON = 1,
+  CURSOR = 2
+};
+
+struct IcoData
+{
+  int pdelta;
+  int w, h;
+  int cols;
+  int bpp, planes;
+  int hot_x, hot_y;
+  unsigned int bmoffset, bmsize;
+};
+
+bool LoadIcoHeaderHelper( FILE* fp,
+                          IcoData& chosen,
+                          Dali::Vector<unsigned char>& map,
+                          unsigned int& fsize )
+{
+  memset( &chosen, 0, sizeof(chosen) );
+
+  if(fp == NULL)
+  {
+    DALI_LOG_ERROR("Error loading bitmap\n");
+    return false;
+  }
+  size_t position = 0;
+  unsigned short word;
+  unsigned char byte;
+
+  if( fseek(fp,0,SEEK_END) )
+  {
+    DALI_LOG_ERROR("Error seeking ICO data\n");
+    return false;
+  }
+
+  long positionIndicator = ftell(fp);
+  fsize = 0u;
+
+  if( positionIndicator > -1L )
+  {
+    fsize = static_cast<unsigned int>(positionIndicator);
+  }
+
+  if( 0u == fsize )
+  {
+    return false;
+  }
+
+  if( fseek(fp, 0, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking ICO data\n");
+    return false;
+  }
+
+  if (fsize < (ICO_FILE_HEADER + ICO_IMAGE_INFO_HEADER)) //6 + 16 + 40
+  {
+    return false;
+  }
+  map.Resize(fsize);
+
+  if(fread(&map[0], 1, fsize, fp) != fsize)
+  {
+    DALI_LOG_WARNING("image file read opeation error!\n");
+    return false;
+  }
+
+  int search = BIGGEST;
+  unsigned short reserved, type, count;
+  if (!read_ushort(&map[0], fsize, &position, &reserved))
+  {
+    return false;
+  }
+  if (!read_ushort(&map[0], fsize, &position, &type))
+  {
+    return false;
+  }
+  if (!read_ushort(&map[0], fsize, &position, &count))
+  {
+    return false;
+  }
+  if (!((reserved == 0) &&
+       ((type == ICON) || (type == CURSOR)) && (count != 0)))
+  {
+    return false;
+  }
+  search = BIGGEST;
+  chosen.pdelta = 0;
+  bool have_choice = false;
+
+  for (unsigned short i = 0; i < count; i++)
+  {
+    unsigned char tw = 0, th = 0, tcols = 0;
+    if (!read_uchar(&map[0], fsize, &position, &tw))
+    {
+      return false;
+    }
+    int w = tw;
+    if (w <= 0)
+    {
+      w = 256;
+    }
+    if (!read_uchar(&map[0], fsize, &position, &th))
+    {
+      return false;
+
+    }
+    int h = th;
+    if (h <= 0)
+    {
+      h = 256;
+    }
+    if (!read_uchar(&map[0], fsize, &position, &tcols))
+    {
+      return false;
+    }
+    int cols = tcols;
+    if (!read_uchar(&map[0], fsize, &position, &byte))
+    {
+      return false;
+    }
+    if (!read_ushort(&map[0], fsize, &position, &word))
+    {
+      return false;
+    }
+    int planes=0;
+    if (type == 1)
+    {
+      planes = word;
+    }
+    //else hot_x = word;
+    if (!read_ushort(&map[0], fsize, &position, &word))
+    {
+      return false;
+    }
+    int bpp=0;
+    if (type == 1)
+    {
+      bpp = word;
+    }
+
+    // 0 colors means 256 for paletized modes.
+    // Note: We must not do this conversion for bpp greater than 8, as there is no palette.
+    if( bpp <= 8 && cols == 0 )
+    {
+      cols = 256;
+    }
+
+    //else hot_y = word;
+    unsigned int bmoffset, bmsize;
+    if (!read_uint(&map[0], fsize, &position, &bmsize))
+    {
+      return false;
+    }
+    if (!read_uint(&map[0], fsize, &position, &bmoffset))
+    {
+      return false;
+    }
+    if ((bmsize <= 0) || (bmoffset <= 0) || (bmoffset >= fsize))
+    {
+      return false;
+    }
+    if (search == BIGGEST)
+    {
+      int pdelta = w * h;
+      if ((!have_choice) ||
+       ((pdelta >= chosen.pdelta) &&
+           (((bpp >= 3) && (bpp >= chosen.bpp)) ||
+               ((bpp < 3) && (cols >= chosen.cols)))))
+      {
+        have_choice = true;
+        chosen.pdelta = pdelta;
+        chosen.w = w;
+        chosen.h = h;
+        chosen.cols = cols;
+        chosen.bpp = bpp;
+        chosen.planes = planes;
+        chosen.bmsize = bmsize;
+        chosen.bmoffset = bmoffset;
+      }
+    }
+  }
+
+  if (chosen.bmoffset == 0)
+  {
+    return false;
+  }
+
+  return true;
+}
+
+}//unnamed namespace
+
+bool LoadIcoHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height )
+{
+  IcoData chosen;
+  Dali::Vector<unsigned char> map;
+  unsigned int fsize;
+  FILE* const fp = input.file;
+
+  if ( false == LoadIcoHeaderHelper(fp, chosen, map, fsize) )
+  {
+    return false;
+  }
+
+  width = chosen.w;
+  height = chosen.h;
+
+  return true;
+}
+
+bool LoadBitmapFromIco( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap )
+{
+  IcoData chosen;
+  Dali::Vector<unsigned char> map;
+  unsigned int fsize;
+  FILE* const fp = input.file;
+
+  if ( false == LoadIcoHeaderHelper(fp, chosen, map, fsize) )
+  {
+    return false;
+  }
+
+  Dali::Vector<unsigned int> pal;
+  Dali::Vector<unsigned int> surface;
+  Dali::Vector<unsigned char> maskbuf;
+  Dali::Vector<unsigned char> pixbuf;
+  pal.Resize(256 * 4);
+
+  unsigned int dword;
+  unsigned short word;
+
+  int diff_size = 0;
+  unsigned int* pix;
+
+  size_t position = chosen.bmoffset;//22 == position
+
+  unsigned int w = chosen.w;
+  unsigned int h = chosen.h;
+  unsigned int cols = chosen.cols;
+
+  // read bmp header time... let's do some checking
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // headersize - dont care
+  }
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // width
+  }
+  if (dword > 0)
+  {
+    if (dword != w)
+    {
+      w = dword;
+      diff_size = 1;
+    }
+  }
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // height
+  }
+  if (dword > 0)
+  {
+    if (dword != (h * 2))
+    {
+      h = dword / 2;
+      diff_size = 1;
+    }
+  }
+  if (diff_size)
+  {
+    DALI_LOG_WARNING("Broken ICO file!\n");
+  }
+
+  // Set up the surface as soon as we have the width and height, so we have a black image if there are any further errors.
+  surface.Resize( w * h * 4 );
+  memset( &surface[0], 0, w * h * 4 );
+
+  if (!read_ushort(&map[0], fsize, &position, &word))
+  {
+    return false; // planes
+  }
+  //planes2 = word;
+  if (!read_ushort(&map[0], fsize, &position, &word))
+  {
+    return false; // bitcount
+  }
+  unsigned int bitcount = word;
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // compression
+  }
+  //compression = dword;
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // imagesize
+  }
+  //imagesize = dword;
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // z pixels per m
+  }
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // y pizels per m
+  }
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // colors used
+  }
+  //colorsused = dword;
+  if (!read_uint(&map[0], fsize, &position, &dword))
+  {
+    return false; // colors important
+  }
+
+  for( unsigned int i = 0; i < cols ; i ++ )
+  {
+    unsigned char a, r, g, b;
+
+    if (!read_uchar(&map[0], fsize, &position, &b))
+    {
+      return false;
+    }
+    if (!read_uchar(&map[0], fsize, &position, &g))
+    {
+      return false;
+    }
+    if (!read_uchar(&map[0], fsize, &position, &r))
+    {
+      return false;
+    }
+    if (!read_uchar(&map[0], fsize, &position, &a))
+    {
+      return false;
+    }
+    pal[i] = ARGB_JOIN( 0xff, b, g, r );
+  }
+
+  // This is the reference way of calculating the total number of bytes necessary to store one row of pixels.
+  unsigned int stride = ( ( ( bitcount * w ) + 31 ) / 32 ) * 4;
+  unsigned int bitStride = ( ( w + 31 ) / 32 ) * 4;
+
+  // Pixbuf only ever contains one scanline worth of data.
+  pixbuf.Resize( stride );
+  maskbuf.Resize( bitStride * h );
+
+  // Handle different bits-per-pixel.
+  // Note: Switch is in order of most common format first.
+  switch( bitcount )
+  {
+    case 32:
+    {
+      unsigned char* p = &map[position];
+      pix = &surface[0] + ( ( h - 1 ) * w );
+
+      for( unsigned int i = 0; i < h; i++ )
+      {
+        for( unsigned int j = 0; j < w; j++ )
+        {
+          *pix++ = ARGB_JOIN( p[3], p[0], p[1], p[2] );
+          p += 4;
+        }
+        // Move the output up 1 line (we subtract 2 lines because we moved forward one line while copying).
+        pix -= ( w * 2 );
+      }
+      break;
+    }
+
+    case 24:
+    {
+      for( unsigned int i = 0; i < h; i++ )
+      {
+        pix = &surface[0] + ( ( h - 1 - i ) * w );
+        if( !read_mem( &map[0], fsize, &position, &pixbuf[0], stride ) )
+        {
+          return false;
+        }
+        unsigned char* p = &pixbuf[0];
+        for( unsigned int j = 0; j < w; j++ )
+        {
+          *pix++ = ARGB_JOIN( 0xff, p[0], p[1], p[2] );
+          p += 3;
+        }
+      }
+      break;
+    }
+
+    case 8:
+    {
+      for( unsigned int i = 0; i < h; i++ )
+      {
+        pix = &surface[0] + ( ( h - 1 - i ) * w );
+        if( !read_mem( &map[0], fsize, &position, &pixbuf[0], stride ) )
+        {
+          return false;
+        }
+        unsigned char* p = &pixbuf[0];
+        for( unsigned int j = 0; j < w; j++ )
+        {
+          *pix++ = pal[*p++];
+        }
+      }
+      break;
+    }
+
+    case 4:
+    {
+      for( unsigned int i = 0; i < h; i++ )
+      {
+        pix = &surface[0] + ( ( h - 1 - i ) * w );
+        if( !read_mem( &map[0], fsize, &position, &pixbuf[0], stride ) )
+        {
+          return false;
+        }
+        unsigned char* p = &pixbuf[0];
+        for( unsigned int j = 0; j < w; j++ )
+        {
+          if( j & 0x1 )
+          {
+            *pix = pal[*p & 0x0f];
+            p++;
+          }
+          else
+          {
+            *pix = pal[*p >> 4];
+          }
+          pix++;
+        }
+      }
+      break;
+    }
+
+    case 1:
+    {
+      for( unsigned int i = 0; i < h; i++ )
+      {
+        pix = &surface[0] + ( ( h - 1 - i ) * w );
+        if( !read_mem( &map[0], fsize, &position, &pixbuf[0], stride ) )
+        {
+          return false;
+        }
+        unsigned char* p = &pixbuf[0];
+
+        for( unsigned int j = 0; j < w; j += 8 )
+        {
+          *pix++ = pal[ *p >> 7 ];
+          *pix++ = pal[ *p >> 6 & 0x01 ];
+          *pix++ = pal[ *p >> 5 & 0x01 ];
+          *pix++ = pal[ *p >> 4 & 0x01 ];
+          *pix++ = pal[ *p >> 3 & 0x01 ];
+          *pix++ = pal[ *p >> 2 & 0x01 ];
+          *pix++ = pal[ *p >> 1 & 0x01 ];
+          *pix++ = pal[ *p >> 0 & 0x01 ];
+
+          p++;
+        }
+      }
+      break;
+    }
+
+    default:
+    {
+      DALI_LOG_WARNING( "Image file contains unsupported bits-per-pixel %d\n", bitcount );
+      return false;
+    }
+  }
+
+  // From the spec: If bpp is less than 32, there will be a 1bpp mask bitmap also.
+  if( bitcount < 32 )
+  {
+    if( !read_mem( &map[0], fsize, &position, &maskbuf[0], bitStride * h ) )
+    {
+      return false;
+    }
+
+    // Apply mask.
+    // Precalc to save time in the loops.
+    unsigned int bytesPerWidth = w / 8;
+    unsigned int bytesRemainingPerWidth = w - ( bytesPerWidth << 3 );
+
+    // Loop for each line of the image.
+    for( unsigned int i = 0; i < h; ++i )
+    {
+      unsigned char *m = &maskbuf[0] + ( bitStride * i );
+      pix = &surface[0] + ( ( h - 1 - i ) * w );
+
+      // Do chunks of 8 pixels first so mask operations can be unrolled.
+      for( unsigned int j = 0; j < bytesPerWidth; ++j )
+      {
+        // Unrolled 8 bits of the mask to avoid many conditions and branches.
+        A_VAL( pix++ ) = ( *m & ( 1 << 7 ) ) ? 0x00 : 0xff;
+        A_VAL( pix++ ) = ( *m & ( 1 << 6 ) ) ? 0x00 : 0xff;
+        A_VAL( pix++ ) = ( *m & ( 1 << 5 ) ) ? 0x00 : 0xff;
+        A_VAL( pix++ ) = ( *m & ( 1 << 4 ) ) ? 0x00 : 0xff;
+        A_VAL( pix++ ) = ( *m & ( 1 << 3 ) ) ? 0x00 : 0xff;
+        A_VAL( pix++ ) = ( *m & ( 1 << 2 ) ) ? 0x00 : 0xff;
+        A_VAL( pix++ ) = ( *m & ( 1 << 1 ) ) ? 0x00 : 0xff;
+        A_VAL( pix++ ) = ( *m & ( 1 << 0 ) ) ? 0x00 : 0xff;
+        m++;
+      }
+
+      // Handle any remaining width ( < 8 ) or images that are < 8 wide.
+      if( bytesRemainingPerWidth > 0 )
+      {
+        for( unsigned int j = 0; j < bytesRemainingPerWidth; ++j )
+        {
+          // Note: Although we are doing less that a bytes worth of mask, we still always start on the first bit.
+          // If the image is smaller than 8 pixels wide, each mask will still start on a new byte.
+          A_VAL( pix++ ) = ( *m & ( 1 << ( 7 - j ) ) ) ? 0x00 : 0xff;
+        }
+        m++;
+      }
+    }
+  }
+
+  bitmap = Dali::Devel::PixelBuffer::New(w, h, Pixel::Format::RGBA8888);
+  auto pixels = bitmap.GetBuffer();
+  memcpy( pixels, &surface[0], w * h * 4 );
+
+  return true;
+}
+
+}
+
+}
diff --git a/dali/internal/imaging/common/loader-ico.h b/dali/internal/imaging/common/loader-ico.h
new file mode 100755 (executable)
index 0000000..c68f154
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef DALI_TIZEN_PLATFORM_LOADER_ICO_H
+#define DALI_TIZEN_PLATFORM_LOADER_ICO_H
+
+/*
+ * Copyright (c) 2019 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 <cstdio>
+#include <dali/devel-api/adaptor-framework/image-loader-input.h>
+
+namespace Dali
+{
+namespace Devel
+{
+class PixelBuffer;
+}
+
+namespace TizenPlatform
+{
+
+class ResourceLoadingClient;
+
+namespace Ico
+{
+//00 00 01 00 01 00 20 20
+const unsigned char MAGIC_BYTE_1 = 0x00;
+const unsigned char MAGIC_BYTE_2 = 0x00;
+}
+/**
+ * @param[in]  input  Information about the input image (including file pointer)
+ * @param[out] bitmap The bitmap class where the decoded image will be stored
+ * @return  true if file decoded successfully, false otherwise
+ */
+bool LoadBitmapFromIco( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap );
+
+/**
+ * @param[in]  input  Information about the input image (including file pointer)
+ * @param[out] width of image
+ * @param[out] height of image
+ * @return  true if header loaded successfully, false otherwise
+ */
+bool LoadIcoHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // DALI_TIZEN_PLATFORM_LOADER_ICO_H
diff --git a/dali/internal/imaging/common/loader-jpeg-turbo.cpp b/dali/internal/imaging/common/loader-jpeg-turbo.cpp
new file mode 100755 (executable)
index 0000000..2566d26
--- /dev/null
@@ -0,0 +1,1171 @@
+/*
+ * 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 <dali/internal/imaging/common/loader-jpeg.h>
+
+// EXTERNAL HEADERS
+#include <functional>
+#include <array>
+#include <utility>
+#include <memory>
+#include <libexif/exif-data.h>
+#include <libexif/exif-loader.h>
+#include <libexif/exif-tag.h>
+#include <turbojpeg.h>
+#include <jpeglib.h>
+#include <cstring>
+#include <setjmp.h>
+
+#include <dali/public-api/object/property-map.h>
+#include <dali/public-api/object/property-array.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+
+
+// INTERNAL HEADERS
+#include <dali/internal/legacy/tizen/platform-capabilities.h>
+#include <dali/internal/imaging/common/image-operations.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+#include <dali/internal/imaging/common/pixel-buffer-impl.h>
+
+namespace
+{
+using Dali::Vector;
+namespace Pixel = Dali::Pixel;
+using PixelArray = unsigned char*;
+const unsigned int DECODED_L8 = 1;
+const unsigned int DECODED_RGB888 = 3;
+const unsigned int DECODED_RGBA8888 = 4;
+
+/** Transformations that can be applied to decoded pixels to respect exif orientation
+  *  codes in image headers */
+enum class JpegTransform
+{
+  NONE,             //< no transformation 0th-Row = top & 0th-Column = left
+  FLIP_HORIZONTAL,  //< horizontal flip 0th-Row = top & 0th-Column = right
+  FLIP_VERTICAL,    //< vertical flip   0th-Row = bottom & 0th-Column = right
+  TRANSPOSE,        //< transpose across UL-to-LR axis  0th-Row = bottom & 0th-Column = left
+  TRANSVERSE,       //< transpose across UR-to-LL axis  0th-Row = left   & 0th-Column = top
+  ROTATE_90,        //< 90-degree clockwise rotation  0th-Row = right  & 0th-Column = top
+  ROTATE_180,       //< 180-degree rotation  0th-Row = right  & 0th-Column = bottom
+  ROTATE_270,       //< 270-degree clockwise (or 90 ccw) 0th-Row = left  & 0th-Column = bottom
+};
+
+/**
+  * @brief Error handling bookeeping for the JPEG Turbo library's
+  * setjmp/longjmp simulated exceptions.
+  */
+struct JpegErrorState
+{
+  struct jpeg_error_mgr errorManager;
+  jmp_buf jumpBuffer;
+};
+
+/**
+  * @brief Called by the JPEG library when it hits an error.
+  * We jump out of the library so our loader code can return an error.
+  */
+void  JpegErrorHandler ( j_common_ptr cinfo )
+{
+  DALI_LOG_ERROR( "JpegErrorHandler(): libjpeg-turbo fatal error in JPEG decoding.\n" );
+  /* cinfo->err really points to a JpegErrorState struct, so coerce pointer */
+  JpegErrorState * myerr = reinterpret_cast<JpegErrorState *>( cinfo->err );
+
+  /* Return control to the setjmp point */
+  longjmp( myerr->jumpBuffer, 1 );
+}
+
+void JpegOutputMessageHandler( j_common_ptr cinfo )
+{
+  /* Stop libjpeg from printing to stderr - Do Nothing */
+}
+
+/**
+  * LibJPEG Turbo tjDecompress2 API doesn't distinguish between errors that still allow
+  * the JPEG to be displayed and fatal errors.
+  */
+bool IsJpegErrorFatal( const std::string& errorMessage )
+{
+  if( ( errorMessage.find("Corrupt JPEG data") != std::string::npos ) ||
+      ( errorMessage.find("Invalid SOS parameters") != std::string::npos ) ||
+      ( errorMessage.find("Invalid JPEG file structure") != std::string::npos ) ||
+      ( errorMessage.find("Unsupported JPEG process") != std::string::npos ) ||
+      ( errorMessage.find("Unsupported marker type") != std::string::npos ) ||
+      ( errorMessage.find("Bogus marker length") != std::string::npos ) ||
+      ( errorMessage.find("Bogus DQT index") != std::string::npos ) ||
+      ( errorMessage.find("Bogus Huffman table definition") != std::string::npos ))
+  {
+    return false;
+  }
+  return true;
+}
+
+// helpers for safe exif memory handling
+using ExifHandle = std::unique_ptr<ExifData, decltype(exif_data_free)*>;
+
+ExifHandle MakeNullExifData()
+{
+  return ExifHandle{nullptr, exif_data_free};
+}
+
+ExifHandle MakeExifDataFromData(unsigned char* data, unsigned int size)
+{
+  return ExifHandle{exif_data_new_from_data(data, size), exif_data_free};
+}
+
+// Helpers for safe Jpeg memory handling
+using JpegHandle = std::unique_ptr<void /*tjhandle*/, decltype(tjDestroy)*>;
+
+JpegHandle MakeJpegCompressor()
+{
+  return JpegHandle{tjInitCompress(), tjDestroy};
+}
+
+JpegHandle MakeJpegDecompressor()
+{
+  return JpegHandle{tjInitDecompress(), tjDestroy};
+}
+
+using JpegMemoryHandle = std::unique_ptr<unsigned char, decltype(tjFree)*>;
+
+JpegMemoryHandle MakeJpegMemory()
+{
+  return JpegMemoryHandle{nullptr, tjFree};
+}
+
+template<class T, class Deleter>
+class UniquePointerSetter final
+{
+public:
+  UniquePointerSetter(std::unique_ptr<T, Deleter>& uniquePointer)
+  : mUniquePointer(uniquePointer),
+    mRawPointer(nullptr)
+  {}
+
+  /// @brief Pointer to Pointer cast operator
+  operator T** () { return &mRawPointer; }
+
+  /// @brief Destructor, reset the unique_ptr
+  ~UniquePointerSetter() { mUniquePointer.reset(mRawPointer); }
+
+private:
+  std::unique_ptr<T, Deleter>& mUniquePointer;
+  T* mRawPointer;
+};
+
+template<typename T, typename Deleter>
+UniquePointerSetter<T, Deleter> SetPointer(std::unique_ptr<T, Deleter>& uniquePointer)
+{
+  return UniquePointerSetter<T, Deleter>{uniquePointer};
+}
+
+using TransformFunction = std::function<void(PixelArray,unsigned, unsigned)>;
+using TransformFunctionArray = std::array<TransformFunction, 3>; // 1, 3 and 4 bytes per pixel
+
+/// @brief Select the transform function depending on the pixel format
+TransformFunction GetTransformFunction(const TransformFunctionArray& functions,
+                                       Pixel::Format pixelFormat)
+{
+  auto function = TransformFunction{};
+
+  int decodedPixelSize = Pixel::GetBytesPerPixel(pixelFormat);
+  switch( decodedPixelSize )
+  {
+    case DECODED_L8:
+    {
+      function = functions[0];
+      break;
+    }
+    case DECODED_RGB888:
+    {
+      function = functions[1];
+      break;
+    }
+    case DECODED_RGBA8888:
+    {
+      function = functions[2];
+      break;
+    }
+    default:
+    {
+      DALI_LOG_ERROR("Transform operation not supported on this Pixel::Format!");
+      function = functions[1];
+      break;
+    }
+  }
+  return function;
+}
+
+// Storing Exif fields as properties
+template<class R, class V>
+R ConvertExifNumeric( const ExifEntry& entry )
+{
+  return static_cast<R>((*reinterpret_cast<V*>(entry.data)));
+}
+
+void AddExifFieldPropertyMap( Dali::Property::Map& out, const ExifEntry& entry, ExifIfd ifd )
+{
+  auto shortName = std::string(exif_tag_get_name_in_ifd(entry.tag, ifd ));
+  switch( entry.format )
+  {
+    case EXIF_FORMAT_ASCII:
+    {
+      out.Insert( shortName, std::string( reinterpret_cast<char *>(entry.data), entry.size ) );
+      break;
+    }
+    case EXIF_FORMAT_SHORT:
+    {
+      out.Insert( shortName, ConvertExifNumeric<int, unsigned short>(entry) );
+      break;
+    }
+    case EXIF_FORMAT_LONG:
+    {
+      out.Insert( shortName, ConvertExifNumeric<int, unsigned long>(entry) );
+      break;
+    }
+    case EXIF_FORMAT_SSHORT:
+    {
+      out.Insert( shortName, ConvertExifNumeric<int, short>(entry) );
+      break;
+    }
+    case EXIF_FORMAT_SLONG:
+    {
+      out.Insert( shortName, ConvertExifNumeric<int, long>(entry) );
+      break;
+    }
+    case EXIF_FORMAT_FLOAT:
+    {
+      out.Insert (shortName, ConvertExifNumeric<float, float>(entry) );
+      break;
+    }
+    case EXIF_FORMAT_DOUBLE:
+    {
+      out.Insert( shortName, ConvertExifNumeric<float, double>(entry) );
+      break;
+    }
+    case EXIF_FORMAT_RATIONAL:
+    {
+      auto values = reinterpret_cast<unsigned int*>( entry.data );
+      Dali::Property::Array array;
+      array.Add( static_cast<int>(values[0]) );
+      array.Add( static_cast<int>(values[1]) );
+      out.Insert(shortName, array);
+      break;
+    }
+    case EXIF_FORMAT_SBYTE:
+    {
+      out.Insert(shortName, "EXIF_FORMAT_SBYTE Unsupported");
+      break;
+    }
+    case EXIF_FORMAT_BYTE:
+    {
+      out.Insert(shortName, "EXIF_FORMAT_BYTE Unsupported");
+      break;
+    }
+    case EXIF_FORMAT_SRATIONAL:
+    {
+      auto values = reinterpret_cast<int*>( entry.data );
+      Dali::Property::Array array;
+      array.Add(values[0]);
+      array.Add(values[1]);
+      out.Insert(shortName, array);
+      break;
+    }
+    case EXIF_FORMAT_UNDEFINED:
+    default:
+    {
+      std::stringstream ss;
+      ss << "EXIF_FORMAT_UNDEFINED, size: " << entry.size << ", components: " << entry.components;
+      out.Insert( shortName, ss.str());
+    }
+  }
+}
+
+/// @brief Apply a transform to a buffer
+bool Transform(const TransformFunctionArray& transformFunctions,
+               PixelArray buffer,
+               int width,
+               int height,
+               Pixel::Format pixelFormat )
+{
+  auto transformFunction = GetTransformFunction(transformFunctions, pixelFormat);
+  if(transformFunction)
+  {
+    transformFunction(buffer, width, height);
+  }
+  return bool(transformFunction);
+}
+
+/// @brief Auxiliar type to represent pixel data with different number of bytes
+template<size_t N>
+struct PixelType
+{
+  char _[N];
+};
+
+template<size_t N>
+void FlipVertical(PixelArray buffer, int width, int height)
+{
+  // Destination pixel, set as the first pixel of screen
+  auto to = reinterpret_cast<PixelType<N>*>( buffer );
+
+  // Source pixel, as the image is flipped horizontally and vertically,
+  // the source pixel is the end of the buffer of size width * height
+  auto from = reinterpret_cast<PixelType<N>*>(buffer) + width * height - 1;
+
+  for (auto ix = 0, endLoop = (width * height) / 2; ix < endLoop; ++ix, ++to, --from)
+  {
+    std::swap(*from, *to);
+  }
+}
+
+template<size_t N>
+void FlipHorizontal(PixelArray buffer, int width, int height)
+{
+  for(auto iy = 0; iy < height; ++iy)
+  {
+    //Set the destination pixel as the beginning of the row
+    auto to = reinterpret_cast<PixelType<N>*>(buffer) + width * iy;
+    //Set the source pixel as the end of the row to flip in X axis
+    auto from = reinterpret_cast<PixelType<N>*>(buffer) + width * (iy + 1) - 1;
+    for(auto ix = 0; ix < width / 2; ++ix, ++to, --from)
+    {
+      std::swap(*from, *to);
+    }
+  }
+}
+
+template<size_t N>
+void Transpose(PixelArray buffer, int width, int height)
+{
+  //Transform vertically only
+  for(auto iy = 0; iy < height / 2; ++iy)
+  {
+    for(auto ix = 0; ix < width; ++ix)
+    {
+      auto to = reinterpret_cast<PixelType<N>*>(buffer) + iy * width + ix;
+      auto from = reinterpret_cast<PixelType<N>*>(buffer) + (height - 1 - iy) * width + ix;
+      std::swap(*from, *to);
+    }
+  }
+}
+
+template<size_t N>
+void Transverse(PixelArray buffer, int width, int height)
+{
+  using PixelT = PixelType<N>;
+  Vector<PixelT> data;
+  data.Resize( width * height );
+  auto dataPtr = data.Begin();
+
+  auto original = reinterpret_cast<PixelT*>(buffer);
+  std::copy(original, original + width * height, dataPtr);
+
+  auto to = original;
+  for( auto iy = 0; iy < width; ++iy )
+  {
+    for( auto ix = 0; ix < height; ++ix, ++to )
+    {
+      auto from = dataPtr + ix * width + iy;
+      *to = *from;
+    }
+  }
+}
+
+
+template<size_t N>
+void Rotate90(PixelArray buffer, int width, int height)
+{
+  using PixelT = PixelType<N>;
+  Vector<PixelT> data;
+  data.Resize(width * height);
+  auto dataPtr = data.Begin();
+
+  auto original = reinterpret_cast<PixelT*>(buffer);
+  std::copy(original, original + width * height, dataPtr);
+
+  std::swap(width, height);
+  auto hw = width * height;
+  hw = - hw - 1;
+
+  auto to = original + width - 1;
+  auto from = dataPtr;
+
+  for(auto ix = width; --ix >= 0;)
+  {
+    for(auto iy = height; --iy >= 0; ++from)
+    {
+      *to = *from;
+      to += width;
+    }
+    to += hw;
+  }
+}
+
+template<size_t N>
+void Rotate180(PixelArray buffer, int width, int height)
+{
+  using PixelT = PixelType<N>;
+  Vector<PixelT> data;
+  data.Resize(width * height);
+  auto dataPtr = data.Begin();
+
+  auto original = reinterpret_cast<PixelT*>(buffer);
+  std::copy(original, original + width * height, dataPtr);
+
+  auto to = original;
+  for( auto iy = 0; iy < width; iy++ )
+  {
+    for( auto ix = 0; ix < height; ix++ )
+    {
+      auto from = dataPtr + (height - ix) * width - 1 - iy;
+      *to = *from;
+      ++to;
+    }
+  }
+}
+
+
+template<size_t N>
+void Rotate270(PixelArray buffer, int width, int height)
+{
+  using PixelT = PixelType<N>;
+  Vector<PixelT> data;
+  data.Resize(width * height);
+  auto dataPtr = data.Begin();
+
+  auto original = reinterpret_cast<PixelT*>(buffer);
+  std::copy(original, original + width * height, dataPtr);
+
+  auto w = height;
+  std::swap(width, height);
+  auto hw = width * height;
+
+  auto* to = original + hw  - width;
+  auto* from = dataPtr;
+
+  w = -w;
+  hw =  hw + 1;
+  for(auto ix = width; --ix >= 0;)
+  {
+    for(auto iy = height; --iy >= 0;)
+    {
+      *to = *from;
+      ++from;
+      to += w;
+    }
+    to += hw;
+  }
+}
+
+} // namespace
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+JpegTransform ConvertExifOrientation(ExifData* exifData);
+bool TransformSize( int requiredWidth, int requiredHeight,
+                    FittingMode::Type fittingMode, SamplingMode::Type samplingMode,
+                    JpegTransform transform,
+                    int& preXformImageWidth, int& preXformImageHeight,
+                    int& postXformImageWidth, int& postXformImageHeight );
+
+bool LoadJpegHeader( FILE *fp, unsigned int &width, unsigned int &height )
+{
+  // using libjpeg API to avoid having to read the whole file in a buffer
+  struct jpeg_decompress_struct cinfo;
+  struct JpegErrorState jerr;
+  cinfo.err = jpeg_std_error( &jerr.errorManager );
+
+  jerr.errorManager.output_message = JpegOutputMessageHandler;
+  jerr.errorManager.error_exit = JpegErrorHandler;
+
+  // On error exit from the JPEG lib, control will pass via JpegErrorHandler
+  // into this branch body for cleanup and error return:
+  if(setjmp(jerr.jumpBuffer))
+  {
+    jpeg_destroy_decompress(&cinfo);
+    return false;
+  }
+
+// jpeg_create_decompress internally uses C casts
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+  jpeg_create_decompress( &cinfo );
+#pragma GCC diagnostic pop
+
+  jpeg_stdio_src( &cinfo, fp );
+
+  // Check header to see if it is  JPEG file
+  if( jpeg_read_header( &cinfo, TRUE ) != JPEG_HEADER_OK )
+  {
+    width = height = 0;
+    jpeg_destroy_decompress( &cinfo );
+    return false;
+  }
+
+  width = cinfo.image_width;
+  height = cinfo.image_height;
+
+  jpeg_destroy_decompress( &cinfo );
+  return true;
+}
+
+bool LoadBitmapFromJpeg( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap )
+{
+  const int flags= 0;
+  FILE* const fp = input.file;
+
+  if( fseek(fp,0,SEEK_END) )
+  {
+    DALI_LOG_ERROR("Error seeking to end of file\n");
+    return false;
+  }
+
+  long positionIndicator = ftell(fp);
+  unsigned int jpegBufferSize = 0u;
+  if( positionIndicator > -1L )
+  {
+    jpegBufferSize = static_cast<unsigned int>(positionIndicator);
+  }
+
+  if( 0u == jpegBufferSize )
+  {
+    return false;
+  }
+
+  if( fseek(fp, 0, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking to start of file\n");
+    return false;
+  }
+
+  Vector<unsigned char> jpegBuffer;
+  try
+  {
+    jpegBuffer.Resize( jpegBufferSize );
+  }
+  catch(...)
+  {
+    DALI_LOG_ERROR( "Could not allocate temporary memory to hold JPEG file of size %uMB.\n", jpegBufferSize / 1048576U );
+    return false;
+  }
+  unsigned char * const jpegBufferPtr = jpegBuffer.Begin();
+
+  // Pull the compressed JPEG image bytes out of a file and into memory:
+  if( fread( jpegBufferPtr, 1, jpegBufferSize, fp ) != jpegBufferSize )
+  {
+    DALI_LOG_WARNING("Error on image file read.\n");
+    return false;
+  }
+
+  if( fseek(fp, 0, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking to start of file\n");
+  }
+
+  auto jpeg = MakeJpegDecompressor();
+
+  if(!jpeg)
+  {
+    DALI_LOG_ERROR("%s\n", tjGetErrorStr());
+    return false;
+  }
+
+  auto transform = JpegTransform::NONE;
+
+  // extract exif data
+  auto exifData = MakeExifDataFromData(jpegBufferPtr, jpegBufferSize);
+
+  if( exifData && input.reorientationRequested )
+  {
+    transform = ConvertExifOrientation(exifData.get());
+  }
+
+  std::unique_ptr<Property::Map> exifMap;
+  exifMap.reset( new Property::Map() );
+
+  for( auto k = 0u; k < EXIF_IFD_COUNT; ++k )
+  {
+    auto content = exifData->ifd[k];
+    for (auto i = 0u; i < content->count; ++i)
+    {
+      auto       &&tag      = content->entries[i];
+      const char *shortName = exif_tag_get_name_in_ifd(tag->tag, static_cast<ExifIfd>(k));
+      if(shortName)
+      {
+        AddExifFieldPropertyMap(*exifMap, *tag, static_cast<ExifIfd>(k));
+      }
+    }
+  }
+
+  // Push jpeg data in memory buffer through TurboJPEG decoder to make a raw pixel array:
+  int chrominanceSubsampling = -1;
+  int preXformImageWidth = 0, preXformImageHeight = 0;
+
+  // In Ubuntu, the turbojpeg version is not correct. so build error occurs.
+  // Temporarily separate Ubuntu and other profiles.
+#ifndef DALI_PROFILE_UBUNTU
+  int jpegColorspace = -1;
+  if( tjDecompressHeader3( jpeg.get(), jpegBufferPtr, jpegBufferSize, &preXformImageWidth, &preXformImageHeight, &chrominanceSubsampling, &jpegColorspace ) == -1 )
+  {
+    DALI_LOG_ERROR("%s\n", tjGetErrorStr());
+    // Do not set width and height to 0 or return early as this sometimes fails only on determining subsampling type.
+  }
+#else
+  if( tjDecompressHeader2( jpeg.get(), jpegBufferPtr, jpegBufferSize, &preXformImageWidth, &preXformImageHeight, &chrominanceSubsampling ) == -1 )
+  {
+    DALI_LOG_ERROR("%s\n", tjGetErrorStr());
+    // Do not set width and height to 0 or return early as this sometimes fails only on determining subsampling type.
+  }
+#endif
+
+  if(preXformImageWidth == 0 || preXformImageHeight == 0)
+  {
+    DALI_LOG_WARNING("Invalid Image!\n");
+    return false;
+  }
+
+  int requiredWidth  = input.scalingParameters.dimensions.GetWidth();
+  int requiredHeight = input.scalingParameters.dimensions.GetHeight();
+
+  // If transform is a 90 or 270 degree rotation, the logical width and height
+  // request from the client needs to be adjusted to account by effectively
+  // rotating that too, and the final width and height need to be swapped:
+  int postXformImageWidth = preXformImageWidth;
+  int postXformImageHeight = preXformImageHeight;
+
+
+  int scaledPreXformWidth   = preXformImageWidth;
+  int scaledPreXformHeight  = preXformImageHeight;
+  int scaledPostXformWidth  = postXformImageWidth;
+  int scaledPostXformHeight = postXformImageHeight;
+
+  TransformSize( requiredWidth, requiredHeight,
+                 input.scalingParameters.scalingMode,
+                 input.scalingParameters.samplingMode,
+                 transform,
+                 scaledPreXformWidth, scaledPreXformHeight,
+                 scaledPostXformWidth, scaledPostXformHeight );
+
+
+  // Colorspace conversion options
+  TJPF pixelLibJpegType = TJPF_RGB;
+  Pixel::Format pixelFormat = Pixel::RGB888;
+#ifndef DALI_PROFILE_UBUNTU
+  switch (jpegColorspace)
+  {
+    case TJCS_RGB:
+    // YCbCr is not an absolute colorspace but rather a mathematical transformation of RGB designed solely for storage and transmission.
+    // YCbCr images must be converted to RGB before they can actually be displayed.
+    case TJCS_YCbCr:
+    {
+      pixelLibJpegType = TJPF_RGB;
+      pixelFormat = Pixel::RGB888;
+      break;
+    }
+    case TJCS_GRAY:
+    {
+      pixelLibJpegType = TJPF_GRAY;
+      pixelFormat = Pixel::L8;
+      break;
+    }
+    case TJCS_CMYK:
+    case TJCS_YCCK:
+    {
+      pixelLibJpegType = TJPF_CMYK;
+      pixelFormat = Pixel::RGBA8888;
+      break;
+    }
+    default:
+    {
+      pixelLibJpegType = TJPF_RGB;
+      pixelFormat = Pixel::RGB888;
+      break;
+    }
+  }
+#endif
+  // Allocate a bitmap and decompress the jpeg buffer into its pixel buffer:
+  bitmap = Dali::Devel::PixelBuffer::New(scaledPostXformWidth, scaledPostXformHeight, pixelFormat);
+
+  // set metadata
+  GetImplementation(bitmap).SetMetadata( std::move(exifMap) );
+
+  auto bitmapPixelBuffer = bitmap.GetBuffer();
+
+  if( tjDecompress2( jpeg.get(), jpegBufferPtr, jpegBufferSize, reinterpret_cast<unsigned char*>( bitmapPixelBuffer ), scaledPreXformWidth, 0, scaledPreXformHeight, pixelLibJpegType, flags ) == -1 )
+  {
+    std::string errorString = tjGetErrorStr();
+
+    if( IsJpegErrorFatal( errorString ) )
+    {
+        DALI_LOG_ERROR("%s\n", errorString.c_str() );
+        return false;
+    }
+    else
+    {
+        DALI_LOG_WARNING("%s\n", errorString.c_str() );
+    }
+  }
+
+  const unsigned int  bufferWidth  = GetTextureDimension( scaledPreXformWidth );
+  const unsigned int  bufferHeight = GetTextureDimension( scaledPreXformHeight );
+
+  bool result = false;
+  switch(transform)
+  {
+    case JpegTransform::NONE:
+    {
+      result = true;
+      break;
+    }
+    // 3 orientation changes for a camera held perpendicular to the ground or upside-down:
+    case JpegTransform::ROTATE_180:
+    {
+      static auto rotate180Functions = TransformFunctionArray {
+        &Rotate180<1>,
+        &Rotate180<3>,
+        &Rotate180<4>,
+      };
+      result = Transform(rotate180Functions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat );
+      break;
+    }
+    case JpegTransform::ROTATE_270:
+    {
+      static auto rotate270Functions = TransformFunctionArray {
+        &Rotate270<1>,
+        &Rotate270<3>,
+        &Rotate270<4>,
+      };
+      result = Transform(rotate270Functions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat );
+      break;
+    }
+    case JpegTransform::ROTATE_90:
+    {
+      static auto rotate90Functions = TransformFunctionArray {
+        &Rotate90<1>,
+        &Rotate90<3>,
+        &Rotate90<4>,
+      };
+      result = Transform(rotate90Functions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat );
+      break;
+    }
+    case JpegTransform::FLIP_VERTICAL:
+    {
+      static auto flipVerticalFunctions = TransformFunctionArray {
+        &FlipVertical<1>,
+        &FlipVertical<3>,
+        &FlipVertical<4>,
+      };
+      result = Transform(flipVerticalFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat );
+      break;
+    }
+    // Less-common orientation changes, since they don't correspond to a camera's physical orientation:
+    case JpegTransform::FLIP_HORIZONTAL:
+    {
+      static auto flipHorizontalFunctions = TransformFunctionArray {
+        &FlipHorizontal<1>,
+        &FlipHorizontal<3>,
+        &FlipHorizontal<4>,
+      };
+      result = Transform(flipHorizontalFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat );
+      break;
+    }
+    case JpegTransform::TRANSPOSE:
+    {
+      static auto transposeFunctions = TransformFunctionArray {
+        &Transpose<1>,
+        &Transpose<3>,
+        &Transpose<4>,
+      };
+      result = Transform(transposeFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat );
+      break;
+    }
+    case JpegTransform::TRANSVERSE:
+    {
+      static auto transverseFunctions = TransformFunctionArray {
+        &Transverse<1>,
+        &Transverse<3>,
+        &Transverse<4>,
+      };
+      result = Transform(transverseFunctions, bitmapPixelBuffer, bufferWidth, bufferHeight, pixelFormat );
+      break;
+    }
+    default:
+    {
+      DALI_LOG_ERROR( "Unsupported JPEG Orientation transformation: %x.\n", transform );
+      break;
+    }
+  }
+
+  return result;
+}
+
+bool EncodeToJpeg( const unsigned char* const pixelBuffer, Vector< unsigned char >& encodedPixels,
+                   const std::size_t width, const std::size_t height, const Pixel::Format pixelFormat, unsigned quality )
+{
+
+  if( !pixelBuffer )
+  {
+    DALI_LOG_ERROR("Null input buffer\n");
+    return false;
+  }
+
+  // Translate pixel format enum:
+  int jpegPixelFormat = -1;
+
+  switch( pixelFormat )
+  {
+    case Pixel::RGB888:
+    {
+      jpegPixelFormat = TJPF_RGB;
+      break;
+    }
+    case Pixel::RGBA8888:
+    {
+      // Ignore the alpha:
+      jpegPixelFormat = TJPF_RGBX;
+      break;
+    }
+    case Pixel::BGRA8888:
+    {
+      // Ignore the alpha:
+      jpegPixelFormat = TJPF_BGRX;
+      break;
+    }
+    default:
+    {
+      DALI_LOG_ERROR( "Unsupported pixel format for encoding to JPEG.\n" );
+      return false;
+    }
+  }
+
+  // Assert quality is in the documented allowable range of the jpeg-turbo lib:
+  DALI_ASSERT_DEBUG( quality >= 1 );
+  DALI_ASSERT_DEBUG( quality <= 100 );
+  if( quality < 1 )
+  {
+    quality = 1;
+  }
+  if( quality > 100 )
+  {
+    quality = 100;
+  }
+
+  // Initialise a JPEG codec:
+  {
+    auto jpeg = MakeJpegCompressor();
+    if( !jpeg )
+    {
+      DALI_LOG_ERROR( "JPEG Compressor init failed: %s\n", tjGetErrorStr() );
+      return false;
+    }
+
+
+    // Safely wrap the jpeg codec's buffer in case we are about to throw, then
+    // save the pixels to a persistent buffer that we own and let our cleaner
+    // class clean up the buffer as it goes out of scope:
+    auto dstBuffer = MakeJpegMemory();
+
+    // Run the compressor:
+    unsigned long dstBufferSize = 0;
+    const int flags = 0;
+
+    if( tjCompress2( jpeg.get(),
+                     const_cast<unsigned char*>(pixelBuffer),
+                     width, 0, height,
+                     jpegPixelFormat, SetPointer(dstBuffer), &dstBufferSize,
+                     TJSAMP_444, quality, flags ) )
+    {
+      DALI_LOG_ERROR("JPEG Compression failed: %s\n", tjGetErrorStr());
+      return false;
+    }
+
+    encodedPixels.Resize( dstBufferSize );
+    memcpy( encodedPixels.Begin(), dstBuffer.get(), dstBufferSize );
+  }
+  return true;
+}
+
+
+JpegTransform ConvertExifOrientation(ExifData* exifData)
+{
+  auto transform = JpegTransform::NONE;
+  ExifEntry * const entry = exif_data_get_entry(exifData, EXIF_TAG_ORIENTATION);
+  int orientation = 0;
+  if( entry )
+  {
+    orientation = exif_get_short(entry->data, exif_data_get_byte_order(entry->parent->parent));
+    switch( orientation )
+    {
+      case 1:
+      {
+        transform = JpegTransform::NONE;
+        break;
+      }
+      case 2:
+      {
+        transform = JpegTransform::FLIP_HORIZONTAL;
+        break;
+      }
+      case 3:
+      {
+        transform = JpegTransform::FLIP_VERTICAL;
+        break;
+      }
+      case 4:
+      {
+        transform = JpegTransform::TRANSPOSE;
+        break;
+      }
+      case 5:
+      {
+        transform = JpegTransform::TRANSVERSE;
+        break;
+      }
+      case 6:
+      {
+        transform = JpegTransform::ROTATE_90;
+        break;
+      }
+      case 7:
+      {
+        transform = JpegTransform::ROTATE_180;
+        break;
+      }
+      case 8:
+      {
+        transform = JpegTransform::ROTATE_270;
+        break;
+      }
+      default:
+      {
+        // Try to keep loading the file, but let app developer know there was something fishy:
+        DALI_LOG_WARNING( "Incorrect/Unknown Orientation setting found in EXIF header of JPEG image (%x). Orientation setting will be ignored.\n", entry );
+        break;
+      }
+    }
+  }
+  return transform;
+}
+
+bool TransformSize( int requiredWidth, int requiredHeight,
+                    FittingMode::Type fittingMode, SamplingMode::Type samplingMode,
+                    JpegTransform transform,
+                    int& preXformImageWidth, int& preXformImageHeight,
+                    int& postXformImageWidth, int& postXformImageHeight )
+{
+  bool success = true;
+
+  if( transform == JpegTransform::ROTATE_90 || transform == JpegTransform::ROTATE_270 || transform == JpegTransform::ROTATE_180 || transform == JpegTransform::TRANSVERSE)
+  {
+    std::swap( requiredWidth, requiredHeight );
+    std::swap( postXformImageWidth, postXformImageHeight );
+  }
+
+  // Apply the special rules for when there are one or two zeros in requested dimensions:
+  const ImageDimensions correctedDesired = Internal::Platform::CalculateDesiredDimensions( ImageDimensions( postXformImageWidth, postXformImageHeight), ImageDimensions( requiredWidth, requiredHeight ) );
+  requiredWidth = correctedDesired.GetWidth();
+  requiredHeight = correctedDesired.GetHeight();
+
+  // Rescale image during decode using one of the decoder's built-in rescaling
+  // ratios (expected to be powers of 2), keeping the final image at least as
+  // wide and high as was requested:
+
+  int numFactors = 0;
+  tjscalingfactor* factors = tjGetScalingFactors( &numFactors );
+  if( factors == NULL )
+  {
+    DALI_LOG_WARNING("TurboJpeg tjGetScalingFactors error!\n");
+    success = false;
+  }
+  else
+  {
+    // Internal jpeg downscaling is the same as our BOX_X sampling modes so only
+    // apply it if the application requested one of those:
+    // (use a switch case here so this code will fail to compile if other modes are added)
+    bool downscale = true;
+    switch( samplingMode )
+    {
+      case SamplingMode::BOX:
+      case SamplingMode::BOX_THEN_NEAREST:
+      case SamplingMode::BOX_THEN_LINEAR:
+      case SamplingMode::DONT_CARE:
+      {
+        downscale = true;
+        break;
+      }
+      case SamplingMode::NO_FILTER:
+      case SamplingMode::NEAREST:
+      case SamplingMode::LINEAR:
+      {
+        downscale = false;
+        break;
+      }
+    }
+
+    int scaleFactorIndex( 0 );
+    if( downscale )
+    {
+      // Find nearest supported scaling factor (factors are in sequential order, getting smaller)
+      for( int i = 1; i < numFactors; ++i )
+      {
+        bool widthLessRequired  = TJSCALED( postXformImageWidth,  factors[i]) < requiredWidth;
+        bool heightLessRequired = TJSCALED( postXformImageHeight, factors[i]) < requiredHeight;
+        // If either scaled dimension is smaller than the desired one, we were done at the last iteration
+        if ( (fittingMode == FittingMode::SCALE_TO_FILL) && (widthLessRequired || heightLessRequired) )
+        {
+          break;
+        }
+        // If both dimensions are smaller than the desired one, we were done at the last iteration:
+        if ( (fittingMode == FittingMode::SHRINK_TO_FIT) && ( widthLessRequired && heightLessRequired ) )
+        {
+          break;
+        }
+        // If the width is smaller than the desired one, we were done at the last iteration:
+        if ( fittingMode == FittingMode::FIT_WIDTH && widthLessRequired )
+        {
+          break;
+        }
+        // If the width is smaller than the desired one, we were done at the last iteration:
+        if ( fittingMode == FittingMode::FIT_HEIGHT && heightLessRequired )
+        {
+          break;
+        }
+        // This factor stays is within our fitting mode constraint so remember it:
+        scaleFactorIndex = i;
+      }
+    }
+
+    // Regardless of requested size, downscale to avoid exceeding the maximum texture size:
+    for( int i = scaleFactorIndex; i < numFactors; ++i )
+    {
+      // Continue downscaling to below maximum texture size (if possible)
+      scaleFactorIndex = i;
+
+      if( TJSCALED(postXformImageWidth,  (factors[i])) < static_cast< int >( Dali::GetMaxTextureSize() ) &&
+          TJSCALED(postXformImageHeight, (factors[i])) < static_cast< int >( Dali::GetMaxTextureSize() ) )
+      {
+        // Current scale-factor downscales to below maximum texture size
+        break;
+      }
+    }
+
+    // We have finally chosen the scale-factor, return width/height values
+    if( scaleFactorIndex > 0 )
+    {
+      preXformImageWidth   = TJSCALED(preXformImageWidth,   (factors[scaleFactorIndex]));
+      preXformImageHeight  = TJSCALED(preXformImageHeight,  (factors[scaleFactorIndex]));
+      postXformImageWidth  = TJSCALED(postXformImageWidth,  (factors[scaleFactorIndex]));
+      postXformImageHeight = TJSCALED(postXformImageHeight, (factors[scaleFactorIndex]));
+    }
+  }
+
+  return success;
+}
+
+ExifHandle LoadExifData( FILE* fp )
+{
+  auto exifData = MakeNullExifData();
+  unsigned char dataBuffer[1024];
+
+  if( fseek( fp, 0, SEEK_SET ) )
+  {
+    DALI_LOG_ERROR("Error seeking to start of file\n");
+  }
+  else
+  {
+    auto exifLoader = std::unique_ptr<ExifLoader, decltype(exif_loader_unref)*>{
+        exif_loader_new(), exif_loader_unref };
+
+    while( !feof(fp) )
+    {
+      int size = fread( dataBuffer, 1, sizeof( dataBuffer ), fp );
+      if( size <= 0 )
+      {
+        break;
+      }
+      if( ! exif_loader_write( exifLoader.get(), dataBuffer, size ) )
+      {
+        break;
+      }
+    }
+
+    exifData.reset( exif_loader_get_data( exifLoader.get() ) );
+  }
+
+  return exifData;
+}
+
+bool LoadJpegHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height )
+{
+  unsigned int requiredWidth  = input.scalingParameters.dimensions.GetWidth();
+  unsigned int requiredHeight = input.scalingParameters.dimensions.GetHeight();
+  FILE* const fp = input.file;
+
+  bool success = false;
+  if( requiredWidth == 0 && requiredHeight == 0 )
+  {
+    success = LoadJpegHeader( fp, width, height );
+  }
+  else
+  {
+    // Double check we get the same width/height from the header
+    unsigned int headerWidth;
+    unsigned int headerHeight;
+    if( LoadJpegHeader( fp, headerWidth, headerHeight ) )
+    {
+      auto transform = JpegTransform::NONE;
+
+      if( input.reorientationRequested )
+      {
+        auto exifData = LoadExifData( fp );
+        if( exifData )
+        {
+          transform = ConvertExifOrientation(exifData.get());
+        }
+
+        int preXformImageWidth = headerWidth;
+        int preXformImageHeight = headerHeight;
+        int postXformImageWidth = headerWidth;
+        int postXformImageHeight = headerHeight;
+
+        success = TransformSize( requiredWidth, requiredHeight, input.scalingParameters.scalingMode, input.scalingParameters.samplingMode, transform, preXformImageWidth, preXformImageHeight, postXformImageWidth, postXformImageHeight );
+        if(success)
+        {
+          width = postXformImageWidth;
+          height = postXformImageHeight;
+        }
+      }
+      else
+      {
+        success = true;
+        width = headerWidth;
+        height = headerHeight;
+      }
+    }
+  }
+  return success;
+}
+
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/dali/internal/imaging/common/loader-jpeg.h b/dali/internal/imaging/common/loader-jpeg.h
new file mode 100755 (executable)
index 0000000..29ec9dc
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef DALI_TIZEN_PLATFORM_LOADER_JPEG_H
+#define DALI_TIZEN_PLATFORM_LOADER_JPEG_H
+
+/*
+ * Copyright (c) 2019 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 <stdio.h>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/images/pixel.h>
+#include <dali/internal/legacy/tizen/image-encoder.h>
+#include <dali/devel-api/adaptor-framework/image-loader-input.h>
+
+namespace Dali
+{
+namespace Devel
+{
+class PixelBuffer;
+}
+
+
+namespace TizenPlatform
+{
+
+class ResourceLoadingClient;
+
+namespace Jpeg
+{
+const unsigned char MAGIC_BYTE_1 = 0xFF;
+const unsigned char MAGIC_BYTE_2 = 0xD8;
+} // namespace Jpeg
+
+/**
+ * Loads the bitmap from an JPEG file.  This function checks the header first
+ * and if it is not a JPEG file, then it returns straight away.
+ * @param[in]  input  Information about the input image (including file pointer)
+ * @param[out] bitmap The bitmap class where the decoded image will be stored
+ * @return  true if file decoded successfully, false otherwise
+ */
+bool LoadBitmapFromJpeg( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap );
+
+/**
+ * Loads the header of a JPEG file and fills in the width and height appropriately.
+ * If the width and height are set on entry, it will set the width and height
+ * to the closest scaled size (exactly as will be loaded by LoadBitmapFromJpeg with the same
+ * attributes)
+ * @param[in]   fp      Pointer to the Image file
+ * @param[in]  attributes  Describes the dimensions, pixel format and other details for loading the image data
+ * @param[in/out]  width   Is set with the width of the image
+ * @param[in/out]  height  Is set with the height of the image
+ * @return true if the file's header was read successully, false otherwise
+ */
+bool LoadJpegHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+/**
+ * Encode raw pixel data to JPEG format.
+ * @param[in]  pixelBuffer    Pointer to raw pixel data to be encoded
+ * @param[out] encodedPixels  Encoded pixel data. Existing contents will be overwritten
+ * @param[in]  width          Image width
+ * @param[in]  height         Image height
+ * @param[in]  pixelFormat    Input pixel format (must be Pixel::RGB888)
+ * @param[in]  quality        JPEG quality on usual 1 to 100 scale.
+ */
+bool EncodeToJpeg(const unsigned char* pixelBuffer, Vector< unsigned char >& encodedPixels, std::size_t width, std::size_t height, Pixel::Format pixelFormat, unsigned quality = 80);
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // DALI_TIZEN_PLATFORM_LOADER_JPEG_H
diff --git a/dali/internal/imaging/common/loader-ktx.cpp b/dali/internal/imaging/common/loader-ktx.cpp
new file mode 100755 (executable)
index 0000000..e431239
--- /dev/null
@@ -0,0 +1,620 @@
+/*
+ * 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 <dali/internal/imaging/common/loader-ktx.h>
+
+// EXTERNAL INCLUDES
+#include <cstring>
+#include <dali/public-api/common/compile-time-assert.h>
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/internal/imaging/common/pixel-buffer-impl.h>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace
+{
+
+/** Max width or height of an image. */
+const unsigned MAX_TEXTURE_DIMENSION = 4096;
+/** Max bytes of image data allowed. Not a precise number, just a sanity check. */
+const unsigned MAX_IMAGE_DATA_SIZE = MAX_TEXTURE_DIMENSION * MAX_TEXTURE_DIMENSION;
+/** We don't read any of this but limit it to a resonable amount in order to be
+ * friendly to files from random tools. */
+const unsigned MAX_BYTES_OF_KEYVALUE_DATA = 65536U;
+
+typedef uint8_t Byte;
+
+const Byte FileIdentifier[] = {
+   0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
+};
+
+
+/** The formats we support inside a KTX file container.
+ *  Currently only compressed formats are allowed as we'd rather
+ *  use a PNG or JPEG with their own compression for the general
+ *  cases. */
+enum KtxInternalFormat
+{
+  KTX_NOTEXIST = 0,
+
+  // GLES 2 Extension formats:
+  KTX_ETC1_RGB8_OES                               = 0x8D64,
+  KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG             = 0x8C00,
+
+  // GLES 3 Standard compressed formats (values same as in gl3.h):
+  KTX_COMPRESSED_R11_EAC                          = 0x9270,
+  KTX_COMPRESSED_SIGNED_R11_EAC                   = 0x9271,
+  KTX_COMPRESSED_RG11_EAC                         = 0x9272,
+  KTX_COMPRESSED_SIGNED_RG11_EAC                  = 0x9273,
+  KTX_COMPRESSED_RGB8_ETC2                        = 0x9274,
+  KTX_COMPRESSED_SRGB8_ETC2                       = 0x9275,
+  KTX_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2    = 0x9276,
+  KTX_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2   = 0x9277,
+  KTX_COMPRESSED_RGBA8_ETC2_EAC                   = 0x9278,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC            = 0x9279,
+
+  // GLES 3.1 compressed formats:
+  KTX_COMPRESSED_RGBA_ASTC_4x4_KHR                = 0x93B0,
+  KTX_COMPRESSED_RGBA_ASTC_5x4_KHR                = 0x93B1,
+  KTX_COMPRESSED_RGBA_ASTC_5x5_KHR                = 0x93B2,
+  KTX_COMPRESSED_RGBA_ASTC_6x5_KHR                = 0x93B3,
+  KTX_COMPRESSED_RGBA_ASTC_6x6_KHR                = 0x93B4,
+  KTX_COMPRESSED_RGBA_ASTC_8x5_KHR                = 0x93B5,
+  KTX_COMPRESSED_RGBA_ASTC_8x6_KHR                = 0x93B6,
+  KTX_COMPRESSED_RGBA_ASTC_8x8_KHR                = 0x93B7,
+  KTX_COMPRESSED_RGBA_ASTC_10x5_KHR               = 0x93B8,
+  KTX_COMPRESSED_RGBA_ASTC_10x6_KHR               = 0x93B9,
+  KTX_COMPRESSED_RGBA_ASTC_10x8_KHR               = 0x93BA,
+  KTX_COMPRESSED_RGBA_ASTC_10x10_KHR              = 0x93BB,
+  KTX_COMPRESSED_RGBA_ASTC_12x10_KHR              = 0x93BC,
+  KTX_COMPRESSED_RGBA_ASTC_12x12_KHR              = 0x93BD,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR        = 0x93D0,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR        = 0x93D1,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR        = 0x93D2,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR        = 0x93D3,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR        = 0x93D4,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR        = 0x93D5,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR        = 0x93D6,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR        = 0x93D7,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR       = 0x93D8,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR       = 0x93D9,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR       = 0x93DA,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR      = 0x93DB,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR      = 0x93DC,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR      = 0x93DD,
+
+  // Uncompressed Alpha format
+  KTX_UNCOMPRESSED_ALPHA8                         = 0x1906,
+
+  KTX_SENTINEL = ~0u
+};
+
+const unsigned KtxInternalFormats[] =
+{
+  // GLES 2 Extension formats:
+  KTX_ETC1_RGB8_OES,
+  KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG,
+
+  // GLES 3 Standard compressed formats:
+  KTX_COMPRESSED_R11_EAC,
+  KTX_COMPRESSED_SIGNED_R11_EAC,
+  KTX_COMPRESSED_RG11_EAC,
+  KTX_COMPRESSED_SIGNED_RG11_EAC,
+  KTX_COMPRESSED_RGB8_ETC2,
+  KTX_COMPRESSED_SRGB8_ETC2,
+  KTX_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
+  KTX_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
+  KTX_COMPRESSED_RGBA8_ETC2_EAC,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,
+
+  // GLES 3.1 Compressed formats:
+  KTX_COMPRESSED_RGBA_ASTC_4x4_KHR,
+  KTX_COMPRESSED_RGBA_ASTC_5x4_KHR,
+  KTX_COMPRESSED_RGBA_ASTC_5x5_KHR,
+  KTX_COMPRESSED_RGBA_ASTC_6x5_KHR,
+  KTX_COMPRESSED_RGBA_ASTC_6x6_KHR,
+  KTX_COMPRESSED_RGBA_ASTC_8x5_KHR,
+  KTX_COMPRESSED_RGBA_ASTC_8x6_KHR,
+  KTX_COMPRESSED_RGBA_ASTC_8x8_KHR,
+  KTX_COMPRESSED_RGBA_ASTC_10x5_KHR,
+  KTX_COMPRESSED_RGBA_ASTC_10x6_KHR,
+  KTX_COMPRESSED_RGBA_ASTC_10x8_KHR,
+  KTX_COMPRESSED_RGBA_ASTC_10x10_KHR,
+  KTX_COMPRESSED_RGBA_ASTC_12x10_KHR,
+  KTX_COMPRESSED_RGBA_ASTC_12x12_KHR,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR,
+  KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR,
+
+  // Uncompressed Alpha format
+  KTX_UNCOMPRESSED_ALPHA8,
+
+  KTX_SENTINEL
+};
+
+struct KtxFileHeader
+{
+  Byte   identifier[12];
+  uint32_t endianness;
+  uint32_t glType;
+  uint32_t glTypeSize;
+  uint32_t glFormat;
+  uint32_t glInternalFormat;
+  uint32_t glBaseInternalFormat;
+  uint32_t pixelWidth;
+  uint32_t pixelHeight;
+  uint32_t pixelDepth;
+  uint32_t numberOfArrayElements;
+  uint32_t numberOfFaces;
+  uint32_t numberOfMipmapLevels;
+  uint32_t bytesOfKeyValueData;
+} __attribute__ ( (__packed__));
+// Packed attribute stops the structure from being aligned to compiler defaults
+// so we can be sure of reading the whole thing from file in one call to fread.
+
+/**
+ * Function to read from the file directly into our structure.
+ * @param[in]  fp     The file to read from
+ * @param[out] header The structure we want to store our information in
+ * @return true, if read successful, false otherwise
+ */
+inline bool ReadHeader( FILE* filePointer, KtxFileHeader& header )
+{
+  const unsigned int readLength = sizeof( KtxFileHeader );
+
+  // Load the information directly into our structure
+  if( fread( &header, 1, readLength, filePointer ) != readLength )
+  {
+    return false;
+  }
+
+  return true;
+}
+
+/** Check whether the array passed in is the right size and matches the magic
+ *  values defined to be at the start of a KTX file by the specification.*/
+template<int BYTES_IN_SIGNATURE>
+bool CheckFileIdentifier(const Byte * const signature)
+{
+  const unsigned signatureSize = BYTES_IN_SIGNATURE;
+  const unsigned identifierSize = sizeof(FileIdentifier);
+  DALI_COMPILE_TIME_ASSERT(signatureSize == identifierSize);
+  const bool signatureGood = 0 == memcmp( signature, FileIdentifier, std::min( signatureSize, identifierSize ) );
+  return signatureGood;
+}
+
+/**
+ * @returns True if the argument is a GLES compressed texture format that we support.
+ */
+bool ValidInternalFormat(const unsigned format)
+{
+  unsigned candidateFormat = 0;
+  for(unsigned iFormat = 0; (candidateFormat = KtxInternalFormats[iFormat]) != KTX_SENTINEL; ++iFormat)
+  {
+    if(format == candidateFormat)
+    {
+      return true;
+    }
+  }
+  DALI_LOG_ERROR("Rejecting unsupported compressed format when loading compressed texture from KTX file: 0x%x.\n", format);
+  return false;
+}
+
+/**
+ * @returns The Pixel::Format Dali enum corresponding to the KTX internal format
+ *          passed in, or Pixel::INVALID_PIXEL_FORMAT if the format is not valid.
+ **/
+bool ConvertPixelFormat(const uint32_t ktxPixelFormat, Dali::Pixel::Format& format)
+{
+  using namespace Dali::Pixel;
+  switch(ktxPixelFormat)
+  {
+    // GLES 2 extension compressed formats:
+    case KTX_ETC1_RGB8_OES:
+    {
+      format = COMPRESSED_RGB8_ETC1;
+      break;
+    }
+    case KTX_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
+    {
+      format = COMPRESSED_RGB_PVRTC_4BPPV1;
+      break;
+    }
+
+    // GLES 3 extension compressed formats:
+    case KTX_COMPRESSED_R11_EAC:
+    {
+      format = COMPRESSED_R11_EAC;
+      break;
+    }
+    case KTX_COMPRESSED_SIGNED_R11_EAC:
+    {
+      format = COMPRESSED_SIGNED_R11_EAC;
+      break;
+    }
+    case KTX_COMPRESSED_RG11_EAC:
+    {
+      format = COMPRESSED_RG11_EAC;
+      break;
+    }
+    case KTX_COMPRESSED_SIGNED_RG11_EAC:
+    {
+      format = COMPRESSED_SIGNED_RG11_EAC;
+      break;
+    }
+    case KTX_COMPRESSED_RGB8_ETC2:
+    {
+      format = COMPRESSED_RGB8_ETC2;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ETC2:
+    {
+      format = COMPRESSED_SRGB8_ETC2;
+      break;
+    }
+    case KTX_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+    {
+      format = COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
+    {
+      format = COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2;
+      break;
+    }
+    case KTX_COMPRESSED_RGBA8_ETC2_EAC:
+    {
+      format = COMPRESSED_RGBA8_ETC2_EAC;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
+    {
+      format = COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;
+      break;
+    }
+
+    // GLES 3.1 extension compressed formats:
+    case KTX_COMPRESSED_RGBA_ASTC_4x4_KHR:
+    {
+      format = COMPRESSED_RGBA_ASTC_4x4_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_RGBA_ASTC_5x4_KHR:
+    {
+      format = COMPRESSED_RGBA_ASTC_5x4_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_RGBA_ASTC_5x5_KHR:
+    {
+      format = COMPRESSED_RGBA_ASTC_5x5_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_RGBA_ASTC_6x5_KHR:
+    {
+      format = COMPRESSED_RGBA_ASTC_6x5_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_RGBA_ASTC_6x6_KHR:
+    {
+      format = COMPRESSED_RGBA_ASTC_6x6_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_RGBA_ASTC_8x5_KHR:
+    {
+      format = COMPRESSED_RGBA_ASTC_8x5_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_RGBA_ASTC_8x6_KHR:
+    {
+      format = COMPRESSED_RGBA_ASTC_8x6_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_RGBA_ASTC_8x8_KHR:
+    {
+      format = COMPRESSED_RGBA_ASTC_8x8_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_RGBA_ASTC_10x5_KHR:
+    {
+      format = COMPRESSED_RGBA_ASTC_10x5_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_RGBA_ASTC_10x6_KHR:
+    {
+      format = COMPRESSED_RGBA_ASTC_10x6_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_RGBA_ASTC_10x8_KHR:
+    {
+      format = COMPRESSED_RGBA_ASTC_10x8_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_RGBA_ASTC_10x10_KHR:
+    {
+      format = COMPRESSED_RGBA_ASTC_10x10_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_RGBA_ASTC_12x10_KHR:
+    {
+      format = COMPRESSED_RGBA_ASTC_12x10_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_RGBA_ASTC_12x12_KHR:
+    {
+      format = COMPRESSED_RGBA_ASTC_12x12_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
+    {
+      format = COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
+    {
+      format = COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
+    {
+      format = COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
+    {
+      format = COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
+    {
+      format = COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
+    {
+      format = COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
+    {
+      format = COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
+    {
+      format = COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
+    {
+      format = COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
+    {
+      format = COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
+    {
+      format = COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
+    {
+      format = COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
+    {
+      format = COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR;
+      break;
+    }
+    case KTX_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
+    {
+      format = COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR;
+      break;
+    }
+
+    // Uncompressed Alpha format
+    case KTX_UNCOMPRESSED_ALPHA8:
+    {
+      format = A8;
+      break;
+    }
+
+    default:
+    {
+       return false;
+    }
+  }
+  return true;
+}
+
+bool LoadKtxHeader( FILE * const fp, unsigned int& width, unsigned int& height, KtxFileHeader& fileHeader )
+{
+  // Pull the bytes of the file header in as a block:
+  if ( !ReadHeader( fp, fileHeader ) )
+  {
+    return false;
+  }
+  width = fileHeader.pixelWidth;
+  height = fileHeader.pixelHeight;
+
+  if ( width > MAX_TEXTURE_DIMENSION || height > MAX_TEXTURE_DIMENSION )
+  {
+    return false;
+  }
+
+  // Validate file header contents meet our minimal subset:
+  const bool signatureGood                            = CheckFileIdentifier<sizeof(fileHeader.identifier)>(fileHeader.identifier);
+  const bool fileEndiannessMatchesSystemEndianness    = fileHeader.endianness == 0x04030201; // Magic number from KTX spec.
+  const bool glTypeIsCompressed                       = fileHeader.glType == 0;
+  const bool glTypeSizeCompatibleWithCompressedTex    = fileHeader.glTypeSize == 1;
+  const bool glFormatCompatibleWithCompressedTex      = fileHeader.glFormat == 0;
+  const bool glInternalFormatIsSupportedCompressedTex = ValidInternalFormat(fileHeader.glInternalFormat);
+  // Ignore glBaseInternalFormat
+  const bool textureIsNot3D                           = fileHeader.pixelDepth == 0 || fileHeader.pixelDepth == 1;
+  const bool textureIsNotAnArray                      = fileHeader.numberOfArrayElements == 0 || fileHeader.numberOfArrayElements == 1;
+  const bool textureIsNotACubemap                     = fileHeader.numberOfFaces == 0 || fileHeader.numberOfFaces == 1;
+  const bool textureHasNoMipmapLevels                 = fileHeader.numberOfMipmapLevels == 0 || fileHeader.numberOfMipmapLevels == 1;
+  const bool keyValueDataNotTooLarge                  = fileHeader.bytesOfKeyValueData <= MAX_BYTES_OF_KEYVALUE_DATA;
+
+  bool headerIsValid = signatureGood && fileEndiannessMatchesSystemEndianness &&
+                     glTypeSizeCompatibleWithCompressedTex && textureIsNot3D && textureIsNotAnArray &&
+                     textureIsNotACubemap && textureHasNoMipmapLevels && keyValueDataNotTooLarge;
+
+  if( !glTypeIsCompressed )  // check for uncompressed Alpha
+  {
+    const bool isAlpha = ( ( fileHeader.glBaseInternalFormat == KTX_UNCOMPRESSED_ALPHA8 ) && ( fileHeader.glFormat == KTX_UNCOMPRESSED_ALPHA8 ) &&
+                         ( fileHeader.glInternalFormat == KTX_UNCOMPRESSED_ALPHA8 ) );
+    headerIsValid = headerIsValid && isAlpha;
+  }
+  else
+  {
+    headerIsValid = headerIsValid && glFormatCompatibleWithCompressedTex && glInternalFormatIsSupportedCompressedTex;
+  }
+
+  if( !headerIsValid )
+  {
+     DALI_LOG_ERROR( "KTX file invalid or using unsupported features. Header tests: sig: %d, endian: %d, gl_type: %d, gl_type_size: %d, gl_format: %d, internal_format: %d, depth: %d, array: %d, faces: %d, mipmap: %d, vey-vals: %d.\n", 0+signatureGood, 0+fileEndiannessMatchesSystemEndianness, 0+glTypeIsCompressed, 0+glTypeSizeCompatibleWithCompressedTex, 0+glFormatCompatibleWithCompressedTex, 0+glInternalFormatIsSupportedCompressedTex, 0+textureIsNot3D, 0+textureIsNotAnArray, 0+textureIsNotACubemap, 0+textureHasNoMipmapLevels, 0+keyValueDataNotTooLarge);
+  }
+
+  // Warn if there is space wasted in the file:
+  if( fileHeader.bytesOfKeyValueData > 0U )
+  {
+    DALI_LOG_WARNING("Loading of KTX file with key/value header data requested. This should be stripped in application asset/resource build.\n");
+  }
+
+  return headerIsValid;
+}
+
+
+} // unnamed namespace
+
+// File loading API entry-point:
+bool LoadKtxHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height )
+{
+  KtxFileHeader fileHeader;
+  FILE* const fp = input.file;
+
+  bool ret = LoadKtxHeader(fp, width, height, fileHeader);
+  return ret;
+}
+
+// File loading API entry-point:
+bool LoadBitmapFromKtx( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap )
+{
+  DALI_COMPILE_TIME_ASSERT( sizeof(Byte) == 1);
+  DALI_COMPILE_TIME_ASSERT( sizeof(uint32_t) == 4);
+
+  FILE* const fp = input.file;
+  if( fp == NULL )
+  {
+    DALI_LOG_ERROR( "Null file handle passed to KTX compressed bitmap file loader.\n" );
+    return false;
+  }
+  KtxFileHeader fileHeader;
+
+  // Load the header info
+  unsigned int width, height;
+
+  if (!LoadKtxHeader(fp, width, height, fileHeader))
+  {
+      return false;
+  }
+
+  // Skip the key-values:
+  const long int imageSizeOffset = sizeof(KtxFileHeader) + fileHeader.bytesOfKeyValueData;
+  if(fseek(fp, imageSizeOffset, SEEK_SET))
+  {
+    DALI_LOG_ERROR( "Seek past key/vals in KTX compressed bitmap file failed.\n" );
+    return false;
+  }
+
+  // Load the size of the image data:
+  uint32_t imageByteCount = 0;
+  if ( fread( &imageByteCount, 1, 4, fp ) != 4 )
+  {
+    DALI_LOG_ERROR( "Read of image size failed.\n" );
+    return false;
+  }
+  // Sanity-check the image size:
+  if( imageByteCount > MAX_IMAGE_DATA_SIZE ||
+      // A compressed texture should certainly be less than 2 bytes per texel:
+      imageByteCount > width * height * 2)
+  {
+    DALI_LOG_ERROR( "KTX file with too-large image-data field.\n" );
+    return false;
+  }
+
+  Pixel::Format pixelFormat;
+  const bool pixelFormatKnown = ConvertPixelFormat(fileHeader.glInternalFormat, pixelFormat);
+  if(!pixelFormatKnown)
+  {
+    DALI_LOG_ERROR( "No internal pixel format supported for KTX file pixel format.\n" );
+    return false;
+  }
+
+  // Load up the image bytes:
+  bitmap = Dali::Devel::PixelBuffer::New(width, height, pixelFormat);
+
+  // Compressed format won't allocate the buffer
+  auto pixels = bitmap.GetBuffer();
+  if( !pixels )
+  {
+    // allocate buffer manually
+    auto &impl = GetImplementation(bitmap);
+    impl.AllocateFixedSize(imageByteCount);
+    pixels = bitmap.GetBuffer();
+  }
+
+  if(!pixels)
+  {
+    DALI_LOG_ERROR( "Unable to reserve a pixel buffer to load the requested bitmap into.\n" );
+    return false;
+  }
+
+  const size_t bytesRead = fread(pixels, 1, imageByteCount, fp);
+  if(bytesRead != imageByteCount)
+  {
+    DALI_LOG_ERROR( "Read of image pixel data failed.\n" );
+    return false;
+  }
+
+  return true;
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/dali/internal/imaging/common/loader-ktx.h b/dali/internal/imaging/common/loader-ktx.h
new file mode 100755 (executable)
index 0000000..6853da0
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef DALI_TIZEN_PLATFORM_LOADER_KTX_H
+#define DALI_TIZEN_PLATFORM_LOADER_KTX_H
+
+/*
+ * Copyright (c) 2019 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 <cstdio>
+#include <dali/devel-api/adaptor-framework/image-loader-input.h>
+
+namespace Dali
+{
+namespace Devel
+{
+class PixelBuffer;
+}
+
+namespace TizenPlatform
+{
+
+class ResourceLoadingClient;
+
+namespace Ktx
+{
+const unsigned char MAGIC_BYTE_1 = 0xAB;
+const unsigned char MAGIC_BYTE_2 = 0x4B;
+} // namespace Ktx
+
+/**
+ * Loads a compressed bitmap from a KTX file without decoding it.
+ * This function checks the header first
+ * and if it is not a KTX file, then it returns straight away.
+ * @param[in]  input  Information about the input image (including file pointer)
+ * @param[out] bitmap The bitmap class where the decoded image will be stored
+ * @return  true if file loaded successfully, false otherwise
+ */
+bool LoadBitmapFromKtx( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap );
+
+/**
+ * Loads the header of a KTX file and fills in the width and height appropriately.
+ * @param[in]   fp      Pointer to the Image file
+ * @param[in]  attributes  Describes the dimensions, pixel format and other details for loading the image data
+ * @param[out]  width   Is set with the width of the image
+ * @param[out]  height  Is set with the height of the image
+ * @return true if the file's header was read successully, false otherwise
+ */
+bool LoadKtxHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // DALI_TIZEN_PLATFORM_LOADER_KTX_H
diff --git a/dali/internal/imaging/common/loader-png.cpp b/dali/internal/imaging/common/loader-png.cpp
new file mode 100755 (executable)
index 0000000..4b51af3
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ * 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/internal/imaging/common/loader-png.h>
+
+#include <cstring>
+
+#include <zlib.h>
+#include <png.h>
+
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/images/image.h>
+#include <dali/internal/legacy/tizen/platform-capabilities.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+
+namespace Dali
+{
+namespace TizenPlatform
+{
+
+namespace
+{
+
+// simple class to enforce clean-up of PNG structures
+struct auto_png
+{
+  auto_png(png_structp& _png, png_infop& _info)
+  : png(_png),
+    info(_info)
+  {
+  }
+
+  ~auto_png()
+  {
+    if(NULL != png)
+    {
+      png_destroy_read_struct(&png, &info, NULL);
+    }
+  }
+
+  png_structp& png;
+  png_infop& info;
+}; // struct auto_png;
+
+bool LoadPngHeader(FILE *fp, unsigned int &width, unsigned int &height, png_structp &png, png_infop &info)
+{
+  png_byte header[8] = { 0 };
+
+  // Check header to see if it is a PNG file
+  size_t size = fread(header, 1, 8, fp);
+  if(size != 8)
+  {
+    return false;
+  }
+
+  if(png_sig_cmp(header, 0, 8))
+  {
+    return false;
+  }
+
+  png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+
+  if(!png)
+  {
+    DALI_LOG_WARNING("Can't create PNG read structure\n");
+    return false;
+  }
+
+  info = png_create_info_struct(png);
+  if(!info)
+  {
+    DALI_LOG_WARNING("png_create_info_struct failed\n");
+    return false;
+  }
+
+  png_set_expand(png);
+
+  if(setjmp(png_jmpbuf(png)))
+  {
+    DALI_LOG_WARNING("error during png_init_io\n");
+    return false;
+  }
+
+  png_init_io(png, fp);
+  png_set_sig_bytes(png, 8);
+
+  // read image info
+  png_read_info(png, info);
+
+  // dimensions
+  width = png_get_image_width(png, info);
+  height = png_get_image_height(png, info);
+
+  return true;
+}
+
+} // namespace - anonymous
+
+bool LoadPngHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height )
+{
+  png_structp png = NULL;
+  png_infop info = NULL;
+  auto_png autoPng(png, info);
+
+  bool success = LoadPngHeader( input.file, width, height, png, info );
+
+  return success;
+}
+
+bool LoadBitmapFromPng( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap )
+{
+  png_structp png = NULL;
+  png_infop info = NULL;
+  auto_png autoPng(png, info);
+
+  /// @todo: consider parameters
+  unsigned int y;
+  unsigned int width, height;
+  png_bytep *rows;
+  unsigned int bpp = 0; // bytes per pixel
+  bool valid = false;
+
+  // Load info from the header
+  if( !LoadPngHeader( input.file, width, height, png, info ) )
+  {
+    return false;
+  }
+
+  Pixel::Format pixelFormat = Pixel::RGBA8888;
+
+  // decide pixel format
+  unsigned int colordepth = png_get_bit_depth(png, info);
+
+  // Ask PNGLib to convert high precision images into something we can use:
+  if (colordepth == 16)
+  {
+    png_set_strip_16(png);
+    colordepth = 8;
+  }
+
+  png_byte colortype = png_get_color_type(png, info);
+
+  if( colortype == PNG_COLOR_TYPE_GRAY ||
+      colortype == PNG_COLOR_TYPE_GRAY_ALPHA )
+  {
+    if( colortype == PNG_COLOR_TYPE_GRAY )
+    {
+      pixelFormat = Pixel::L8;
+      if( png_get_valid(png, info, PNG_INFO_tRNS) )
+      {
+        colortype = PNG_COLOR_TYPE_GRAY_ALPHA;
+        /* expand transparency entry -> alpha channel if present */
+        png_set_tRNS_to_alpha(png);
+        pixelFormat = Pixel::LA88;
+      }
+    }
+    else
+    {
+      pixelFormat = Pixel::LA88;
+    }
+
+    if( colordepth < 8 )
+    {
+      /* expand gray (w/reduced bits) -> 8-bit RGB if necessary */
+      png_set_expand_gray_1_2_4_to_8(png);
+      /* pack all pixels to byte boundaries */
+      png_set_packing(png);
+    }
+    valid = true;
+  }
+  else if(colortype == PNG_COLOR_TYPE_RGB )
+  {
+    switch(colordepth)
+    {
+      case 8:
+      {
+        pixelFormat = Pixel::RGB888;
+        valid = true;
+        break;
+      }
+      case 5:      /// @todo is this correct for RGB16 5-6-5 ?
+      {
+        pixelFormat = Pixel::RGB565;
+        valid = true;
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+  else if(colortype == PNG_COLOR_TYPE_RGBA)
+  {
+    switch(colordepth)
+    {
+      case 8:
+      {
+        pixelFormat = Pixel::RGBA8888;
+        valid = true;
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+  else if(colortype == PNG_COLOR_TYPE_PALETTE)
+  {
+    switch(colordepth)
+    {
+      case 1:
+      {
+        pixelFormat = Pixel::LA88;
+        valid = true;
+        break;
+      }
+
+      case 2:
+      case 4:
+      case 8:
+      {
+        /* Expand paletted or RGB images with transparency to full alpha channels
+         * so the data will be available as RGBA quartets. PNG_INFO_tRNS = 0x10
+         */
+        if(png_get_valid(png, info, PNG_INFO_tRNS) == 0x10)
+        {
+          pixelFormat = Pixel::RGBA8888;
+          valid = true;
+        }
+        else
+        {
+          pixelFormat = Pixel::RGB888;
+          png_set_packing(png);
+          png_set_packswap(png);
+          png_set_palette_to_rgb(png);
+          valid = true;
+        }
+        break;
+      }
+      default:
+      {
+        break;
+      }
+    }
+  }
+
+  if( !valid )
+  {
+    DALI_LOG_WARNING( "Unsupported png format\n" );
+    return false;
+  }
+
+  // bytes per pixel
+  bpp = Pixel::GetBytesPerPixel(pixelFormat);
+
+  png_read_update_info(png, info);
+
+  if(setjmp(png_jmpbuf(png)))
+  {
+    DALI_LOG_WARNING("error during png_read_image\n");
+    return false;
+  }
+
+  unsigned int rowBytes = png_get_rowbytes(png, info);
+
+  unsigned int bufferWidth   = GetTextureDimension(width);
+  unsigned int bufferHeight  = GetTextureDimension(height);
+  unsigned int stride        = bufferWidth*bpp;
+
+  // not sure if this ever happens
+  if( rowBytes > stride )
+  {
+    stride = GetTextureDimension(rowBytes);
+
+    bpp = stride / bufferWidth;
+    switch(bpp)
+    {
+      case 3:
+        pixelFormat = Pixel::RGB888;
+        break;
+      case 4:
+        pixelFormat = Pixel::RGBA8888;
+        break;
+      default:
+        break;
+    }
+
+  }
+
+  // decode the whole image into bitmap buffer
+  auto pixels = (bitmap = Dali::Devel::PixelBuffer::New(bufferWidth, bufferHeight, pixelFormat)).GetBuffer();
+
+  DALI_ASSERT_DEBUG(pixels);
+  rows = reinterpret_cast< png_bytep* >( malloc(sizeof(png_bytep) * height) );
+  for(y=0; y<height; y++)
+  {
+    rows[y] = pixels + y * stride;
+  }
+
+  // decode image
+  png_read_image(png, rows);
+
+  free(rows);
+
+  return true;
+}
+
+// simple class to enforce clean-up of PNG structures
+struct AutoPngWrite
+{
+  AutoPngWrite(png_structp& _png, png_infop& _info)
+  : png(_png),
+    info(_info)
+  {
+  }
+
+  ~AutoPngWrite()
+  {
+    if(NULL != png)
+    {
+      png_destroy_write_struct(&png, &info);
+    }
+  }
+
+  png_structp& png;
+  png_infop& info;
+}; // struct AutoPngWrite;
+
+namespace
+{
+  // Custom libpng write callbacks that buffer to a vector instead of a file:
+
+  /**
+   * extern "C" linkage is used because this is a callback that we pass to a C
+   * library which is part of the underlying platform and so potentially compiled
+   * as C rather than C++.
+   * @see http://stackoverflow.com/a/2594222
+   * */
+  extern "C" void WriteData(png_structp png_ptr, png_bytep data, png_size_t length)
+  {
+    DALI_ASSERT_DEBUG(png_ptr && data);
+    if(!png_ptr || !data)
+    {
+      return;
+    }
+    // Make sure we don't try to propagate a C++ exception up the call stack of a pure C library:
+    try
+    {
+      // Recover our buffer for writing into:
+      Vector<unsigned char>* const encoded_img = static_cast< Vector<unsigned char>* >( png_get_io_ptr(png_ptr) );
+      if(encoded_img)
+      {
+        const Vector<unsigned char>::SizeType bufferSize = encoded_img->Count();
+        encoded_img->Resize( bufferSize + length ); //< Can throw OOM.
+        unsigned char* const bufferBack = encoded_img->Begin() + bufferSize;
+        memcpy(bufferBack, data, length);
+      }
+      else
+      {
+        DALI_LOG_ERROR("PNG buffer for write to memory was passed from libpng as null.\n");
+      }
+    }
+    catch(...)
+    {
+      DALI_LOG_ERROR("C++ Exception caught\n");
+    }
+  }
+
+  /** Override the flush with a NOP to prevent libpng trying cstdlib file io. */
+  extern "C" void FlushData(png_structp png_ptr)
+  {
+#ifdef DEBUG_ENABLED
+    Debug::LogMessage(Debug::DebugInfo, "PNG Flush");
+#endif // DEBUG_ENABLED
+  }
+}
+
+/**
+ * Potential improvements:
+ * 1. Detect <= 256 colours and write in palette mode.
+ * 2. Detect grayscale (will early-out quickly for colour images).
+ * 3. Store colour space / gamma correction info related to the device screen?
+ *    http://www.libpng.org/pub/png/book/chapter10.html
+ * 4. Refactor with callers to write straight through to disk and save keeping a big buffer around.
+ * 5. Prealloc buffer (reserve) to input size / <A number greater than 2 (expexcted few realloc but without using lots of memory) | 1 (expected zero reallocs but using a lot of memory)>.
+ * 6. Set the modification time with png_set_tIME(png_ptr, info_ptr, mod_time);
+ * 7. If caller asks for no compression, bypass libpng and blat raw data to
+ *    disk, topped and tailed with header/tail blocks.
+ */
+bool EncodeToPng( const unsigned char* const pixelBuffer, Vector<unsigned char>& encodedPixels, std::size_t width, std::size_t height, Pixel::Format pixelFormat )
+{
+  // Translate pixel format enum:
+  int pngPixelFormat = -1;
+  unsigned pixelBytes = 0;
+  bool rgbaOrder = true;
+
+  // Account for RGB versus BGR and presence of alpha in input pixels:
+  switch( pixelFormat )
+  {
+    case Pixel::RGB888:
+    {
+      pngPixelFormat = PNG_COLOR_TYPE_RGB;
+      pixelBytes = 3;
+      break;
+    }
+    case Pixel::BGRA8888:
+    {
+      rgbaOrder = false;
+      ///! No break: fall through:
+    }
+    case Pixel::RGBA8888:
+    {
+      pngPixelFormat = PNG_COLOR_TYPE_RGB_ALPHA;
+      pixelBytes = 4;
+      break;
+    }
+    default:
+    {
+      DALI_LOG_ERROR( "Unsupported pixel format for encoding to PNG.\n" );
+      return false;
+    }
+  }
+
+  const int interlace = PNG_INTERLACE_NONE;
+
+  png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+  if(!png_ptr)
+  {
+    return false;
+  }
+  /* Allocate/initialize the image information data.  REQUIRED */
+  png_infop info_ptr = png_create_info_struct( png_ptr );
+  if(!info_ptr)
+  {
+    png_destroy_write_struct(&png_ptr, NULL);
+    return false;
+  }
+
+  /* Set error handling.  REQUIRED if you aren't supplying your own
+   * error handling functions in the png_create_write_struct() call.
+   */
+  if(setjmp(png_jmpbuf(png_ptr)))
+  {
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+    return false;
+  }
+
+  // Since we are going to write to memory instead of a file, lets provide
+  // libpng with a custom write function and ask it to pass back our
+  // Vector buffer each time it calls back to flush data to "file":
+  png_set_write_fn(png_ptr, &encodedPixels, WriteData, FlushData);
+
+  // png_set_compression_level( png_ptr, Z_BEST_COMPRESSION);
+  png_set_compression_level(png_ptr, Z_BEST_SPEED);
+  // png_set_compression_level( png_ptr, Z_NO_COMPRESSION); //! We could just generate png directly without libpng in this case.
+
+  // Explicitly limit the number of filters used per scanline to speed us up:
+  // png_set_filter(png_ptr, 0, PNG_FILTER_NONE); ///!ToDo: Try this once baseline profile is in place.
+       // PNG_FILTER_SUB   |
+       // PNG_FILTER_UP    |
+       // PNG_FILTER_AVE   |
+       // PNG_FILTER_PAETH |
+       // PNG_ALL_FILTERS);
+  // Play with Zlib parameters in optimisation phase:
+    // png_set_compression_mem_level(png_ptr, 8);
+    // png_set_compression_strategy(png_ptr,
+        // Z_DEFAULT_STRATEGY);
+    // png_set_compression_window_bits(png_ptr, 15);
+    // png_set_compression_method(png_ptr, 8);
+    // png_set_compression_buffer_size(png_ptr, 8192)
+
+  // Let lib_png know if the pixel bytes are in BGR(A) order:
+  if(!rgbaOrder)
+  {
+    png_set_bgr( png_ptr );
+  }
+
+  // Set the image information:
+  png_set_IHDR(png_ptr, info_ptr, width, height, 8,
+     pngPixelFormat, interlace,
+     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
+
+  // Start to output the PNG data to our buffer:
+  png_write_info(png_ptr, info_ptr);
+
+  // Walk the rows:
+  const unsigned row_step = width * pixelBytes;
+  png_bytep row_ptr = const_cast<png_bytep>(pixelBuffer);
+  const png_bytep row_end = row_ptr + height * row_step;
+  for(; row_ptr < row_end; row_ptr += row_step)
+  {
+    png_write_row(png_ptr, row_ptr);
+  }
+
+  /* It is REQUIRED to call this to finish writing the rest of the file */
+  png_write_end(png_ptr, info_ptr);
+  /* Clean up after the write, and free any memory allocated */
+  png_destroy_write_struct(&png_ptr, &info_ptr);
+  return true;
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/dali/internal/imaging/common/loader-png.h b/dali/internal/imaging/common/loader-png.h
new file mode 100755 (executable)
index 0000000..d2d52fb
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef DALI_TIZEN_PLATFORM_LOADER_PNG_H
+#define DALI_TIZEN_PLATFORM_LOADER_PNG_H
+
+/*
+ * Copyright (c) 2019 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 <cstdio>
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/images/pixel.h>
+#include <dali/internal/legacy/tizen/image-encoder.h>
+#include <dali/devel-api/adaptor-framework/image-loader-input.h>
+
+namespace Dali
+{
+namespace Devel
+{
+class PixelBuffer;
+}
+
+namespace TizenPlatform
+{
+
+class ResourceLoadingClient;
+
+namespace Png
+{
+const unsigned char MAGIC_BYTE_1 = 0x89;
+const unsigned char MAGIC_BYTE_2 = 0x50;
+} // namespace Png
+
+/**
+ * Loads the bitmap from an PNG file.  This function checks the header first
+ * and if it is not a PNG file, then it returns straight away.
+ * @param[in]  input  Information about the input image (including file pointer)
+ * @param[out] bitmap The bitmap class where the decoded image will be stored
+ * @return  true if file decoded successfully, false otherwise
+ */
+bool LoadBitmapFromPng( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap );
+
+/**
+ * Loads the header of a PNG file and fills in the width and height appropriately.
+ * @param[in]   fp      Pointer to the Image file
+ * @param[in]  attributes  Describes the dimensions, pixel format and other details for loading the image data
+ * @param[out]  width   Is set with the width of the image
+ * @param[out]  height  Is set with the height of the image
+ * @return true if the file's header was read successully, false otherwise
+ */
+bool LoadPngHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+/**
+ * Encode raw pixel data to PNG format.
+ * @param[in]  pixelBuffer    Pointer to raw pixel data to be encoded
+ * @param[out] encodedPixels  Encoded pixel data. Existing contents will be overwritten
+ * @param[in]  width          Image width
+ * @param[in]  height         Image height
+ * @param[in]  pixelFormat    Input pixel format (must be Pixel::RGB888)
+ */
+bool EncodeToPng( const unsigned char* pixelBuffer, Vector<unsigned char>& encodedPixels, std::size_t width, std::size_t height, Pixel::Format pixelFormat );
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // DALI_TIZEN_PLATFORM_LOADER_PNG_H
diff --git a/dali/internal/imaging/common/loader-wbmp.cpp b/dali/internal/imaging/common/loader-wbmp.cpp
new file mode 100755 (executable)
index 0000000..6942442
--- /dev/null
@@ -0,0 +1,301 @@
+/*
+ * 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.
+ *
+ */
+
+// HEADER
+#include <dali/internal/imaging/common/loader-wbmp.h>
+
+// EXTERNAL INCLUDES
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_LOADER_WBMP");
+#endif
+
+#define IMG_MAX_SIZE 65536
+
+#define IMG_TOO_BIG(w, h) \
+        ((((unsigned long long)w) * ((unsigned long long)h)) >= \
+           ((1ULL << (29)) - 2048))
+
+
+//extract multiple bytes integer , and saved in *data
+int extractMultiByteInteger(unsigned int *data, void *map, size_t length, size_t *position)
+{
+  // the header field contains an image type indentifier of multi-byte length(TypeField), an octet of general header info(FixHeaderField)
+  //,  a multi-byte width field(Width) and a multi-byte height field(Height) and so on.
+  // The actual organisation of the image data depends on the image type
+  // for Ext Headers flag (7th bit), 1 = More will follow, 0 = Last octet
+  // so in the for loop, if(buf & 0x80 == 0), loop will be exited
+  int targetMultiByteInteger = 0, readBufCount;
+  unsigned char buf;
+
+  for (readBufCount = 0;;)
+  {
+    // readBufCount means the count that fetched data from map
+    // extractMultiByteInteger() is to fetch wbmp type , width, and height
+    // for wbmp type, when readBufCount == 1, buf = 0x00, it will exit the loop
+    // for width, it have 4 bytes, so when readBufCount == 4, it must exit the loop
+    // for general width and height, if(buf & 0x80) == 0, then the next byte does not need to fetch again
+    // first step, readBufCount = 1 , read int(4 bytes) to buf, if buf & 0x80 !=0, the buf need to continue to fetch
+    // second step, readBufCount = 2, read next( 4 bytes) to buf, if buf & 0x80 == 0, then assigned the buf to target
+    if ((readBufCount ++) == 4)
+    {
+      return -1;
+    }
+    if (*position > length)
+    {
+      return -1;
+    }
+    buf = reinterpret_cast< unsigned char * >( map )[(*position)++];
+    targetMultiByteInteger = (targetMultiByteInteger << 7) | (buf & 0x7f);
+
+    if ((buf & 0x80) == 0)
+    {
+      DALI_LOG_INFO(gLogFilter, Debug::Verbose, "position: %d, readBufCount: %d\n", *position, readBufCount);
+      break;
+    }
+  }
+  *data = targetMultiByteInteger;
+  return 0;
+}
+
+}// end unnamed namespace
+
+bool LoadBitmapFromWbmp( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap )
+{
+  FILE* const fp = input.file;
+  if(fp == NULL)
+  {
+    DALI_LOG_ERROR("Error loading bitmap\n");
+    return false;
+  }
+  Dali::Vector<unsigned char> map;
+  Dali::Vector<unsigned char> surface;//unsigned int
+  size_t position = 0;
+
+  unsigned int w, h;
+  unsigned int type;
+  unsigned int line_length;
+  unsigned char *line = NULL;
+  unsigned int cur = 0, x, y;
+
+  if( fseek(fp,0,SEEK_END) )
+  {
+    DALI_LOG_ERROR("Error seeking WBMP data\n");
+    return false;
+  }
+  long positionIndicator = ftell(fp);
+
+  unsigned int fsize( 0u );
+  if( positionIndicator > -1L )
+  {
+    fsize = static_cast<unsigned int>(positionIndicator);
+  }
+
+  if( 0u == fsize )
+  {
+    DALI_LOG_ERROR("Error: filesize is 0!\n");
+    return false;
+  }
+
+  if( fseek(fp, 0, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking WBMP data\n");
+    return false;
+  }
+  if(fsize <= 4)
+  {
+    DALI_LOG_ERROR("Error: WBMP Raw Data Not Found!\n");
+    return false;
+  }
+  if(fsize > 4096 * 4096 * 4)
+  {
+    DALI_LOG_ERROR("Error: WBMP size is too large!\n");
+    return false;
+  }
+  map.Resize(fsize);
+
+  if(fread(&map[0], 1, fsize, fp) != fsize)
+  {
+    DALI_LOG_WARNING("image file read opeation error!\n");
+    return false;
+  }
+
+  if (extractMultiByteInteger(&type, &map[0], fsize, &position) < 0)
+  {
+    return false;
+  }
+
+  position++; /* skipping one byte */
+
+  if (extractMultiByteInteger(&w, &map[0], fsize, &position) < 0)
+  {
+    return false;
+  }
+  if (extractMultiByteInteger(&h, &map[0], fsize, &position) < 0)
+  {
+    return false;
+  }
+  if(type != 0)
+  {
+    DALI_LOG_ERROR("Unknown Format!\n");
+    return false;
+  }
+
+  if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE))
+  {
+    return false;
+  }
+
+  surface.Resize(w* h );//(w * h * 4);
+  memset(&surface[0], 0, w * h ); // w * h * 4
+
+  line_length = (w + 7) >> 3;
+  for (y = 0; y < h; y ++)
+  {
+    if (position + line_length > fsize)
+    {
+      return false;
+    }
+    line = &map[0] + position;
+    position += line_length;
+    for (x = 0; x < w; x++)
+    {
+      int idx = x >> 3;
+      int offset = 1 << (0x07 - (x & 0x07));
+      if (line[idx] & offset)
+      {
+        surface[cur] = 0xff;//0xffffffff;
+      }
+      else
+      {
+        surface[cur] = 0x00;//0xff000000;
+      }
+      cur++;
+    }
+  }
+  auto pixels = (bitmap = Dali::Devel::PixelBuffer::New(w, h, Pixel::L8)).GetBuffer();
+
+  memcpy( pixels, &surface[0], w * h ); //w * h * 4
+
+  return true;
+}
+
+
+bool LoadWbmpHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height )
+{
+  FILE* const fp = input.file;
+  if(fp == NULL)
+  {
+    DALI_LOG_ERROR("Error loading bitmap\n");
+    return false;
+  }
+  Dali::Vector<unsigned char> map;
+  size_t position = 0;
+
+  unsigned int  w, h;
+  unsigned int type;
+  if( fseek(fp,0,SEEK_END) )
+  {
+    DALI_LOG_ERROR("Error seeking WBMP data\n");
+    return false;
+  }
+  long positionIndicator = ftell(fp);
+
+  unsigned int fsize( 0u );
+  if( positionIndicator > -1L )
+  {
+    fsize = static_cast<unsigned int>(positionIndicator);
+  }
+
+  if( 0u == fsize )
+  {
+    return false;
+  }
+
+  if( fseek(fp, 0, SEEK_SET) )
+  {
+    DALI_LOG_ERROR("Error seeking WBMP data\n");
+    return false;
+  }
+  if(fsize <= 4)
+  {
+    DALI_LOG_ERROR("Error: WBMP Raw Data Not Found!\n");
+    return false;
+  }
+
+  // type(1 byte) + fixedheader(1 byte) + width(uint) + height(uint)
+  unsigned int headerSize = 1 + 1 + 4 + 4;// 8 + 8 + 32 + 32;
+  headerSize = std::min(headerSize, fsize);
+
+  map.Resize(headerSize);
+  if(fread(&map[0], 1, headerSize, fp) != headerSize)
+  {
+    DALI_LOG_WARNING("image file read opeation error!\n");
+    return false;
+  }
+
+  if (extractMultiByteInteger(&type, &map[0], headerSize, &position) < 0)
+  {
+    DALI_LOG_ERROR("Error: unable to read type!\n");
+    return false;
+  }
+  position++; /* skipping one byte */
+  if(type != 0)
+  {
+    DALI_LOG_ERROR("Error: unknown format!\n");
+    return false;
+  }
+  if (extractMultiByteInteger(&w, &map[0], headerSize, &position) < 0)
+  {
+    DALI_LOG_ERROR("Error: can not read width!\n");
+    return false;
+  }
+  if (extractMultiByteInteger(&h, &map[0], headerSize, &position) < 0)
+  {
+    DALI_LOG_ERROR("Error: can not read height!\n");
+    return false;
+  }
+
+  if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) )
+  {
+    DALI_LOG_ERROR("Error: file size is not supported!\n");
+    return false;
+  }
+
+  width = w;
+  height = h;
+  return true;
+}
+
+}
+}
diff --git a/dali/internal/imaging/common/loader-wbmp.h b/dali/internal/imaging/common/loader-wbmp.h
new file mode 100755 (executable)
index 0000000..ccc8038
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef DALI_TIZEN_PLATFORM_LOADER_WBMP_H
+#define DALI_TIZEN_PLATFORM_LOADER_WBMP_H
+
+/*
+ * Copyright (c) 2019 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 <cstdio>
+#include <dali/devel-api/adaptor-framework/image-loader-input.h>
+
+namespace Dali
+{
+
+namespace Devel
+{
+class PixelBuffer;
+}
+
+namespace TizenPlatform
+{
+
+class ResourceLoadingClient;
+
+/**
+ * @param[in]  input  Information about the input image (including file pointer)
+ * @param[out] bitmap The bitmap class where the decoded image will be stored
+ * @return  true if file decoded successfully, false otherwise
+ */
+bool LoadBitmapFromWbmp( const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap );
+
+/**
+ * @param[in]  input  Information about the input image (including file pointer)
+ * @param[out] width of image
+ * @param[out] height of image
+ * @return  true if header loaded successfully, false otherwise
+ */
+bool LoadWbmpHeader( const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height );
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // DALI_TIZEN_PLATFORM_LOADER_WBMP_H
diff --git a/dali/internal/imaging/common/native-bitmap-buffer-impl.cpp b/dali/internal/imaging/common/native-bitmap-buffer-impl.cpp
new file mode 100644 (file)
index 0000000..1741803
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/imaging/common/native-bitmap-buffer-impl.h>
+
+// EXTERNAL HEADERS
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/bitmap.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/graphics/gles/gl-implementation.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+NativeBitmapBuffer::NativeBitmapBuffer( Adaptor* adaptor, unsigned int width, unsigned int height, Pixel::Format pFormat )
+: mGlAbstraction( nullptr),
+  mWidth(width),
+  mHeight(height),
+  mPixelFormat(pFormat),
+  mLastReadBuffer(NULL)
+{
+  DALI_ASSERT_ALWAYS( adaptor );
+  mBuffer = new Integration::LocklessBuffer( width * height * Pixel::GetBytesPerPixel(pFormat) );
+
+  GraphicsInterface* graphics = &(adaptor->GetGraphicsInterface());
+  auto eglGraphics = static_cast<EglGraphics *>(graphics);
+  mGlAbstraction = &(eglGraphics->GetGlAbstraction());
+}
+
+NativeBitmapBuffer::~NativeBitmapBuffer()
+{
+  delete mBuffer;
+}
+
+void NativeBitmapBuffer::PrepareTexture()
+{
+  DALI_ASSERT_ALWAYS( mBuffer );
+  GLenum pixelFormat = GL_RGBA;
+  GLenum pixelDataType = GL_UNSIGNED_BYTE;
+
+  Integration::ConvertToGlFormat( mPixelFormat, pixelDataType, pixelFormat );
+
+  const unsigned char* buf = mBuffer->Read();
+
+  if( buf && buf != mLastReadBuffer ) // Prevent same buffer being uploaded multiple times
+  {
+    mLastReadBuffer = buf;
+
+    // The active texture has already been set to a sampler and bound.
+    mGlAbstraction->TexImage2D( GL_TEXTURE_2D, 0, pixelFormat, mWidth, mHeight, 0, pixelFormat, pixelDataType, buf );
+  }
+}
+
+void NativeBitmapBuffer::Write( const unsigned char *src, size_t size )
+{
+  mBuffer->Write( src, size ); // Write will cause LocklessBuffer to switch to the other buffer
+}
+
+bool NativeBitmapBuffer::GlExtensionCreate()
+{
+  return true;
+}
+
+void NativeBitmapBuffer::GlExtensionDestroy()
+{
+}
+
+unsigned int NativeBitmapBuffer::TargetTexture()
+{
+  return 0;
+}
+
+unsigned int NativeBitmapBuffer::GetWidth() const
+{
+  return mWidth;
+}
+
+unsigned int NativeBitmapBuffer::GetHeight() const
+{
+  return mHeight;
+}
+
+bool NativeBitmapBuffer::RequiresBlending() const
+{
+  return Pixel::HasAlpha( mPixelFormat );
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/imaging/common/native-bitmap-buffer-impl.h b/dali/internal/imaging/common/native-bitmap-buffer-impl.h
new file mode 100644 (file)
index 0000000..f1ff5fc
--- /dev/null
@@ -0,0 +1,130 @@
+#ifndef DALI_NATIVE_BITMAP_BUFFER_H
+#define DALI_NATIVE_BITMAP_BUFFER_H
+
+/*
+ * Copyright (c) 2019 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 HEADERS
+#include <dali/public-api/images/native-image-interface.h>
+#include <dali/public-api/images/pixel.h>
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/integration-api/lockless-buffer.h>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/graphics/common/graphics-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class NativeBitmapBuffer;
+typedef IntrusivePtr<NativeBitmapBuffer> NativeBitmapBufferPtr;
+
+/**
+ * A Bitmap-based implementation of the NativeImage interface.
+ */
+class NativeBitmapBuffer : public NativeImageInterface
+{
+
+public:
+  /**
+   * Constructor.
+   * @param adaptor Adaptor used
+   * @param width width of image
+   * @param height height of image
+   * @param pixelFormat pixel format for image
+   */
+  NativeBitmapBuffer( Adaptor* adaptor, unsigned int width, unsigned int height, Pixel::Format pixelFormat );
+
+  /**
+   * virtual destructor
+   */
+  virtual ~NativeBitmapBuffer();
+
+  /**
+   * Write to buffer. Does not block.
+   * @param[in] src  data source
+   * @param[in] size size of data in bytes
+   * @return true if successful, false if currently reading from buffer in render thread
+   */
+  void Write( const unsigned char* src, size_t size );
+
+public:
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionCreate()
+   */
+  virtual bool GlExtensionCreate();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionDestroy()
+   */
+  virtual void GlExtensionDestroy();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::TargetTexture()
+   */
+  virtual unsigned int TargetTexture();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::PrepareTexture()
+   */
+  virtual void PrepareTexture();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetWidth()
+   */
+  virtual unsigned int GetWidth() const;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetHeight()
+   */
+  virtual unsigned int GetHeight() const;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::RequiresBlending()
+   */
+  virtual bool RequiresBlending() const;
+
+private:
+  NativeBitmapBuffer( const NativeBitmapBuffer& );             ///< not defined
+  NativeBitmapBuffer& operator =( const NativeBitmapBuffer& ); ///< not defined
+  NativeBitmapBuffer(); ///< not defined
+
+private:
+  Integration::GlAbstraction*  mGlAbstraction; ///< GlAbstraction used
+
+  Integration::LocklessBuffer* mBuffer;        ///< bitmap data double buffered
+  unsigned int                 mWidth;         ///< Image width
+  unsigned int                 mHeight;        ///< Image height
+  Pixel::Format                mPixelFormat;   ///< Image pixelformat
+  const unsigned char*         mLastReadBuffer; ///< last buffer that was read
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_NATIVE_BITMAP_BUFFER_H
diff --git a/dali/internal/imaging/common/native-image-source-factory.h b/dali/internal/imaging/common/native-image-source-factory.h
new file mode 100644 (file)
index 0000000..f334f65
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef DALI_INTERNAL_NATIVE_IMAGE_SOURCE_FACTORY_H
+#define DALI_INTERNAL_NATIVE_IMAGE_SOURCE_FACTORY_H
+
+/*
+ * Copyright (c) 2018 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 <memory>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/native-image-source.h>
+#include <dali/devel-api/adaptor-framework/native-image-source-queue.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class NativeImageSource;
+class NativeImageSourceQueue;
+
+class NativeImageSourceFactory
+{
+public:
+
+  NativeImageSourceFactory() = default;
+  virtual ~NativeImageSourceFactory() = default;
+
+  virtual std::unique_ptr< NativeImageSource > CreateNativeImageSource( uint32_t width, uint32_t height,
+                                                                        Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource ) = 0;
+
+  virtual std::unique_ptr< NativeImageSourceQueue > CreateNativeImageSourceQueue( uint32_t width, uint32_t height,
+                                                                                  Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue ) = 0;
+
+};
+
+extern std::unique_ptr< NativeImageSourceFactory > GetNativeImageSourceFactory();
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // DALI_INTERNAL_NATIVE_IMAGE_SOURCE_FACTORY_H
diff --git a/dali/internal/imaging/common/native-image-source-impl.h b/dali/internal/imaging/common/native-image-source-impl.h
new file mode 100755 (executable)
index 0000000..d5f292f
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef DALI_INTERNAL_NATIVE_IMAGE_SOURCE_IMPL_H
+#define DALI_INTERNAL_NATIVE_IMAGE_SOURCE_IMPL_H
+
+/*
+ * Copyright (c) 2018 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 <dali/public-api/adaptor-framework/native-image-source.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Dali internal NativeImageSource.
+ */
+class NativeImageSource
+{
+public:
+
+  /**
+   * Create a new NativeImageSource internally.
+   * Depending on hardware the width and height may have to be a power of two.
+   * @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
+   * @return A smart-pointer to a newly allocated image.
+   */
+  static NativeImageSource* New(uint32_t width,
+                                uint32_t height,
+                                Dali::NativeImageSource::ColorDepth depth,
+                                Any nativeImageSource);
+  /**
+   * @copydoc Dali::NativeImageSource::GetNativeImageSource()
+   */
+  virtual Any GetNativeImageSource() const = 0;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetPixels()
+   */
+  virtual bool GetPixels(std::vector<unsigned char> &pixbuf, uint32_t &width, uint32_t &height, Pixel::Format& pixelFormat ) const = 0;
+
+  /**
+   * @copydoc Dali::NativeImageSource::EncodeToFile(const std::string& )
+   */
+  virtual bool EncodeToFile(const std::string& filename) const = 0;
+
+  /**
+   * @copydoc Dali::NativeImageSource::SetSource( Any source )
+   */
+  virtual void SetSource( Any source ) = 0;
+
+  /**
+   * @copydoc Dali::NativeImageSource::IsColorDepthSupported( ColorDepth colorDepth )
+   */
+  virtual bool IsColorDepthSupported( Dali::NativeImageSource::ColorDepth colorDepth ) = 0;
+
+  /**
+   * destructor
+   */
+  virtual ~NativeImageSource() = default;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GlExtensionCreate()
+   */
+  virtual bool GlExtensionCreate() = 0;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GlExtensionDestroy()
+   */
+  virtual void GlExtensionDestroy() = 0;
+
+  /**
+   * @copydoc Dali::NativeImageSource::TargetTexture()
+   */
+  virtual uint32_t TargetTexture() = 0;
+
+  /**
+   * @copydoc Dali::NativeImageSource::PrepareTexture()
+   */
+  virtual void PrepareTexture() = 0;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetWidth()
+   */
+  virtual uint32_t GetWidth() const = 0;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetHeight()
+   */
+  virtual uint32_t GetHeight() const = 0;
+
+  /**
+   * @copydoc Dali::NativeImageSource::RequiresBlending()
+   */
+  virtual bool RequiresBlending() const = 0;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetExtension()
+   */
+  virtual NativeImageInterface::Extension* GetNativeImageInterfaceExtension() = 0;
+
+  /**
+   * @brief Dali::DevelNativeImageSource::AcquireBuffer()
+   */
+  virtual uint8_t* AcquireBuffer( uint16_t& width, uint16_t& height, uint16_t& stride ) = 0;
+
+  /**
+   * @brief Dali::DevelNativeImageSource::ReleaseBuffer()
+   */
+  virtual bool ReleaseBuffer() = 0;
+
+public:
+  inline static Internal::Adaptor::NativeImageSource& GetImplementation( Dali::NativeImageSource& image ) { return *image.mImpl; }
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_NATIVE_IMAGE_SOURCE_IMPL_H
diff --git a/dali/internal/imaging/common/native-image-source-queue-impl.h b/dali/internal/imaging/common/native-image-source-queue-impl.h
new file mode 100755 (executable)
index 0000000..889935e
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef DALI_INTERNAL_NATIVE_IMAGE_SOURCE_QUEUE_IMPL_H
+#define DALI_INTERNAL_NATIVE_IMAGE_SOURCE_QUEUE_IMPL_H
+
+/*
+ * Copyright (c) 2018 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 <dali/devel-api/adaptor-framework/native-image-source-queue.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Dali internal NativeImageSourceQueue.
+ */
+class NativeImageSourceQueue
+{
+public:
+
+  /**
+   * @copydoc Dali::NativeImageSourceQueue::New()
+   */
+  static NativeImageSourceQueue* New( uint32_t width, uint32_t height, Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue );
+
+  /**
+   * @copydoc Dali::NativeImageSourceQueue::GetNativeImageSourceQueue()
+   */
+  virtual Any GetNativeImageSourceQueue() const = 0;
+
+  /**
+   * @copydoc Dali::NativeImageSourceQueue::SetSize
+   */
+  virtual void SetSize( uint32_t width, uint32_t height ) = 0;
+
+  /**
+   * destructor
+   */
+  virtual ~NativeImageSourceQueue() = default;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionCreate()
+   */
+  virtual bool GlExtensionCreate() = 0;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionDestroy()
+   */
+  virtual void GlExtensionDestroy() = 0;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::TargetTexture()
+   */
+  virtual uint32_t TargetTexture() = 0;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::PrepareTexture()
+   */
+  virtual void PrepareTexture() = 0;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetWidth()
+   */
+  virtual uint32_t GetWidth() const = 0;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetHeight()
+   */
+  virtual uint32_t GetHeight() const = 0;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::RequiresBlending()
+   */
+  virtual bool RequiresBlending() const = 0;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetExtension()
+   */
+  virtual NativeImageInterface::Extension* GetNativeImageInterfaceExtension() = 0;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_NATIVE_IMAGE_SOURCE_QUEUE_IMPL_H
diff --git a/dali/internal/imaging/common/pixel-buffer-impl.cpp b/dali/internal/imaging/common/pixel-buffer-impl.cpp
new file mode 100755 (executable)
index 0000000..7490bf4
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/imaging/common/pixel-buffer-impl.h>
+
+// EXTERNAL INCLUDES
+#include <stdlib.h>
+#include <cstring>
+
+// INTERNAL INCLUDES
+#include <dali/internal/imaging/common/pixel-manipulation.h>
+#include <dali/internal/imaging/common/alpha-mask.h>
+#include <dali/internal/imaging/common/gaussian-blur.h>
+#include <dali/internal/imaging/common/image-operations.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const float TWO_PI = 2.f * Math::PI; ///< 360 degrees in radians
+} // namespace
+
+PixelBuffer::PixelBuffer( unsigned char* buffer,
+                          unsigned int bufferSize,
+                          unsigned int width,
+                          unsigned int height,
+                          Dali::Pixel::Format pixelFormat )
+: mMetadata(),
+  mBuffer( buffer ),
+  mBufferSize( bufferSize ),
+  mWidth( width ),
+  mHeight( height ),
+  mPixelFormat( pixelFormat ),
+  mPreMultiplied( false )
+{
+}
+
+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;
+}
+
+const unsigned char* const PixelBuffer::GetConstBuffer() 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& inMask, float contentScale, bool cropToMask )
+{
+  if( cropToMask )
+  {
+    // First scale this buffer by the contentScale, and crop to the mask size
+    // If it's too small, then scale the mask to match the image size
+    // Then apply the mask
+    ScaleAndCrop( contentScale, ImageDimensions( inMask.GetWidth(), inMask.GetHeight() ) );
+
+    if( inMask.mWidth > mWidth || inMask.mHeight > mHeight )
+    {
+      PixelBufferPtr mask = NewResize( inMask, ImageDimensions( mWidth, mHeight ) );
+      ApplyMaskInternal( *mask );
+    }
+    else
+    {
+      ApplyMaskInternal( inMask );
+    }
+  }
+  else
+  {
+    // First, scale the mask to match the image size,
+    // then apply the mask.
+    PixelBufferPtr mask = NewResize( inMask, ImageDimensions( mWidth, mHeight ) );
+    ApplyMaskInternal( *mask );
+  }
+}
+
+void PixelBuffer::ApplyMaskInternal( 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 );
+    TakeOwnershipOfBuffer( *newPixelBuffer );
+    // On leaving scope, newPixelBuffer will get destroyed.
+  }
+}
+
+void PixelBuffer::TakeOwnershipOfBuffer( PixelBuffer& pixelBuffer )
+{
+  ReleaseBuffer();
+
+  // Take ownership of new buffer
+  mBuffer = pixelBuffer.mBuffer;
+  pixelBuffer.mBuffer = NULL;
+  mBufferSize = pixelBuffer.mBufferSize;
+  mWidth = pixelBuffer.mWidth;
+  mHeight = pixelBuffer.mHeight;
+  mPixelFormat = pixelBuffer.mPixelFormat;
+}
+
+void PixelBuffer::ReleaseBuffer()
+{
+  if( mBuffer )
+  {
+    free( mBuffer );
+  }
+}
+
+void PixelBuffer::AllocateFixedSize( uint32_t size )
+{
+  ReleaseBuffer();
+  mBuffer = reinterpret_cast<unsigned char*>(malloc( size ));
+  mBufferSize = size;
+}
+
+bool PixelBuffer::Rotate( Degree angle )
+{
+  // Check first if Rotate() can perform the operation in the current pixel buffer.
+
+  bool validPixelFormat = false;
+  switch( mPixelFormat )
+  {
+    case Pixel::A8:
+    case Pixel::L8:
+    case Pixel::LA88:
+    case Pixel::RGB888:
+    case Pixel::RGB8888:
+    case Pixel::BGR8888:
+    case Pixel::RGBA8888:
+    case Pixel::BGRA8888: // FALL THROUGH
+    {
+      validPixelFormat = true;
+      break;
+    }
+    default:
+    {
+      // This pixel format is not supported for this operation.
+      validPixelFormat = false;
+      break;
+    }
+  }
+
+  if( !validPixelFormat )
+  {
+    // Can't rotate the pixel buffer with the current pixel format.
+    DALI_LOG_ERROR( "Can't rotate the pixel buffer with the current pixel format\n" );
+    return false;
+  }
+
+  float radians = Radian( angle ).radian;
+
+  // Transform the input angle into the range [0..2PI]
+  radians = fmod( radians, TWO_PI );
+  radians += ( radians < 0.f ) ? TWO_PI : 0.f;
+
+  if( radians < Dali::Math::MACHINE_EPSILON_10 )
+  {
+    // Nothing to do if the angle is zero.
+    return true;
+  }
+
+  const unsigned int pixelSize = Pixel::GetBytesPerPixel( mPixelFormat );
+
+  uint8_t* pixelsOut = nullptr;
+  Platform::RotateByShear( mBuffer,
+                           mWidth,
+                           mHeight,
+                           pixelSize,
+                           radians,
+                           pixelsOut,
+                           mWidth,
+                           mHeight );
+
+  // Check whether the rotation succedded and set the new pixel buffer data.
+  const bool success = nullptr != pixelsOut;
+
+  if( success )
+  {
+    // Release the memory of the current pixel buffer.
+    ReleaseBuffer();
+
+    // Set the new pixel buffer.
+    mBuffer = pixelsOut;
+    pixelsOut = nullptr;
+    mBufferSize = mWidth * mHeight * pixelSize;
+  }
+
+  return success;
+}
+
+void PixelBuffer::ScaleAndCrop( float scaleFactor, ImageDimensions cropDimensions )
+{
+  ImageDimensions outDimensions( float(mWidth) * scaleFactor,
+                                 float(mHeight) * scaleFactor );
+
+  if( outDimensions.GetWidth() != mWidth || outDimensions.GetHeight() != mHeight )
+  {
+    Resize( outDimensions );
+  }
+
+  ImageDimensions postCropDimensions(
+    std::min(cropDimensions.GetWidth(), outDimensions.GetWidth()),
+    std::min(cropDimensions.GetHeight(), outDimensions.GetHeight()));
+
+  if( postCropDimensions.GetWidth() < outDimensions.GetWidth() ||
+      postCropDimensions.GetHeight() < outDimensions.GetHeight() )
+  {
+    uint16_t x = ( outDimensions.GetWidth()  - postCropDimensions.GetWidth() ) / 2;
+    uint16_t y = ( outDimensions.GetHeight() - postCropDimensions.GetHeight() ) / 2;
+    Crop( x, y, postCropDimensions );
+  }
+}
+
+void PixelBuffer::Crop( uint16_t x, uint16_t y, ImageDimensions cropDimensions )
+{
+  PixelBufferPtr outBuffer = NewCrop( *this, x, y, cropDimensions );
+  TakeOwnershipOfBuffer( *outBuffer );
+}
+
+PixelBufferPtr PixelBuffer::NewCrop( const PixelBuffer& inBuffer, uint16_t x, uint16_t y, ImageDimensions cropDimensions )
+{
+  PixelBufferPtr outBuffer = PixelBuffer::New( cropDimensions.GetWidth(), cropDimensions.GetHeight(), inBuffer.GetPixelFormat() );
+  int bytesPerPixel = Pixel::GetBytesPerPixel( inBuffer.mPixelFormat );
+  int srcStride = inBuffer.mWidth * bytesPerPixel;
+  int destStride = cropDimensions.GetWidth() * bytesPerPixel;
+
+  // Clamp crop to right edge
+  if( x + cropDimensions.GetWidth() > inBuffer.mWidth )
+  {
+    destStride = ( inBuffer.mWidth - x ) * bytesPerPixel;
+  }
+
+  int srcOffset = x * bytesPerPixel + y * srcStride;
+  int destOffset = 0;
+  unsigned char* destBuffer = outBuffer->mBuffer;
+
+  // Clamp crop to last row
+  unsigned int endRow = y + cropDimensions.GetHeight();
+  if( endRow > inBuffer.mHeight )
+  {
+    endRow = inBuffer.mHeight - 1 ;
+  }
+  for( uint16_t row = y; row < endRow; ++row )
+  {
+    memcpy(destBuffer + destOffset, inBuffer.mBuffer + srcOffset, destStride );
+    srcOffset += srcStride;
+    destOffset += destStride;
+  }
+  return outBuffer;
+
+}
+
+void PixelBuffer::SetMetadata( const Property::Map& map )
+{
+  mMetadata.reset(new Property::Map(map));
+}
+
+bool PixelBuffer::GetMetadata(Property::Map& outMetadata) const
+{
+  if( !mMetadata )
+  {
+    return false;
+  }
+  outMetadata = *mMetadata;
+  return true;
+}
+
+void PixelBuffer::SetMetadata(std::unique_ptr<Property::Map> metadata)
+{
+  mMetadata = std::move(metadata);
+}
+
+void PixelBuffer::Resize( ImageDimensions outDimensions )
+{
+  if( mWidth != outDimensions.GetWidth() || mHeight != outDimensions.GetHeight() )
+  {
+    PixelBufferPtr outBuffer = NewResize( *this, outDimensions );
+    TakeOwnershipOfBuffer( *outBuffer );
+  }
+}
+
+PixelBufferPtr PixelBuffer::NewResize( const PixelBuffer& inBuffer, ImageDimensions outDimensions )
+{
+  PixelBufferPtr outBuffer = PixelBuffer::New( outDimensions.GetWidth(), outDimensions.GetHeight(), inBuffer.GetPixelFormat() );
+  ImageDimensions inDimensions( inBuffer.mWidth, inBuffer.mHeight );
+
+  bool hasAlpha = Pixel::HasAlpha( inBuffer.mPixelFormat );
+  int bytesPerPixel = Pixel::GetBytesPerPixel( inBuffer.mPixelFormat );
+
+  Resampler::Filter filterType = Resampler::LANCZOS4;
+  if( inDimensions.GetWidth() < outDimensions.GetWidth() && inDimensions.GetHeight() < outDimensions.GetHeight() )
+  {
+    filterType = Resampler::MITCHELL;
+  }
+
+  // This method only really works for 8 bit wide channels.
+  // (But could be expanded to work)
+  if( inBuffer.mPixelFormat == Pixel::A8 ||
+      inBuffer.mPixelFormat == Pixel::L8 ||
+      inBuffer.mPixelFormat == Pixel::LA88 ||
+      inBuffer.mPixelFormat == Pixel::RGB888 ||
+      inBuffer.mPixelFormat == Pixel::RGB8888 ||
+      inBuffer.mPixelFormat == Pixel::BGR8888 ||
+      inBuffer.mPixelFormat == Pixel::RGBA8888 ||
+      inBuffer.mPixelFormat == Pixel::BGRA8888 )
+  {
+    Dali::Internal::Platform::Resample( inBuffer.mBuffer, inDimensions,
+                                        outBuffer->GetBuffer(), outDimensions,
+                                        filterType, bytesPerPixel, hasAlpha );
+  }
+  else
+  {
+    DALI_LOG_ERROR( "Trying to resize an image with too narrow a channel width" );
+  }
+
+  return outBuffer;
+}
+
+void PixelBuffer::ApplyGaussianBlur( const float blurRadius )
+{
+  // This method only works for pixel buffer in RGBA format.
+  if( mWidth > 0 && mHeight > 0 && mPixelFormat == Pixel::RGBA8888 )
+  {
+    if ( blurRadius > Math::MACHINE_EPSILON_1 )
+    {
+      PerformGaussianBlurRGBA( *this, blurRadius );
+    }
+  }
+  else
+  {
+    DALI_LOG_ERROR( "Trying to apply gaussian blur to an empty pixel buffer or a pixel buffer not in RGBA format" );
+  }
+}
+
+void PixelBuffer::MultiplyColorByAlpha()
+{
+  auto bytesPerPixel = Pixel::GetBytesPerPixel( mPixelFormat );
+
+  // Compressed textures have unknown size of the pixel. Alpha premultiplication
+  // must be skipped in such case
+  if( Pixel::GetBytesPerPixel(mPixelFormat) && Pixel::HasAlpha(mPixelFormat) )
+  {
+    unsigned char* pixel = mBuffer;
+    const unsigned int bufferSize = mWidth * mHeight;
+
+    for( unsigned int i=0; i<bufferSize; ++i )
+    {
+      unsigned int alpha = ReadChannel( pixel, mPixelFormat, Adaptor::ALPHA );
+      {
+        auto red       = ReadChannel( pixel, mPixelFormat, Adaptor::RED);
+        auto green     = ReadChannel( pixel, mPixelFormat, Adaptor::GREEN);
+        auto blue      = ReadChannel( pixel, mPixelFormat, Adaptor::BLUE);
+        auto luminance = ReadChannel( pixel, mPixelFormat, Adaptor::LUMINANCE);
+        WriteChannel( pixel, mPixelFormat, Adaptor::RED, red*alpha / 255 );
+        WriteChannel( pixel, mPixelFormat, Adaptor::GREEN, green*alpha/255 );
+        WriteChannel( pixel, mPixelFormat, Adaptor::BLUE, blue*alpha/255 );
+        WriteChannel( pixel, mPixelFormat, Adaptor::LUMINANCE, luminance*alpha/255 );
+      }
+      pixel += bytesPerPixel;
+    }
+  }
+  mPreMultiplied = true;
+}
+
+bool PixelBuffer::IsAlphaPreMultiplied() const
+{
+  return mPreMultiplied;
+}
+
+}// namespace Adaptor
+}// namespace Internal
+}// namespace Dali
diff --git a/dali/internal/imaging/common/pixel-buffer-impl.h b/dali/internal/imaging/common/pixel-buffer-impl.h
new file mode 100755 (executable)
index 0000000..b0a0bdc
--- /dev/null
@@ -0,0 +1,321 @@
+#ifndef DALI_INTERNAL_ADAPTOR_PIXEL_BUFFER_H
+#define DALI_INTERNAL_ADAPTOR_PIXEL_BUFFER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/adaptor-framework/pixel-buffer.h>
+#include <dali/public-api/images/image-operations.h> // For ImageDimensions
+#include <dali/public-api/images/pixel-data.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/object/property-map.h>
+
+// EXTERNAL INCLUDES
+#include <memory>
+
+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;
+
+  /**
+   * @copydoc Devel::PixelBuffer::GetBuffer()
+   */
+  const unsigned char* const GetConstBuffer() 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;
+
+  /**
+   * @brief 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
+   * @param[in] contentScale The scaling factor to apply to the content
+   * @param[in] cropToMask Whether to crop the output to the mask size (true) or scale the
+   * mask to the content size (false)
+   */
+  void ApplyMask( const PixelBuffer& mask, float contentScale, bool cropToMask );
+
+  /**
+   * @brief Apply a Gaussian blur to the current buffer with the given radius.
+   *
+   * @param[in] blurRadius The radius for Gaussian blur
+   */
+  void ApplyGaussianBlur( const float blurRadius );
+
+  /**
+   * Crops this buffer to the given crop rectangle. Assumes the crop rectangle
+   * is within the bounds of this size.
+   * @param[in] x The top left corner's X
+   * @param[in] y The top left corner's y
+   * @param[in] cropDimensions The dimensions of the crop
+   */
+  void Crop( uint16_t x, uint16_t y, ImageDimensions cropDimensions );
+
+  /**
+   * Resizes the buffer to the given dimensions. Uses either Lanczos4 for downscaling
+   * or Mitchell for upscaling
+   * @param[in] outDimensions The new dimensions
+   */
+  void Resize( ImageDimensions outDimensions );
+
+  /**
+   * Multiplies the image's color values by the alpha value. This provides better
+   * blending capability.
+   */
+  void MultiplyColorByAlpha();
+
+  /**
+   * @brief Sets image metadata
+   *
+   * @param map Property map containing Exif fields
+   */
+  void SetMetadata( const Property::Map& map );
+
+  /**
+   * @brief Returns image metadata as a property map
+   * @param[out] outMetadata Property map to copy the data into
+   * @return True on success
+   */
+  bool GetMetadata(Property::Map& outMetadata) const;
+
+  /**
+   * @brief Sets metadata property map for the pixel buffer
+   * @note The function takes over the ownership of the property map
+   * @param[in] metadata Property map to copy the data into
+   */
+  void SetMetadata(std::unique_ptr<Property::Map> metadata);
+
+  /**
+   * Allocates fixed amount of memory for the pixel data. Used by compressed formats.
+   * @param[in] size Size of memory to be allocated
+   */
+  void AllocateFixedSize( uint32_t size );
+
+  /**
+   * @copydoc Devel::PixelBuffer::Rotate()
+   */
+  bool Rotate( Degree angle );
+
+  /**
+   * @copydoc Devel::PixelBuffer::IsAlphaPreMultiplied()
+   */
+  bool IsAlphaPreMultiplied() const;
+
+private:
+  /*
+   * Undefined copy constructor.
+   */
+  PixelBuffer(const PixelBuffer& other);
+
+  /*
+   * Undefined assignment operator.
+   */
+  PixelBuffer& operator= (const PixelBuffer& other);
+
+  /**
+   * Internal method to apply the mask to this buffer. Expects that they are the same size.
+   */
+  void ApplyMaskInternal( const PixelBuffer& mask );
+
+  /**
+   * Takes ownership of the other object's pixel buffer.
+   */
+  void TakeOwnershipOfBuffer( PixelBuffer& pixelBuffer );
+
+  /**
+   * Release the buffer
+   */
+  void ReleaseBuffer();
+
+  /**
+   * Scales this buffer buffer by the given factor, and crops at the center to the
+   * given dimensions.
+   */
+  void ScaleAndCrop( float scaleFactor, ImageDimensions cropDimensions );
+
+  /**
+   * Creates a new buffer which is a crop of the passed in buffer,
+   * using the given crop rectangle. Assumes the crop rectangle is
+   * within the bounds of this size.
+   * @param[in] inBuffer The source buffer
+   * @param[in] x The top left corner's X
+   * @param[in] y The top left corner's y
+   * @param[in] cropDimensions The dimensions of the crop
+   * @return the new pixel buffer
+   */
+  static PixelBufferPtr NewCrop( const PixelBuffer& inBuffer, uint16_t x, uint16_t y, ImageDimensions cropDimensions );
+
+  /**
+   * Creates a new buffer which is a resized version of the passed in buffer.
+   * Uses either Lanczos4 for downscaling, or Mitchell for upscaling.
+   * @param[in] inBuffer The source buffer
+   * @param[in] outDimensions The new dimensions
+   * @return a new buffer of the given size.
+   */
+  static PixelBufferPtr NewResize( const PixelBuffer& inBuffer, ImageDimensions outDimensions );
+
+private:
+
+  std::unique_ptr<Property::Map>  mMetadata;         ///< Metadata fields
+  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
+  bool                            mPreMultiplied; ///< PreMultiplied
+};
+
+} // 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
diff --git a/dali/internal/imaging/common/pixel-manipulation.cpp b/dali/internal/imaging/common/pixel-manipulation.cpp
new file mode 100644 (file)
index 0000000..e37c88e
--- /dev/null
@@ -0,0 +1,716 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// CLASS HEADER
+#include <dali/internal/imaging/common/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:
+    case Dali::Pixel::RGB16F:
+    case Dali::Pixel::RGB32F:
+    {
+      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 &= static_cast<unsigned char>( ~0xF8 );
+        *pixelData |= static_cast<unsigned char>( (channelValue << 3) & 0xF8 );
+      }
+      else if( channel == GREEN )
+      {
+        *pixelData &= static_cast<unsigned char>( ~0x07 );
+        *pixelData |= static_cast<unsigned char>( (channelValue >> 3) & 0x07 );
+
+        *(pixelData+1) &= static_cast<unsigned char>( ~0xE0 );
+        *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 5) & 0xE0 );
+      }
+      else if( channel == BLUE )
+      {
+        *(pixelData+1) &= static_cast<unsigned char>( ~0x1F );
+        *(pixelData+1) |= static_cast<unsigned char>( channelValue & 0x1F );
+      }
+      break;
+    }
+
+    case Dali::Pixel::BGR565:
+    {
+      if( channel == BLUE )
+      {
+        *pixelData &= static_cast<unsigned char>( ~0xF8 );
+        *pixelData |= static_cast<unsigned char>( (channelValue << 3) & 0xF8 );
+      }
+      else if( channel == GREEN )
+      {
+        *pixelData &= static_cast<unsigned char>( ~0x07 );
+        *pixelData |= static_cast<unsigned char>( (channelValue >> 3) & 0x07 );
+
+        *(pixelData+1) &= static_cast<unsigned char>( ~0xE0 );
+        *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 5) & 0xE0 );
+      }
+      else if( channel == RED )
+      {
+        *(pixelData+1) &= static_cast<unsigned char>( ~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 &= static_cast<unsigned char>( ~0xF0 );
+        *pixelData |= static_cast<unsigned char>( (channelValue << 4) & 0xF0 );
+      }
+      else if( channel == GREEN )
+      {
+        *pixelData &= static_cast<unsigned char>( ~0x0F );
+        *pixelData |= static_cast<unsigned char>( channelValue & 0x0F );
+      }
+      else if( channel == BLUE )
+      {
+        *(pixelData+1) &= static_cast<unsigned char>( ~0xF0 );
+        *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 4) & 0xF0 );
+      }
+      else if( channel == ALPHA )
+      {
+        *(pixelData+1) &= static_cast<unsigned char>( ~0x0F );
+        *(pixelData+1) |= static_cast<unsigned char>( channelValue & 0x0F );
+      }
+      break;
+    }
+
+    case Dali::Pixel::BGRA4444:
+    {
+      if( channel == BLUE )
+      {
+        *pixelData &= static_cast<unsigned char>( ~0xF0 );
+        *pixelData |= static_cast<unsigned char>( (channelValue << 4) & 0xF0 );
+      }
+      else if( channel == GREEN )
+      {
+        *pixelData &= static_cast<unsigned char>( ~0x0F );
+        *pixelData |= static_cast<unsigned char>( channelValue & 0x0F );
+      }
+      else if( channel == RED )
+      {
+        *(pixelData+1) &= static_cast<unsigned char>( ~0xF0 );
+        *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 4) & 0xF0 );
+      }
+      else if( channel == ALPHA )
+      {
+        *(pixelData+1) &= static_cast<unsigned char>( ~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 &= static_cast<unsigned char>( ~0xF8 );
+        *pixelData |= static_cast<unsigned char>( (channelValue << 3) & 0xF8 );
+      }
+      else if( channel == GREEN )
+      {
+        *pixelData &= static_cast<unsigned char>( ~0x07 );
+        *pixelData |= static_cast<unsigned char>( (channelValue >> 2) & 0x07 );
+
+        *(pixelData+1) &= static_cast<unsigned char>( ~0xC0 );
+        *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 6) & 0xC0 );
+      }
+      else if( channel == BLUE )
+      {
+        *(pixelData+1) &= static_cast<unsigned char>( ~0x3E );
+        *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 1) & 0x3E );
+      }
+      else if( channel == ALPHA )
+      {
+        *(pixelData+1) &= static_cast<unsigned char>( ~0x01 );
+        *(pixelData+1) |= static_cast<unsigned char>( channelValue & 0x01 );
+      }
+      break;
+    }
+
+    case Dali::Pixel::BGRA5551:
+    {
+      if( channel == BLUE )
+      {
+        *pixelData &= static_cast<unsigned char>( ~0xF8 );
+        *pixelData |= static_cast<unsigned char>( (channelValue << 3) & 0xF8 );
+      }
+      else if( channel == GREEN )
+      {
+        *pixelData &= static_cast<unsigned char>( ~0x07 );
+        *pixelData |= static_cast<unsigned char>( (channelValue >> 2) & 0x07 );
+
+        *(pixelData+1) &= static_cast<unsigned char>( ~0xC0 );
+        *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 6) & 0xC0 );
+      }
+      else if( channel == RED )
+      {
+        *(pixelData+1) &= static_cast<unsigned char>( ~0x3E );
+        *(pixelData+1) |= static_cast<unsigned char>( (channelValue << 1 ) & 0x3E );
+      }
+      else if( channel == ALPHA )
+      {
+        *(pixelData+1) &= static_cast<unsigned char>( ~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
diff --git a/dali/internal/imaging/common/pixel-manipulation.h b/dali/internal/imaging/common/pixel-manipulation.h
new file mode 100644 (file)
index 0000000..611b5a6
--- /dev/null
@@ -0,0 +1,101 @@
+#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
diff --git a/dali/internal/imaging/file.list b/dali/internal/imaging/file.list
new file mode 100644 (file)
index 0000000..6558e96
--- /dev/null
@@ -0,0 +1,53 @@
+
+# module: imaging, backend: common
+SET( adaptor_imaging_common_src_files
+    ${adaptor_imaging_dir}/common/native-bitmap-buffer-impl.cpp
+    ${adaptor_imaging_dir}/common/pixel-buffer-impl.cpp
+    ${adaptor_imaging_dir}/common/alpha-mask.cpp
+    ${adaptor_imaging_dir}/common/gaussian-blur.cpp
+    ${adaptor_imaging_dir}/common/http-utils.cpp
+    ${adaptor_imaging_dir}/common/image-loader.cpp
+    ${adaptor_imaging_dir}/common/image-loader-plugin-proxy.cpp
+    ${adaptor_imaging_dir}/common/image-operations.cpp
+    ${adaptor_imaging_dir}/common/loader-astc.cpp
+    ${adaptor_imaging_dir}/common/loader-bmp.cpp
+    ${adaptor_imaging_dir}/common/loader-gif.cpp
+    ${adaptor_imaging_dir}/common/loader-ico.cpp
+    ${adaptor_imaging_dir}/common/loader-jpeg-turbo.cpp
+    ${adaptor_imaging_dir}/common/loader-ktx.cpp
+    ${adaptor_imaging_dir}/common/loader-png.cpp
+    ${adaptor_imaging_dir}/common/loader-wbmp.cpp
+    ${adaptor_imaging_dir}/common/pixel-manipulation.cpp
+)
+
+# module: imaging, backend: tizen
+SET( adaptor_imaging_tizen_src_files
+    ${adaptor_imaging_dir}/common/file-download.cpp
+    ${adaptor_imaging_dir}/tizen/native-image-source-factory-tizen.cpp
+    ${adaptor_imaging_dir}/tizen/native-image-source-impl-tizen.cpp
+    ${adaptor_imaging_dir}/tizen/native-image-source-queue-impl-tizen.cpp
+)
+
+# module: imaging, backend: ubuntu-x11
+SET( adaptor_imaging_ubuntu_x11_src_files
+    ${adaptor_imaging_dir}/common/file-download.cpp
+    ${adaptor_imaging_dir}/ubuntu-x11/native-image-source-factory-x.cpp
+    ${adaptor_imaging_dir}/ubuntu-x11/native-image-source-impl-x.cpp
+    ${adaptor_imaging_dir}/ubuntu-x11/native-image-source-queue-impl-x.cpp
+)
+
+# module: imaging, backend: android
+SET( adaptor_imaging_android_src_files
+    ${adaptor_imaging_dir}/common/file-download.cpp
+    ${adaptor_imaging_dir}/android/native-image-source-factory-android.cpp
+    ${adaptor_imaging_dir}/android/native-image-source-impl-android.cpp
+    ${adaptor_imaging_dir}/android/native-image-source-queue-impl-android.cpp
+)
+
+# module: imaging, backend: windows
+SET( adaptor_imaging_windows_src_files
+    ${adaptor_imaging_dir}/windows/curl-environment-win.cpp
+    ${adaptor_imaging_dir}/windows/file-download-win.cpp
+    ${adaptor_imaging_dir}/windows/native-image-source-factory-win.cpp
+    ${adaptor_imaging_dir}/windows/native-image-source-impl-win.cpp
+)
diff --git a/dali/internal/imaging/tizen/native-image-source-factory-tizen.cpp b/dali/internal/imaging/tizen/native-image-source-factory-tizen.cpp
new file mode 100644 (file)
index 0000000..8214508
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/imaging/tizen/native-image-source-factory-tizen.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/imaging/tizen/native-image-source-impl-tizen.h>
+#include <dali/internal/imaging/tizen/native-image-source-queue-impl-tizen.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+std::unique_ptr< NativeImageSource > NativeImageSourceFactoryTizen::CreateNativeImageSource( uint32_t width, uint32_t height,
+                                                                                             Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
+{
+  return std::unique_ptr< NativeImageSource >( NativeImageSourceTizen::New( width, height, depth, nativeImageSource ) );
+}
+
+std::unique_ptr< NativeImageSourceQueue > NativeImageSourceFactoryTizen::CreateNativeImageSourceQueue( uint32_t width, uint32_t height,
+                                                                                                       Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue )
+{
+  return std::unique_ptr< NativeImageSourceQueue >( NativeImageSourceQueueTizen::New( width, height, depth, nativeImageSourceQueue ) );
+}
+
+// this should be created from somewhere
+std::unique_ptr< NativeImageSourceFactory > GetNativeImageSourceFactory()
+{
+  // returns native image source factory
+  return std::unique_ptr< NativeImageSourceFactoryTizen >( new NativeImageSourceFactoryTizen() );
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/dali/internal/imaging/tizen/native-image-source-factory-tizen.h b/dali/internal/imaging/tizen/native-image-source-factory-tizen.h
new file mode 100644 (file)
index 0000000..165954e
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef DALI_INTERNAL_NATIVE_IMAGE_SOURCE_FACTORY_TIZEN_H
+#define DALI_INTERNAL_NATIVE_IMAGE_SOURCE_FACTORY_TIZEN_H
+
+/*
+ * Copyright (c) 2018 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 <dali/internal/imaging/common/native-image-source-factory.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class NativeImageSourceFactoryTizen : public NativeImageSourceFactory
+{
+public:
+
+  std::unique_ptr< NativeImageSource > CreateNativeImageSource( uint32_t width, uint32_t height,
+                                                                Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource ) override;
+
+  std::unique_ptr< NativeImageSourceQueue > CreateNativeImageSourceQueue( uint32_t width, uint32_t height,
+                                                                          Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue ) override;
+
+};
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // DALI_INTERNAL_NATIVE_IMAGE_SOURCE_FACTORY_TIZEN_H
diff --git a/dali/internal/imaging/tizen/native-image-source-impl-tizen.cpp b/dali/internal/imaging/tizen/native-image-source-impl-tizen.cpp
new file mode 100755 (executable)
index 0000000..2682522
--- /dev/null
@@ -0,0 +1,557 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/imaging/tizen/native-image-source-impl-tizen.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/gl-defines.h>
+#include <cstring>
+#include <tbm_surface_internal.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/common/egl-image-extensions.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/integration-api/adaptor-framework/render-surface-interface.h>
+
+// Allow this to be encoded and saved:
+#include <dali/devel-api/adaptor-framework/bitmap-saver.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const char* FRAGMENT_PREFIX = "#extension GL_OES_EGL_image_external:require\n";
+const char* SAMPLER_TYPE = "samplerExternalOES";
+
+tbm_format FORMATS_BLENDING_REQUIRED[] = {
+  TBM_FORMAT_ARGB4444, TBM_FORMAT_ABGR4444,
+  TBM_FORMAT_RGBA4444, TBM_FORMAT_BGRA4444,
+  TBM_FORMAT_RGBX5551, TBM_FORMAT_BGRX5551,
+  TBM_FORMAT_ARGB1555, TBM_FORMAT_ABGR1555,
+  TBM_FORMAT_RGBA5551, TBM_FORMAT_BGRA5551,
+  TBM_FORMAT_ARGB8888, TBM_FORMAT_ABGR8888,
+  TBM_FORMAT_RGBA8888, TBM_FORMAT_BGRA8888,
+  TBM_FORMAT_ARGB2101010, TBM_FORMAT_ABGR2101010,
+  TBM_FORMAT_RGBA1010102, TBM_FORMAT_BGRA1010102
+};
+
+const int NUM_FORMATS_BLENDING_REQUIRED = 18;
+
+}
+
+using Dali::Integration::PixelBuffer;
+
+NativeImageSourceTizen* NativeImageSourceTizen::New( uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
+{
+  NativeImageSourceTizen* image = new NativeImageSourceTizen( width, height, depth, nativeImageSource );
+  DALI_ASSERT_DEBUG( image && "NativeImageSource allocation failed." );
+
+  if( image )
+  {
+    image->Initialize();
+  }
+
+  return image;
+}
+
+NativeImageSourceTizen::NativeImageSourceTizen( uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
+: mWidth( width ),
+  mHeight( height ),
+  mOwnTbmSurface( false ),
+  mTbmSurface( NULL ),
+  mTbmFormat( 0 ),
+  mBlendingRequired( false ),
+  mColorDepth( depth ),
+  mEglImageKHR( NULL ),
+  mEglGraphics( NULL ),
+  mEglImageExtensions( NULL ),
+  mSetSource( false ),
+  mMutex(),
+  mIsBufferAcquired( false )
+{
+  DALI_ASSERT_ALWAYS( Adaptor::IsAvailable() );
+
+  GraphicsInterface* graphics = &( Adaptor::GetImplementation( Adaptor::Get() ).GetGraphicsInterface() );
+  mEglGraphics = static_cast<EglGraphics *>(graphics);
+
+  mTbmSurface = GetSurfaceFromAny( nativeImageSource );
+
+  if( mTbmSurface != NULL )
+  {
+    tbm_surface_internal_ref( mTbmSurface );
+    mBlendingRequired = CheckBlending( tbm_surface_get_format( mTbmSurface ) );
+    mWidth = tbm_surface_get_width( mTbmSurface );
+    mHeight = tbm_surface_get_height( mTbmSurface );
+  }
+}
+
+void NativeImageSourceTizen::Initialize()
+{
+  if( mTbmSurface != NULL || mWidth == 0 || mHeight == 0 )
+  {
+    return;
+  }
+
+  tbm_format format = TBM_FORMAT_RGB888;
+  int depth = 0;
+
+  switch( mColorDepth )
+  {
+    case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
+    {
+      format = TBM_FORMAT_ARGB8888;
+      depth = 32;
+      break;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_8:
+    {
+      format = TBM_FORMAT_C8;
+      depth = 8;
+      break;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_16:
+    {
+      format = TBM_FORMAT_RGB565;
+      depth = 16;
+      break;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_24:
+    {
+      format = TBM_FORMAT_RGB888;
+      depth = 24;
+      break;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_32:
+    {
+      format = TBM_FORMAT_ARGB8888;
+      depth = 32;
+      break;
+    }
+    default:
+    {
+      DALI_LOG_WARNING( "Wrong color depth.\n" );
+      return;
+    }
+  }
+
+  // set whether blending is required according to pixel format based on the depth
+  /* default pixel format is RGB888
+     If depth = 8, Pixel::A8;
+     If depth = 16, Pixel::RGB565;
+     If depth = 32, Pixel::RGBA8888 */
+  mBlendingRequired = ( depth == 32 || depth == 8 );
+
+  mTbmSurface = tbm_surface_create( mWidth, mHeight, format );
+  mOwnTbmSurface = true;
+}
+
+tbm_surface_h NativeImageSourceTizen::GetSurfaceFromAny( Any source ) const
+{
+  if( source.Empty() )
+  {
+    return NULL;
+  }
+
+  if( source.GetType() == typeid( tbm_surface_h ) )
+  {
+    return AnyCast< tbm_surface_h >( source );
+  }
+  else
+  {
+    return NULL;
+  }
+}
+
+void NativeImageSourceTizen::DestroySurface()
+{
+  if( mTbmSurface )
+  {
+    if( mIsBufferAcquired )
+    {
+      ReleaseBuffer();
+    }
+    if( mOwnTbmSurface )
+    {
+      if( tbm_surface_destroy( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
+      {
+        DALI_LOG_ERROR( "Failed to destroy tbm_surface\n" );
+      }
+    }
+    else
+    {
+      tbm_surface_internal_unref( mTbmSurface );
+    }
+  }
+}
+
+NativeImageSourceTizen::~NativeImageSourceTizen()
+{
+  DestroySurface();
+}
+
+Any NativeImageSourceTizen::GetNativeImageSource() const
+{
+  return Any( mTbmSurface );
+}
+
+bool NativeImageSourceTizen::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
+{
+  Dali::Mutex::ScopedLock lock( mMutex );
+  if( mTbmSurface != NULL )
+  {
+    tbm_surface_info_s surface_info;
+
+    if( tbm_surface_map( mTbmSurface, TBM_SURF_OPTION_READ, &surface_info) != TBM_SURFACE_ERROR_NONE )
+    {
+      DALI_LOG_ERROR( "Fail to map tbm_surface\n" );
+
+      width = 0;
+      height = 0;
+
+      return false;
+    }
+
+    tbm_format format = surface_info.format;
+    uint32_t stride = surface_info.planes[0].stride;
+    unsigned char* ptr = surface_info.planes[0].ptr;
+
+    width = mWidth;
+    height = mHeight;
+    size_t lineSize;
+    size_t offset;
+    size_t cOffset;
+
+    switch( format )
+    {
+      case TBM_FORMAT_RGB888:
+      {
+        lineSize = width*3;
+        pixelFormat = Pixel::RGB888;
+        pixbuf.resize( lineSize*height );
+        unsigned char* bufptr = &pixbuf[0];
+
+        for( unsigned int r = 0; r < height; ++r, bufptr += lineSize )
+        {
+          for( unsigned int c = 0; c < width; ++c )
+          {
+            cOffset = c*3;
+            offset = cOffset + r*stride;
+            *(bufptr+cOffset) = ptr[offset+2];
+            *(bufptr+cOffset+1) = ptr[offset+1];
+            *(bufptr+cOffset+2) = ptr[offset];
+          }
+        }
+        break;
+      }
+      case TBM_FORMAT_RGBA8888:
+      {
+        lineSize = width*4;
+        pixelFormat = Pixel::RGBA8888;
+        pixbuf.resize( lineSize*height );
+        unsigned char* bufptr = &pixbuf[0];
+
+        for( unsigned int r = 0; r < height; ++r, bufptr += lineSize )
+        {
+          for( unsigned int c = 0; c < width; ++c )
+          {
+            cOffset = c*4;
+            offset = cOffset + r*stride;
+            *(bufptr+cOffset) = ptr[offset+3];
+            *(bufptr+cOffset+1) = ptr[offset+2];
+            *(bufptr+cOffset+2) = ptr[offset+1];
+            *(bufptr+cOffset+3) = ptr[offset];
+          }
+        }
+        break;
+      }
+      case TBM_FORMAT_ARGB8888:
+      {
+        lineSize = width*4;
+        pixelFormat = Pixel::RGBA8888;
+        pixbuf.resize( lineSize*height );
+        unsigned char* bufptr = &pixbuf[0];
+
+        for( unsigned int r = 0; r < height; ++r, bufptr += lineSize )
+        {
+          for( unsigned int c = 0; c < width; ++c )
+          {
+            cOffset = c*4;
+            offset = cOffset + r*stride;
+            *(bufptr+cOffset) = ptr[offset];
+            *(bufptr+cOffset+1) = ptr[offset+3];
+            *(bufptr+cOffset+2) = ptr[offset+2];
+            *(bufptr+cOffset+3) = ptr[offset+1];
+          }
+        }
+        break;
+      }
+      default:
+      {
+        DALI_ASSERT_ALWAYS( 0 && "Tbm surface has unsupported pixel format.\n" );
+
+        return false;
+      }
+    }
+
+    if( tbm_surface_unmap( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
+    {
+      DALI_LOG_ERROR( "Fail to unmap tbm_surface\n" );
+    }
+
+    return true;
+  }
+
+  DALI_LOG_WARNING( "TBM surface does not exist.\n" );
+
+  width = 0;
+  height = 0;
+
+  return false;
+}
+
+bool NativeImageSourceTizen::EncodeToFile(const std::string& filename) const
+{
+  std::vector< unsigned char > pixbuf;
+  unsigned int width(0), height(0);
+  Pixel::Format pixelFormat;
+
+  if(GetPixels(pixbuf, width, height, pixelFormat))
+  {
+    return Dali::EncodeToFile(&pixbuf[0], filename, pixelFormat, width, height);
+  }
+  return false;
+}
+
+void NativeImageSourceTizen::SetSource( Any source )
+{
+  Dali::Mutex::ScopedLock lock( mMutex );
+
+  DestroySurface();
+
+  mOwnTbmSurface = false;
+  mTbmSurface = GetSurfaceFromAny( source );
+
+  if( mTbmSurface != NULL )
+  {
+    mSetSource = true;
+    tbm_surface_internal_ref( mTbmSurface );
+    mBlendingRequired = CheckBlending( tbm_surface_get_format( mTbmSurface ) );
+    mWidth = tbm_surface_get_width( mTbmSurface );
+    mHeight = tbm_surface_get_height( mTbmSurface );
+  }
+}
+
+bool NativeImageSourceTizen::IsColorDepthSupported( Dali::NativeImageSource::ColorDepth colorDepth )
+{
+  uint32_t* formats;
+  uint32_t formatNum;
+  tbm_format format = TBM_FORMAT_RGB888;
+
+  switch( colorDepth )
+  {
+    case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
+    {
+      format = TBM_FORMAT_ARGB8888;
+      break;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_8:
+    {
+      format = TBM_FORMAT_C8;
+      break;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_16:
+    {
+      format = TBM_FORMAT_RGB565;
+      break;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_24:
+    {
+      format = TBM_FORMAT_RGB888;
+      break;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_32:
+    {
+      format = TBM_FORMAT_ARGB8888;
+      break;
+    }
+  }
+
+  if( tbm_surface_query_formats( &formats, &formatNum ) )
+  {
+    for( unsigned int i = 0; i < formatNum; i++ )
+    {
+      if( formats[i] == format )
+      {
+        free( formats );
+        return true;
+      }
+    }
+  }
+
+  free( formats );
+  return false;
+}
+
+bool NativeImageSourceTizen::GlExtensionCreate()
+{
+  // casting from an unsigned int to a void *, which should then be cast back
+  // to an unsigned int in the driver.
+  EGLClientBuffer eglBuffer = reinterpret_cast< EGLClientBuffer >(mTbmSurface);
+  if( !eglBuffer || !tbm_surface_internal_is_valid( mTbmSurface ) )
+  {
+    return false;
+  }
+
+  mEglImageExtensions = mEglGraphics->GetImageExtensions();
+  DALI_ASSERT_DEBUG( mEglImageExtensions );
+
+  mEglImageKHR = mEglImageExtensions->CreateImageKHR( eglBuffer );
+
+  return mEglImageKHR != NULL;
+}
+
+void NativeImageSourceTizen::GlExtensionDestroy()
+{
+  Dali::Mutex::ScopedLock lock( mMutex );
+  if( mEglImageKHR )
+  {
+    mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
+
+    mEglImageKHR = NULL;
+  }
+}
+
+uint32_t NativeImageSourceTizen::TargetTexture()
+{
+  mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
+
+  return 0;
+}
+
+void NativeImageSourceTizen::PrepareTexture()
+{
+  Dali::Mutex::ScopedLock lock( mMutex );
+  if( mSetSource )
+  {
+    void* eglImage = mEglImageKHR;
+
+    if( GlExtensionCreate() )
+    {
+      TargetTexture();
+    }
+
+    mEglImageExtensions->DestroyImageKHR( eglImage );
+
+    mSetSource = false;
+  }
+}
+
+const char* NativeImageSourceTizen::GetCustomFragmentPreFix()
+{
+  return FRAGMENT_PREFIX;
+}
+
+const char* NativeImageSourceTizen::GetCustomSamplerTypename()
+{
+  return SAMPLER_TYPE;
+}
+
+int NativeImageSourceTizen::GetEglImageTextureTarget()
+{
+  return GL_TEXTURE_EXTERNAL_OES;
+}
+
+bool NativeImageSourceTizen::CheckBlending( tbm_format format )
+{
+  if( mTbmFormat != format )
+  {
+    for(int i = 0; i < NUM_FORMATS_BLENDING_REQUIRED; ++i)
+    {
+      if( format == FORMATS_BLENDING_REQUIRED[i] )
+      {
+        mBlendingRequired = true;
+        break;
+      }
+    }
+    mTbmFormat = format;
+  }
+
+  return mBlendingRequired;
+}
+
+uint8_t* NativeImageSourceTizen::AcquireBuffer( uint16_t& width, uint16_t& height, uint16_t& stride )
+{
+  Dali::Mutex::ScopedLock lock( mMutex );
+  if( mTbmSurface != NULL )
+  {
+    tbm_surface_info_s info;
+
+    if( tbm_surface_map( mTbmSurface, TBM_SURF_OPTION_READ, &info) != TBM_SURFACE_ERROR_NONE )
+    {
+      DALI_LOG_ERROR( "Fail to map tbm_surface\n" );
+
+      width = 0;
+      height = 0;
+
+      return NULL;
+    }
+    tbm_surface_internal_ref( mTbmSurface );
+    mIsBufferAcquired = true;
+
+    stride = info.planes[0].stride;
+    width = mWidth;
+    height = mHeight;
+
+    return info.planes[0].ptr;
+  }
+  return NULL;
+}
+
+
+bool NativeImageSourceTizen::ReleaseBuffer()
+{
+  Dali::Mutex::ScopedLock lock( mMutex );
+  bool ret = false;
+  if( mTbmSurface != NULL )
+  {
+    ret = ( tbm_surface_unmap( mTbmSurface ) == TBM_SURFACE_ERROR_NONE );
+    if( !ret )
+    {
+      DALI_LOG_ERROR( "Fail to unmap tbm_surface\n" );
+    }
+    tbm_surface_internal_unref( mTbmSurface );
+    mIsBufferAcquired = false;
+  }
+  return ret;
+}
+
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
diff --git a/dali/internal/imaging/tizen/native-image-source-impl-tizen.h b/dali/internal/imaging/tizen/native-image-source-impl-tizen.h
new file mode 100755 (executable)
index 0000000..d40142c
--- /dev/null
@@ -0,0 +1,216 @@
+#ifndef DALI_INTERNAL_NATIVE_IMAGE_SOURCE_IMPL_TIZEN_H
+#define DALI_INTERNAL_NATIVE_IMAGE_SOURCE_IMPL_TIZEN_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <tbm_surface.h>
+#include <dali/devel-api/images/native-image-interface-extension.h>
+#include <dali/devel-api/threading/mutex.h>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/native-image-source.h>
+#include <dali/internal/imaging/common/native-image-source-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class EglGraphics;
+class EglImageExtensions;
+
+/**
+ * Dali internal NativeImageSource.
+ */
+class NativeImageSourceTizen: public Internal::Adaptor::NativeImageSource, public NativeImageInterface::Extension
+{
+public:
+
+  /**
+   * Create a new NativeImageSource internally.
+   * Depending on hardware the width and height may have to be a power of two.
+   * @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 tbm_surface_h or is empty
+   * @return A smart-pointer to a newly allocated image.
+   */
+  static NativeImageSourceTizen* New(uint32_t width,
+                          uint32_t height,
+                          Dali::NativeImageSource::ColorDepth depth,
+                          Any nativeImageSource);
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetNativeImageSource()
+   */
+  Any GetNativeImageSource() const override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetPixels()
+   */
+  bool GetPixels(std::vector<unsigned char> &pixbuf, uint32_t &width, uint32_t &height, Pixel::Format& pixelFormat ) const  override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::EncodeToFile(const std::string& )
+   */
+  bool EncodeToFile(const std::string& filename) const override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::SetSource( Any source )
+   */
+  void SetSource( Any source ) override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::IsColorDepthSupported( ColorDepth colorDepth )
+   */
+  bool IsColorDepthSupported( Dali::NativeImageSource::ColorDepth colorDepth ) override;
+
+  /**
+   * destructor
+   */
+  ~NativeImageSourceTizen() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GlExtensionCreate()
+   */
+  bool GlExtensionCreate() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GlExtensionDestroy()
+   */
+  void GlExtensionDestroy() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::TargetTexture()
+   */
+  uint32_t TargetTexture() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::PrepareTexture()
+   */
+  void PrepareTexture() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetWidth()
+   */
+  uint32_t GetWidth() const override
+  {
+    return mWidth;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetHeight()
+   */
+  uint32_t GetHeight() const override
+  {
+    return mHeight;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageSource::RequiresBlending()
+   */
+  bool RequiresBlending() const override
+  {
+    return mBlendingRequired;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetExtension()
+   */
+  NativeImageInterface::Extension* GetNativeImageInterfaceExtension() override
+  {
+    return this;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageInterface::Extension::GetCustomFragmentPreFix()
+   */
+  const char* GetCustomFragmentPreFix() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::Extension::GetCustomSamplerTypename()
+   */
+  const char* GetCustomSamplerTypename() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::Extension::GetEglImageTextureTarget()
+   */
+  int GetEglImageTextureTarget() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::NativeImageSource::AcquireBuffer()
+   */
+  uint8_t* AcquireBuffer( uint16_t& width, uint16_t& height, uint16_t& stride ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::NativeImageSource::ReleaseBuffer()
+   */
+  bool ReleaseBuffer() override;
+
+private:
+
+  /**
+   * Private constructor; @see NativeImageSource::New()
+   * @param[in] width The width of the image.
+   * @param[in] height The height of the image.
+   * @param[in] colour depth of the image.
+   * @param[in] nativeImageSource contains either: pixmap of type X11 Pixmap , a Ecore_X_Pixmap or is empty
+   */
+  NativeImageSourceTizen(uint32_t width,
+              unsigned  int height,
+              Dali::NativeImageSource::ColorDepth depth,
+              Any nativeImageSource);
+
+  void Initialize();
+
+  tbm_surface_h GetSurfaceFromAny( Any source ) const;
+
+  bool CheckBlending( tbm_format format );
+
+  void DestroySurface();
+
+private:
+
+  uint32_t mWidth;                        ///< image width
+  uint32_t mHeight;                       ///< image height
+  bool mOwnTbmSurface;                        ///< Whether we created pixmap or not
+  tbm_surface_h mTbmSurface;
+  tbm_format mTbmFormat;
+  bool mBlendingRequired;                      ///< Whether blending is required
+  Dali::NativeImageSource::ColorDepth mColorDepth;  ///< color depth of image
+  void* mEglImageKHR;                         ///< From EGL extension
+  EglGraphics* mEglGraphics;                  ///< EGL Graphics
+  EglImageExtensions* mEglImageExtensions;    ///< The EGL Image Extensions
+  bool mSetSource;
+  mutable Dali::Mutex mMutex;
+  bool mIsBufferAcquired;                      ///< Whether AcquireBuffer is called
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_NATIVE_IMAGE_SOURCE_IMPL_TIZEN_H
diff --git a/dali/internal/imaging/tizen/native-image-source-queue-impl-tizen.cpp b/dali/internal/imaging/tizen/native-image-source-queue-impl-tizen.cpp
new file mode 100644 (file)
index 0000000..e7fa554
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/imaging/tizen/native-image-source-queue-impl-tizen.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/gl-defines.h>
+#include <tbm_surface_internal.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/common/egl-image-extensions.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+#define TBM_SURFACE_QUEUE_SIZE  3
+
+const char* FRAGMENT_PREFIX = "#extension GL_OES_EGL_image_external:require\n";
+const char* SAMPLER_TYPE = "samplerExternalOES";
+
+int FORMATS_BLENDING_REQUIRED[] = {
+  TBM_FORMAT_ARGB4444, TBM_FORMAT_ABGR4444,
+  TBM_FORMAT_RGBA4444, TBM_FORMAT_BGRA4444,
+  TBM_FORMAT_RGBX5551, TBM_FORMAT_BGRX5551,
+  TBM_FORMAT_ARGB1555, TBM_FORMAT_ABGR1555,
+  TBM_FORMAT_RGBA5551, TBM_FORMAT_BGRA5551,
+  TBM_FORMAT_ARGB8888, TBM_FORMAT_ABGR8888,
+  TBM_FORMAT_RGBA8888, TBM_FORMAT_BGRA8888,
+  TBM_FORMAT_ARGB2101010, TBM_FORMAT_ABGR2101010,
+  TBM_FORMAT_RGBA1010102, TBM_FORMAT_BGRA1010102
+};
+
+const int NUM_FORMATS_BLENDING_REQUIRED = 18;
+
+}
+
+NativeImageSourceQueueTizen* NativeImageSourceQueueTizen::New( uint32_t width, uint32_t height, Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue )
+{
+  NativeImageSourceQueueTizen* image = new NativeImageSourceQueueTizen( width, height, depth, nativeImageSourceQueue );
+  DALI_ASSERT_DEBUG( image && "NativeImageSourceQueueTizen allocation failed." );
+
+  if( image )
+  {
+    image->Initialize( depth );
+  }
+
+  return image;
+}
+
+NativeImageSourceQueueTizen::NativeImageSourceQueueTizen( uint32_t width, uint32_t height, Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue )
+: mMutex(),
+  mWidth( width ),
+  mHeight( height ),
+  mTbmQueue( NULL ),
+  mConsumeSurface( NULL ),
+  mEglImages(),
+  mEglGraphics( NULL ),
+  mEglImageExtensions( NULL ),
+  mOwnTbmQueue( false ),
+  mBlendingRequired( false )
+{
+  DALI_ASSERT_ALWAYS( Adaptor::IsAvailable() );
+
+  GraphicsInterface* graphics = &( Adaptor::GetImplementation( Adaptor::Get() ).GetGraphicsInterface() );
+  mEglGraphics = static_cast<EglGraphics *>(graphics);
+
+  mTbmQueue = GetSurfaceFromAny( nativeImageSourceQueue );
+
+  if( mTbmQueue != NULL )
+  {
+    mBlendingRequired = CheckBlending( tbm_surface_queue_get_format( mTbmQueue ) );
+    mWidth = tbm_surface_queue_get_width( mTbmQueue );
+    mHeight = tbm_surface_queue_get_height( mTbmQueue );
+  }
+}
+
+NativeImageSourceQueueTizen::~NativeImageSourceQueueTizen()
+{
+  if( mOwnTbmQueue )
+  {
+    if( mTbmQueue != NULL )
+    {
+      tbm_surface_queue_destroy( mTbmQueue );
+    }
+  }
+}
+
+void NativeImageSourceQueueTizen::Initialize( Dali::NativeImageSourceQueue::ColorDepth depth )
+{
+  if( mWidth == 0 || mHeight == 0 )
+  {
+    return;
+  }
+
+  if( mTbmQueue == NULL )
+  {
+    int format = TBM_FORMAT_ARGB8888;
+
+    switch( depth )
+    {
+      case Dali::NativeImageSourceQueue::COLOR_DEPTH_DEFAULT:
+      case Dali::NativeImageSourceQueue::COLOR_DEPTH_32:
+      {
+        format = TBM_FORMAT_ARGB8888;
+        mBlendingRequired = true;
+        break;
+      }
+      case Dali::NativeImageSourceQueue::COLOR_DEPTH_24:
+      {
+        format = TBM_FORMAT_RGB888;
+        mBlendingRequired = false;
+        break;
+      }
+      default:
+      {
+        DALI_LOG_WARNING( "Wrong color depth.\n" );
+        return;
+      }
+    }
+
+    mTbmQueue = tbm_surface_queue_create( TBM_SURFACE_QUEUE_SIZE, mWidth, mHeight, format, 0 );
+    if( !mTbmQueue )
+    {
+      DALI_LOG_ERROR( "NativeImageSourceQueueTizen::Initialize: tbm_surface_queue_create is failed! [%p]\n", mTbmQueue );
+      return;
+    }
+
+    mOwnTbmQueue = true;
+  }
+}
+
+tbm_surface_queue_h NativeImageSourceQueueTizen::GetSurfaceFromAny( Any source ) const
+{
+  if( source.Empty() )
+  {
+    return NULL;
+  }
+
+  if( source.GetType() == typeid( tbm_surface_queue_h ) )
+  {
+    return AnyCast< tbm_surface_queue_h >( source );
+  }
+  else
+  {
+    return NULL;
+  }
+}
+
+Any NativeImageSourceQueueTizen::GetNativeImageSourceQueue() const
+{
+  return Any( mTbmQueue );
+}
+
+void NativeImageSourceQueueTizen::SetSize( uint32_t width, uint32_t height )
+{
+  Dali::Mutex::ScopedLock lock( mMutex );
+
+  tbm_surface_queue_reset( mTbmQueue, width, height, tbm_surface_queue_get_format( mTbmQueue ) );
+
+  mWidth = width;
+  mHeight = height;
+
+  ResetEglImageList();
+}
+
+bool NativeImageSourceQueueTizen::GlExtensionCreate()
+{
+  mEglImageExtensions = mEglGraphics->GetImageExtensions();
+  DALI_ASSERT_DEBUG( mEglImageExtensions );
+
+  return true;
+}
+
+void NativeImageSourceQueueTizen::GlExtensionDestroy()
+{
+  Dali::Mutex::ScopedLock lock( mMutex );
+
+  ResetEglImageList();
+}
+
+uint32_t NativeImageSourceQueueTizen::TargetTexture()
+{
+  return 0;
+}
+
+void NativeImageSourceQueueTizen::PrepareTexture()
+{
+  Dali::Mutex::ScopedLock lock( mMutex );
+
+  tbm_surface_h oldSurface = mConsumeSurface;
+
+  if( tbm_surface_queue_can_acquire( mTbmQueue, 0 ) )
+  {
+    if( tbm_surface_queue_acquire( mTbmQueue, &mConsumeSurface ) != TBM_SURFACE_QUEUE_ERROR_NONE )
+    {
+      DALI_LOG_ERROR( "Failed to aquire a tbm_surface\n" );
+      return;
+    }
+
+    if( oldSurface )
+    {
+      if( tbm_surface_internal_is_valid( oldSurface ) )
+      {
+        tbm_surface_queue_release( mTbmQueue, oldSurface );
+      }
+    }
+
+    if( mConsumeSurface )
+    {
+      bool existing = false;
+      for( auto&& iter : mEglImages )
+      {
+        if( iter.first == mConsumeSurface )
+        {
+          // Find the surface in the existing list
+          existing = true;
+          mEglImageExtensions->TargetTextureKHR( iter.second );
+          break;
+        }
+      }
+
+      if( !existing )
+      {
+        // Push the surface
+        tbm_surface_internal_ref( mConsumeSurface );
+
+        void* eglImageKHR = mEglImageExtensions->CreateImageKHR( reinterpret_cast< EGLClientBuffer >( mConsumeSurface ) );
+        mEglImageExtensions->TargetTextureKHR( eglImageKHR );
+
+        mEglImages.push_back( EglImagePair( mConsumeSurface, eglImageKHR) );
+      }
+    }
+  }
+}
+
+const char* NativeImageSourceQueueTizen::GetCustomFragmentPreFix()
+{
+  return FRAGMENT_PREFIX;
+}
+
+const char* NativeImageSourceQueueTizen::GetCustomSamplerTypename()
+{
+  return SAMPLER_TYPE;
+}
+
+int NativeImageSourceQueueTizen::GetEglImageTextureTarget()
+{
+  return GL_TEXTURE_EXTERNAL_OES;
+}
+
+void NativeImageSourceQueueTizen::ResetEglImageList()
+{
+  if( mConsumeSurface )
+  {
+    if( tbm_surface_internal_is_valid( mConsumeSurface ) )
+    {
+      tbm_surface_queue_release( mTbmQueue, mConsumeSurface );
+    }
+    mConsumeSurface = NULL;
+  }
+
+  for( auto&& iter : mEglImages )
+  {
+    mEglImageExtensions->DestroyImageKHR( iter.second );
+
+    tbm_surface_internal_unref( iter.first );
+  }
+  mEglImages.clear();
+}
+
+bool NativeImageSourceQueueTizen::CheckBlending( int format )
+{
+  for( int i = 0; i < NUM_FORMATS_BLENDING_REQUIRED; ++i )
+  {
+    if( format == FORMATS_BLENDING_REQUIRED[i] )
+    {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
diff --git a/dali/internal/imaging/tizen/native-image-source-queue-impl-tizen.h b/dali/internal/imaging/tizen/native-image-source-queue-impl-tizen.h
new file mode 100755 (executable)
index 0000000..88b27cb
--- /dev/null
@@ -0,0 +1,184 @@
+#ifndef DALI_INTERNAL_NATIVE_IMAGE_SOURCE_QUEUE_IMPL_TIZEN_H
+#define DALI_INTERNAL_NATIVE_IMAGE_SOURCE_QUEUE_IMPL_TIZEN_H
+
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/images/native-image-interface-extension.h>
+#include <dali/devel-api/threading/mutex.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <tbm_surface.h>
+#include <tbm_surface_queue.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/imaging/common/native-image-source-queue-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class EglGraphics;
+class EglImageExtensions;
+
+/**
+ * Dali internal NativeImageSource.
+ */
+class NativeImageSourceQueueTizen: public Internal::Adaptor::NativeImageSourceQueue, public NativeImageInterface::Extension
+{
+public:
+
+  /**
+   * Create a new NativeImageSourceQueueTizen internally.
+   * Depending on hardware the width and height may have to be a power of two.
+   * @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] nativeImageSourceQueue contains tbm_surface_queue_h or is empty
+   * @return A smart-pointer to a newly allocated image.
+   */
+  static NativeImageSourceQueueTizen* New( uint32_t width, uint32_t height, Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue );
+
+  /**
+   * @copydoc Dali::NativeImageSourceQueue::GetNativeImageSourceQueue()
+   */
+  Any GetNativeImageSourceQueue() const override;
+
+  /**
+   * @copydoc Dali::NativeImageSourceQueue::SetSize
+   */
+  void SetSize( uint32_t width, uint32_t height ) override;
+
+  /**
+   * destructor
+   */
+  ~NativeImageSourceQueueTizen() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionCreate()
+   */
+  bool GlExtensionCreate() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionDestroy()
+   */
+  void GlExtensionDestroy() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::TargetTexture()
+   */
+  uint32_t TargetTexture() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::PrepareTexture()
+   */
+  void PrepareTexture() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetWidth()
+   */
+  uint32_t GetWidth() const override
+  {
+    return mWidth;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetHeight()
+   */
+  uint32_t GetHeight() const override
+  {
+    return mHeight;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageInterface::RequiresBlending()
+   */
+  bool RequiresBlending() const override
+  {
+    return mBlendingRequired;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetExtension()
+   */
+  NativeImageInterface::Extension* GetNativeImageInterfaceExtension() override
+  {
+    return this;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageInterface::Extension::GetCustomFragmentPreFix()
+   */
+  const char* GetCustomFragmentPreFix() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::Extension::GetCustomSamplerTypename()
+   */
+  const char* GetCustomSamplerTypename() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::Extension::GetEglImageTextureTarget()
+   */
+  int GetEglImageTextureTarget() override;
+
+private:
+
+  /**
+   * Private constructor; @see NativeImageSourceQueue::New()
+   * @param[in] width The width of the image.
+   * @param[in] height The height of the image.
+   * @param[in] colour depth of the image.
+   * @param[in] nativeImageSourceQueue contains tbm_surface_queue_h or is empty
+   */
+  NativeImageSourceQueueTizen( uint32_t width, uint32_t height, Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue );
+
+  void Initialize( Dali::NativeImageSourceQueue::ColorDepth depth );
+
+  void ResetEglImageList();
+
+  tbm_surface_queue_h GetSurfaceFromAny( Any source ) const;
+
+  bool CheckBlending( int format );
+
+private:
+
+  typedef std::pair< tbm_surface_h, void* > EglImagePair;
+
+  Dali::Mutex                      mMutex;                ///< Mutex
+  uint32_t                         mWidth;                ///< image width
+  uint32_t                         mHeight;               ///< image height
+  tbm_surface_queue_h              mTbmQueue;             ///< Tbm surface queue handle
+  tbm_surface_h                    mConsumeSurface;       ///< The current tbm surface
+  std::vector< EglImagePair >      mEglImages;            ///< EGL Image vector
+  EglGraphics*                     mEglGraphics;          ///< EGL Graphics
+  EglImageExtensions*              mEglImageExtensions;   ///< The EGL Image Extensions
+  bool                             mOwnTbmQueue;          ///< Whether we created tbm queue
+  bool                             mBlendingRequired;     ///< Whether blending is required
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_NATIVE_IMAGE_SOURCE_QUEUE_IMPL_TIZEN_H
diff --git a/dali/internal/imaging/ubuntu-x11/native-image-source-factory-x.cpp b/dali/internal/imaging/ubuntu-x11/native-image-source-factory-x.cpp
new file mode 100644 (file)
index 0000000..42b6c39
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/imaging/ubuntu-x11/native-image-source-factory-x.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/imaging/ubuntu-x11/native-image-source-impl-x.h>
+#include <dali/internal/imaging/ubuntu-x11/native-image-source-queue-impl-x.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+std::unique_ptr< NativeImageSource > NativeImageSourceFactoryX::CreateNativeImageSource( uint32_t width, uint32_t height,
+                                                                                         Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
+{
+  return std::unique_ptr< NativeImageSource >( NativeImageSourceX::New( width, height, depth, nativeImageSource ) );
+}
+
+std::unique_ptr< NativeImageSourceQueue > NativeImageSourceFactoryX::CreateNativeImageSourceQueue( uint32_t width, uint32_t height,
+                                                                                                   Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue )
+{
+  return std::unique_ptr< NativeImageSourceQueue >( NativeImageSourceQueueX::New( width, height, depth, nativeImageSourceQueue ) );
+}
+
+// this should be created from somewhere
+std::unique_ptr< NativeImageSourceFactory > GetNativeImageSourceFactory()
+{
+  // returns native image source factory
+  return std::unique_ptr< NativeImageSourceFactoryX >( new NativeImageSourceFactoryX() );
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/dali/internal/imaging/ubuntu-x11/native-image-source-factory-x.h b/dali/internal/imaging/ubuntu-x11/native-image-source-factory-x.h
new file mode 100644 (file)
index 0000000..303d689
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef DALI_INTERNAL_NATIVE_IMAGE_SOURCE_FACTORY_X_H
+#define DALI_INTERNAL_NATIVE_IMAGE_SOURCE_FACTORY_X_H
+
+/*
+ * Copyright (c) 2018 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 <dali/internal/imaging/common/native-image-source-factory.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class NativeImageSourceFactoryX : public NativeImageSourceFactory
+{
+public:
+
+  std::unique_ptr< NativeImageSource > CreateNativeImageSource( uint32_t width, uint32_t height,
+                                                                Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource ) override;
+
+  std::unique_ptr< NativeImageSourceQueue > CreateNativeImageSourceQueue( uint32_t width, uint32_t height,
+                                                                          Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue ) override;
+
+};
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // DALI_INTERNAL_NATIVE_IMAGE_SOURCE_FACTORY_X_H
diff --git a/dali/internal/imaging/ubuntu-x11/native-image-source-impl-x.cpp b/dali/internal/imaging/ubuntu-x11/native-image-source-impl-x.cpp
new file mode 100755 (executable)
index 0000000..51c89d3
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/imaging/ubuntu-x11/native-image-source-impl-x.h>
+
+// EXTERNAL INCLUDES
+#include <dali/internal/system/linux/dali-ecore-x.h>
+#include <X11/Xutil.h>
+#include <X11/Xlib.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/common/egl-image-extensions.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/devel-api/adaptor-framework/bitmap-saver.h>
+#include <dali/integration-api/adaptor-framework/render-surface-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+using Dali::Integration::PixelBuffer;
+
+// Pieces needed to save compressed images (temporary location while plumbing):
+namespace
+{
+
+  /**
+   * Free an allocated XImage on destruction.
+   */
+  struct XImageJanitor
+  {
+    XImageJanitor( XImage* const  pXImage ) : mXImage( pXImage )
+    {
+      DALI_ASSERT_DEBUG(pXImage != 0 && "Null pointer to XImage.");
+    }
+
+    ~XImageJanitor()
+    {
+      if( mXImage )
+      {
+        if( !XDestroyImage(mXImage) )
+        {
+          DALI_LOG_ERROR("XImage deallocation failure");
+        }
+      }
+    }
+    XImage* const  mXImage;
+  private:
+    XImageJanitor( const XImageJanitor& rhs );
+    XImageJanitor& operator = ( const XImageJanitor& rhs );
+  };
+}
+
+NativeImageSourceX* NativeImageSourceX::New( uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
+{
+  NativeImageSourceX* image = new NativeImageSourceX( width, height, depth, nativeImageSource );
+  DALI_ASSERT_DEBUG( image && "NativeImageSource allocation failed." );
+
+  // 2nd phase construction
+  if(image) //< Defensive in case we ever compile without exceptions.
+  {
+    image->Initialize();
+  }
+
+  return image;
+}
+
+NativeImageSourceX::NativeImageSourceX( uint32_t width, uint32_t height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
+: mWidth( width ),
+  mHeight( height ),
+  mOwnPixmap( true ),
+  mPixmap( 0 ),
+  mBlendingRequired( false ),
+  mColorDepth( depth ),
+  mEglImageKHR( NULL ),
+  mEglImageExtensions( NULL )
+{
+  DALI_ASSERT_ALWAYS( Adaptor::IsAvailable() );
+
+  GraphicsInterface* graphics = &( Adaptor::GetImplementation( Adaptor::Get() ).GetGraphicsInterface() );
+  auto eglGraphics = static_cast<EglGraphics *>(graphics);
+
+  mEglImageExtensions = eglGraphics->GetImageExtensions();
+
+  DALI_ASSERT_DEBUG( mEglImageExtensions );
+
+  // assign the pixmap
+  mPixmap = GetPixmapFromAny(nativeImageSource);
+}
+
+void NativeImageSourceX::Initialize()
+{
+  // if pixmap has been created outside of X11 Image we can return
+  if (mPixmap)
+  {
+    // we don't own the pixmap
+    mOwnPixmap = false;
+
+    // find out the pixmap width / height and color depth
+    GetPixmapDetails();
+    return;
+  }
+
+  // get the pixel depth
+  int depth = GetPixelDepth(mColorDepth);
+
+  // set whether blending is required according to pixel format based on the depth
+  /* default pixel format is RGB888
+     If depth = 8, Pixel::A8;
+     If depth = 16, Pixel::RGB565;
+     If depth = 32, Pixel::RGBA8888 */
+  mBlendingRequired = ( depth == 32 || depth == 8 );
+
+  mPixmap = ecore_x_pixmap_new( 0, mWidth, mHeight, depth );
+  ecore_x_sync();
+}
+
+NativeImageSourceX::~NativeImageSourceX()
+{
+  if (mOwnPixmap && mPixmap)
+  {
+    ecore_x_pixmap_free(mPixmap);
+  }
+}
+
+Any NativeImageSourceX::GetNativeImageSource() const
+{
+  // return ecore x11 type
+  return Any(mPixmap);
+}
+
+bool NativeImageSourceX::GetPixels(std::vector<unsigned char>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
+{
+  DALI_ASSERT_DEBUG(sizeof(unsigned) == 4);
+  bool success = false;
+  width  = mWidth;
+  height = mHeight;
+
+  // Open a display connection
+  Display* displayConnection = XOpenDisplay( 0 );
+
+  XImageJanitor xImageJanitor( XGetImage( displayConnection,
+                                          mPixmap,
+                                          0, 0, // x,y of subregion to extract.
+                                          width, height, // of subregion to extract.
+                                          0xFFFFFFFF,
+                                          ZPixmap ) );
+  XImage* const  pXImage = xImageJanitor.mXImage;
+  DALI_ASSERT_DEBUG(pXImage && "XImage (from pixmap) could not be retrieved from the server");
+  if(!pXImage)
+  {
+    DALI_LOG_ERROR("Could not retrieve Ximage.\n");
+  }
+  else
+  {
+    switch(pXImage->depth)
+    {
+      // Note, depth is a logical value. On target the framebuffer is still 32bpp
+      // (see pXImage->bits_per_pixel) so we go through XGetPixel() and swizzle.
+      // Note, this could be the default, fallback case for all depths if *pXImage
+      // didn't have blank RGB masks (X bug), but we have to hardcode the masks and
+      // shifts instead.
+      case 24:
+      {
+        pixelFormat = Pixel::RGB888;
+        pixbuf.resize(width*height*3);
+        unsigned char* bufPtr = &pixbuf[0];
+
+        for(unsigned y = height-1; y < height; --y)
+        {
+          for(unsigned x = 0; x < width; ++x, bufPtr+=3)
+          {
+            const unsigned pixel = XGetPixel(pXImage,x,y);
+
+            // store as RGB
+            const unsigned blue  =  pixel & 0xFFU;
+            const unsigned green = (pixel >> 8)  & 0xFFU;
+            const unsigned red   = (pixel >> 16) & 0xFFU;
+
+            *bufPtr = red;
+            *(bufPtr+1) = green;
+            *(bufPtr+2) = blue;
+          }
+        }
+        success = true;
+        break;
+      }
+      case 32:
+      {
+        if(pXImage->data)
+        {
+          // Sweep through the image, doing a vertical flip, but handling each scanline as
+          // an inlined intrinsic/builtin memcpy (should be fast):
+          pixbuf.resize(width*height*4);
+          unsigned * bufPtr = reinterpret_cast<unsigned *>(&pixbuf[0]);
+          const unsigned xDataLineSkip = pXImage->bytes_per_line;
+          const size_t copy_count = static_cast< size_t >( width ) * 4;
+          pixelFormat = Pixel::BGRA8888;
+
+          for(unsigned y = height-1; y < height; --y, bufPtr += width)
+          {
+            const char * const in = pXImage->data + xDataLineSkip * y;
+
+            // Copy a whole scanline at a time:
+            DALI_ASSERT_DEBUG( size_t( bufPtr ) >= size_t( &pixbuf[0] ));
+            DALI_ASSERT_DEBUG( reinterpret_cast<size_t>( bufPtr ) + copy_count <= reinterpret_cast<size_t>( &pixbuf[pixbuf.size()] ) );
+            DALI_ASSERT_DEBUG( in >= pXImage->data );
+            DALI_ASSERT_DEBUG( in + copy_count <= pXImage->data + xDataLineSkip * height );
+            __builtin_memcpy( bufPtr, in, copy_count );
+          }
+          success = true;
+        }
+        else
+        {
+          DALI_LOG_ERROR("XImage has null data pointer.\n");
+        }
+        break;
+      }
+      // Make a case for 16 bit modes especially to remember that the only reason we don't support them is a bug in X:
+      case 16:
+      {
+        DALI_ASSERT_DEBUG(pXImage->red_mask && pXImage->green_mask && pXImage->blue_mask && "No image masks mean 16 bit modes are not possible.");
+        ///! If the above assert doesn't fail in a debug build, the X bug may have been fixed, so revisit this function.
+        ///! No break, fall through to the general unsupported format warning below.
+      }
+      default:
+      {
+        DALI_LOG_WARNING("Pixmap has unsupported bit-depth for getting pixels: %u\n", pXImage->depth);
+      }
+    }
+  }
+  if(!success)
+  {
+    DALI_LOG_ERROR("Failed to get pixels from NativeImageSource.\n");
+    pixbuf.resize(0);
+    width = 0;
+    height = 0;
+  }
+
+  // Close the display connection
+  XCloseDisplay( displayConnection );
+
+  return success;
+}
+
+bool NativeImageSourceX::EncodeToFile(const std::string& filename) const
+{
+  std::vector< unsigned char > pixbuf;
+  unsigned int width(0), height(0);
+  Pixel::Format pixelFormat;
+
+  if(GetPixels(pixbuf, width, height, pixelFormat))
+  {
+    return Dali::EncodeToFile(&pixbuf[0], filename, pixelFormat, width, height);
+  }
+  return false;
+}
+
+void NativeImageSourceX::SetSource( Any source )
+{
+  mPixmap = GetPixmapFromAny( source );
+
+  if (mPixmap)
+  {
+    // we don't own the pixmap
+    mOwnPixmap = false;
+
+    // find out the pixmap width / height and color depth
+    GetPixmapDetails();
+  }
+}
+
+bool NativeImageSourceX::IsColorDepthSupported( Dali::NativeImageSource::ColorDepth colorDepth )
+{
+  return true;
+}
+
+bool NativeImageSourceX::GlExtensionCreate()
+{
+  // if the image existed previously delete it.
+  if (mEglImageKHR != NULL)
+  {
+    GlExtensionDestroy();
+  }
+
+  // casting from an unsigned int to a void *, which should then be cast back
+  // to an unsigned int in the driver.
+  EGLClientBuffer eglBuffer = reinterpret_cast< EGLClientBuffer > (mPixmap);
+
+  mEglImageKHR = mEglImageExtensions->CreateImageKHR( eglBuffer );
+
+  return mEglImageKHR != NULL;
+}
+
+void NativeImageSourceX::GlExtensionDestroy()
+{
+  mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
+
+  mEglImageKHR = NULL;
+}
+
+uint32_t NativeImageSourceX::TargetTexture()
+{
+  mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
+
+  return 0;
+}
+
+void NativeImageSourceX::PrepareTexture()
+{
+}
+
+int NativeImageSourceX::GetPixelDepth(Dali::NativeImageSource::ColorDepth depth) const
+{
+  switch (depth)
+  {
+    case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
+    {
+      // Get the default screen depth
+      return ecore_x_default_depth_get(ecore_x_display_get(), ecore_x_default_screen_get());
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_8:
+    {
+      return 8;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_16:
+    {
+      return 16;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_24:
+    {
+      return 24;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_32:
+    {
+      return 32;
+    }
+    default:
+    {
+      DALI_ASSERT_DEBUG(0 && "unknown color enum");
+      return 0;
+    }
+  }
+}
+
+Ecore_X_Pixmap NativeImageSourceX::GetPixmapFromAny(Any pixmap) const
+{
+  if (pixmap.Empty())
+  {
+    return 0;
+  }
+
+  // see if it is of type x11 pixmap
+  if (pixmap.GetType() == typeid (Pixmap))
+  {
+    // get the x pixmap type
+    Pixmap xpixmap = AnyCast<Pixmap>(pixmap);
+
+    // cast it to a ecore pixmap type
+    return static_cast<Ecore_X_Pixmap>(xpixmap);
+  }
+  else
+  {
+    return AnyCast<Ecore_X_Pixmap>(pixmap);
+  }
+}
+
+void NativeImageSourceX::GetPixmapDetails()
+{
+  int x, y;
+
+  // get the width, height and depth
+  ecore_x_pixmap_geometry_get( mPixmap, &x, &y, reinterpret_cast< int* >( &mWidth ), reinterpret_cast< int* >( &mHeight ) );
+
+  // set whether blending is required according to pixel format based on the depth
+  /* default pixel format is RGB888
+     If depth = 8, Pixel::A8;
+     If depth = 16, Pixel::RGB565;
+     If depth = 32, Pixel::RGBA8888 */
+  int depth = ecore_x_pixmap_depth_get(mPixmap);
+  mBlendingRequired = ( depth == 32 || depth == 8 );
+}
+
+uint8_t* NativeImageSourceX::AcquireBuffer( uint16_t& width, uint16_t& height, uint16_t& stride )
+{
+  return NULL;
+}
+
+
+bool NativeImageSourceX::ReleaseBuffer()
+{
+  return false;
+}
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
diff --git a/dali/internal/imaging/ubuntu-x11/native-image-source-impl-x.h b/dali/internal/imaging/ubuntu-x11/native-image-source-impl-x.h
new file mode 100755 (executable)
index 0000000..5306938
--- /dev/null
@@ -0,0 +1,210 @@
+#ifndef DALI_INTERNAL_NATIVE_IMAGE_SOURCE_H
+#define DALI_INTERNAL_NATIVE_IMAGE_SOURCE_H
+
+/*
+ * Copyright (c) 2019 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/internal/system/linux/dali-ecore-x.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/common/graphics-interface.h>
+
+#include <dali/public-api/adaptor-framework/native-image-source.h>
+
+#include <dali/internal/imaging/common/native-image-source-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class EglImageExtensions;
+
+/**
+ * Dali internal NativeImageSource.
+ */
+class NativeImageSourceX : public Internal::Adaptor::NativeImageSource
+{
+public:
+
+  /**
+   * Create a new NativeImageSource internally.
+   * Depending on hardware the width and height may have to be a power of two.
+   * @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
+   * @return A smart-pointer to a newly allocated image.
+   */
+  static NativeImageSourceX* New( uint32_t width,
+                          uint32_t height,
+                          Dali::NativeImageSource::ColorDepth depth,
+                          Any nativeImageSource);
+  /**
+   * @copydoc Dali::NativeImageSource::GetNativeImageSource()
+   */
+  Any GetNativeImageSource() const override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetPixels()
+   */
+  bool GetPixels(std::vector<unsigned char> &pixbuf, uint32_t &width, uint32_t &height, Pixel::Format& pixelFormat ) const override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::EncodeToFile(const std::string& )
+   */
+  bool EncodeToFile(const std::string& filename) const override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::SetSource( Any source )
+   */
+  void SetSource( Any source ) override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::IsColorDepthSupported( ColorDepth colorDepth )
+   */
+  bool IsColorDepthSupported( Dali::NativeImageSource::ColorDepth colorDepth ) override;
+
+  /**
+   * destructor
+   */
+  ~NativeImageSourceX() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GlExtensionCreate()
+   */
+  bool GlExtensionCreate() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GlExtensionDestroy()
+   */
+  void GlExtensionDestroy() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::TargetTexture()
+   */
+  uint32_t TargetTexture() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::PrepareTexture()
+   */
+  void PrepareTexture() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetWidth()
+   */
+  uint32_t GetWidth() const override
+  {
+    return mWidth;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetHeight()
+   */
+  uint32_t GetHeight() const override
+  {
+    return mHeight;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageSource::RequiresBlending()
+   */
+  bool RequiresBlending() const override
+  {
+    return mBlendingRequired;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetExtension()
+   */
+  NativeImageInterface::Extension* GetNativeImageInterfaceExtension() override
+  {
+    return nullptr;
+  }
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::NativeImageSource::AcquireBuffer()
+   */
+  uint8_t* AcquireBuffer( uint16_t& width, uint16_t& height, uint16_t& stride ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::NativeImageSource::ReleaseBuffer()
+   */
+  bool ReleaseBuffer() override;
+
+private:
+
+  /**
+   * Private constructor; @see NativeImageSource::New()
+   * @param[in] width The width of the image.
+   * @param[in] height The height of the image.
+   * @param[in] colour depth of the image.
+   * @param[in] nativeImageSource contains either: pixmap of type X11 Pixmap , a Ecore_X_Pixmap or is empty
+   */
+  NativeImageSourceX( uint32_t width,
+              uint32_t height,
+              Dali::NativeImageSource::ColorDepth depth,
+              Any nativeImageSource);
+
+  /**
+   * 2nd phase construction.
+   */
+  void Initialize();
+
+  /**
+   * Uses X11 to get the default depth.
+   * @param depth the PixelImage depth enum
+   * @return default x11 pixel depth
+   */
+  int GetPixelDepth(Dali::NativeImageSource::ColorDepth depth) const;
+
+  /**
+   * Gets the pixmap from the Any parameter
+   * @param pixmap contains either: pixmap of type X11 Pixmap , a Ecore_X_Pixmap or is empty
+   * @return pixmap x11 pixmap
+   */
+  Ecore_X_Pixmap GetPixmapFromAny(Any pixmap) const;
+
+  /**
+   * Given an existing pixmap, the function uses X to find out
+   * the width, heigth and depth of that pixmap.
+   */
+  void GetPixmapDetails();
+
+private:
+
+  uint32_t mWidth;                            ///< image width
+  uint32_t mHeight;                           ///< image heights
+  bool mOwnPixmap;                            ///< Whether we created pixmap or not
+  Ecore_X_Pixmap mPixmap;                     ///< From Xlib
+  bool mBlendingRequired;                      ///< Whether blending is required
+  Dali::NativeImageSource::ColorDepth mColorDepth;  ///< color depth of image
+  void* mEglImageKHR;                         ///< From EGL extension
+  EglImageExtensions* mEglImageExtensions;    ///< The EGL Image Extensions
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_NATIVE_IMAGE_SOURCE_H
diff --git a/dali/internal/imaging/ubuntu-x11/native-image-source-queue-impl-x.cpp b/dali/internal/imaging/ubuntu-x11/native-image-source-queue-impl-x.cpp
new file mode 100644 (file)
index 0000000..4bd539b
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/imaging/ubuntu-x11/native-image-source-queue-impl-x.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/gl-defines.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/common/egl-image-extensions.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+#define TBM_SURFACE_QUEUE_SIZE  3
+
+const char* FRAGMENT_PREFIX = "\n";
+const char* SAMPLER_TYPE = "sampler2D";
+
+}
+
+NativeImageSourceQueueX* NativeImageSourceQueueX::New( uint32_t width, uint32_t height, Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue )
+{
+  NativeImageSourceQueueX* image = new NativeImageSourceQueueX( width, height, depth, nativeImageSourceQueue );
+  return image;
+}
+
+NativeImageSourceQueueX::NativeImageSourceQueueX( uint32_t width, uint32_t height, Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue )
+: mWidth( width ),
+  mHeight( height )
+{
+  DALI_LOG_ERROR( "NativeImageSourceQueueX::NativeImageSourceQueueX: Not supported\n" );
+}
+
+NativeImageSourceQueueX::~NativeImageSourceQueueX()
+{
+}
+
+Any NativeImageSourceQueueX::GetNativeImageSourceQueue() const
+{
+  return Any();
+}
+
+void NativeImageSourceQueueX::SetSize( uint32_t width, uint32_t height )
+{
+  mWidth = width;
+  mHeight = height;
+}
+
+bool NativeImageSourceQueueX::GlExtensionCreate()
+{
+  return true;
+}
+
+void NativeImageSourceQueueX::GlExtensionDestroy()
+{
+}
+
+uint32_t NativeImageSourceQueueX::TargetTexture()
+{
+  return 0;
+}
+
+void NativeImageSourceQueueX::PrepareTexture()
+{
+}
+
+const char* NativeImageSourceQueueX::GetCustomFragmentPreFix()
+{
+  return FRAGMENT_PREFIX;
+}
+
+const char* NativeImageSourceQueueX::GetCustomSamplerTypename()
+{
+  return SAMPLER_TYPE;
+}
+
+int NativeImageSourceQueueX::GetEglImageTextureTarget()
+{
+  return 0;
+}
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
diff --git a/dali/internal/imaging/ubuntu-x11/native-image-source-queue-impl-x.h b/dali/internal/imaging/ubuntu-x11/native-image-source-queue-impl-x.h
new file mode 100755 (executable)
index 0000000..c252bec
--- /dev/null
@@ -0,0 +1,163 @@
+#ifndef DALI_INTERNAL_NATIVE_IMAGE_SOURCE_QUEUE_IMPL_X_H
+#define DALI_INTERNAL_NATIVE_IMAGE_SOURCE_QUEUE_IMPL_X_H
+
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/images/native-image-interface-extension.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/imaging/common/native-image-source-queue-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class EglGraphics;
+class EglImageExtensions;
+
+/**
+ * Dali internal NativeImageSourceQueue.
+ */
+class NativeImageSourceQueueX: public Internal::Adaptor::NativeImageSourceQueue, public NativeImageInterface::Extension
+{
+public:
+
+  /**
+   * Create a new NativeImageSourceQueueX internally.
+   * Depending on hardware the width and height may have to be a power of two.
+   * @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] nativeImageSourceQueue contains tbm_surface_queue_h or is empty
+   * @return A smart-pointer to a newly allocated image.
+   */
+  static NativeImageSourceQueueX* New( uint32_t width, uint32_t height, Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue );
+
+  /**
+   * @copydoc Dali::NativeImageSourceQueue::GetNativeImageSourceQueue()
+   */
+  Any GetNativeImageSourceQueue() const override;
+
+  /**
+   * @copydoc Dali::NativeImageSourceQueue::SetSize
+   */
+  void SetSize( uint32_t width, uint32_t height ) override;
+
+  /**
+   * destructor
+   */
+  ~NativeImageSourceQueueX() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionCreate()
+   */
+  bool GlExtensionCreate() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionDestroy()
+   */
+  void GlExtensionDestroy() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::TargetTexture()
+   */
+  uint32_t TargetTexture() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::PrepareTexture()
+   */
+  void PrepareTexture() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetWidth()
+   */
+  uint32_t GetWidth() const override
+  {
+    return mWidth;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetHeight()
+   */
+  uint32_t GetHeight() const override
+  {
+    return mHeight;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageInterface::RequiresBlending()
+   */
+  bool RequiresBlending() const override
+  {
+    return true;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetExtension()
+   */
+  NativeImageInterface::Extension* GetNativeImageInterfaceExtension() override
+  {
+    return this;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageInterface::Extension::GetCustomFragmentPreFix()
+   */
+  const char* GetCustomFragmentPreFix() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::Extension::GetCustomSamplerTypename()
+   */
+  const char* GetCustomSamplerTypename() override;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::Extension::GetEglImageTextureTarget()
+   */
+  int GetEglImageTextureTarget() override;
+
+private:
+
+  /**
+   * Private constructor; @see NativeImageSourceQueue::New()
+   * @param[in] width The width of the image.
+   * @param[in] height The height of the image.
+   * @param[in] colour depth of the image.
+   * @param[in] nativeImageSourceQueue contains tbm_surface_queue_h or is empty
+   */
+  NativeImageSourceQueueX( uint32_t width, uint32_t height, Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue );
+
+private:
+
+  uint32_t    mWidth;                ///< image width
+  uint32_t    mHeight;               ///< image height
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_NATIVE_IMAGE_SOURCE_QUEUE_IMPL_X_H
diff --git a/dali/internal/imaging/windows/curl-environment-win.cpp b/dali/internal/imaging/windows/curl-environment-win.cpp
new file mode 100755 (executable)
index 0000000..8e4dbed
--- /dev/null
@@ -0,0 +1,50 @@
+/*\r
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// EXTERNAL INCLUDES\r
+#include <string>\r
+#include <curl/curl.h>\r
+\r
+#undef TRANSPARENT\r
+#undef CopyMemory\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali/internal/imaging/common/file-download.h>\r
+#include <dali/integration-api/debug.h>\r
+#include <dali/internal/system/common/file-closer.h>\r
+#include <dali/internal/window-system/windows/platform-implement-win.h>\r
+\r
+namespace Dali\r
+{\r
+\r
+namespace TizenPlatform\r
+{\r
+\r
+const int CONNECTION_TIMEOUT_SECONDS( 30L );\r
+const long VERBOSE_MODE = 0L;                // 0 == off, 1 == on\r
+const long CLOSE_CONNECTION_ON_ERROR = 1L;   // 0 == off, 1 == on\r
+const long EXCLUDE_HEADER = 0L;\r
+const long INCLUDE_HEADER = 1L;\r
+const long INCLUDE_BODY = 0L;\r
+const long EXCLUDE_BODY = 1L;\r
+\r
+namespace Network\r
+{\r
+\r
+}\r
+}\r
+}\r
diff --git a/dali/internal/imaging/windows/file-download-win.cpp b/dali/internal/imaging/windows/file-download-win.cpp
new file mode 100755 (executable)
index 0000000..3f7db68
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2018 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.
+ *
+ */
+
+// HEADER
+#include <dali/internal/imaging/common/file-download.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <pthread.h>
+#include <cstring>
+#include <curl/curl.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/file-writer.h>
+
+using namespace Dali::Integration;
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+namespace // unnamed namespace
+{
+
+const int CONNECTION_TIMEOUT_SECONDS( 30L );
+const long VERBOSE_MODE = 0L;                // 0 == off, 1 == on
+const long CLOSE_CONNECTION_ON_ERROR = 1L;   // 0 == off, 1 == on
+const long EXCLUDE_HEADER = 0L;
+const long INCLUDE_HEADER = 1L;
+const long INCLUDE_BODY = 0L;
+const long EXCLUDE_BODY = 1L;
+
+/**
+ * Curl library environment. Direct initialize ensures it's constructed before adaptor
+ * or application creates any threads.
+ */
+static Dali::TizenPlatform::Network::CurlEnvironment gCurlEnvironment;
+
+// Without a write function or a buffer (file descriptor) to write to, curl will pump out
+// header/body contents to stdout
+size_t __cdecl DummyWrite(char *ptr, size_t size, size_t nmemb, void *userdata)
+{
+  return size * nmemb;
+}
+
+struct ChunkData
+{
+  std::vector< uint8_t > data;
+};
+
+size_t __cdecl ChunkLoader(char *ptr, size_t size, size_t nmemb, void *userdata)
+{
+  std::vector<ChunkData>* chunks = static_cast<std::vector<ChunkData>*>( userdata );
+  int numBytes = size*nmemb;
+  if( chunks != nullptr )
+  {
+    chunks->push_back( ChunkData() );
+    ChunkData& chunkData = (*chunks)[chunks->size()-1];
+    chunkData.data.reserve( numBytes );
+    memcpy( chunkData.data.data(), ptr, numBytes );
+  }
+  return numBytes;
+}
+
+static size_t __cdecl WriteFunction( void *input, size_t uSize, size_t uCount, void *avg )
+{
+  fwrite( (const char*)input, uSize, uCount, (FILE*)avg );
+  return uSize * uCount;
+}
+
+void InitWriteFunction( void* curlHandle )
+{
+  curl_easy_setopt( curlHandle, CURLOPT_WRITEFUNCTION, WriteFunction );
+}
+
+CURLcode DownloadFileDataWithSize( CURL* curlHandle, Dali::Vector<uint8_t>& dataBuffer, size_t dataSize )
+{
+  CURLcode result( CURLE_OK );
+
+  // create
+  Dali::Internal::Platform::FileWriter fileWriter( dataBuffer, dataSize );
+  FILE* dataBufferFilePointer = fileWriter.GetFile();
+  if( nullptr != dataBufferFilePointer )
+  {
+    // we only want the body which contains the file data
+    curl_easy_setopt( curlHandle, CURLOPT_HEADER, EXCLUDE_HEADER );
+    curl_easy_setopt( curlHandle, CURLOPT_NOBODY, INCLUDE_BODY );
+
+    // disable the write callback, and get curl to write directly into our data buffer
+    InitWriteFunction( curlHandle );
+
+    curl_easy_setopt( curlHandle, CURLOPT_WRITEDATA, dataBufferFilePointer );
+
+    // synchronous request of the body data
+    result = curl_easy_perform( curlHandle );
+  }
+  return result;
+}
+
+CURLcode DownloadFileDataByChunk( CURL* curlHandle, Dali::Vector<uint8_t>& dataBuffer, size_t& dataSize )
+{
+  // create
+  std::vector< ChunkData > chunks;
+
+  // we only want the body which contains the file data
+  curl_easy_setopt( curlHandle, CURLOPT_HEADER, EXCLUDE_HEADER );
+  curl_easy_setopt( curlHandle, CURLOPT_NOBODY, INCLUDE_BODY );
+
+  // Enable the write callback.
+  curl_easy_setopt( curlHandle, CURLOPT_WRITEFUNCTION, ChunkLoader );
+  curl_easy_setopt( curlHandle, CURLOPT_WRITEDATA, &chunks );
+
+  // synchronous request of the body data
+  CURLcode result = curl_easy_perform( curlHandle );
+
+  // chunks should now contain all of the chunked data. Reassemble into a single vector
+  dataSize = 0;
+  for( size_t i=0; i<chunks.size() ; ++i )
+  {
+    dataSize += chunks[i].data.capacity();
+  }
+  dataBuffer.Resize(dataSize);
+
+  size_t offset = 0;
+  for( size_t i=0; i<chunks.size() ; ++i )
+  {
+    memcpy( &dataBuffer[offset], chunks[i].data.data(), chunks[i].data.capacity() ); 
+    offset += chunks[i].data.capacity();
+  }
+
+  return result;
+}
+
+void ConfigureCurlOptions( void* curlHandle, const std::string& url )
+{
+  curl_easy_setopt( curlHandle, CURLOPT_URL, url.c_str() );
+  //curl_easy_setopt( curlHandle, CURLOPT_VERBOSE, VERBOSE_MODE );
+  curl_easy_setopt( curlHandle, CURLOPT_PROXY, "109.123.100.31:3128" );
+
+  // CURLOPT_FAILONERROR is not fail-safe especially when authentication is involved ( see manual )
+  // Removed CURLOPT_FAILONERROR option
+  curl_easy_setopt( curlHandle, CURLOPT_CONNECTTIMEOUT, CONNECTION_TIMEOUT_SECONDS );
+  curl_easy_setopt( curlHandle, CURLOPT_HEADER, INCLUDE_HEADER );
+  curl_easy_setopt( curlHandle, CURLOPT_NOBODY, EXCLUDE_BODY );
+}
+
+bool DownloadFile( CURL* curlHandle,
+                   const std::string& url,
+                   Dali::Vector<uint8_t>& dataBuffer,
+                   size_t& dataSize,
+                   size_t maximumAllowedSizeBytes )
+{
+  CURLcode result( CURLE_OK );
+  double size(0);
+
+  // setup curl to download just the header so we can extract the content length
+  ConfigureCurlOptions( curlHandle, url );
+
+  curl_easy_setopt( curlHandle, CURLOPT_WRITEFUNCTION, DummyWrite);
+
+  // perform the request to get the header
+  result = curl_easy_perform( curlHandle );
+
+  if( result != CURLE_OK)
+  {
+    DALI_LOG_ERROR( "Failed to download http header for \"%s\" with error code %d\n", url.c_str(), result );
+    return false;
+  }
+
+  // get the content length, -1 == size is not known
+  curl_easy_getinfo( curlHandle,CURLINFO_CONTENT_LENGTH_DOWNLOAD , &size );
+
+
+  if( size >= maximumAllowedSizeBytes )
+  {
+    DALI_LOG_ERROR( "File content length %f > max allowed %zu \"%s\" \n", size, maximumAllowedSizeBytes, url.c_str() );
+    return false;
+  }
+  else if( size > 0 )
+  {
+    // If we know the size up front, allocate once and avoid chunk copies.
+    dataSize = static_cast<size_t>( size );
+    result = DownloadFileDataWithSize( curlHandle, dataBuffer, dataSize );
+  }
+  else
+  {
+    result = DownloadFileDataByChunk( curlHandle, dataBuffer, dataSize );
+  }
+
+  if( result != CURLE_OK )
+  {
+    DALI_LOG_ERROR( "Failed to download image file \"%s\" with error code %d\n", url.c_str(), result );
+    return false;
+  }
+  return true;
+}
+
+
+} // unnamed namespace
+
+
+namespace Network
+{
+
+CurlEnvironment::CurlEnvironment()
+{
+  // Must be called before we attempt any loads. e.g. by using curl_easy_init()
+  // and before we start any threads.
+  curl_global_init(CURL_GLOBAL_ALL);
+}
+
+CurlEnvironment::~CurlEnvironment()
+{
+  curl_global_cleanup();
+}
+
+bool DownloadRemoteFileIntoMemory( const std::string& url,
+                                   Dali::Vector<uint8_t>& dataBuffer,
+                                   size_t& dataSize,
+                                   size_t maximumAllowedSizeBytes )
+{
+  if( url.empty() )
+  {
+    DALI_LOG_WARNING("empty url requested \n");
+    return false;
+  }
+
+  // start a libcurl easy session, this internally calls curl_global_init, if we ever have more than one download
+  // thread we need to explicity call curl_global_init() on startup from a single thread.
+
+  CURL* curlHandle = curl_easy_init();
+
+  bool result = DownloadFile( curlHandle, url, dataBuffer,  dataSize, maximumAllowedSizeBytes);
+
+  // clean up session
+  curl_easy_cleanup( curlHandle );
+
+  return result;
+}
+
+} // namespace Network
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/dali/internal/imaging/windows/native-image-source-factory-win.cpp b/dali/internal/imaging/windows/native-image-source-factory-win.cpp
new file mode 100755 (executable)
index 0000000..aa1662f
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/imaging/windows/native-image-source-factory-win.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/imaging/windows/native-image-source-impl-win.h>
+#include <dali/internal/imaging/common/native-image-source-queue-impl.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+std::unique_ptr< NativeImageSource > NativeImageSourceFactoryWin::CreateNativeImageSource( unsigned int width, unsigned int height,
+                                                                                         Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
+{
+  return std::unique_ptr< NativeImageSource >( NativeImageSourceWin::New( width, height, depth, nativeImageSource ) );
+}
+
+std::unique_ptr< NativeImageSourceQueue > NativeImageSourceFactoryWin::CreateNativeImageSourceQueue( unsigned int width, unsigned int height,
+                                                                                                   Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue )
+{
+  return std::unique_ptr< NativeImageSourceQueue >( nullptr );
+}
+
+// this should be created from somewhere
+std::unique_ptr< NativeImageSourceFactory > GetNativeImageSourceFactory()
+{
+  // returns native image source factory
+  return std::unique_ptr< NativeImageSourceFactoryWin >( new NativeImageSourceFactoryWin() );
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/dali/internal/imaging/windows/native-image-source-factory-win.h b/dali/internal/imaging/windows/native-image-source-factory-win.h
new file mode 100755 (executable)
index 0000000..d4f289a
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef DALI_INTERNAL_NATIVE_IMAGE_SOURCE_FACTORY_X_H
+#define DALI_INTERNAL_NATIVE_IMAGE_SOURCE_FACTORY_X_H
+
+/*
+ * Copyright (c) 2018 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 <dali/internal/imaging/common/native-image-source-factory.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class NativeImageSourceFactoryWin : public NativeImageSourceFactory
+{
+public:
+
+  std::unique_ptr< NativeImageSource > CreateNativeImageSource( unsigned int width, unsigned int height,
+                                                                Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource ) override;
+
+  std::unique_ptr< NativeImageSourceQueue > CreateNativeImageSourceQueue( unsigned int width, unsigned int height,
+                                                                          Dali::NativeImageSourceQueue::ColorDepth depth, Any nativeImageSourceQueue ) override;
+
+};
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // DALI_INTERNAL_NATIVE_IMAGE_SOURCE_FACTORY_X_H
diff --git a/dali/internal/imaging/windows/native-image-source-impl-win.cpp b/dali/internal/imaging/windows/native-image-source-impl-win.cpp
new file mode 100755 (executable)
index 0000000..12db4fd
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/imaging/windows/native-image-source-impl-win.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/graphics/common/egl-image-extensions.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/window-system/windows/platform-implement-win.h>
+#include <dali/devel-api/adaptor-framework/bitmap-saver.h>
+#include <dali/integration-api/adaptor-framework/render-surface-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+using Dali::Integration::PixelBuffer;
+
+NativeImageSourceWin* NativeImageSourceWin::New(unsigned int width, unsigned int height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
+{
+  NativeImageSourceWin* image = new NativeImageSourceWin( width, height, depth, nativeImageSource );
+  DALI_ASSERT_DEBUG( image && "NativeImageSource allocation failed." );
+
+  // 2nd phase construction
+  if(image) //< Defensive in case we ever compile without exceptions.
+  {
+    image->Initialize();
+  }
+
+  return image;
+}
+
+NativeImageSourceWin::NativeImageSourceWin( unsigned int width, unsigned int height, Dali::NativeImageSource::ColorDepth depth, Any nativeImageSource )
+: mWidth( width ),
+  mHeight( height ),
+  mOwnPixmap( true ),
+  mPixmap( 0 ),
+  mBlendingRequired( false ),
+  mColorDepth( depth ),
+  mEglImageKHR( NULL ),
+  mEglImageExtensions( NULL )
+{
+  DALI_ASSERT_ALWAYS( Adaptor::IsAvailable() );
+
+  GraphicsInterface* graphics = &( Adaptor::GetImplementation( Adaptor::Get() ).GetGraphicsInterface() );
+  auto eglGraphics = static_cast<EglGraphics *>(graphics);
+
+  mEglImageExtensions = eglGraphics->GetImageExtensions();
+
+  DALI_ASSERT_DEBUG( mEglImageExtensions );
+
+  // assign the pixmap
+  mPixmap = GetPixmapFromAny(nativeImageSource);
+}
+
+void NativeImageSourceWin::Initialize()
+{
+  // if pixmap has been created outside of Windows Image we can return
+  if (mPixmap)
+  {
+    // we don't own the pixmap
+    mOwnPixmap = false;
+
+    // find out the pixmap width / height and color depth
+    GetPixmapDetails();
+    return;
+  }
+
+  // get the pixel depth
+  int depth = GetPixelDepth(mColorDepth);
+
+  // set whether blending is required according to pixel format based on the depth
+  /* default pixel format is RGB888
+     If depth = 8, Pixel::A8;
+     If depth = 16, Pixel::RGB565;
+     If depth = 32, Pixel::RGBA8888 */
+  mBlendingRequired = ( depth == 32 || depth == 8 );
+}
+
+NativeImageSourceWin::~NativeImageSourceWin()
+{
+}
+
+Any NativeImageSourceWin::GetNativeImageSource() const
+{
+  return Any(mPixmap);
+}
+
+bool NativeImageSourceWin::GetPixels(std::vector<uint8_t>& pixbuf, unsigned& width, unsigned& height, Pixel::Format& pixelFormat) const
+{
+  DALI_ASSERT_DEBUG(sizeof(unsigned) == 4);
+  bool success = false;
+  width  = mWidth;
+  height = mHeight;
+
+  return success;
+}
+
+bool NativeImageSourceWin::EncodeToFile(const std::string& filename) const
+{
+  std::vector< uint8_t > pixbuf;
+  uint32_t width(0), height(0);
+  Pixel::Format pixelFormat;
+
+  if(GetPixels(pixbuf, width, height, pixelFormat))
+  {
+    return Dali::EncodeToFile(&pixbuf[0], filename, pixelFormat, width, height);
+  }
+  return false;
+}
+
+void NativeImageSourceWin::SetSource( Any source )
+{
+  mPixmap = GetPixmapFromAny( source );
+
+  if (mPixmap)
+  {
+    // we don't own the pixmap
+    mOwnPixmap = false;
+
+    // find out the pixmap width / height and color depth
+    GetPixmapDetails();
+  }
+}
+
+bool NativeImageSourceWin::IsColorDepthSupported( Dali::NativeImageSource::ColorDepth colorDepth )
+{
+  return true;
+}
+
+bool NativeImageSourceWin::GlExtensionCreate()
+{
+  // if the image existed previously delete it.
+  if (mEglImageKHR != NULL)
+  {
+    GlExtensionDestroy();
+  }
+
+  // casting from an unsigned int to a void *, which should then be cast back
+  // to an unsigned int in the driver.
+  EGLClientBuffer eglBuffer = reinterpret_cast< EGLClientBuffer > (mPixmap);
+
+  mEglImageKHR = mEglImageExtensions->CreateImageKHR( eglBuffer );
+
+  return mEglImageKHR != NULL;
+}
+
+void NativeImageSourceWin::GlExtensionDestroy()
+{
+  mEglImageExtensions->DestroyImageKHR(mEglImageKHR);
+
+  mEglImageKHR = NULL;
+}
+
+unsigned int NativeImageSourceWin::TargetTexture()
+{
+  mEglImageExtensions->TargetTextureKHR(mEglImageKHR);
+
+  return 0;
+}
+
+void NativeImageSourceWin::PrepareTexture()
+{
+}
+
+int NativeImageSourceWin::GetPixelDepth(Dali::NativeImageSource::ColorDepth depth) const
+{
+  switch (depth)
+  {
+    case Dali::NativeImageSource::COLOR_DEPTH_DEFAULT:
+    {
+      return 32;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_8:
+    {
+      return 8;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_16:
+    {
+      return 16;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_24:
+    {
+      return 24;
+    }
+    case Dali::NativeImageSource::COLOR_DEPTH_32:
+    {
+      return 32;
+    }
+    default:
+    {
+      DALI_ASSERT_DEBUG(0 && "unknown color enum");
+      return 0;
+    }
+  }
+}
+
+unsigned int NativeImageSourceWin::GetPixmapFromAny(Any pixmap) const
+{
+  if (pixmap.Empty())
+  {
+    return 0;
+  }
+
+  // see if it is of type Windows pixmap
+  if (pixmap.GetType() == typeid ( unsigned int ))
+  {
+    // get the Windows pixmap type
+    unsigned int xpixmap = AnyCast<unsigned int>(pixmap);
+
+    // cast it to a Windows pixmap type
+    return static_cast<unsigned int>(xpixmap);
+  }
+  else
+  {
+    return AnyCast<unsigned int>(pixmap);
+  }
+}
+
+void NativeImageSourceWin::GetPixmapDetails()
+{
+}
+
+uint8_t* NativeImageSourceWin::AcquireBuffer( uint16_t& width, uint16_t& height, uint16_t& stride )
+{
+  return NULL;
+}
+
+
+bool NativeImageSourceWin::ReleaseBuffer()
+{
+  return false;
+}
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
diff --git a/dali/internal/imaging/windows/native-image-source-impl-win.h b/dali/internal/imaging/windows/native-image-source-impl-win.h
new file mode 100755 (executable)
index 0000000..6fe3fab
--- /dev/null
@@ -0,0 +1,205 @@
+#ifndef DALI_INTERNAL_NATIVE_IMAGE_SOURCE_H
+#define DALI_INTERNAL_NATIVE_IMAGE_SOURCE_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/adaptor-framework/native-image-source.h>
+
+#include <dali/internal/imaging/common/native-image-source-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class EglImageExtensions;
+
+/**
+ * Dali internal NativeImageSource.
+ */
+class NativeImageSourceWin : public Internal::Adaptor::NativeImageSource
+{
+public:
+
+  /**
+   * Create a new NativeImageSource internally.
+   * Depending on hardware the width and height may have to be a power of two.
+   * @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 Win32 Pixmap , a WinPixmap or is empty
+   * @return A smart-pointer to a newly allocated image.
+   */
+  static NativeImageSourceWin* New(unsigned int width,
+                          unsigned int height,
+                          Dali::NativeImageSource::ColorDepth depth,
+                          Any nativeImageSource);
+  /**
+   * @copydoc Dali::NativeImageSource::GetNativeImageSource()
+   */
+  Any GetNativeImageSource() const override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetPixels()
+   */
+  bool GetPixels(std::vector<unsigned char> &pixbuf, unsigned int &width, unsigned int &height, Pixel::Format& pixelFormat ) const override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::EncodeToFile(const std::string& )
+   */
+  bool EncodeToFile(const std::string& filename) const override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::SetSource( Any source )
+   */
+  void SetSource( Any source ) override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::IsColorDepthSupported( ColorDepth colorDepth )
+   */
+  bool IsColorDepthSupported( Dali::NativeImageSource::ColorDepth colorDepth ) override;
+
+  /**
+   * destructor
+   */
+  ~NativeImageSourceWin() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GlExtensionCreate()
+   */
+  bool GlExtensionCreate() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GlExtensionDestroy()
+   */
+  void GlExtensionDestroy() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::TargetTexture()
+   */
+  unsigned int TargetTexture() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::PrepareTexture()
+   */
+  void PrepareTexture() override;
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetWidth()
+   */
+  unsigned int GetWidth() const override
+  {
+    return mWidth;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageSource::GetHeight()
+   */
+  unsigned int GetHeight() const override
+  {
+    return mHeight;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageSource::RequiresBlending()
+   */
+  bool RequiresBlending() const override
+  {
+    return mBlendingRequired;
+  }
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetExtension()
+   */
+  NativeImageInterface::Extension* GetNativeImageInterfaceExtension() override
+  {
+    return nullptr;
+  }
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::NativeImageSource::AcquireBuffer()
+   */
+  uint8_t* AcquireBuffer( uint16_t& width, uint16_t& height, uint16_t& stride ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::NativeImageSource::ReleaseBuffer()
+   */
+  bool ReleaseBuffer() override;
+
+private:
+
+  /**
+   * Private constructor; @see NativeImageSource::New()
+   * @param[in] width The width of the image.
+   * @param[in] height The height of the image.
+   * @param[in] colour depth of the image.
+   * @param[in] nativeImageSource contains either: pixmap of type Win32 Pixmap , a WinPixmap or is empty
+   */
+  NativeImageSourceWin(unsigned int width,
+              unsigned  int height,
+              Dali::NativeImageSource::ColorDepth depth,
+              Any nativeImageSource);
+
+  /**
+   * 2nd phase construction.
+   */
+  void Initialize();
+
+  /**
+   * Uses X11 to get the default depth.
+   * @param depth the PixelImage depth enum
+   * @return default win32 pixel depth
+   */
+  int GetPixelDepth(Dali::NativeImageSource::ColorDepth depth) const;
+
+  /**
+   * Gets the pixmap from the Any parameter
+   * @param pixmap contains either: pixmap of type Win32 Pixmap , a WinPixmap or is empty
+   * @return pixmap x11 pixmap
+   */
+  unsigned int GetPixmapFromAny(Any pixmap) const;
+
+  /**
+   * Given an existing pixmap, the function uses X to find out
+   * the width, heigth and depth of that pixmap.
+   */
+  void GetPixmapDetails();
+
+private:
+
+  unsigned int mWidth;                        ///< image width
+  unsigned int mHeight;                       ///< image heights
+  bool mOwnPixmap;                            ///< Whether we created pixmap or not
+  unsigned int mPixmap;                       ///< From Windows
+  bool mBlendingRequired;                      ///< Whether blending is required
+  Dali::NativeImageSource::ColorDepth mColorDepth;  ///< color depth of image
+  void* mEglImageKHR;                         ///< From EGL extension
+  EglImageExtensions* mEglImageExtensions;    ///< The EGL Image Extensions
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_NATIVE_IMAGE_SOURCE_H
diff --git a/dali/internal/input/common/input-method-context-factory.h b/dali/internal/input/common/input-method-context-factory.h
new file mode 100755 (executable)
index 0000000..f000748
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef DALI_INTERNAL_INPUT_COMMON_INPUT_METHOD_CONTEXT_FACTORY_H
+#define DALI_INTERNAL_INPUT_COMMON_INPUT_METHOD_CONTEXT_FACTORY_H
+
+/*
+ * Copyright (c) 2018 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/internal/input/common/input-method-context-impl.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+namespace InputMethodContextFactory
+{
+
+// Factory function creating new InputMethodContext
+// Symbol exists but may be overriden during linking
+InputMethodContextPtr CreateInputMethodContext( Dali::Actor actor );
+
+}
+}
+}
+
+}
+
+#endif //DALI_INTERNAL_INPUT_COMMON_INPUT_METHOD_CONTEXT_FACTORY_H
diff --git a/dali/internal/input/common/input-method-context-impl.cpp b/dali/internal/input/common/input-method-context-impl.cpp
new file mode 100755 (executable)
index 0000000..3598bd0
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 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/internal/input/common/input-method-context-impl.h>
+#include <dali/internal/input/common/input-method-context-factory.h>
+#include <dali/internal/system/common/locale-utils.h>
+#include <dali/devel-api/common/singleton-service.h>
+
+namespace Dali
+{
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+InputMethodContextPtr InputMethodContext::New( Dali::Actor actor )
+{
+  return Dali::Internal::Adaptor::InputMethodContextFactory::CreateInputMethodContext( actor );
+}
+
+const std::string& InputMethodContext::GetSurroundingText() const
+{
+  static std::string str("");
+  return str;
+}
+
+InputMethodContext::InputMethodContext()
+: mBackupOperations( Operation::MAX_COUNT )
+{
+}
+
+void InputMethodContext::ApplyBackupOperations()
+{
+  // Items in mBackupOperations will be changed while the iteration
+  OperationList copiedList = mBackupOperations;
+
+  for( auto& operation : copiedList )
+  {
+    if( operation )
+    {
+      operation();
+    }
+  }
+}
+
+}
+}
+}
diff --git a/dali/internal/input/common/input-method-context-impl.h b/dali/internal/input/common/input-method-context-impl.h
new file mode 100755 (executable)
index 0000000..4125be2
--- /dev/null
@@ -0,0 +1,402 @@
+#ifndef DALI_INTERNAL_INPUT_COMMON_INPUT_METHOD_CONTEXT_IMPL_H
+#define DALI_INTERNAL_INPUT_COMMON_INPUT_METHOD_CONTEXT_IMPL_H
+
+/*
+ * Copyright (c) 2019 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 <functional>
+#include <memory>
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/integration-api/events/key-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/input-method-context.h>
+
+namespace Dali
+{
+
+class RenderSurface;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class InputMethodContext;
+typedef IntrusivePtr< InputMethodContext > InputMethodContextPtr;
+using ImfContext = void;
+
+class InputMethodContext : public Dali::BaseObject
+{
+
+public:
+
+  using ActivatedSignalType = Dali::InputMethodContext::ActivatedSignalType;
+  using KeyboardEventSignalType = Dali::InputMethodContext::KeyboardEventSignalType;
+  using StatusSignalType = Dali::InputMethodContext::StatusSignalType;
+  using VoidSignalType = Dali::InputMethodContext::VoidSignalType;
+  using KeyboardTypeSignalType = Dali::InputMethodContext::KeyboardTypeSignalType;
+  using LanguageChangedSignalType = Dali::InputMethodContext::LanguageChangedSignalType;
+  using KeyboardResizedSignalType = Dali::InputMethodContext::KeyboardResizedSignalType;
+  using ContentReceivedSignalType = Dali::InputMethodContext::ContentReceivedSignalType;
+
+public:
+
+  /**
+   * Create a new input method context instance.
+   */
+  static InputMethodContextPtr New( Dali::Actor actor );
+
+  /**
+   * Initialize the object.
+   */
+  virtual void Initialize() {}
+
+  /**
+   * Connect Callbacks required for InputMethodContext.
+   * If you don't connect InputMethodContext callbacks, you can't get the key events.
+   * The events are PreeditChanged, Commit, DeleteSurrounding and PrivateCommand.
+   */
+  virtual void ConnectCallbacks() {}
+
+  /**
+   * Disconnect Callbacks attached to input method context.
+   */
+  virtual void DisconnectCallbacks() {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::Finalize()
+   */
+  virtual void Finalize() {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::Activate()
+   */
+  virtual void Activate() {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::Deactivate()
+   */
+  virtual void Deactivate() {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::Reset()
+   */
+  virtual void Reset() {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetContext()
+   */
+  virtual ImfContext* GetContext() { return nullptr; }
+
+  /**
+   * @copydoc Dali::InputMethodContext::RestoreAfterFocusLost()
+   */
+  virtual bool RestoreAfterFocusLost() const { return false; }
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetRestoreAfterFocusLost()
+   */
+  virtual void SetRestoreAfterFocusLost( bool toggle ) {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::PreEditChanged()
+   */
+  virtual void PreEditChanged( void *data, ImfContext* imfContext, void *eventInfo ) {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::CommitReceived()
+   */
+  virtual void CommitReceived( void *data, ImfContext* imfContext, void *eventInfo ) {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::RetrieveSurrounding()
+   */
+  /*Eina_Bool*/
+  virtual bool RetrieveSurrounding( void *data, ImfContext* imfContext, char** text, int* cursorPosition ) { return false; }
+
+  /**
+   * @copydoc Dali::InputMethodContext::DeleteSurrounding()
+   */
+  virtual void DeleteSurrounding( void *data, ImfContext* imfContext, void *eventInfo ) {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::SendPrivateCommand()
+   */
+  virtual void SendPrivateCommand( void* data, ImfContext* imfContext, void* eventInfo ) {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::SendCommitContent()
+   */
+  virtual void SendCommitContent( void* data, ImfContext* imfContext, void* eventInfo ) {}
+
+  // Cursor related
+  /**
+   * @copydoc Dali::InputMethodContext::NotifyCursorPosition()
+   */
+  virtual void NotifyCursorPosition() {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetCursorPosition()
+   */
+  virtual void SetCursorPosition( unsigned int cursorPosition ) {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetCursorPosition()
+   */
+  virtual unsigned int GetCursorPosition() const { return 0; }
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetSurroundingText()
+   */
+  virtual void SetSurroundingText( const std::string& text ) {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetSurroundingText()
+   */
+  virtual const std::string& GetSurroundingText() const;
+
+  /**
+  * @copydoc Dali::InputMethodContext::NotifyTextInputMultiLine()
+  */
+  virtual void NotifyTextInputMultiLine( bool multiLine ) {}
+
+  /**
+  * @copydoc Dali::InputMethodContext::GetTextDirection()
+  */
+  virtual Dali::InputMethodContext::TextDirection GetTextDirection() { return Dali::InputMethodContext::TextDirection(); }
+
+  /**
+  * @copydoc Dali::InputMethodContext::GetInputMethodArea()
+  */
+  virtual Dali::Rect<int> GetInputMethodArea() { return Dali::Rect<int>(); }
+
+  /**
+  * @copydoc Dali::InputMethodContext::ApplyOptions()
+  */
+  virtual void ApplyOptions( const InputMethodOptions& options ) {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetInputPanelData()
+   */
+  virtual void SetInputPanelData( const std::string& data ) {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetInputPanelData()
+   */
+  virtual void GetInputPanelData( std::string& data ) {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetInputPanelState()
+   */
+  virtual Dali::InputMethodContext::State GetInputPanelState() { return Dali::InputMethodContext::State(); }
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetReturnKeyState()
+   */
+  virtual void SetReturnKeyState( bool visible ) {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::AutoEnableInputPanel()
+   */
+  virtual void AutoEnableInputPanel( bool enabled ) {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::ShowInputPanel()
+   */
+  virtual void ShowInputPanel() {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::HideInputPanel()
+   */
+  virtual void HideInputPanel() {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetKeyboardType()
+   */
+  virtual Dali::InputMethodContext::KeyboardType GetKeyboardType() { return Dali::InputMethodContext::KeyboardType(); }
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetInputPanelLocale()
+   */
+  virtual std::string GetInputPanelLocale() { return std::string(); }
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetContentMIMETypes()
+   */
+  virtual void SetContentMIMETypes( const std::string& mimeTypes ) {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::FilterEventKey()
+   */
+  virtual bool FilterEventKey( const Dali::KeyEvent& keyEvent ) { return false; }
+
+  /**
+   * @copydoc Dali::InputMethodContext::AllowTextPrediction()
+   */
+  virtual void AllowTextPrediction( bool prediction ) {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::IsTextPredictionAllowed()
+   */
+  virtual bool IsTextPredictionAllowed() const { return false; }
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetInputPanelLanguage()
+   */
+  virtual void SetInputPanelLanguage( Dali::InputMethodContext::InputPanelLanguage language ) {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetInputPanelLanguage()
+   */
+  virtual Dali::InputMethodContext::InputPanelLanguage GetInputPanelLanguage() const { return Dali::InputMethodContext::InputPanelLanguage(); }
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetInputPanelPosition()
+   */
+  virtual void SetInputPanelPosition( unsigned int x, unsigned int y ) {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetPreeditStyle()
+   */
+  virtual void GetPreeditStyle( Dali::InputMethodContext::PreEditAttributeDataContainer& attrs ) const {}
+
+public:  // Signals
+
+  /**
+   * @copydoc Dali::InputMethodContext::ActivatedSignal()
+   */
+  ActivatedSignalType& ActivatedSignal() { return mActivatedSignal; }
+
+  /**
+   * @copydoc Dali::InputMethodContext::EventReceivedSignal()
+   */
+  KeyboardEventSignalType& EventReceivedSignal() { return mEventSignal; }
+
+  /**
+   * @copydoc Dali::InputMethodContext::StatusChangedSignal()
+   */
+  StatusSignalType& StatusChangedSignal() { return mKeyboardStatusSignal; }
+
+  /**
+   * @copydoc Dali::InputMethodContext::ResizedSignal()
+   */
+  KeyboardResizedSignalType& ResizedSignal()  { return mKeyboardResizeSignal; }
+
+  /**
+   * @copydoc Dali::InputMethodContext::LanguageChangedSignal()
+   */
+  LanguageChangedSignalType& LanguageChangedSignal() { return mKeyboardLanguageChangedSignal; }
+
+  /**
+   * @copydoc Dali::InputMethodContext::KeyboardTypeChangedSignal()
+   */
+  KeyboardTypeSignalType& KeyboardTypeChangedSignal() { return mKeyboardTypeChangedSignal; }
+
+  /**
+   * @copydoc Dali::InputMethodContext::ContentReceivedSignal()
+   */
+  ContentReceivedSignalType& ContentReceivedSignal() { return mContentReceivedSignal; }
+
+public:
+
+  /**
+   * Constructor
+   */
+  InputMethodContext();
+
+  /**
+   * Destructor
+   */
+  ~InputMethodContext() override = default;
+
+private:
+
+  InputMethodContext( const InputMethodContext& ) = delete;
+  InputMethodContext& operator=( InputMethodContext& )  = delete;
+
+protected:
+  /**
+   * @brief Struct for providing Operation enumeration
+   */
+  struct Operation
+  {
+    enum Type
+    {
+      ALLOW_TEXT_PREDICTION = 0,
+      AUTO_ENABLE_INPUT_PANEL,
+      NOTIFY_TEXT_INPUT_MULTILINE,
+      SET_CONTENT_MIME_TYPES,
+      SET_INPUT_PANEL_DATA,
+      SET_INPUT_PANEL_LANGUAGE,
+      SET_INPUT_PANEL_POSITION,
+      SET_RETURN_KEY_STATE,
+      MAX_COUNT
+    };
+  };
+
+  using OperationList = std::vector< std::function<void()> >;
+
+  /**
+   * @brief Apply backup operations to the InputMethodContext
+   */
+  void ApplyBackupOperations();
+
+protected:
+
+  ActivatedSignalType        mActivatedSignal;
+  KeyboardEventSignalType    mEventSignal;
+  StatusSignalType           mKeyboardStatusSignal;
+  KeyboardResizedSignalType  mKeyboardResizeSignal;
+  LanguageChangedSignalType  mKeyboardLanguageChangedSignal;
+  KeyboardTypeSignalType     mKeyboardTypeChangedSignal;
+  ContentReceivedSignalType  mContentReceivedSignal;
+  OperationList              mBackupOperations;
+
+public:
+
+  inline static Internal::Adaptor::InputMethodContext& GetImplementation(Dali::InputMethodContext& inputMethodContext)
+  {
+    DALI_ASSERT_ALWAYS( inputMethodContext && "InputMethodContext handle is empty" );
+
+    BaseObject& handle = inputMethodContext.GetBaseObject();
+
+    return static_cast<Internal::Adaptor::InputMethodContext&>(handle);
+  }
+
+  inline static const Internal::Adaptor::InputMethodContext& GetImplementation(const Dali::InputMethodContext& inputMethodContext)
+  {
+    DALI_ASSERT_ALWAYS( inputMethodContext && "InputMethodContext handle is empty" );
+
+    const BaseObject& handle = inputMethodContext.GetBaseObject();
+
+    return static_cast<const Internal::Adaptor::InputMethodContext&>(handle);
+  }
+
+};
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_INPUT_COMMON_INPUT_METHOD_CONTEXT_IMPL_H
diff --git a/dali/internal/input/common/key-grab.cpp b/dali/internal/input/common/key-grab.cpp
new file mode 100644 (file)
index 0000000..d7b07c2
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/public-api/adaptor-framework/key-grab.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/window-system/common/window-impl.h>
+
+namespace Dali
+{
+
+namespace KeyGrab
+{
+
+bool GrabKeyTopmost( Window window, Dali::KEY daliKey )
+{
+  Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation( window );
+  return windowImpl.GrabKey( daliKey, TOPMOST );
+}
+
+bool UngrabKeyTopmost( Window window, Dali::KEY daliKey )
+{
+  Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation( window );
+  return windowImpl.UngrabKey( daliKey );
+}
+
+bool GrabKey( Window window, Dali::KEY daliKey, KeyGrabMode grabMode )
+{
+  Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation( window );
+  return windowImpl.GrabKey( daliKey, grabMode );
+}
+
+
+bool UngrabKey( Window window, Dali::KEY daliKey )
+{
+  Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation( window );
+  return windowImpl.UngrabKey( daliKey );
+}
+
+
+bool GrabKeyList( Window window, const Dali::Vector<Dali::KEY>& daliKeyVector, const Dali::Vector<KeyGrabMode>& grabModeVector, Dali::Vector<bool>& returnVector)
+{
+  Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation( window );
+  return windowImpl.GrabKeyList( daliKeyVector, grabModeVector, returnVector );
+}
+
+bool UngrabKeyList( Window window, const Dali::Vector<Dali::KEY>& daliKeyVector, Dali::Vector<bool>& returnVector)
+{
+  Dali::Internal::Adaptor::Window& windowImpl = Dali::GetImplementation( window );
+  return windowImpl.UngrabKeyList( daliKeyVector, returnVector );
+}
+
+} // namespace KeyGrab
+
+} // namespace Dali
+
diff --git a/dali/internal/input/common/key-impl.cpp b/dali/internal/input/common/key-impl.cpp
new file mode 100644 (file)
index 0000000..30c6893
--- /dev/null
@@ -0,0 +1,314 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/input/common/key-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dlfcn.h>
+#include <map>
+#include <string.h>
+#include <iostream>
+
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace KeyLookup
+{
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gKeyExtensionLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_KEY_EXTENSION");
+#endif
+
+// Path for loading extension keys
+#if _GLIBCXX_USE_CXX11_ABI
+const char* KEY_EXTENSION_PLUGIN_SO( "libdali-key-extension.so" );
+#else
+const char* KEY_EXTENSION_PLUGIN_SO( "libdali-key-extension-cxx03.so" );
+#endif
+
+class KeyMap
+{
+  public:
+
+  KeyMap():
+  mExtensionKeyLookupTable(NULL),
+  mPlugin(NULL),
+  mHandle(NULL),
+  mCreateKeyExtensionPluginPtr(NULL),
+  mDestroyKeyExtensionPluginPtr(NULL),
+  mLookup( cmpString ),
+  mExtensionLookup( cmpString ),
+  mExtensionLookupCount(0),
+  mIsLookupTableInitialized( false ),
+  mIsExtensionLookupTableInitialized( false )
+  {
+  }
+
+  ~KeyMap()
+  {
+    if( mHandle != NULL )
+    {
+      if( mDestroyKeyExtensionPluginPtr != NULL )
+      {
+        mDestroyKeyExtensionPluginPtr( mPlugin );
+      }
+
+      dlclose( mHandle );
+    }
+  }
+
+  int GetDaliKeyEnum( const char* keyName )
+  {
+    // If lookup table is not initialized, initialize lookup table
+    if( !mIsLookupTableInitialized )
+    {
+      InitializeLookupTable();
+    }
+
+    Lookup::const_iterator i = mLookup.find( keyName );
+
+    if( i == mLookup.end() )
+    {
+      // If cannot find target, find it at the extension
+      // If extension lookup table is not initialized, initialize extension lookup table
+      if( !mIsExtensionLookupTableInitialized )
+      {
+        InitializeExtensionLookupTable();
+      }
+
+      // Find at extension
+      i = mExtensionLookup.find( keyName );
+
+      if( i == mExtensionLookup.end() )
+      {
+        return -1;
+      }
+      else
+      {
+        return (*i).second.first;
+      }
+    }
+    else
+    {
+      return (*i).second.first;
+    }
+  }
+
+  const char* GetKeyName( int daliKeyCode )
+  {
+    // If lookup table is not initialized, initialize lookup table
+    if( !mIsLookupTableInitialized )
+    {
+      InitializeLookupTable();
+    }
+
+    for( size_t i = 0; i < KEY_LOOKUP_COUNT ; ++i )
+    {
+      if( KeyLookupTable[i].daliKeyCode == daliKeyCode )
+      {
+        return KeyLookupTable[i].keyName;
+      }
+    }
+
+    // If extension lookup table is not initialized, initialize extension lookup table
+    if( !mIsExtensionLookupTableInitialized )
+    {
+      InitializeExtensionLookupTable();
+    }
+
+    for( size_t i = 0; i < mExtensionLookupCount ; ++i )
+    {
+      if( mExtensionKeyLookupTable[i].daliKeyCode == daliKeyCode )
+      {
+        return mExtensionKeyLookupTable[i].keyName;
+      }
+    }
+
+    return NULL;
+  }
+
+  bool IsDeviceButton( const char* keyName )
+  {
+    // If lookup table is not initialized, initialize lookup table
+    if( !mIsLookupTableInitialized )
+    {
+      InitializeLookupTable();
+    }
+
+    Lookup::const_iterator i = mLookup.find( keyName );
+    if( i == mLookup.end() )
+    {
+      // If cannot find target, find it at the extension.
+      // If extension lookup table is not initialized, initialize extension lookup table
+      if( !mIsExtensionLookupTableInitialized )
+      {
+        InitializeExtensionLookupTable();
+      }
+
+      // Find at extension
+      i = mExtensionLookup.find( keyName );
+
+      if( i == mExtensionLookup.end() )
+      {
+        return false;
+      }
+      else
+      {
+        return (*i).second.second;
+      }
+    }
+    else
+    {
+      return (*i).second.second;
+    }
+
+    return false;
+  }
+
+
+  private:
+
+  void InitializeLookupTable()
+  {
+    // create the lookup
+    for( size_t i = 0; i < KEY_LOOKUP_COUNT ; ++i )
+    {
+      mLookup[ KeyLookupTable[i].keyName ] = DaliKeyType( KeyLookupTable[i].daliKeyCode, KeyLookupTable[i].deviceButton );
+    }
+
+    mIsLookupTableInitialized = true;
+  }
+
+  void InitializeExtensionLookupTable()
+  {
+    // Try to load extension keys
+    char* error = NULL;
+    mHandle = dlopen( KEY_EXTENSION_PLUGIN_SO, RTLD_NOW );
+    error = dlerror();
+
+    if( mHandle == NULL )
+    {
+      DALI_LOG_INFO( gKeyExtensionLogFilter, Debug::General, "Failed to get handle from libdali-key-extension.so\n" );
+      return;
+    }
+
+    if( error != NULL )
+    {
+      DALI_LOG_INFO( gKeyExtensionLogFilter, Debug::General, "dlopen got error: %s  \n", error );
+      return;
+    }
+
+    mCreateKeyExtensionPluginPtr = reinterpret_cast< CreateKeyExtensionPluginFunction >( dlsym( mHandle, "CreateKeyExtensionPlugin" ) );
+    if( mCreateKeyExtensionPluginPtr == NULL )
+    {
+      DALI_LOG_INFO( gKeyExtensionLogFilter, Debug::General, "Failed to get CreateKeyExtensionPlugin function\n" );
+      return;
+    }
+
+    mPlugin = mCreateKeyExtensionPluginPtr();
+    if( mPlugin == NULL )
+    {
+      DALI_LOG_INFO( gKeyExtensionLogFilter, Debug::General, "Failed to create plugin object\n" );
+      return;
+    }
+
+    mDestroyKeyExtensionPluginPtr = reinterpret_cast< DestroyKeyExtensionPluginFunction >( dlsym( mHandle, "DestroyKeyExtensionPlugin" ) );
+    if( mDestroyKeyExtensionPluginPtr == NULL )
+    {
+      DALI_LOG_INFO( gKeyExtensionLogFilter, Debug::General, "Failed to get DestroyKeyExtensionPlugin function\n" );
+      return;
+    }
+
+    mExtensionKeyLookupTable = mPlugin->GetKeyLookupTable();
+    mExtensionLookupCount = mPlugin->GetKeyLookupTableCount();
+
+    // Add extension keys to lookup
+    for( size_t i = 0; i < mExtensionLookupCount ; ++i )
+    {
+      mExtensionLookup[ mExtensionKeyLookupTable[i].keyName  ] = DaliKeyType( mExtensionKeyLookupTable[i].daliKeyCode, mExtensionKeyLookupTable[i].deviceButton );
+    }
+
+    mIsExtensionLookupTableInitialized = true;
+  }
+
+  /**
+   * compare function, to compare string by pointer
+   */
+  static bool cmpString( const char* a, const char* b)
+  {
+    return strcmp(a, b) < 0;
+  }
+
+  KeyExtensionPlugin::KeyLookup* mExtensionKeyLookupTable;                               ///< Lookup table for extension keys
+  Dali::KeyExtensionPlugin* mPlugin;                                                     ///< Key extension plugin handle
+  void* mHandle;                                                                         ///< Handle for the loaded library
+  typedef Dali::KeyExtensionPlugin* (*CreateKeyExtensionPluginFunction)();               ///< Type of function pointer to get KeyExtensionPlugin object
+  typedef void (*DestroyKeyExtensionPluginFunction)( Dali::KeyExtensionPlugin* plugin ); ///< Type of function pointer to delete KeyExtensionPlugin object
+  CreateKeyExtensionPluginFunction mCreateKeyExtensionPluginPtr;                         ///< Function pointer to get KeyExtensionPlugin object
+  DestroyKeyExtensionPluginFunction mDestroyKeyExtensionPluginPtr;                       ///< Function pointer to delete KeyExtensionPlugin object
+
+  typedef std::pair< int, bool > DaliKeyType;
+  typedef std::map<const char* /* key name */, DaliKeyType /* key code */, bool(*) ( char const* a, char const* b) > Lookup;
+  Lookup mLookup;
+  Lookup mExtensionLookup;
+  size_t mExtensionLookupCount;                                                          ///< count of extension lookup table
+  bool mIsLookupTableInitialized;                                                        ///< flag for basic lookup table initialization
+  bool mIsExtensionLookupTableInitialized;                                               ///< flag for extension lookup table initialization
+};
+KeyMap globalKeyLookup;
+
+} // un-named name space
+
+bool IsKey( const Dali::KeyEvent& keyEvent, Dali::KEY daliKey)
+{
+  int key = globalKeyLookup.GetDaliKeyEnum( keyEvent.keyPressedName.c_str() );
+  return daliKey == key;
+}
+
+bool IsDeviceButton( const char* keyName )
+{
+  return globalKeyLookup.IsDeviceButton( keyName );
+}
+
+const char* GetKeyName( Dali::KEY daliKey )
+{
+  return globalKeyLookup.GetKeyName( daliKey );
+}
+
+int GetDaliKeyCode( const char* keyName )
+{
+  return globalKeyLookup.GetDaliKeyEnum( keyName );
+}
+
+} // namespace KeyLookup
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/input/common/key-impl.h b/dali/internal/input/common/key-impl.h
new file mode 100644 (file)
index 0000000..2bc22b6
--- /dev/null
@@ -0,0 +1,83 @@
+#ifndef DALI_KEY_IMPL_H
+#define DALI_KEY_IMPL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/adaptor-framework/key.h>
+#include <dali/devel-api/adaptor-framework/key-extension-plugin.h>
+#include <dali/devel-api/adaptor-framework/key-devel.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Implementation of the Key matching
+ */
+namespace KeyLookup
+{
+
+struct KeyLookup
+{
+  const char* keyName;          ///< XF86 key name
+  const Dali::KEY daliKeyCode;  ///< Dali key code
+  const bool  deviceButton;     ///< Whether the key is from a button on the device
+};
+
+extern KeyLookup KeyLookupTable[];
+extern const std::size_t KEY_LOOKUP_COUNT;
+
+/**
+ * @copydoc Dali::IsKey()
+ */
+bool IsKey( const Dali::KeyEvent& keyEvent, Dali::KEY daliKey );
+
+/**
+ * Check if a the given key name string is a button on the device itself.
+ * @param keyName A pointer to the key name
+ * @return true if the key is matched, false if not
+ */
+bool IsDeviceButton( const char* keyName );
+
+/**
+ * Get a key name from a dali key code.
+ * @param daliKey The dali key code
+ * @return The key name. NULL if the daliKey does not exist in the supported key lookup table.
+ */
+const char* GetKeyName( Dali::KEY daliKey );
+
+/**
+ * @copydoc Dali::DevelKey::GetDaliKeyCode()
+ */
+int GetDaliKeyCode( const char* keyName );
+
+} // namespace KeyLookup
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_KEY_IMPL_H
diff --git a/dali/internal/input/common/keyboard.cpp b/dali/internal/input/common/keyboard.cpp
new file mode 100644 (file)
index 0000000..5731d39
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/devel-api/adaptor-framework/keyboard.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/window-system/common/window-system.h>
+
+namespace Dali
+{
+
+namespace Keyboard
+{
+
+bool SetRepeatInfo( float rate, float delay )
+{
+  return Dali::Internal::Adaptor::WindowSystem::SetKeyboardRepeatInfo( rate, delay );
+}
+
+bool GetRepeatInfo( float& rate, float& delay )
+{
+  return Dali::Internal::Adaptor::WindowSystem::GetKeyboardRepeatInfo( rate, delay );
+}
+
+} // namespace Keyboard
+
+} // namespace Dali
+
diff --git a/dali/internal/input/common/physical-keyboard-impl.cpp b/dali/internal/input/common/physical-keyboard-impl.cpp
new file mode 100644 (file)
index 0000000..ec7523a
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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
+
+// CLASS HEADER
+#include <dali/internal/input/common/physical-keyboard-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/common/singleton-service.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+Dali::PhysicalKeyboard PhysicalKeyboard::New()
+{
+  Dali::PhysicalKeyboard keyboardHandle;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    keyboardHandle = Dali::PhysicalKeyboard( new PhysicalKeyboard() );
+    service.Register( typeid( keyboardHandle ), keyboardHandle );
+  }
+
+  return keyboardHandle;
+}
+
+Dali::PhysicalKeyboard PhysicalKeyboard::Get()
+{
+  Dali::PhysicalKeyboard keyboardHandle;
+
+  Dali::SingletonService service = SingletonService::Get();
+  if ( service )
+  {
+    BaseHandle handle = service.GetSingleton( typeid( Dali::PhysicalKeyboard ) );
+    if( handle )
+    {
+      // If so, downcast the handle of singleton to focus manager
+      keyboardHandle = Dali::PhysicalKeyboard( dynamic_cast< PhysicalKeyboard* >( handle.GetObjectPtr() ) );
+    }
+  }
+
+  return keyboardHandle;
+}
+
+bool PhysicalKeyboard::IsAttached() const
+{
+  return mAttached;
+}
+
+void PhysicalKeyboard::KeyReceived( bool fromPhysicalKeyboard )
+{
+  if ( mAttached != fromPhysicalKeyboard )
+  {
+    mAttached = fromPhysicalKeyboard;
+
+    Dali::PhysicalKeyboard handle( this );
+    mStatusChangedSignal.Emit( handle );
+  }
+}
+
+PhysicalKeyboard::~PhysicalKeyboard()
+{
+}
+
+PhysicalKeyboard::PhysicalKeyboard()
+: mAttached( false )
+{
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/dali/internal/input/common/physical-keyboard-impl.h b/dali/internal/input/common/physical-keyboard-impl.h
new file mode 100644 (file)
index 0000000..7bf323b
--- /dev/null
@@ -0,0 +1,119 @@
+#ifndef DALI_INTERNAL_PHYSICAL_KEYBOARD_H
+#define DALI_INTERNAL_PHYSICAL_KEYBOARD_H
+
+/*
+ * Copyright (c) 2019 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/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/physical-keyboard.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class PhysicalKeyboard : public BaseObject
+{
+public:
+
+  /**
+   * Creates a new instance of the PhysicalKeyboard.
+   */
+  static Dali::PhysicalKeyboard New();
+
+  /**
+   * Gets the singleton instance of the Physical Keyboard.
+   */
+  static Dali::PhysicalKeyboard Get();
+
+  /**
+   * @copydoc Dali::PhysicalKeyboard::IsAttached()
+   */
+  bool IsAttached() const;
+
+  /**
+   * Should be called by the EventHandler when a key is received. If it's received from a physical
+   * keyboard then the parameter should be true.
+   * @param[in]  fromPhysicalKeyboard  true if received from a physical keyboard, false otherwise.
+   */
+  void KeyReceived( bool fromPhysicalKeyboard );
+
+  // Signals
+
+  /**
+   * @copydoc Dali::PhysicalKeyboard::StatusChangedSignal()
+   */
+  Dali::PhysicalKeyboard::PhysicalKeyboardSignalType& StatusChangedSignal() { return mStatusChangedSignal; }
+
+protected:
+
+  /**
+   * A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~PhysicalKeyboard();
+
+private:
+
+  // Undefined
+  PhysicalKeyboard( const PhysicalKeyboard& );
+  PhysicalKeyboard& operator=( PhysicalKeyboard& );
+
+  /**
+   * Constructor
+   */
+  PhysicalKeyboard();
+
+private:
+
+  Dali::PhysicalKeyboard::PhysicalKeyboardSignalType mStatusChangedSignal; ///< Status changed signal
+  bool mAttached; ///< true if the physical keyboard is attached, false otherwise
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline static Internal::Adaptor::PhysicalKeyboard& GetImplementation( PhysicalKeyboard& keyboard )
+{
+  DALI_ASSERT_ALWAYS( keyboard && "PhysicalKeyboard handle is empty" );
+
+  BaseObject& handle = keyboard.GetBaseObject();
+
+  return static_cast< Internal::Adaptor::PhysicalKeyboard& >( handle );
+}
+
+inline static const  Internal::Adaptor::PhysicalKeyboard& GetImplementation( const PhysicalKeyboard& keyboard )
+{
+  DALI_ASSERT_ALWAYS( keyboard && "PhysicalKeyboard handle is empty" );
+
+  const BaseObject& handle = keyboard.GetBaseObject();
+
+  return static_cast< const Internal::Adaptor::PhysicalKeyboard& >( handle );
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_PHYSICAL_KEYBOARD_H
diff --git a/dali/internal/input/common/virtual-keyboard-impl.h b/dali/internal/input/common/virtual-keyboard-impl.h
new file mode 100755 (executable)
index 0000000..da0fccb
--- /dev/null
@@ -0,0 +1,102 @@
+#ifndef DALI_INTERNAL_VIRTUAL_KEYBOARD_H
+#define DALI_INTERNAL_VIRTUAL_KEYBOARD_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/adaptor-framework/virtual-keyboard.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Implementation of the virtual keyboard namespace
+ */
+namespace VirtualKeyboard
+{
+
+/**
+ * @copydoc Dali::VirtualKeyboard::Show()
+ */
+void Show();
+
+/**
+ * @copydoc Dali::VirtualKeyboard::Hide()
+ */
+void Hide();
+
+/**
+ * @copydoc Dali::VirtualKeyboard::IsVisible()
+ */
+bool IsVisible();
+
+/**
+ * @copydoc Dali::VirtualKeyboard::ApplySettings()
+ */
+void ApplySettings( const Property::Map& settingsMap );
+
+/**
+ * @copydoc Dali::VirtualKeyboard::SetReturnKeyType()
+ */
+void SetReturnKeyType( const Dali::InputMethod::ButtonAction::Type type );
+
+/**
+ * @copydoc Dali::VirtualKeyboard::GetReturnKeyType()
+ */
+Dali::InputMethod::ButtonAction::Type GetReturnKeyType();
+
+/**
+ * @copydoc Dali::VirtualKeyboard::EnablePrediction()
+ */
+void EnablePrediction(const bool enable);
+
+/**
+ * @copydoc Dali::VirtualKeyboard::IsPredictionEnabled()
+ */
+bool IsPredictionEnabled();
+
+/**
+ * @copydoc Dali::VirtualKeyboard::GetSizeAndPosition()
+ */
+Rect<int> GetSizeAndPosition();
+
+/**
+ * @copydoc Dali::VirtualKeyboard::RotateKeyboard()
+ */
+void RotateTo(int angle);
+
+/**
+ * @copydoc Dali::VirtualKeyboard::GetTextDirection
+ */
+Dali::VirtualKeyboard::TextDirection GetTextDirection();
+
+} // namespace VirtualKeyboard
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_VIRTUAL_KEYBOARD_H
diff --git a/dali/internal/input/file.list b/dali/internal/input/file.list
new file mode 100644 (file)
index 0000000..3e447ce
--- /dev/null
@@ -0,0 +1,43 @@
+
+# module: input, backend: common
+SET( adaptor_input_common_src_files 
+    ${adaptor_input_dir}/common/input-method-context-impl.cpp 
+    ${adaptor_input_dir}/common/key-grab.cpp 
+    ${adaptor_input_dir}/common/key-impl.cpp 
+    ${adaptor_input_dir}/common/keyboard.cpp 
+    ${adaptor_input_dir}/common/physical-keyboard-impl.cpp 
+)
+
+# module: input, backend: tizen-wayland
+SET( adaptor_input_tizen_wayland_src_files 
+    ${adaptor_input_dir}/tizen-wayland/ecore-virtual-keyboard.cpp
+    ${adaptor_input_dir}/tizen-wayland/input-method-context-factory-ecore-wl.cpp 
+    ${adaptor_input_dir}/tizen-wayland/input-method-context-impl-ecore-wl.cpp 
+    ${adaptor_input_dir}/tizen-wayland/key-mapping-ecore-wl.cpp 
+    ${adaptor_input_dir}/tizen-wayland/virtual-keyboard-impl-ecore-wl.cpp
+)
+
+# module: input, backend: ubuntu-x11
+SET( adaptor_input_ubuntu_x11_src_files 
+    ${adaptor_input_dir}/tizen-wayland/ecore-virtual-keyboard.cpp
+    ${adaptor_input_dir}/ubuntu-x11/input-method-context-factory-x.cpp 
+    ${adaptor_input_dir}/ubuntu-x11/input-method-context-impl-x.cpp 
+    ${adaptor_input_dir}/ubuntu-x11/key-mapping-x.cpp 
+    ${adaptor_input_dir}/ubuntu-x11/virtual-keyboard-impl-x.cpp
+)
+
+# module: input, backend: generic
+SET( adaptor_input_generic_src_files
+    ${adaptor_input_dir}/generic/input-method-context-factory-generic.cpp
+    ${adaptor_input_dir}/generic/input-method-context-impl-generic.cpp
+    ${adaptor_input_dir}/generic/key-mapping-generic.cpp
+    ${adaptor_input_dir}/generic/virtual-keyboard-impl-generic.cpp
+)
+
+# module: input, backend: windows
+SET( adaptor_input_windows_src_files
+    ${adaptor_input_dir}/windows/input-method-context-factory-win.cpp
+    ${adaptor_input_dir}/windows/input-method-context-impl-win.cpp
+    ${adaptor_input_dir}/windows/key-mapping-win.cpp
+    ${adaptor_input_dir}/windows/virtual-keyboard-impl-win.cpp
+)
diff --git a/dali/internal/input/generic/input-method-context-factory-generic.cpp b/dali/internal/input/generic/input-method-context-factory-generic.cpp
new file mode 100644 (file)
index 0000000..d952a8a
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2019 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 <memory>
+
+// INTERNAL INCLUDES
+#include <dali/internal/input/common/input-method-context-factory.h>
+#include <dali/internal/input/generic/input-method-context-impl-generic.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class InputMethodContext;
+
+namespace InputMethodContextFactory
+{
+
+// InputMethodContext Factory to be implemented by the platform
+InputMethodContextPtr CreateInputMethodContext( Dali::Actor actor )
+{
+  return Dali::Internal::Adaptor::InputMethodContextGeneric::New( actor );
+}
+
+}
+
+}
+
+}
+
+}
diff --git a/dali/internal/input/generic/input-method-context-impl-generic.cpp b/dali/internal/input/generic/input-method-context-impl-generic.cpp
new file mode 100644 (file)
index 0000000..1da21dc
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/input/generic/input-method-context-impl-generic.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_INPUT_METHOD_CONTEXT");
+#endif
+}
+
+InputMethodContextPtr InputMethodContextGeneric::New( Dali::Actor actor )
+{
+  InputMethodContextPtr manager;
+
+  if( actor && Dali::Adaptor::IsAvailable() )
+  {
+    manager = new InputMethodContextGeneric( actor );
+  }
+
+  return manager;
+}
+
+void InputMethodContextGeneric::Finalize()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::Finalize\n" );
+  DisconnectCallbacks();
+}
+
+InputMethodContextGeneric::InputMethodContextGeneric( Dali::Actor actor )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::InputMethodContextGeneric\n" );
+  Initialize();
+}
+
+InputMethodContextGeneric::~InputMethodContextGeneric()
+{
+  Finalize();
+}
+
+void InputMethodContextGeneric::Initialize()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::Initialize\n" );
+}
+
+void InputMethodContextGeneric::ConnectCallbacks()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::ConnectCallbacks\n" );
+}
+
+void InputMethodContextGeneric::DisconnectCallbacks()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::DisconnectCallbacks\n" );
+}
+
+void InputMethodContextGeneric::Activate()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::Activate\n" );
+}
+
+void InputMethodContextGeneric::Deactivate()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::Deactivate\n" );
+}
+
+void InputMethodContextGeneric::Reset()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::Reset\n" );
+}
+
+ImfContext* InputMethodContextGeneric::GetContext()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::GetContext\n" );
+
+  return nullptr;
+}
+
+bool InputMethodContextGeneric::RestoreAfterFocusLost() const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::RestoreAfterFocusLost\n" );
+
+  return false;
+}
+
+void InputMethodContextGeneric::SetRestoreAfterFocusLost( bool toggle )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::SetRestoreAfterFocusLost\n" );
+}
+
+void InputMethodContextGeneric::PreEditChanged( void*, ImfContext* imfContext, void* event_info )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::PreEditChanged\n" );
+}
+
+void InputMethodContextGeneric::CommitReceived( void*, ImfContext* imfContext, void* event_info )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::CommitReceived\n" );
+}
+
+bool InputMethodContextGeneric::RetrieveSurrounding( void* data, ImfContext* imfContext, char** text, int* cursorPosition )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::RetrieveSurrounding\n" );
+  return false;
+}
+
+void InputMethodContextGeneric::DeleteSurrounding( void* data, ImfContext* imfContext, void* event_info )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::DeleteSurrounding\n" );
+}
+
+void InputMethodContextGeneric::SendPrivateCommand( void* data, ImfContext* imfContext, void* eventInfo )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::SendPrivateCommand\n" );
+}
+
+void InputMethodContextGeneric::SendCommitContent( void* data, ImfContext* imfContext, void* eventInfo )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::SendCommitContent\n" );
+}
+
+void InputMethodContextGeneric::NotifyCursorPosition()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::NotifyCursorPosition\n" );
+}
+
+void InputMethodContextGeneric::SetCursorPosition( unsigned int cursorPosition )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::SetCursorPosition\n" );
+}
+
+unsigned int InputMethodContextGeneric::GetCursorPosition() const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::GetCursorPosition\n" );
+
+  return 0;
+}
+
+void InputMethodContextGeneric::SetSurroundingText( const std::string& text )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::SetSurroundingText\n" );
+}
+
+const std::string& InputMethodContextGeneric::GetSurroundingText() const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::GetSurroundingText\n" );
+
+  return "";
+}
+
+void InputMethodContextGeneric::NotifyTextInputMultiLine( bool multiLine )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::NotifyTextInputMultiLine\n" );
+}
+
+Dali::InputMethodContext::TextDirection InputMethodContextGeneric::GetTextDirection()
+{
+  Dali::InputMethodContext::TextDirection direction ( Dali::InputMethodContext::LeftToRight );
+  return direction;
+}
+
+Rect<int> InputMethodContextGeneric::GetInputMethodArea()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::GetInputMethodArea\n" );
+
+  int xPos, yPos, width, height;
+
+  width = height = xPos = yPos = 0;
+  return Rect<int>(xPos,yPos,width,height);
+}
+
+void InputMethodContextGeneric::ApplyOptions( const InputMethodOptions& options )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::ApplyOptions\n" );
+}
+
+void InputMethodContextGeneric::SetInputPanelData( const std::string& data )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::SetInputPanelData\n" );
+}
+
+void InputMethodContextGeneric::GetInputPanelData( std::string& data )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::GetInputPanelData\n" );
+
+  data.assign( "" );
+}
+
+Dali::InputMethodContext::State InputMethodContextGeneric::GetInputPanelState()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::GetInputPanelState\n" );
+  return Dali::InputMethodContext::DEFAULT;
+}
+
+void InputMethodContextGeneric::SetReturnKeyState( bool visible )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::SetReturnKeyState\n" );
+}
+
+void InputMethodContextGeneric::AutoEnableInputPanel( bool enabled )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::AutoEnableInputPanel\n" );
+}
+
+void InputMethodContextGeneric::ShowInputPanel()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::ShowInputPanel\n" );
+}
+
+void InputMethodContextGeneric::HideInputPanel()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::HideInputPanel\n" );
+}
+
+Dali::InputMethodContext::KeyboardType InputMethodContextGeneric::GetKeyboardType()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::GetKeyboardType\n" );
+
+  return Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD;
+}
+
+std::string InputMethodContextGeneric::GetInputPanelLocale()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::GetInputPanelLocale\n" );
+
+  std::string locale = "";
+  return locale;
+}
+
+void InputMethodContextGeneric::SetContentMIMETypes( const std::string& mimeTypes )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::SetContentMIMETypes\n" );
+}
+
+bool InputMethodContextGeneric::FilterEventKey( const Dali::KeyEvent& keyEvent )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::FilterEventKey\n" );
+
+  return false;
+}
+
+void InputMethodContextGeneric::AllowTextPrediction( bool prediction )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::AllowTextPrediction\n" );
+}
+
+bool InputMethodContextGeneric::IsTextPredictionAllowed() const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::IsTextPredictionAllowed\n" );
+
+  return false;
+}
+
+void InputMethodContextGeneric::SetInputPanelLanguage( Dali::InputMethodContext::InputPanelLanguage language )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextGeneric::SetInputPanelLanguage\n" );
+}
+
+Dali::InputMethodContext::InputPanelLanguage InputMethodContextGeneric::GetInputPanelLanguage() const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelLanguage\n" );
+
+  return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
+}
+
+void InputMethodContextGeneric::SetInputPanelPosition( unsigned int x, unsigned int y )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetInputPanelPosition\n" );
+}
+
+void InputMethodContextGeneric::GetPreeditStyle( Dali::InputMethodContext::PreEditAttributeDataContainer& attrs ) const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetPreeditStyle\n" );
+  // Do Nothing
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/dali/internal/input/generic/input-method-context-impl-generic.h b/dali/internal/input/generic/input-method-context-impl-generic.h
new file mode 100644 (file)
index 0000000..693d8de
--- /dev/null
@@ -0,0 +1,294 @@
+#ifndef __DALI_INTERNAL_INPUT_METHOD_CONTEXT_IMPL_GENERIC_H
+#define __DALI_INTERNAL_INPUT_METHOD_CONTEXT_IMPL_GENERIC_H
+
+/*
+ * Copyright (c) 2019 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/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/input-method-context.h>
+#include <dali/internal/input/common/input-method-context-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief Satisfies input API requirements for platforms without input method context support
+ */
+class InputMethodContextGeneric : public Dali::Internal::Adaptor::InputMethodContext
+{
+public:
+  /**
+   * @brief Creates a new InputMethodContext handle
+   *
+   * @param[in] actor The actor that uses the new InputMethodContext instance.
+   * @return InputMethodContext pointer
+   */
+  static InputMethodContextPtr New( Dali::Actor actor );
+
+  /**
+   * Constructor
+   * @param[in] actor The actor that uses the new InputMethodContext instance.
+   */
+  explicit InputMethodContextGeneric( Dali::Actor actor );
+
+public:
+
+  /**
+   * @brief Initializes member data.
+   */
+  void Initialize() override;
+
+  /**
+   * Connect Callbacks required for InputMethodContext.
+   * If you don't connect InputMethodContext callbacks, you can't get the key events.
+   * The events are PreeditChanged, Commit and DeleteSurrounding.
+   */
+  void ConnectCallbacks() override;
+
+  /**
+   * Disconnect Callbacks attached to input method context.
+   */
+  void DisconnectCallbacks() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::Finalize()
+   */
+  void Finalize() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::Activate()
+   */
+  void Activate() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::Deactivate()
+   */
+  void Deactivate() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::Reset()
+   */
+  void Reset() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetContext()
+   */
+  ImfContext* GetContext() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::RestoreAfterFocusLost()
+   */
+  bool RestoreAfterFocusLost() const override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetRestoreAfterFocusLost()
+   */
+  void SetRestoreAfterFocusLost( bool toggle ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::PreEditChanged()
+   */
+  void PreEditChanged( void* data, ImfContext* imfContext, void* eventInfo ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::NotifyCursorPosition()
+   */
+  void CommitReceived( void* data, ImfContext* imfContext, void* eventInfo ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::NotifyCursorPosition()
+   */
+  bool RetrieveSurrounding( void* data, ImfContext* imfContext, char** text, int* cursorPosition ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::DeleteSurrounding()
+   */
+  void DeleteSurrounding( void* data, ImfContext* imfContext, void* eventInfo ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SendPrivateCommand()
+   */
+  void SendPrivateCommand( void* data, ImfContext* imfContext, void* eventInfo ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SendCommitContent()
+   */
+  void SendCommitContent( void* data, ImfContext* imfContext, void* eventInfo ) override;
+
+  // Cursor related
+  /**
+   * @copydoc Dali::InputMethodContext::NotifyCursorPosition()
+   */
+  void NotifyCursorPosition() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetCursorPosition()
+   */
+  void SetCursorPosition( unsigned int cursorPosition ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetCursorPosition()
+   */
+  unsigned int GetCursorPosition() const override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetSurroundingText()
+   */
+  void SetSurroundingText( const std::string& text ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetSurroundingText()
+   */
+  const std::string& GetSurroundingText() const override;
+
+  /**
+  * @copydoc Dali::InputMethodContext::NotifyTextInputMultiLine()
+  */
+  void NotifyTextInputMultiLine( bool multiLine ) override;
+
+  /**
+  * @copydoc Dali::InputMethodContext::GetTextDirection()
+  */
+  Dali::InputMethodContext::TextDirection GetTextDirection() override;
+
+  /**
+  * @copydoc Dali::InputMethodContext::GetInputMethodArea()
+  */
+  Dali::Rect<int> GetInputMethodArea() override;
+
+  /**
+  * @copydoc Dali::InputMethodContext::ApplyOptions()
+  */
+  void ApplyOptions( const InputMethodOptions& options ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetInputPanelData()
+   */
+  void SetInputPanelData( const std::string& data ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetInputPanelData()
+   */
+  void GetInputPanelData( std::string& data ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetInputPanelState()
+   */
+  Dali::InputMethodContext::State GetInputPanelState() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetReturnKeyState()
+   */
+  void SetReturnKeyState( bool visible ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::AutoEnableInputPanel()
+   */
+  void AutoEnableInputPanel( bool enabled ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::ShowInputPanel()
+   */
+  void ShowInputPanel() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::HideInputPanel()
+   */
+  void HideInputPanel() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetKeyboardType()
+   */
+  Dali::InputMethodContext::KeyboardType GetKeyboardType() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetInputPanelLocale()
+   */
+  std::string GetInputPanelLocale() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetContentMIMETypes()
+   */
+  void SetContentMIMETypes( const std::string& mimeTypes ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::FilterEventKey()
+   */
+  bool FilterEventKey( const Dali::KeyEvent& keyEvent ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::AllowTextPrediction()
+   */
+  void AllowTextPrediction( bool prediction ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::IsTextPredictionAllowed()
+   */
+  bool IsTextPredictionAllowed() const override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetInputPanelLanguage()
+   */
+  void SetInputPanelLanguage( Dali::InputMethodContext::InputPanelLanguage language ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetInputPanelLanguage()
+   */
+  Dali::InputMethodContext::InputPanelLanguage GetInputPanelLanguage() const override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetInputPanelPosition()
+   */
+  void SetInputPanelPosition( unsigned int x, unsigned int y ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetPreeditStyle()
+   */
+  void GetPreeditStyle( Dali::InputMethodContext::PreEditAttributeDataContainer& attrs ) const override;
+
+public:
+
+  /**
+   * Destructor.
+   */
+  virtual ~InputMethodContextGeneric();
+
+private:
+
+  // Undefined copy constructor
+  InputMethodContextGeneric( const InputMethodContextGeneric& inputMethodContext) = delete;
+
+  // Undefined assignment operator
+  InputMethodContextGeneric& operator=( const InputMethodContextGeneric& inputMethodContext ) = delete;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_INTERNAL_INPUT_METHOD_CONTEXT_IMPL_GENERIC_H
diff --git a/dali/internal/input/generic/key-mapping-generic.cpp b/dali/internal/input/generic/key-mapping-generic.cpp
new file mode 100644 (file)
index 0000000..0a7833e
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/input/common/key-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace KeyLookup
+{
+
+// matches a DALI_KEY enum, to a key name
+KeyLookup KeyLookupTable[]=
+{
+  // more than one key name can be assigned to a single dali-key code
+  // e.g. "Menu" and "XF86Menu" are both assigned to  DALI_KEY_MENU
+
+  { "Escape",                DALI_KEY_ESCAPE,                                            false },
+  { "Menu",                  DALI_KEY_MENU,                                              false },
+
+  // Now literal strings are used as key names instead of defined symbols in utilX,
+  // since these definition in utilX.h is deprecated
+  { "XF86Camera",            DALI_KEY_CAMERA,                                            false },
+  { "XF86Camera_Full",       DALI_KEY_CONFIG,                                            false },
+  { "XF86PowerOff",          DALI_KEY_POWER,                                             true  },
+  { "XF86Standby",           DALI_KEY_PAUSE,                                             false },
+  { "Cancel",                DALI_KEY_CANCEL,                                            false },
+  { "XF86AudioPlay",         DALI_KEY_PLAY_CD,                                           false },
+  { "XF86AudioStop",         DALI_KEY_STOP_CD,                                           false },
+  { "XF86AudioPause",        DALI_KEY_PAUSE_CD,                                          false },
+  { "XF86AudioNext",         DALI_KEY_NEXT_SONG,                                         false },
+  { "XF86AudioPrev",         DALI_KEY_PREVIOUS_SONG,                                     false },
+  { "XF86AudioRewind",       DALI_KEY_REWIND,                                            false },
+  { "XF86AudioForward",      DALI_KEY_FASTFORWARD,                                       false },
+  { "XF86AudioMedia",        DALI_KEY_MEDIA,                                             false },
+  { "XF86AudioPlayPause",    DALI_KEY_PLAY_PAUSE,                                        false },
+  { "XF86AudioMute",         DALI_KEY_MUTE,                                              false },
+  { "XF86Menu",              DALI_KEY_MENU,                                              true  },
+  { "XF86Home",              DALI_KEY_HOME,                                              true  },
+  { "XF86Back",              DALI_KEY_BACK,                                              true  },
+  { "XF86Send",              DALI_KEY_MENU,                                              true  },
+  { "XF86Phone",             DALI_KEY_HOME,                                              true  },
+  { "XF86Stop",              DALI_KEY_BACK,                                              true  },
+  { "XF86HomePage",          DALI_KEY_HOMEPAGE,                                          false },
+  { "XF86WWW",               DALI_KEY_WEBPAGE,                                           false },
+  { "XF86Mail",              DALI_KEY_MAIL,                                              false },
+  { "XF86ScreenSaver",       DALI_KEY_SCREENSAVER,                                       false },
+  { "XF86MonBrightnessUp",   DALI_KEY_BRIGHTNESS_UP,                                     false },
+  { "XF86MonBrightnessDown", DALI_KEY_BRIGHTNESS_DOWN,                                   false },
+  { "XF86SoftKBD",           DALI_KEY_SOFT_KBD,                                          false },
+  { "XF86QuickPanel",        DALI_KEY_QUICK_PANEL,                                       false },
+  { "XF86TaskPane",          DALI_KEY_TASK_SWITCH,                                       false },
+  { "XF86Apps",              DALI_KEY_APPS,                                              false },
+  { "XF86Search",            DALI_KEY_SEARCH,                                            false },
+  { "XF86Voice",             DALI_KEY_VOICE,                                             false },
+  { "Hangul",                DALI_KEY_LANGUAGE,                                          false },
+  { "XF86AudioRaiseVolume",  DALI_KEY_VOLUME_UP,                                         true  },
+  { "XF86AudioLowerVolume",  DALI_KEY_VOLUME_DOWN,                                       true  },
+
+  { "BackSpace",             DALI_KEY_BACKSPACE,                                         false },
+  { "Left",                  DALI_KEY_CURSOR_LEFT,                                       false },
+  { "Right",                 DALI_KEY_CURSOR_RIGHT,                                      false },
+  { "Shift_L",               DALI_KEY_SHIFT_LEFT,                                        false },
+  { "Shift_R",               DALI_KEY_SHIFT_RIGHT,                                       false },
+  { "Delete",                static_cast<Dali::KEY>( DevelKey::DALI_KEY_DELETE ),        false },
+  { "Control_L",             static_cast<Dali::KEY>( DevelKey::DALI_KEY_CONTROL_LEFT ),  false },
+  { "Control_R",             static_cast<Dali::KEY>( DevelKey::DALI_KEY_CONTROL_RIGHT ), false },
+  { "Return",                static_cast<Dali::KEY>( DevelKey::DALI_KEY_RETURN ),        false }
+};
+
+const std::size_t KEY_LOOKUP_COUNT = (sizeof( KeyLookupTable ))/ (sizeof( KeyLookup ));
+
+} // namespace KeyLookup
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/input/generic/virtual-keyboard-impl-generic.cpp b/dali/internal/input/generic/virtual-keyboard-impl-generic.cpp
new file mode 100644 (file)
index 0000000..6c55384
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/input/common/virtual-keyboard-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace VirtualKeyboard
+{
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_INPUT_METHOD_CONTEXT");
+#endif
+}
+
+void Show()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "VirtualKeyboard::Show\n" );
+}
+
+void Hide()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "VirtualKeyboard::Hide\n" );
+}
+
+bool IsVisible()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "VirtualKeyboard::IsVisible\n" );
+
+  return false;
+}
+
+void ApplySettings( const Property::Map& settingsMap )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "VirtualKeyboard::ApplySettings\n" );
+}
+
+void SetReturnKeyType( const InputMethod::ButtonAction::Type type )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "VirtualKeyboard::SetReturnKeyType\n" );
+}
+
+Dali::InputMethod::ButtonAction::Type GetReturnKeyType()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "VirtualKeyboard::GetReturnKeyType\n" );
+
+  return Dali::InputMethod::ButtonAction::DEFAULT;
+}
+
+void EnablePrediction( const bool enable )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "VirtualKeyboard::EnablePrediction\n" );
+}
+
+bool IsPredictionEnabled()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "VirtualKeyboard::IsPredictionEnabled\n" );
+
+  return false;
+}
+
+Rect<int> GetSizeAndPosition()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "VirtualKeyboard::GetSizeAndPosition\n" );
+
+  Rect<int> ret;
+  return ret;
+}
+
+void RotateTo(int angle)
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "VirtualKeyboard::RotateTo\n" );
+}
+
+Dali::VirtualKeyboard::TextDirection GetTextDirection()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "VirtualKeyboard::GetTextDirection\n" );
+
+  return Dali::VirtualKeyboard::LeftToRight;
+}
+
+} // namespace VirtualKeyboard
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/input/linux/dali-ecore-imf.h b/dali/internal/input/linux/dali-ecore-imf.h
new file mode 100644 (file)
index 0000000..62aef33
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef DALI_INTERNAL_INPUT_LINUX_DALI_ECORE_IMF_H
+#define DALI_INTERNAL_INPUT_LINUX_DALI_ECORE_IMF_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#pragma GCC system_header
+#include <Ecore_IMF.h>
+
+
+
+#endif /* DALI_INTERNAL_INPUT_LINUX_DALI_ECORE_IMF_H */
diff --git a/dali/internal/input/tizen-wayland/ecore-virtual-keyboard.cpp b/dali/internal/input/tizen-wayland/ecore-virtual-keyboard.cpp
new file mode 100755 (executable)
index 0000000..8319094
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/input/common/virtual-keyboard-impl.h>
+
+// EXTERNAL INCLUDES
+#include <algorithm>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/internal/input/common/input-method-context-impl.h>
+#include <dali/internal/input/tizen-wayland/ecore-virtual-keyboard.h>
+#include <dali/internal/system/common/locale-utils.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace VirtualKeyboard
+{
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_VIRTUAL_KEYBOARD");
+#endif
+
+#define TOKEN_STRING(x) #x
+
+//forward declarations
+void InputPanelGeometryChangedCallback ( void *data, Ecore_IMF_Context *context, int value );
+void InputPanelLanguageChangeCallback( void* data, Ecore_IMF_Context* context, int value );
+
+// Signals
+Dali::VirtualKeyboard::StatusSignalType gKeyboardStatusSignal;
+Dali::VirtualKeyboard::VoidSignalType   gKeyboardResizeSignal;
+Dali::VirtualKeyboard::VoidSignalType   gKeyboardLanguageChangedSignal;
+
+void InputPanelStateChangeCallback( void* data, Ecore_IMF_Context* context, int value )
+{
+  switch (value)
+  {
+    case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "VKB ECORE_IMF_INPUT_PANEL_STATE_SHOW\n" );
+
+      gKeyboardStatusSignal.Emit( true );
+
+      break;
+    }
+
+    case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "VKB ECORE_IMF_INPUT_PANEL_STATE_HIDE\n" );
+
+      gKeyboardStatusSignal.Emit( false );
+
+      break;
+    }
+
+    case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
+    default:
+    {
+      // Do nothing
+      break;
+    }
+  }
+}
+
+void InputPanelLanguageChangeCallback( void* data, Ecore_IMF_Context* context, int value )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "VKB InputPanelLanguageChangeCallback\n" );
+
+  // Emit the signal that the language has changed
+  gKeyboardLanguageChangedSignal.Emit();
+}
+
+void InputPanelGeometryChangedCallback ( void *data, Ecore_IMF_Context *context, int value )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "VKB InputPanelGeometryChangedCallback\n" );
+
+  // Emit signal that the keyboard is resized
+  gKeyboardResizeSignal.Emit();
+}
+
+} // unnamed namespace
+
+void ConnectCallbacks( Ecore_IMF_Context *imfContext )
+{
+  if( imfContext )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "VKB ConnectPanelCallbacks\n" );
+
+    ecore_imf_context_input_panel_event_callback_add( imfContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT,    InputPanelStateChangeCallback,     NULL );
+    ecore_imf_context_input_panel_event_callback_add( imfContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback,  NULL );
+    ecore_imf_context_input_panel_event_callback_add( imfContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback, NULL );
+  }
+}
+
+void DisconnectCallbacks( Ecore_IMF_Context *imfContext )
+{
+  if( imfContext )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "VKB DisconnectPanelCallbacks\n" );
+
+    ecore_imf_context_input_panel_event_callback_del( imfContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT,    InputPanelStateChangeCallback     );
+    ecore_imf_context_input_panel_event_callback_del( imfContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback  );
+    ecore_imf_context_input_panel_event_callback_del( imfContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback );
+  }
+}
+
+void Show()
+{
+  DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: Show() is deprecated and will be removed from next release. Use InputMethodContext.Activate() instead.\n" );
+}
+
+void Hide()
+{
+  DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: Hide() is deprecated and will be removed from next release. Use InputMethodContext.Deactivate() instead.\n" );
+}
+
+bool IsVisible()
+{
+  DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: IsVisible() is deprecated and will be removed from next release.\n" );
+  return false;
+}
+
+void ApplySettings( const Property::Map& settingsMap )
+{
+  using namespace InputMethod; // Allows exclusion of namespace in TOKEN_STRING.
+
+  for ( unsigned long i = 0, count = settingsMap.Count(); i < count; ++i )
+  {
+    Property::Key key = settingsMap.GetKeyAt( i );
+    if( key.type == Property::Key::INDEX )
+    {
+      continue;
+    }
+
+    Property::Value item = settingsMap.GetValue(i);
+
+    if ( key == TOKEN_STRING( BUTTON_ACTION ) )
+    {
+      if ( item.GetType() == Property::INTEGER )
+      {
+        int value = item.Get< int >();
+        VirtualKeyboard::SetReturnKeyType( static_cast<InputMethod::ButtonAction::Type>(value) );
+      }
+    }
+    else
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "Provided Settings Key not supported\n" );
+    }
+  }
+}
+
+void EnablePrediction(const bool enable)
+{
+}
+
+bool IsPredictionEnabled()
+{
+  return false;
+}
+
+Rect<int> GetSizeAndPosition()
+{
+  int xPos, yPos, width, height;
+
+  DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: GetSizeAndPosition() is deprecated and will be removed from next release. Use InputMethodContext.GetInputMethodArea() instead.\n" );
+
+  width = height = xPos = yPos = 0;
+  return Rect<int>(xPos,yPos,width,height);
+}
+
+Dali::VirtualKeyboard::TextDirection GetTextDirection()
+{
+  Dali::VirtualKeyboard::TextDirection direction ( Dali::VirtualKeyboard::LeftToRight );
+  return direction;
+}
+
+} // namespace VirtualKeyboard
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/input/tizen-wayland/ecore-virtual-keyboard.h b/dali/internal/input/tizen-wayland/ecore-virtual-keyboard.h
new file mode 100644 (file)
index 0000000..0226342
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef DALI_INTERNAL_ECORE_VIRTUAL_KEYBOARD_H
+#define DALI_INTERNAL_ECORE_VIRTUAL_KEYBOARD_H
+
+/*
+ * Copyright (c) 2019 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/internal/input/linux/dali-ecore-imf.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/virtual-keyboard.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Implementation of the virtual keyboard namespace
+ */
+namespace VirtualKeyboard
+{
+
+/**
+ * Connect the virtual keyboard callbacks.
+ * To get the virtual keyboard callbacks then you have to connect these callback.
+ * If you don't connect callbacks, you can't get virtual keyboard signals.
+ * The signals are StatusChangedSignal, ResizedSignal and LanguageChangedSignal.
+ */
+void ConnectCallbacks( Ecore_IMF_Context *imfContext );
+
+/**
+ * Disconnect the virtual keyboard callbacks.
+ * The signals are StatusChangedSignal, ResizedSignal and LanguageChangedSignal.
+ */
+void DisconnectCallbacks( Ecore_IMF_Context *imfContext );
+
+} // namespace VirtualKeyboard
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ECORE_VIRTUAL_KEYBOARD_H
diff --git a/dali/internal/input/tizen-wayland/input-method-context-factory-ecore-wl.cpp b/dali/internal/input/tizen-wayland/input-method-context-factory-ecore-wl.cpp
new file mode 100755 (executable)
index 0000000..a30e996
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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 <memory>
+#include <dali/internal/input/common/input-method-context-factory.h>
+#include <dali/internal/input/tizen-wayland/input-method-context-impl-ecore-wl.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class InputMethodContext;
+
+namespace InputMethodContextFactory
+{
+
+// InputMethodContext Factory to be implemented by the platform
+InputMethodContextPtr CreateInputMethodContext( Dali::Actor actor )
+{
+  return Dali::Internal::Adaptor::InputMethodContextEcoreWl::New( actor );
+}
+
+}
+
+}
+
+
+
+}
+}
\ No newline at end of file
diff --git a/dali/internal/input/tizen-wayland/input-method-context-impl-ecore-wl.cpp b/dali/internal/input/tizen-wayland/input-method-context-impl-ecore-wl.cpp
new file mode 100755 (executable)
index 0000000..bdbd873
--- /dev/null
@@ -0,0 +1,1325 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+
+#include <dali/internal/input/tizen-wayland/input-method-context-impl-ecore-wl.h>
+
+// EXTERNAL INCLUDES
+#include <Ecore_Input.h>
+
+#ifdef ECORE_WAYLAND2
+#include <Ecore_Wl2.h>
+#else
+#include <Ecore_Wayland.h>
+#endif
+
+#include <dali/public-api/events/key-event.h>
+#include <dali/public-api/adaptor-framework/key.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/input-method.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/integration-api/adaptor-framework/scene-holder.h>
+#include <dali/internal/input/common/key-impl.h>
+#include <dali/internal/system/common/locale-utils.h>
+#include <dali/internal/window-system/common/window-render-surface.h>
+
+Ecore_IMF_Input_Panel_Layout panelLayoutMap[] =
+{
+   ECORE_IMF_INPUT_PANEL_LAYOUT_NORMAL,
+   ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBER,
+   ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL,
+   ECORE_IMF_INPUT_PANEL_LAYOUT_URL,
+   ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER,
+   ECORE_IMF_INPUT_PANEL_LAYOUT_IP,
+   ECORE_IMF_INPUT_PANEL_LAYOUT_MONTH,
+   ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY,
+   ECORE_IMF_INPUT_PANEL_LAYOUT_HEX,
+   ECORE_IMF_INPUT_PANEL_LAYOUT_TERMINAL,
+   ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD,
+   ECORE_IMF_INPUT_PANEL_LAYOUT_DATETIME,
+   ECORE_IMF_INPUT_PANEL_LAYOUT_EMOTICON,
+   ECORE_IMF_INPUT_PANEL_LAYOUT_VOICE
+};
+
+Ecore_IMF_Autocapital_Type autoCapitalMap[] =
+{
+   ECORE_IMF_AUTOCAPITAL_TYPE_NONE,
+   ECORE_IMF_AUTOCAPITAL_TYPE_WORD,
+   ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE,
+   ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER,
+};
+
+Ecore_IMF_Input_Panel_Return_Key_Type returnKeyTypeMap[] =
+{
+   ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT,
+   ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DONE,
+   ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_GO,
+   ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_JOIN,
+   ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_LOGIN,
+   ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_NEXT,
+   ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH,
+   ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEND,
+   ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SIGNIN
+};
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_INPUT_METHOD_CONTEXT");
+#endif
+
+const int kUninitializedWindowId = 0;
+
+// Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
+size_t Utf8SequenceLength(const unsigned char leadByte)
+{
+  size_t length = 0;
+
+  if( ( leadByte & 0x80 ) == 0 )         //ASCII character (lead bit zero)
+  {
+    length = 1;
+  }
+  else if( ( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
+  {
+    length = 2;
+  }
+  else if( ( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
+  {
+    length = 3;
+  }
+  else if( ( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
+  {
+    length = 4;
+  }
+  else if( ( leadByte & 0xfc ) == 0xf8 ) //1111 10xx
+  {
+    length = 5;
+  }
+  else if( ( leadByte & 0xfe ) == 0xfc ) //1111 110x
+  {
+    length = 6;
+  }
+
+  return length;
+}
+
+// Static function calls used by ecore 'c' style callback registration
+void Commit( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
+{
+  if ( data )
+  {
+    InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
+    inputMethodContext->CommitReceived( data, imfContext, eventInfo );
+  }
+}
+
+void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
+{
+  if ( data )
+  {
+    InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
+    inputMethodContext->PreEditChanged( data, imfContext, eventInfo );
+  }
+}
+
+Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
+{
+  if ( data )
+  {
+    InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
+    return inputMethodContext->RetrieveSurrounding( data, imfContext, text, cursorPosition );
+  }
+  else
+  {
+    return false;
+  }
+}
+
+void InputPanelStateChangeCallback( void* data, Ecore_IMF_Context* context, int value )
+{
+  if (!data)
+  {
+    return;
+  }
+  InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
+  switch (value)
+  {
+    case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
+    {
+      inputMethodContext->StatusChangedSignal().Emit( true );
+      break;
+    }
+
+    case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
+    {
+      inputMethodContext->StatusChangedSignal().Emit( false );
+      break;
+    }
+
+    case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
+    default:
+    {
+      // Do nothing
+      break;
+    }
+  }
+}
+
+void InputPanelLanguageChangeCallback( void* data, Ecore_IMF_Context* context, int value )
+{
+  if (!data)
+  {
+    return;
+  }
+  InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
+  // Emit the signal that the language has changed
+  inputMethodContext->LanguageChangedSignal().Emit(value);
+}
+
+void InputPanelGeometryChangedCallback ( void *data, Ecore_IMF_Context *context, int value )
+{
+  if (!data)
+  {
+    return;
+  }
+  InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
+  // Emit signal that the keyboard is resized
+  inputMethodContext->ResizedSignal().Emit(value);
+}
+
+void InputPanelKeyboardTypeChangedCallback( void *data, Ecore_IMF_Context *context, int value )
+{
+  if( !data )
+  {
+    return;
+  }
+
+  InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
+  switch (value)
+  {
+    case ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE:
+    {
+      // Emit Signal that the keyboard type is changed to Software Keyboard
+      inputMethodContext->KeyboardTypeChangedSignal().Emit( Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD );
+      break;
+    }
+    case ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE:
+    {
+      // Emit Signal that the keyboard type is changed to Hardware Keyboard
+      inputMethodContext->KeyboardTypeChangedSignal().Emit( Dali::InputMethodContext::KeyboardType::HARDWARE_KEYBOARD );
+      break;
+    }
+  }
+}
+
+/**
+ * Called when an IMF delete surrounding event is received.
+ * Here we tell the application that it should delete a certain range.
+ */
+void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
+{
+  if ( data )
+  {
+    InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
+    inputMethodContext->DeleteSurrounding( data, imfContext, eventInfo );
+  }
+}
+
+/**
+ * Called when the input method sends a private command.
+ */
+void PrivateCommand( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
+{
+  if ( data )
+  {
+    InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
+    inputMethodContext->SendPrivateCommand( data, imfContext, eventInfo );
+  }
+}
+
+/**
+ * Called when the input method commits content, such as an image.
+ */
+void CommitContent( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
+{
+  if ( data )
+  {
+    InputMethodContextEcoreWl* inputMethodContext = static_cast< InputMethodContextEcoreWl* >( data );
+    inputMethodContext->SendCommitContent( data, imfContext, eventInfo );
+  }
+}
+
+int GetWindowIdFromActor( Dali::Actor actor )
+{
+  int windowId = kUninitializedWindowId;
+
+  if( actor.OnStage() )
+  {
+    Any nativeWindowHandle = Dali::Integration::SceneHolder::Get( actor ).GetNativeHandle();
+
+#ifdef ECORE_WAYLAND2
+    windowId = ecore_wl2_window_id_get( AnyCast< Ecore_Wl2_Window* >( nativeWindowHandle ) );
+#else
+    windowId = ecore_wl_window_id_get( AnyCast< Ecore_Wl_Window* >( nativeWindowHandle ) );
+#endif
+  }
+
+  return windowId;
+}
+
+BaseHandle Create()
+{
+  return Dali::InputMethodContext::New( Dali::Actor() );
+}
+
+Dali::TypeRegistration type( typeid(Dali::InputMethodContext), typeid(Dali::BaseHandle), Create );
+
+} // unnamed namespace
+
+InputMethodContextPtr InputMethodContextEcoreWl::New( Dali::Actor actor )
+{
+  InputMethodContextPtr inputMethodContext;
+
+  // Create instance only if the adaptor is available and the valid actor exists
+  if ( actor && Dali::Adaptor::IsAvailable() )
+  {
+    inputMethodContext = new InputMethodContextEcoreWl( actor );
+  }
+  return inputMethodContext;
+}
+
+void InputMethodContextEcoreWl::Finalize()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext::Finalize\n" );
+
+  DisconnectCallbacks();
+  DeleteContext();
+}
+
+InputMethodContextEcoreWl::InputMethodContextEcoreWl( Dali::Actor actor )
+: mIMFContext(),
+  mIMFCursorPosition( 0 ),
+  mSurroundingText(),
+  mRestoreAfterFocusLost( false ),
+  mIdleCallbackConnected( false ),
+  mWindowId( GetWindowIdFromActor( actor ) )
+{
+  ecore_imf_init();
+
+  actor.OnStageSignal().Connect( this, &InputMethodContextEcoreWl::OnStaged );
+}
+
+InputMethodContextEcoreWl::~InputMethodContextEcoreWl()
+{
+  Finalize();
+  ecore_imf_shutdown();
+}
+
+void InputMethodContextEcoreWl::Initialize()
+{
+  CreateContext();
+  ConnectCallbacks();
+  ApplyBackupOperations();
+}
+
+void InputMethodContextEcoreWl::CreateContext()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext::CreateContext\n" );
+
+  if( mWindowId == kUninitializedWindowId )
+  {
+    return;
+  }
+
+  const char *contextId = ecore_imf_context_default_id_get();
+  if( contextId )
+  {
+    mIMFContext = ecore_imf_context_add( contextId );
+
+    if( mIMFContext )
+    {
+      ecore_imf_context_client_window_set( mIMFContext, reinterpret_cast< void* >( mWindowId ) );
+    }
+    else
+    {
+      DALI_LOG_WARNING( "InputMethodContext Unable to get IMFContext\n" );
+    }
+  }
+  else
+  {
+    DALI_LOG_WARNING( "InputMethodContext Unable to get IMFContext\n" );
+  }
+}
+
+void InputMethodContextEcoreWl::DeleteContext()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DeleteContext\n" );
+
+  if ( mIMFContext )
+  {
+    ecore_imf_context_del( mIMFContext );
+    mIMFContext = NULL;
+  }
+}
+
+// Callbacks for predicitive text support.
+void InputMethodContextEcoreWl::ConnectCallbacks()
+{
+  if ( mIMFContext )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::ConnectCallbacks\n" );
+
+    ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,      PreEdit,    this );
+    ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,               Commit,     this );
+    ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING,   ImfDeleteSurrounding, this );
+    ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand, this );
+    ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT_CONTENT,       CommitContent, this );
+
+    ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT,    InputPanelStateChangeCallback, this );
+    ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback, this );
+    ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback, this );
+    ecore_imf_context_input_panel_event_callback_add( mIMFContext, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, InputPanelKeyboardTypeChangedCallback, this );
+
+    ecore_imf_context_retrieve_surrounding_callback_set( mIMFContext, ImfRetrieveSurrounding, this);
+  }
+}
+
+void InputMethodContextEcoreWl::DisconnectCallbacks()
+{
+  if ( mIMFContext )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DisconnectCallbacks\n" );
+
+    ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,      PreEdit );
+    ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,               Commit );
+    ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING,   ImfDeleteSurrounding );
+    ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PRIVATE_COMMAND_SEND, PrivateCommand );
+    ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT_CONTENT,       CommitContent );
+
+    ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_STATE_EVENT,    InputPanelStateChangeCallback     );
+    ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, InputPanelLanguageChangeCallback  );
+    ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_GEOMETRY_EVENT, InputPanelGeometryChangedCallback );
+    ecore_imf_context_input_panel_event_callback_del( mIMFContext, ECORE_IMF_INPUT_PANEL_KEYBOARD_MODE_EVENT, InputPanelKeyboardTypeChangedCallback );
+
+    // We do not need to unset the retrieve surrounding callback.
+  }
+}
+
+void InputMethodContextEcoreWl::Activate()
+{
+  // Reset mIdleCallbackConnected
+  mIdleCallbackConnected = false;
+
+  if ( mIMFContext )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Activate\n" );
+
+    ecore_imf_context_focus_in( mIMFContext );
+
+    // emit keyboard activated signal
+    Dali::InputMethodContext handle( this );
+    mActivatedSignal.Emit( handle );
+  }
+}
+
+void InputMethodContextEcoreWl::Deactivate()
+{
+  if( mIMFContext )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Deactivate\n" );
+
+    Reset();
+    ecore_imf_context_focus_out( mIMFContext );
+  }
+
+  // Reset mIdleCallbackConnected
+  mIdleCallbackConnected = false;
+}
+
+void InputMethodContextEcoreWl::Reset()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::Reset\n" );
+
+  if ( mIMFContext )
+  {
+    ecore_imf_context_reset( mIMFContext );
+  }
+}
+
+ImfContext* InputMethodContextEcoreWl::GetContext()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetContext\n" );
+
+  return mIMFContext;
+}
+
+bool InputMethodContextEcoreWl::RestoreAfterFocusLost() const
+{
+  return mRestoreAfterFocusLost;
+}
+
+void InputMethodContextEcoreWl::SetRestoreAfterFocusLost( bool toggle )
+{
+  mRestoreAfterFocusLost = toggle;
+}
+
+/**
+ * Called when an InputMethodContext Pre-Edit changed event is received.
+ * We are still predicting what the user is typing.  The latest string is what the InputMethodContext module thinks
+ * the user wants to type.
+ */
+void InputMethodContextEcoreWl::PreEditChanged( void*, ImfContext* imfContext, void* eventInfo )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::PreEditChanged\n" );
+  auto context = static_cast<Ecore_IMF_Context*>( imfContext );
+
+  char* preEditString( NULL );
+  int cursorPosition( 0 );
+  Eina_List* attrs = NULL;
+  Eina_List* l = NULL;
+
+  Ecore_IMF_Preedit_Attr* attr;
+
+  mPreeditAttrs.Clear();
+
+  // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
+  // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
+  ecore_imf_context_preedit_string_with_attributes_get( context, &preEditString, &attrs, &cursorPosition );
+
+  if ( attrs )
+  {
+    // iterate through the list of attributes getting the type, start and end position.
+    for ( l = attrs, (attr =  static_cast<Ecore_IMF_Preedit_Attr*>( eina_list_data_get(l) ) ); l; l = eina_list_next(l), ( attr = static_cast<Ecore_IMF_Preedit_Attr*>( eina_list_data_get(l) ) ))
+    {
+      Dali::InputMethodContext::PreeditAttributeData data;
+      data.startIndex = 0;
+      data.endIndex = 0;
+
+      size_t visualCharacterIndex = 0;
+      size_t byteIndex = 0;
+
+      // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
+      char leadByte = preEditString[byteIndex];
+
+      while( leadByte != '\0' )
+      {
+        leadByte = preEditString[byteIndex]; // Update the character to get the number of its byte
+
+        // attr->end_index is provided as a byte position not character and we need to know the character position.
+        const size_t currentSequenceLength = Utf8SequenceLength( leadByte ); // returns number of bytes used to represent character.
+        if( byteIndex <= attr->start_index )
+        {
+           data.startIndex = visualCharacterIndex;
+        }
+        if( byteIndex >= attr->end_index )
+        {
+          data.endIndex = visualCharacterIndex;
+          break;
+          // end loop as found cursor position that matches byte position
+        }
+        else
+        {
+          byteIndex += currentSequenceLength; // jump to next character
+          visualCharacterIndex++;  // increment character count so we know our position for when we get a match
+        }
+      }
+
+      switch( attr->preedit_type )
+      {
+        case ECORE_IMF_PREEDIT_TYPE_NONE:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::NONE;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB1:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::UNDERLINE;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB2:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::REVERSE;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB3:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::HIGHLIGHT;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB4:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB5:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB6:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB7:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4;
+          break;
+        }
+        default:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::NONE;
+          break;
+        }
+      }
+      mPreeditAttrs.PushBack( data );
+    }
+  }
+
+  if ( Dali::Adaptor::IsAvailable() )
+  {
+    Dali::InputMethodContext handle( this );
+    Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::PRE_EDIT, preEditString, cursorPosition, 0 );
+    Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
+
+    if ( callbackData.update )
+    {
+      SetCursorPosition( callbackData.cursorPosition );
+      SetSurroundingText( callbackData.currentText );
+
+      NotifyCursorPosition();
+    }
+
+    if ( callbackData.preeditResetRequired )
+    {
+      Reset();
+    }
+  }
+  free( preEditString );
+}
+
+void InputMethodContextEcoreWl::CommitReceived( void*, ImfContext* imfContext, void* eventInfo )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::CommitReceived\n" );
+
+  if ( Dali::Adaptor::IsAvailable() )
+  {
+    const std::string keyString( static_cast<char*>( eventInfo ) );
+
+    Dali::InputMethodContext handle( this );
+    Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::COMMIT, keyString, 0, 0 );
+    Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
+
+    if( callbackData.update )
+    {
+      SetCursorPosition( callbackData.cursorPosition );
+      SetSurroundingText( callbackData.currentText );
+
+      NotifyCursorPosition();
+    }
+  }
+}
+
+/**
+ * Called when an InputMethodContext retrieve surround event is received.
+ * Here the InputMethodContext module wishes to know the string we are working with and where within the string the cursor is
+ * We need to signal the application to tell us this information.
+ */
+bool InputMethodContextEcoreWl::RetrieveSurrounding( void* data, ImfContext* imfContext, char** text, int* cursorPosition )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::RetrieveSurrounding\n" );
+
+  Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::GET_SURROUNDING, std::string(), 0, 0 );
+  Dali::InputMethodContext handle( this );
+  Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, imfData );
+
+  if( callbackData.update )
+  {
+    if( cursorPosition )
+    {
+      mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
+      *cursorPosition = mIMFCursorPosition;
+    }
+
+    if( text )
+    {
+      const char* plainText = callbackData.currentText.c_str();
+
+      if( plainText )
+      {
+        // The memory allocated by strdup() can be freed by ecore_imf_context_surrounding_get() internally.
+        *text = strdup( plainText );
+
+        // If the current input panel is password mode, dali should replace the plain text with '*' (Asterisk) character.
+        if( ( ecore_imf_context_input_hint_get( mIMFContext ) & ECORE_IMF_INPUT_HINT_SENSITIVE_DATA ) && *text )
+        {
+          for( char* iter = *text; *iter; ++iter )
+          {
+            *iter = '*';
+          }
+        }
+
+        return EINA_TRUE;
+      }
+    }
+  }
+
+  return EINA_FALSE;
+}
+
+/**
+ * Called when an InputMethodContext delete surrounding event is received.
+ * Here we tell the application that it should delete a certain range.
+ */
+void InputMethodContextEcoreWl::DeleteSurrounding( void* data, ImfContext* imfContext, void* eventInfo )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::DeleteSurrounding\n" );
+
+  if( Dali::Adaptor::IsAvailable() )
+  {
+    Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = static_cast<Ecore_IMF_Event_Delete_Surrounding*>( eventInfo );
+
+    Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::DELETE_SURROUNDING, std::string(), deleteSurroundingEvent->offset, deleteSurroundingEvent->n_chars );
+    Dali::InputMethodContext handle( this );
+    mEventSignal.Emit( handle, imfData );
+  }
+}
+
+/**
+ * Called when the input method sends a private command.
+ */
+void InputMethodContextEcoreWl::SendPrivateCommand( void* data, ImfContext* imfContext, void* eventInfo )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendPrivateCommand\n" );
+
+  if( Dali::Adaptor::IsAvailable() )
+  {
+    const char* privateCommandSendEvent = static_cast<const char*>( eventInfo );
+
+    Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::PRIVATE_COMMAND, privateCommandSendEvent, 0, 0 );
+    Dali::InputMethodContext handle( this );
+    mEventSignal.Emit( handle, imfData );
+  }
+}
+
+/**
+ * Called when the input method commits content, such as an image.
+ */
+void InputMethodContextEcoreWl::SendCommitContent( void* data, ImfContext* imfContext, void* eventInfo )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendCommitContent\n" );
+
+  if( Dali::Adaptor::IsAvailable() )
+  {
+    Ecore_IMF_Event_Commit_Content* commitContent = static_cast<Ecore_IMF_Event_Commit_Content *>( eventInfo );
+    if( commitContent )
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SendCommitContent commit content : %s, description : %s, mime type : %s\n",
+                                                 commitContent->content_uri, commitContent->description, commitContent->mime_types );
+      mContentReceivedSignal.Emit( commitContent->content_uri, commitContent->description, commitContent->mime_types );
+    }
+  }
+}
+
+void InputMethodContextEcoreWl::NotifyCursorPosition()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::NotifyCursorPosition\n" );
+
+  if( mIMFContext )
+  {
+    ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
+  }
+}
+
+void InputMethodContextEcoreWl::SetCursorPosition( unsigned int cursorPosition )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetCursorPosition\n" );
+
+  mIMFCursorPosition = static_cast<int>( cursorPosition );
+}
+
+unsigned int InputMethodContextEcoreWl::GetCursorPosition() const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetCursorPosition\n" );
+
+  return static_cast<unsigned int>( mIMFCursorPosition );
+}
+
+void InputMethodContextEcoreWl::SetSurroundingText( const std::string& text )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetSurroundingText\n" );
+
+  mSurroundingText = text;
+}
+
+const std::string& InputMethodContextEcoreWl::GetSurroundingText() const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetSurroundingText\n" );
+
+  return mSurroundingText;
+}
+
+void InputMethodContextEcoreWl::NotifyTextInputMultiLine( bool multiLine )
+{
+  if( mIMFContext )
+  {
+    Ecore_IMF_Input_Hints currentHint = ecore_imf_context_input_hint_get(mIMFContext);
+    ecore_imf_context_input_hint_set( mIMFContext,
+                                      static_cast< Ecore_IMF_Input_Hints >( multiLine ?
+                                        (currentHint | ECORE_IMF_INPUT_HINT_MULTILINE) :
+                                        (currentHint & ~ECORE_IMF_INPUT_HINT_MULTILINE)));
+  }
+
+  mBackupOperations[Operation::NOTIFY_TEXT_INPUT_MULTILINE] = std::bind( &InputMethodContextEcoreWl::NotifyTextInputMultiLine, this, multiLine );
+}
+
+Dali::InputMethodContext::TextDirection InputMethodContextEcoreWl::GetTextDirection()
+{
+  Dali::InputMethodContext::TextDirection direction ( Dali::InputMethodContext::LeftToRight );
+
+    if ( mIMFContext )
+    {
+      char* locale( NULL );
+      ecore_imf_context_input_panel_language_locale_get( mIMFContext, &locale );
+
+      if ( locale )
+      {
+        direction = static_cast< Dali::InputMethodContext::TextDirection >( Locale::GetDirection( std::string( locale ) ) );
+        free( locale );
+      }
+    }
+
+  return direction;
+}
+
+Rect<int> InputMethodContextEcoreWl::GetInputMethodArea()
+{
+  int xPos, yPos, width, height;
+
+  width = height = xPos = yPos = 0;
+
+  if( mIMFContext )
+  {
+    ecore_imf_context_input_panel_geometry_get( mIMFContext, &xPos, &yPos, &width, &height );
+  }
+  else
+  {
+    DALI_LOG_WARNING("VKB Unable to get IMFContext so GetSize unavailable\n");
+  // return 0 as real size unknown.
+  }
+
+  return Rect<int>(xPos,yPos,width,height);
+}
+
+void InputMethodContextEcoreWl::ApplyOptions( const InputMethodOptions& options )
+{
+  using namespace Dali::InputMethod::Category;
+
+  int index;
+
+  if( mIMFContext == NULL )
+  {
+    DALI_LOG_WARNING("VKB Unable to excute ApplyOptions with Null ImfContext\n");
+    return;
+  }
+
+  if( mOptions.CompareAndSet(PANEL_LAYOUT, options, index) )
+  {
+    ecore_imf_context_input_panel_layout_set( mIMFContext, panelLayoutMap[index] );
+
+    // Sets the input hint which allows input methods to fine-tune their behavior.
+    if( panelLayoutMap[index] == ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD )
+    {
+      ecore_imf_context_input_hint_set( mIMFContext, static_cast< Ecore_IMF_Input_Hints >( ecore_imf_context_input_hint_get( mIMFContext ) | ECORE_IMF_INPUT_HINT_SENSITIVE_DATA ) );
+    }
+    else
+    {
+      ecore_imf_context_input_hint_set( mIMFContext, static_cast< Ecore_IMF_Input_Hints >( ecore_imf_context_input_hint_get( mIMFContext ) & ~ECORE_IMF_INPUT_HINT_SENSITIVE_DATA ) );
+    }
+  }
+  if( mOptions.CompareAndSet(BUTTON_ACTION, options, index) )
+  {
+    ecore_imf_context_input_panel_return_key_type_set( mIMFContext, returnKeyTypeMap[index] );
+  }
+  if( mOptions.CompareAndSet(AUTO_CAPITALIZE, options, index) )
+  {
+    ecore_imf_context_autocapital_type_set( mIMFContext, autoCapitalMap[index] );
+  }
+  if( mOptions.CompareAndSet(VARIATION, options, index) )
+  {
+    ecore_imf_context_input_panel_layout_variation_set( mIMFContext, index );
+  }
+}
+
+void InputMethodContextEcoreWl::SetInputPanelData( const std::string& data )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetInputPanelData\n" );
+
+  if( mIMFContext )
+  {
+    int length = data.length();
+    ecore_imf_context_input_panel_imdata_set( mIMFContext, data.c_str(), length );
+  }
+
+  mBackupOperations[Operation::SET_INPUT_PANEL_DATA] = std::bind( &InputMethodContextEcoreWl::SetInputPanelData, this, data );
+}
+
+void InputMethodContextEcoreWl::GetInputPanelData( std::string& data )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelData\n" );
+
+  if( mIMFContext )
+  {
+    int length = 4096; // The max length is 4096 bytes
+    Dali::Vector< char > buffer;
+    buffer.Resize( length );
+    ecore_imf_context_input_panel_imdata_get( mIMFContext, &buffer[0], &length );
+    data = std::string( buffer.Begin(), buffer.End() );
+  }
+}
+
+Dali::InputMethodContext::State InputMethodContextEcoreWl::GetInputPanelState()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelState\n" );
+
+  if( mIMFContext )
+  {
+    int value;
+    value = ecore_imf_context_input_panel_state_get( mIMFContext );
+
+    switch (value)
+    {
+      case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
+      {
+        return Dali::InputMethodContext::SHOW;
+        break;
+      }
+
+      case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
+      {
+        return Dali::InputMethodContext::HIDE;
+        break;
+      }
+
+      case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
+      {
+        return Dali::InputMethodContext::WILL_SHOW;
+        break;
+      }
+
+      default:
+      {
+        return Dali::InputMethodContext::DEFAULT;
+      }
+    }
+  }
+  return Dali::InputMethodContext::DEFAULT;
+}
+
+void InputMethodContextEcoreWl::SetReturnKeyState( bool visible )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetReturnKeyState\n" );
+
+  if( mIMFContext )
+  {
+    ecore_imf_context_input_panel_return_key_disabled_set( mIMFContext, !visible );
+  }
+
+  mBackupOperations[Operation::SET_RETURN_KEY_STATE] = std::bind( &InputMethodContextEcoreWl::SetReturnKeyState, this, visible );
+}
+
+void InputMethodContextEcoreWl::AutoEnableInputPanel( bool enabled )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::AutoEnableInputPanel\n" );
+
+  if( mIMFContext )
+  {
+    ecore_imf_context_input_panel_enabled_set( mIMFContext, enabled );
+  }
+
+  mBackupOperations[Operation::AUTO_ENABLE_INPUT_PANEL] = std::bind( &InputMethodContextEcoreWl::AutoEnableInputPanel, this, enabled );
+}
+
+void InputMethodContextEcoreWl::ShowInputPanel()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::ShowInputPanel\n" );
+
+  if( mIMFContext )
+  {
+    ecore_imf_context_input_panel_show( mIMFContext );
+  }
+}
+
+void InputMethodContextEcoreWl::HideInputPanel()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::HideInputPanel\n" );
+
+  if( mIMFContext )
+  {
+    ecore_imf_context_input_panel_hide( mIMFContext );
+  }
+}
+
+Dali::InputMethodContext::KeyboardType InputMethodContextEcoreWl::GetKeyboardType()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetKeyboardType\n" );
+
+  if( mIMFContext )
+  {
+    int value;
+    value = ecore_imf_context_keyboard_mode_get( mIMFContext );
+
+    switch (value)
+    {
+      case ECORE_IMF_INPUT_PANEL_SW_KEYBOARD_MODE:
+      {
+        return Dali::InputMethodContext::SOFTWARE_KEYBOARD;
+        break;
+      }
+      case ECORE_IMF_INPUT_PANEL_HW_KEYBOARD_MODE:
+      {
+        return Dali::InputMethodContext::HARDWARE_KEYBOARD;
+        break;
+      }
+    }
+  }
+
+  return Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD;
+}
+
+std::string InputMethodContextEcoreWl::GetInputPanelLocale()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelLocale\n" );
+
+  std::string locale = "";
+
+  if( mIMFContext )
+  {
+    char* value = NULL;
+    ecore_imf_context_input_panel_language_locale_get( mIMFContext, &value );
+
+    if( value )
+    {
+      std::string valueCopy( value );
+      locale = valueCopy;
+
+      // The locale string retrieved must be freed with free().
+      free( value );
+    }
+  }
+  return locale;
+}
+
+void InputMethodContextEcoreWl::SetContentMIMETypes( const std::string& mimeTypes )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetContentMIMETypes\n" );
+
+  if( mIMFContext )
+  {
+    ecore_imf_context_mime_type_accept_set( mIMFContext, mimeTypes.c_str() );
+  }
+
+  mBackupOperations[Operation::SET_CONTENT_MIME_TYPES] = std::bind( &InputMethodContextEcoreWl::SetContentMIMETypes, this, mimeTypes );
+}
+
+bool InputMethodContextEcoreWl::FilterEventKey( const Dali::KeyEvent& keyEvent )
+{
+  bool eventHandled( false );
+
+  // If a device key then skip ecore_imf_context_filter_event.
+  if ( ! KeyLookup::IsDeviceButton( keyEvent.keyPressedName.c_str() ))
+  {
+    //check whether it's key down or key up event
+    if ( keyEvent.state == KeyEvent::Down )
+    {
+      eventHandled = ProcessEventKeyDown( keyEvent );
+    }
+    else if ( keyEvent.state == KeyEvent::Up )
+    {
+      eventHandled = ProcessEventKeyUp( keyEvent );
+    }
+  }
+
+  return eventHandled;
+}
+
+void InputMethodContextEcoreWl::AllowTextPrediction( bool prediction )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::AllowTextPrediction\n" );
+
+  if( mIMFContext )
+  {
+    ecore_imf_context_prediction_allow_set( mIMFContext, prediction );
+  }
+
+  mBackupOperations[Operation::ALLOW_TEXT_PREDICTION] = std::bind( &InputMethodContextEcoreWl::AllowTextPrediction, this, prediction );
+}
+
+bool InputMethodContextEcoreWl::IsTextPredictionAllowed() const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::IsTextPredictionAllowed\n" );
+  bool prediction = false;
+  if( mIMFContext )
+  {
+    prediction = ecore_imf_context_prediction_allow_get( mIMFContext );
+  }
+  return prediction;
+}
+
+void InputMethodContextEcoreWl::SetInputPanelLanguage( Dali::InputMethodContext::InputPanelLanguage language )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetInputPanelLanguage\n" );
+  if( mIMFContext )
+  {
+    switch (language)
+    {
+      case Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC:
+      {
+        ecore_imf_context_input_panel_language_set( mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC );
+        break;
+      }
+      case Dali::InputMethodContext::InputPanelLanguage::ALPHABET:
+      {
+        ecore_imf_context_input_panel_language_set( mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_ALPHABET );
+        break;
+      }
+    }
+  }
+
+  mBackupOperations[Operation::SET_INPUT_PANEL_LANGUAGE] = std::bind( &InputMethodContextEcoreWl::SetInputPanelLanguage, this, language );
+}
+
+Dali::InputMethodContext::InputPanelLanguage InputMethodContextEcoreWl::GetInputPanelLanguage() const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetInputPanelLanguage\n" );
+  if( mIMFContext )
+  {
+    int value;
+    value =  ecore_imf_context_input_panel_language_get( mIMFContext );
+
+    switch (value)
+    {
+      case ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC:
+      {
+        return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
+        break;
+      }
+      case ECORE_IMF_INPUT_PANEL_LANG_ALPHABET:
+      {
+        return Dali::InputMethodContext::InputPanelLanguage::ALPHABET;
+        break;
+      }
+    }
+  }
+  return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
+}
+
+void InputMethodContextEcoreWl::SetInputPanelPosition( unsigned int x, unsigned int y )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::SetInputPanelPosition\n" );
+
+  if( mIMFContext )
+  {
+    ecore_imf_context_input_panel_position_set( mIMFContext, x, y );
+  }
+
+  mBackupOperations[Operation::SET_INPUT_PANEL_POSITION] = std::bind( &InputMethodContextEcoreWl::SetInputPanelPosition, this, x, y );
+}
+
+void InputMethodContextEcoreWl::GetPreeditStyle( Dali::InputMethodContext::PreEditAttributeDataContainer& attrs ) const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextEcoreWl::GetPreeditStyle\n" );
+  attrs = mPreeditAttrs;
+}
+
+bool InputMethodContextEcoreWl::ProcessEventKeyDown( const KeyEvent& keyEvent )
+{
+  bool eventHandled( false );
+  if ( mIMFContext )
+  {
+    Integration::KeyEvent integKeyEvent( keyEvent );
+    std::string key = integKeyEvent.logicalKey;
+
+    std::string compose = keyEvent.GetCompose();
+    std::string deviceName = keyEvent.GetDeviceName();
+
+    // We're consuming key down event so we have to pass to InputMethodContext so that it can parse it as well.
+    Ecore_IMF_Event_Key_Down ecoreKeyDownEvent;
+    ecoreKeyDownEvent.keyname = keyEvent.keyPressedName.c_str();
+    ecoreKeyDownEvent.key = key.c_str();
+    ecoreKeyDownEvent.string = keyEvent.keyPressed.c_str();
+    ecoreKeyDownEvent.compose = compose.c_str();
+    ecoreKeyDownEvent.timestamp = keyEvent.time;
+    ecoreKeyDownEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
+    ecoreKeyDownEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
+    ecoreKeyDownEvent.dev_name = deviceName.c_str();
+    ecoreKeyDownEvent.dev_class = static_cast<Ecore_IMF_Device_Class> ( keyEvent.GetDeviceClass() );//ECORE_IMF_DEVICE_CLASS_KEYBOARD;
+    ecoreKeyDownEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass> ( keyEvent.GetDeviceSubclass() );//ECORE_IMF_DEVICE_SUBCLASS_NONE;
+#if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR) && (ECORE_VERSION_MINOR >= 22)
+    ecoreKeyDownEvent.keycode = keyEvent.keyCode; // Ecore_IMF_Event structure has added 'keycode' variable since ecore_imf 1.22 version.
+#endif // Since ecore_imf 1.22 version
+
+    // If the device is IME and the focused key is the direction keys, then we should send a key event to move a key cursor.
+    if ((keyEvent.GetDeviceName() == "ime") && ((!strncmp(keyEvent.keyPressedName.c_str(), "Left", 4)) ||
+                                   (!strncmp(keyEvent.keyPressedName.c_str(), "Right", 5)) ||
+                                   (!strncmp(keyEvent.keyPressedName.c_str(), "Up", 2)) ||
+                                   (!strncmp(keyEvent.keyPressedName.c_str(), "Down", 4))))
+    {
+      eventHandled = 0;
+    }
+    else
+    {
+      eventHandled = ecore_imf_context_filter_event(mIMFContext,
+                                                    ECORE_IMF_EVENT_KEY_DOWN,
+                                                    reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyDownEvent ) );
+    }
+
+    // If the event has not been handled by InputMethodContext then check if we should reset our input method context
+    if (!eventHandled)
+    {
+      if (!strcmp(keyEvent.keyPressedName.c_str(), "Escape") ||
+          !strcmp(keyEvent.keyPressedName.c_str(), "Return") ||
+          !strcmp(keyEvent.keyPressedName.c_str(), "KP_Enter"))
+      {
+        ecore_imf_context_reset(mIMFContext);
+      }
+    }
+  }
+  return eventHandled;
+}
+
+bool InputMethodContextEcoreWl::ProcessEventKeyUp( const KeyEvent& keyEvent )
+{
+  bool eventHandled( false );
+  if( mIMFContext )
+  {
+    Integration::KeyEvent integKeyEvent( keyEvent );
+    std::string key = integKeyEvent.logicalKey;
+
+    std::string compose = keyEvent.GetCompose();
+    std::string deviceName = keyEvent.GetDeviceName();
+
+    // We're consuming key up event so we have to pass to InputMethodContext so that it can parse it as well.
+    Ecore_IMF_Event_Key_Up ecoreKeyUpEvent;
+    ecoreKeyUpEvent.keyname = keyEvent.keyPressedName.c_str();
+    ecoreKeyUpEvent.key = key.c_str();
+    ecoreKeyUpEvent.string = keyEvent.keyPressed.c_str();
+    ecoreKeyUpEvent.compose = compose.c_str();
+    ecoreKeyUpEvent.timestamp = keyEvent.time;
+    ecoreKeyUpEvent.modifiers =  EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
+    ecoreKeyUpEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
+    ecoreKeyUpEvent.dev_name = deviceName.c_str();
+    ecoreKeyUpEvent.dev_class = static_cast<Ecore_IMF_Device_Class> ( keyEvent.GetDeviceClass() );//ECORE_IMF_DEVICE_CLASS_KEYBOARD;
+    ecoreKeyUpEvent.dev_subclass = static_cast<Ecore_IMF_Device_Subclass> ( keyEvent.GetDeviceSubclass() );//ECORE_IMF_DEVICE_SUBCLASS_NONE;
+#if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR) && (ECORE_VERSION_MINOR >= 22)
+    ecoreKeyUpEvent.keycode = keyEvent.keyCode; // Ecore_IMF_Event structure has added 'keycode' variable since ecore_imf 1.22 version.
+#endif // Since ecore_imf 1.22 version
+
+    eventHandled = ecore_imf_context_filter_event(mIMFContext,
+                                                  ECORE_IMF_EVENT_KEY_UP,
+                                                  reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyUpEvent ) );
+  }
+  return eventHandled;
+}
+
+Ecore_IMF_Keyboard_Modifiers InputMethodContextEcoreWl::EcoreInputModifierToEcoreIMFModifier( unsigned int ecoreModifier )
+{
+  unsigned int modifier( ECORE_IMF_KEYBOARD_MODIFIER_NONE );  // If no other matches returns NONE.
+
+  if ( ecoreModifier & ECORE_EVENT_MODIFIER_SHIFT )  // enums from ecore_input/Ecore_Input.h
+  {
+    modifier |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT;  // enums from ecore_imf/ecore_imf.h
+  }
+
+  if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALT )
+  {
+    modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
+  }
+
+  if ( ecoreModifier & ECORE_EVENT_MODIFIER_CTRL )
+  {
+    modifier |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
+  }
+
+  if ( ecoreModifier & ECORE_EVENT_MODIFIER_WIN )
+  {
+    modifier |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
+  }
+
+  if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALTGR )
+  {
+    modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
+  }
+
+  return static_cast<Ecore_IMF_Keyboard_Modifiers>( modifier );
+}
+
+Ecore_IMF_Keyboard_Locks InputMethodContextEcoreWl::EcoreInputModifierToEcoreIMFLock( unsigned int modifier )
+{
+    unsigned int lock( ECORE_IMF_KEYBOARD_LOCK_NONE ); // If no other matches, returns NONE.
+
+    if( modifier & ECORE_EVENT_LOCK_NUM )
+    {
+      lock |= ECORE_IMF_KEYBOARD_LOCK_NUM; // Num lock is active.
+    }
+
+    if( modifier & ECORE_EVENT_LOCK_CAPS )
+    {
+      lock |= ECORE_IMF_KEYBOARD_LOCK_CAPS; // Caps lock is active.
+    }
+
+    if( modifier & ECORE_EVENT_LOCK_SCROLL )
+    {
+      lock |= ECORE_IMF_KEYBOARD_LOCK_SCROLL; // Scroll lock is active.
+    }
+
+    return static_cast<Ecore_IMF_Keyboard_Locks>( lock );
+}
+
+void InputMethodContextEcoreWl::OnStaged( Dali::Actor actor )
+{
+  int windowId = GetWindowIdFromActor( actor );
+
+  if( mWindowId != windowId )
+  {
+    mWindowId = windowId;
+
+    // Reset
+    Finalize();
+    Initialize();
+  }
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/dali/internal/input/tizen-wayland/input-method-context-impl-ecore-wl.h b/dali/internal/input/tizen-wayland/input-method-context-impl-ecore-wl.h
new file mode 100755 (executable)
index 0000000..8a37100
--- /dev/null
@@ -0,0 +1,360 @@
+#ifndef DALI_INTERNAL_INPUT_METHOD_CONTEXT_IMPL_ECORE_WL_H
+#define DALI_INTERNAL_INPUT_METHOD_CONTEXT_IMPL_ECORE_WL_H
+
+/*
+ * Copyright (c) 2019 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/internal/input/linux/dali-ecore-imf.h>
+#include <dali/internal/system/linux/dali-ecore.h>
+
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/integration-api/events/key-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/input/common/input-method-context-impl.h>
+
+namespace Dali
+{
+
+class RenderSurface;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class InputMethodContextEcoreWl : public Dali::Internal::Adaptor::InputMethodContext, public Dali::ConnectionTracker
+{
+public:
+
+  /**
+   * @brief Creates a new InputMethodContext handle
+   *
+   * @param[in] actor The actor that uses the new InputMethodContext instance.
+   * @return InputMethodContext pointer
+   */
+  static InputMethodContextPtr New( Dali::Actor actor );
+
+  /**
+   * @brief Initializes member data.
+   */
+  void Initialize() override;
+
+public:
+
+  /**
+   * @copydoc Dali::InputMethodContext::Finalize()
+   */
+  void Finalize() override;
+
+  /**
+   * Connect Callbacks required for InputMethodContext.
+   * If you don't connect InputMethodContext callbacks, you can't get the key events.
+   * The events are PreeditChanged, Commit, DeleteSurrounding and PrivateCommand.
+   */
+  void ConnectCallbacks() override;
+
+  /**
+   * Disconnect Callbacks attached to input method context.
+   */
+  void DisconnectCallbacks() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::Activate()
+   */
+  void Activate() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::Deactivate()
+   */
+  void Deactivate() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::Reset()
+   */
+  void Reset() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetContext()
+   */
+  ImfContext* GetContext() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::RestoreAfterFocusLost()
+   */
+  bool RestoreAfterFocusLost() const override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetRestoreAfterFocusLost()
+   */
+  void SetRestoreAfterFocusLost( bool toggle ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::PreEditChanged()
+   */
+  void PreEditChanged( void *data, ImfContext *imfContext, void *eventInfo ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::NotifyCursorPosition()
+   */
+  void CommitReceived( void *data, ImfContext *imfContext, void *eventInfo ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::NotifyCursorPosition()
+   */
+  bool RetrieveSurrounding( void *data, ImfContext *imfContext, char** text, int* cursorPosition ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::DeleteSurrounding()
+   */
+  void DeleteSurrounding( void *data, ImfContext *imfContext, void *eventInfo ) override;
+
+ /**
+  * @copydoc Dali::InputMethodContext::SendPrivateCommand()
+  */
+  void SendPrivateCommand( void* data, ImfContext* imfContext, void* eventInfo ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SendCommitContent()
+   */
+   void SendCommitContent( void* data, ImfContext* imfContext, void* eventInfo ) override;
+
+  // Cursor related
+  /**
+   * @copydoc Dali::InputMethodContext::NotifyCursorPosition()
+   */
+  void NotifyCursorPosition() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetCursorPosition()
+   */
+  void SetCursorPosition( unsigned int cursorPosition ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetCursorPosition()
+   */
+  unsigned int GetCursorPosition() const override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetSurroundingText()
+   */
+  void SetSurroundingText( const std::string& text ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetSurroundingText()
+   */
+  const std::string& GetSurroundingText() const override;
+
+  /**
+  * @copydoc Dali::InputMethodContext::NotifyTextInputMultiLine()
+  */
+  void NotifyTextInputMultiLine( bool multiLine ) override;
+
+  /**
+  * @copydoc Dali::InputMethodContext::GetTextDirection()
+  */
+  Dali::InputMethodContext::TextDirection GetTextDirection() override;
+
+  /**
+  * @copydoc Dali::InputMethodContext::GetInputMethodArea()
+  */
+  Dali::Rect<int> GetInputMethodArea() override;
+
+  /**
+  * @copydoc Dali::InputMethodContext::ApplyOptions()
+  */
+  void ApplyOptions( const InputMethodOptions& options ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetInputPanelData()
+   */
+  void SetInputPanelData( const std::string& data ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetInputPanelData()
+   */
+  void GetInputPanelData( std::string& data ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetInputPanelState()
+   */
+  Dali::InputMethodContext::State GetInputPanelState() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetReturnKeyState()
+   */
+  void SetReturnKeyState( bool visible ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::AutoEnableInputPanel()
+   */
+  void AutoEnableInputPanel( bool enabled ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::ShowInputPanel()
+   */
+  void ShowInputPanel() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::HideInputPanel()
+   */
+  void HideInputPanel() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetKeyboardType()
+   */
+  Dali::InputMethodContext::KeyboardType GetKeyboardType() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetInputPanelLocale()
+   */
+  std::string GetInputPanelLocale() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetContentMIMETypes()
+   */
+  void SetContentMIMETypes( const std::string& mimeTypes ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::FilterEventKey()
+   */
+  bool FilterEventKey( const Dali::KeyEvent& keyEvent ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::AllowTextPrediction()
+   */
+  void AllowTextPrediction( bool prediction ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::IsTextPredictionAllowed()
+   */
+  bool IsTextPredictionAllowed() const override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetInputPanelLanguage()
+   */
+  void SetInputPanelLanguage( Dali::InputMethodContext::InputPanelLanguage language ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetInputPanelLanguage()
+   */
+  Dali::InputMethodContext::InputPanelLanguage GetInputPanelLanguage() const override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetInputPanelPosition()
+   */
+  void SetInputPanelPosition( unsigned int x, unsigned int y ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetPreeditStyle()
+   */
+  void GetPreeditStyle( Dali::InputMethodContext::PreEditAttributeDataContainer& attrs ) const override;
+
+private:
+  /**
+   * Context created the first time and kept until deleted.
+   */
+  void CreateContext();
+
+  /**
+   * @copydoc Dali::InputMethodContext::DeleteContext()
+   */
+  void DeleteContext();
+
+private:
+
+  /**
+   * @brief Process event key down, whether filter a key to isf.
+   *
+   * @param[in] keyEvent The event key to be handled.
+   * @return Whether the event key is handled.
+   */
+  bool ProcessEventKeyDown( const KeyEvent& keyEvent );
+
+  /**
+   * @brief Process event key up, whether filter a key to isf.
+   *
+   * @param[in] keyEvent The event key to be handled.
+   * @return Whether the event key is handled.
+   */
+  bool ProcessEventKeyUp( const KeyEvent& keyEvent );
+
+  /**
+  * Ecore_Event_Modifier enums in Ecore_Input.h do not match Ecore_IMF_Keyboard_Modifiers in Ecore_IMF.h.
+  * This function converts from Ecore_Event_Modifier to Ecore_IMF_Keyboard_Modifiers enums.
+  * @param[in] ecoreModifier the Ecore_Event_Modifier input.
+  * @return the Ecore_IMF_Keyboard_Modifiers output.
+  */
+  Ecore_IMF_Keyboard_Modifiers EcoreInputModifierToEcoreIMFModifier( unsigned int ecoreModifier );
+
+  /**
+   * EcoreInputModifierToEcoreIMFLock function converts from Ecore_Event_Modifier to Ecore_IMF_Keyboard_Locks enums.
+   * @param[in] modifier the Ecore_Event_Modifier input.
+   * @return the Ecore_IMF_Keyboard_Locks output.
+   */
+  Ecore_IMF_Keyboard_Locks EcoreInputModifierToEcoreIMFLock( unsigned int modifier );
+
+  /**
+   * Called when the binded actor is added to a window.
+   */
+  void OnStaged( Dali::Actor actor );
+
+private:
+  /**
+   * @brief Constructor.
+   */
+  explicit InputMethodContextEcoreWl( Dali::Actor actor );
+
+protected:
+  /**
+   * Destructor.
+   */
+  virtual ~InputMethodContextEcoreWl() override;
+
+private:
+  // Undefined copy constructor
+  explicit InputMethodContextEcoreWl( const InputMethodContextEcoreWl& inputMethodContext) = delete;
+
+  // Undefined assignment operator
+  InputMethodContextEcoreWl& operator=( const InputMethodContextEcoreWl& inputMethodContext ) = delete;
+
+private:
+  Ecore_IMF_Context* mIMFContext;
+  int mIMFCursorPosition;
+  std::string mSurroundingText;
+
+  bool mRestoreAfterFocusLost:1;             ///< Whether the keyboard needs to be restored (activated ) after focus regained.
+  bool mIdleCallbackConnected:1;             ///< Whether the idle callback is already connected.
+
+  std::vector<Dali::Integration::KeyEvent> mKeyEvents; ///< Stores key events to be sent from idle call-back.
+  InputMethodOptions mOptions;
+  Dali::InputMethodContext::PreEditAttributeDataContainer mPreeditAttrs; ///< Stores preedit attribute data
+
+  int mWindowId;
+};
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_INPUT_METHOD_CONTEXT_IMPL_ECORE_WL_H
diff --git a/dali/internal/input/tizen-wayland/key-mapping-ecore-wl.cpp b/dali/internal/input/tizen-wayland/key-mapping-ecore-wl.cpp
new file mode 100644 (file)
index 0000000..5135819
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * 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 <dali/internal/input/common/key-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace KeyLookup
+{
+
+// matches a DALI_KEY enum, to a key name
+KeyLookup KeyLookupTable[]=
+{
+  // more than one key name can be assigned to a single dali-key code
+  // e.g. "Menu" and "XF86Menu" are both assigned to  DALI_KEY_MENU
+
+  { "Escape",                DALI_KEY_ESCAPE  ,                                          false },
+  { "Menu",                  DALI_KEY_MENU,                                              false },
+
+  // Now literal strings are used as key names instead of defined symbols in utilX,
+  // since these definition in utilX.h is deprecated
+  { "XF86Camera",            DALI_KEY_CAMERA,                                            false },
+  { "XF86Camera_Full",       DALI_KEY_CONFIG,                                            false },
+  { "XF86PowerOff",          DALI_KEY_POWER,                                             true  },
+  { "XF86Standby",           DALI_KEY_PAUSE,                                             false },
+  { "Cancel",                DALI_KEY_CANCEL,                                            false },
+  { "XF86AudioPlay",         DALI_KEY_PLAY_CD,                                           false },
+  { "XF86AudioStop",         DALI_KEY_STOP_CD,                                           false },
+  { "XF86AudioPause",        DALI_KEY_PAUSE_CD,                                          false },
+  { "XF86AudioNext",         DALI_KEY_NEXT_SONG,                                         false },
+  { "XF86AudioPrev",         DALI_KEY_PREVIOUS_SONG,                                     false },
+  { "XF86AudioRewind",       DALI_KEY_REWIND,                                            false },
+  { "XF86AudioForward",      DALI_KEY_FASTFORWARD,                                       false },
+  { "XF86AudioMedia",        DALI_KEY_MEDIA,                                             false },
+  { "XF86AudioPlayPause",    DALI_KEY_PLAY_PAUSE,                                        false },
+  { "XF86AudioMute",         DALI_KEY_MUTE,                                              false },
+  { "XF86Menu",              DALI_KEY_MENU,                                              true  },
+  { "XF86Home",              DALI_KEY_HOME,                                              true  },
+  { "XF86Back",              DALI_KEY_BACK,                                              true  },
+  { "XF86Send",              DALI_KEY_MENU,                                              true  },
+  { "XF86Phone",             DALI_KEY_HOME,                                              true  },
+  { "XF86Stop",              DALI_KEY_BACK,                                              true  },
+  { "XF86HomePage",          DALI_KEY_HOMEPAGE,                                          false },
+  { "XF86WWW",               DALI_KEY_WEBPAGE,                                           false },
+  { "XF86Mail",              DALI_KEY_MAIL,                                              false },
+  { "XF86ScreenSaver",       DALI_KEY_SCREENSAVER,                                       false },
+  { "XF86MonBrightnessUp",   DALI_KEY_BRIGHTNESS_UP,                                     false },
+  { "XF86MonBrightnessDown", DALI_KEY_BRIGHTNESS_DOWN,                                   false },
+  { "XF86SoftKBD",           DALI_KEY_SOFT_KBD,                                          false },
+  { "XF86QuickPanel",        DALI_KEY_QUICK_PANEL,                                       false },
+  { "XF86TaskPane",          DALI_KEY_TASK_SWITCH,                                       false },
+  { "XF86Apps",              DALI_KEY_APPS,                                              false },
+  { "XF86Search",            DALI_KEY_SEARCH,                                            false },
+  { "XF86Voice",             DALI_KEY_VOICE,                                             false },
+  { "Hangul",                DALI_KEY_LANGUAGE,                                          false },
+  { "XF86AudioRaiseVolume",  DALI_KEY_VOLUME_UP,                                         true  },
+  { "XF86AudioLowerVolume",  DALI_KEY_VOLUME_DOWN,                                       true  },
+
+  { "BackSpace",             DALI_KEY_BACKSPACE,                                         false },
+  { "Left",                  DALI_KEY_CURSOR_LEFT,                                       false },
+  { "Right",                 DALI_KEY_CURSOR_RIGHT,                                      false },
+  { "Up",                    DALI_KEY_CURSOR_UP,                                         false },
+  { "Down",                  DALI_KEY_CURSOR_DOWN,                                       false },
+  { "Shift_L",               DALI_KEY_SHIFT_LEFT,                                        false },
+  { "Shift_R",               DALI_KEY_SHIFT_RIGHT,                                       false },
+  { "Delete",                static_cast<Dali::KEY>( DevelKey::DALI_KEY_DELETE ),        false },
+  { "Control_L",             static_cast<Dali::KEY>( DevelKey::DALI_KEY_CONTROL_LEFT ),  false },
+  { "Control_R",             static_cast<Dali::KEY>( DevelKey::DALI_KEY_CONTROL_RIGHT ), false },
+  { "Return",                static_cast<Dali::KEY>( DevelKey::DALI_KEY_RETURN ),        false }
+};
+
+const std::size_t KEY_LOOKUP_COUNT = (sizeof( KeyLookupTable ))/ (sizeof( KeyLookup ));
+
+} // namespace KeyLookup
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/input/tizen-wayland/virtual-keyboard-impl-ecore-wl.cpp b/dali/internal/input/tizen-wayland/virtual-keyboard-impl-ecore-wl.cpp
new file mode 100755 (executable)
index 0000000..82e2a95
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/input/common/virtual-keyboard-impl.h>
+
+// EXTERNAL INCLUDES
+#include <algorithm>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/internal/input/linux/dali-ecore-imf.h>
+#include <dali/internal/system/common/locale-utils.h>
+#include <dali/internal/system/linux/dali-ecore.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace VirtualKeyboard
+{
+
+Dali::InputMethod::ButtonAction::Type gButtonActionFunction = Dali::InputMethod::ButtonAction::DEFAULT;
+
+Ecore_IMF_Input_Panel_Return_Key_Type buttonActionMapping(Dali::InputMethod::ButtonAction::Type buttonAction )
+{
+  switch( buttonAction )
+  {
+    case InputMethod::ButtonAction::DEFAULT:     return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+    case InputMethod::ButtonAction::DONE:        return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DONE;
+    case InputMethod::ButtonAction::GO:          return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_GO;
+    case InputMethod::ButtonAction::JOIN:        return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_JOIN;
+    case InputMethod::ButtonAction::LOGIN:       return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_LOGIN;
+    case InputMethod::ButtonAction::NEXT:        return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_NEXT;
+    case InputMethod::ButtonAction::PREVIOUS:    return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+    case InputMethod::ButtonAction::SEARCH:      return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH;
+    case InputMethod::ButtonAction::SEND:        return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEND;
+    case InputMethod::ButtonAction::SIGNIN:      return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+    case InputMethod::ButtonAction::UNSPECIFIED: return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+    case InputMethod::ButtonAction::NONE:        return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+    default:                                     return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+  }
+}
+
+void RotateTo(int angle)
+{
+}
+
+void SetReturnKeyType( const InputMethod::ButtonAction::Type type )
+{
+}
+
+Dali::InputMethod::ButtonAction::Type GetReturnKeyType()
+{
+  return gButtonActionFunction;
+}
+
+} // namespace VirtualKeyboard
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/input/ubuntu-x11/dali-ecore-input.h b/dali/internal/input/ubuntu-x11/dali-ecore-input.h
new file mode 100644 (file)
index 0000000..4598b70
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef DALI_INTERNAL_INPUT_UBUNTU_X11_DALI_ECORE_INPUT_H
+#define DALI_INTERNAL_INPUT_UBUNTU_X11_DALI_ECORE_INPUT_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#pragma GCC system_header
+#include <Ecore_Input.h>
+
+
+
+#endif /* DALI_INTERNAL_INPUT_UBUNTU_X11_DALI_ECORE_INPUT_H */
diff --git a/dali/internal/input/ubuntu-x11/input-method-context-factory-x.cpp b/dali/internal/input/ubuntu-x11/input-method-context-factory-x.cpp
new file mode 100755 (executable)
index 0000000..fb0fe9e
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 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 <memory>
+#include <dali/internal/input/common/input-method-context-factory.h>
+#include <dali/internal/input/ubuntu-x11/input-method-context-impl-x.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class InputMethodContext;
+
+namespace InputMethodContextFactory
+{
+
+// InputMethodContext Factory to be implemented by the platform
+InputMethodContextPtr CreateInputMethodContext( Dali::Actor actor )
+{
+  return Dali::Internal::Adaptor::InputMethodContextX::New( actor );
+}
+
+}
+
+}
+
+
+
+}
+}
\ No newline at end of file
diff --git a/dali/internal/input/ubuntu-x11/input-method-context-impl-x.cpp b/dali/internal/input/ubuntu-x11/input-method-context-impl-x.cpp
new file mode 100755 (executable)
index 0000000..f9fe6ae
--- /dev/null
@@ -0,0 +1,1027 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/input/ubuntu-x11/input-method-context-impl-x.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/events/key-event.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/key.h>
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/input/common/key-impl.h>
+#include <dali/internal/input/common/virtual-keyboard-impl.h>
+#include <dali/internal/input/linux/dali-ecore-imf.h>
+#include <dali/internal/input/tizen-wayland/ecore-virtual-keyboard.h>
+#include <dali/internal/input/ubuntu-x11/dali-ecore-input.h>
+#include <dali/internal/system/common/locale-utils.h>
+#include <dali/internal/system/linux/dali-ecore.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_INPUT_METHOD_CONTEXT");
+#endif
+
+// Currently this code is internal to dali/dali/internal/event/text/utf8.h but should be made Public and used from there instead.
+size_t Utf8SequenceLength(const unsigned char leadByte)
+{
+  size_t length = 0;
+
+  if( ( leadByte & 0x80 ) == 0 )         //ASCII character (lead bit zero)
+  {
+    length = 1;
+  }
+  else if( ( leadByte & 0xe0 ) == 0xc0 ) //110x xxxx
+  {
+    length = 2;
+  }
+  else if( ( leadByte & 0xf0 ) == 0xe0 ) //1110 xxxx
+  {
+    length = 3;
+  }
+  else if( ( leadByte & 0xf8 ) == 0xf0 ) //1111 0xxx
+  {
+    length = 4;
+  }
+  else if( ( leadByte & 0xfc ) == 0xf8 ) //1111 10xx
+  {
+    length = 5;
+  }
+  else if( ( leadByte & 0xfe ) == 0xfc ) //1111 110x
+  {
+    length = 6;
+  }
+
+  return length;
+}
+
+// Static function calls used by ecore 'c' style callback registration
+void Commit( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
+{
+  if ( data )
+  {
+    InputMethodContextX* inputMethodContext = static_cast< InputMethodContextX* >( data );
+    inputMethodContext->CommitReceived( data, imfContext, eventInfo );
+  }
+}
+
+void PreEdit( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
+{
+  if ( data )
+  {
+    InputMethodContextX* inputMethodContext = static_cast< InputMethodContextX* >( data );
+    inputMethodContext->PreEditChanged( data, imfContext, eventInfo );
+  }
+}
+
+Eina_Bool ImfRetrieveSurrounding(void *data, Ecore_IMF_Context *imfContext, char** text, int* cursorPosition )
+{
+  if ( data )
+  {
+    InputMethodContextX* inputMethodContext = static_cast< InputMethodContextX* >( data );
+    return inputMethodContext->RetrieveSurrounding( data, imfContext, text, cursorPosition );
+  }
+  else
+  {
+    return false;
+  }
+}
+
+/**
+ * Called when an InputMethodContext delete surrounding event is received.
+ * Here we tell the application that it should delete a certain range.
+ */
+void ImfDeleteSurrounding( void *data, Ecore_IMF_Context *imfContext, void *eventInfo )
+{
+  if ( data )
+  {
+    InputMethodContextX* inputMethodContext = static_cast< InputMethodContextX* >( data );
+    inputMethodContext->DeleteSurrounding( data, imfContext, eventInfo );
+  }
+}
+
+} // unnamed namespace
+
+InputMethodContextPtr InputMethodContextX::New( Dali::Actor actor )
+{
+  InputMethodContextPtr manager;
+
+  if( actor && Dali::Adaptor::IsAvailable() )
+  {
+    manager = new InputMethodContextX( actor );
+  }
+
+  return manager;
+}
+
+void InputMethodContextX::Finalize()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::Finalize\n" );
+  VirtualKeyboard::DisconnectCallbacks( mIMFContext );
+  DisconnectCallbacks();
+  DeleteContext();
+}
+
+InputMethodContextX::InputMethodContextX( Dali::Actor actor )
+: mIMFContext(),
+  mEcoreXwin( 0 ),
+  mIMFCursorPosition( 0 ),
+  mSurroundingText(),
+  mRestoreAfterFocusLost( false ),
+  mIdleCallbackConnected( false )
+{
+  ecore_imf_init();
+
+  actor.OnStageSignal().Connect( this, &InputMethodContextX::OnStaged );
+}
+
+InputMethodContextX::~InputMethodContextX()
+{
+  Finalize();
+  ecore_imf_shutdown();
+}
+
+void InputMethodContextX::Initialize()
+{
+  CreateContext();
+  ConnectCallbacks();
+  VirtualKeyboard::ConnectCallbacks( mIMFContext );
+}
+
+void InputMethodContextX::CreateContext()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::CreateContext\n" );
+
+  if( !mEcoreXwin )
+  {
+    return;
+  }
+
+  const char *contextId = ecore_imf_context_default_id_get();
+  if( contextId )
+  {
+    mIMFContext = ecore_imf_context_add( contextId );
+
+    if( mIMFContext )
+    {
+      ecore_imf_context_client_window_set( mIMFContext, reinterpret_cast<void*>( mEcoreXwin ) );
+    }
+    else
+    {
+      DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext Unable to get IMFContext\n");
+    }
+  }
+  else
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContext Unable to get IMFContext\n");
+  }
+}
+
+void InputMethodContextX::DeleteContext()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::DeleteContext\n" );
+
+  if ( mIMFContext )
+  {
+    ecore_imf_context_del( mIMFContext );
+    mIMFContext = NULL;
+  }
+}
+
+// Callbacks for predicitive text support.
+void InputMethodContextX::ConnectCallbacks()
+{
+  if ( mIMFContext )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::ConnectCallbacks\n" );
+
+    ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,    PreEdit,    this );
+    ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,             Commit,     this );
+    ecore_imf_context_event_callback_add( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding, this );
+
+    ecore_imf_context_retrieve_surrounding_callback_set( mIMFContext, ImfRetrieveSurrounding, this);
+  }
+}
+
+void InputMethodContextX::DisconnectCallbacks()
+{
+  if ( mIMFContext )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::DisconnectCallbacks\n" );
+
+    ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_PREEDIT_CHANGED,    PreEdit );
+    ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_COMMIT,             Commit );
+    ecore_imf_context_event_callback_del( mIMFContext, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, ImfDeleteSurrounding );
+
+    // We do not need to unset the retrieve surrounding callback.
+  }
+}
+
+void InputMethodContextX::Activate()
+{
+  // Reset mIdleCallbackConnected
+  mIdleCallbackConnected = false;
+
+  if ( mIMFContext )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::Activate\n" );
+
+    ecore_imf_context_focus_in( mIMFContext );
+
+    // emit keyboard activated signal
+    Dali::InputMethodContext handle( this );
+    mActivatedSignal.Emit( handle );
+  }
+}
+
+void InputMethodContextX::Deactivate()
+{
+  if( mIMFContext )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::Deactivate\n" );
+
+    Reset();
+    ecore_imf_context_focus_out( mIMFContext );
+  }
+
+  // Reset mIdleCallbackConnected
+  mIdleCallbackConnected = false;
+}
+
+void InputMethodContextX::Reset()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::Reset\n" );
+
+  if ( mIMFContext )
+  {
+    ecore_imf_context_reset( mIMFContext );
+  }
+}
+
+ImfContext* InputMethodContextX::GetContext()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetContext\n" );
+
+  return mIMFContext;
+}
+
+bool InputMethodContextX::RestoreAfterFocusLost() const
+{
+  return mRestoreAfterFocusLost;
+}
+
+void InputMethodContextX::SetRestoreAfterFocusLost( bool toggle )
+{
+  mRestoreAfterFocusLost = toggle;
+}
+
+/**
+ * Called when an InputMethodContext Pre-Edit changed event is received.
+ * We are still predicting what the user is typing.  The latest string is what the InputMethodContext module thinks
+ * the user wants to type.
+ */
+void InputMethodContextX::PreEditChanged( void*, ImfContext* imfContext, void* eventInfo )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::PreEditChanged\n" );
+  auto context = static_cast<Ecore_IMF_Context*>( imfContext );
+
+  char* preEditString( NULL );
+  int cursorPosition( 0 );
+  Eina_List* attrs = NULL;
+  Eina_List* l = NULL;
+
+  Ecore_IMF_Preedit_Attr* attr;
+
+  mPreeditAttrs.Clear();
+
+  // Retrieves attributes as well as the string the cursor position offset from start of pre-edit string.
+  // the attributes (attrs) is used in languages that use the soft arrows keys to insert characters into a current pre-edit string.
+  ecore_imf_context_preedit_string_with_attributes_get( context, &preEditString, &attrs, &cursorPosition );
+
+  if ( attrs )
+  {
+    // iterate through the list of attributes getting the type, start and end position.
+    for ( l = attrs, (attr =  static_cast<Ecore_IMF_Preedit_Attr*>( eina_list_data_get(l) ) ); l; l = eina_list_next(l), ( attr = static_cast<Ecore_IMF_Preedit_Attr*>( eina_list_data_get(l) ) ))
+    {
+      Dali::InputMethodContext::PreeditAttributeData data;
+      data.startIndex = 0;
+      data.endIndex = 0;
+
+      size_t visualCharacterIndex = 0;
+      size_t byteIndex = 0;
+
+      // iterate through null terminated string checking each character's position against the given byte position ( attr->end_index ).
+      char leadByte = preEditString[byteIndex];
+
+      while( leadByte != '\0' )
+      {
+        leadByte = preEditString[byteIndex]; // Update the character to get the number of its byte
+
+        // attr->end_index is provided as a byte position not character and we need to know the character position.
+        const size_t currentSequenceLength = Utf8SequenceLength( leadByte ); // returns number of bytes used to represent character.
+        if( byteIndex <= attr->start_index )
+        {
+           data.startIndex = visualCharacterIndex;
+        }
+        if( byteIndex >= attr->end_index )
+        {
+          data.endIndex = visualCharacterIndex;
+          break;
+          // end loop as found cursor position that matches byte position
+        }
+        else
+        {
+          byteIndex += currentSequenceLength; // jump to next character
+          visualCharacterIndex++;  // increment character count so we know our position for when we get a match
+        }
+      }
+
+      switch( attr->preedit_type )
+      {
+        case ECORE_IMF_PREEDIT_TYPE_NONE:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::NONE;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB1:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::UNDERLINE;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB2:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::REVERSE;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB3:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::HIGHLIGHT;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB4:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_1;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB5:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_2;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB6:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_3;
+          break;
+        }
+        case ECORE_IMF_PREEDIT_TYPE_SUB7:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::CUSTOM_PLATFORM_STYLE_4;
+          break;
+        }
+        default:
+        {
+          data.preeditType = Dali::InputMethodContext::PreeditStyle::NONE;
+          break;
+        }
+      }
+      mPreeditAttrs.PushBack( data );
+    }
+  }
+
+  if ( Dali::Adaptor::IsAvailable() )
+  {
+    Dali::InputMethodContext handle( this );
+    Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::PRE_EDIT, preEditString, cursorPosition, 0 );
+    Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
+
+    if( callbackData.update )
+    {
+      mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
+
+      NotifyCursorPosition();
+    }
+
+    if( callbackData.preeditResetRequired )
+    {
+      Reset();
+    }
+  }
+  free( preEditString );
+}
+
+void InputMethodContextX::CommitReceived( void*, ImfContext* imfContext, void* eventInfo )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::CommitReceived\n" );
+
+  if ( Dali::Adaptor::IsAvailable() )
+  {
+    const std::string keyString( static_cast<char*>( eventInfo ) );
+
+    Dali::InputMethodContext handle( this );
+    Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::COMMIT, keyString, 0, 0 );
+    Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );
+
+    if( callbackData.update )
+    {
+      mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
+
+      NotifyCursorPosition();
+    }
+  }
+}
+
+/**
+ * Called when an InputMethodContext retrieve surround event is received.
+ * Here the InputMethodContext module wishes to know the string we are working with and where within the string the cursor is
+ * We need to signal the application to tell us this information.
+ */
+bool InputMethodContextX::RetrieveSurrounding( void* data, ImfContext* imfContext, char** text, int* cursorPosition )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::RetrieveSurrounding\n" );
+
+  Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::GET_SURROUNDING, std::string(), 0, 0 );
+  Dali::InputMethodContext handle( this );
+  Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, imfData );
+
+  if( callbackData.update )
+  {
+    if( text )
+    {
+      *text = strdup( callbackData.currentText.c_str() );
+    }
+
+    if( cursorPosition )
+    {
+      mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
+      *cursorPosition = mIMFCursorPosition;
+    }
+  }
+
+  return EINA_TRUE;
+}
+
+/**
+ * Called when an InputMethodContext delete surrounding event is received.
+ * Here we tell the application that it should delete a certain range.
+ */
+void InputMethodContextX::DeleteSurrounding( void* data, ImfContext* imfContext, void* eventInfo )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::DeleteSurrounding\n" );
+
+  if( Dali::Adaptor::IsAvailable() )
+  {
+    Ecore_IMF_Event_Delete_Surrounding* deleteSurroundingEvent = static_cast<Ecore_IMF_Event_Delete_Surrounding*>( eventInfo );
+
+    Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::DELETE_SURROUNDING, std::string(), deleteSurroundingEvent->offset, deleteSurroundingEvent->n_chars );
+    Dali::InputMethodContext handle( this );
+    Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, imfData );
+
+    if( callbackData.update )
+    {
+      mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );
+
+      NotifyCursorPosition();
+    }
+  }
+}
+
+void InputMethodContextX::NotifyCursorPosition()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::NotifyCursorPosition\n" );
+
+  if( mIMFContext )
+  {
+    ecore_imf_context_cursor_position_set( mIMFContext, mIMFCursorPosition );
+  }
+}
+
+void InputMethodContextX::SetCursorPosition( unsigned int cursorPosition )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetCursorPosition\n" );
+
+  mIMFCursorPosition = static_cast<int>( cursorPosition );
+}
+
+unsigned int InputMethodContextX::GetCursorPosition() const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetCursorPosition\n" );
+
+  return static_cast<unsigned int>( mIMFCursorPosition );
+}
+
+void InputMethodContextX::SetSurroundingText( const std::string& text )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetSurroundingText\n" );
+
+  mSurroundingText = text;
+}
+
+const std::string& InputMethodContextX::GetSurroundingText() const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetSurroundingText\n" );
+
+  return mSurroundingText;
+}
+
+void InputMethodContextX::NotifyTextInputMultiLine( bool multiLine )
+{
+}
+
+Dali::InputMethodContext::TextDirection InputMethodContextX::GetTextDirection()
+{
+  Dali::InputMethodContext::TextDirection direction ( Dali::InputMethodContext::LeftToRight );
+
+    if ( mIMFContext )
+    {
+      char* locale( NULL );
+      ecore_imf_context_input_panel_language_locale_get( mIMFContext, &locale );
+
+      if ( locale )
+      {
+        direction = static_cast< Dali::InputMethodContext::TextDirection >( Locale::GetDirection( std::string( locale ) ) );
+        free( locale );
+      }
+    }
+
+  return direction;
+}
+
+Rect<int> InputMethodContextX::GetInputMethodArea()
+{
+  int xPos, yPos, width, height;
+
+  width = height = xPos = yPos = 0;
+
+  if( mIMFContext )
+  {
+    ecore_imf_context_input_panel_geometry_get( mIMFContext, &xPos, &yPos, &width, &height );
+  }
+  else
+  {
+    DALI_LOG_WARNING("VKB Unable to get InputMethodContext Context so GetSize unavailable\n");
+  }
+
+  return Rect<int>(xPos,yPos,width,height);
+}
+
+void InputMethodContextX::ApplyOptions( const InputMethodOptions& options )
+{
+  using namespace Dali::InputMethod::Category;
+
+  int index;
+
+  if (mIMFContext == NULL)
+  {
+    DALI_LOG_WARNING("VKB Unable to excute ApplyOptions with Null ImfContext\n");
+    return;
+  }
+
+  if ( mOptions.CompareAndSet(PANEL_LAYOUT, options, index) )
+  {
+  }
+  if ( mOptions.CompareAndSet(BUTTON_ACTION, options, index) )
+  {
+  }
+  if ( mOptions.CompareAndSet(AUTO_CAPITALIZE, options, index) )
+  {
+  }
+  if ( mOptions.CompareAndSet(VARIATION, options, index) )
+  {
+  }
+}
+
+void InputMethodContextX::SetInputPanelData( const std::string& data )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetInputPanelData\n" );
+
+  if( mIMFContext )
+  {
+    int length = data.length();
+    ecore_imf_context_input_panel_imdata_set( mIMFContext, data.c_str(), length );
+  }
+}
+
+void InputMethodContextX::GetInputPanelData( std::string& data )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelData\n" );
+
+  if( mIMFContext )
+  {
+    int length = 4096; // The max length is 4096 bytes
+    Dali::Vector< char > buffer;
+    buffer.Resize( length );
+    ecore_imf_context_input_panel_imdata_get( mIMFContext, &buffer[0], &length );
+    data = std::string( buffer.Begin(), buffer.End() );
+  }
+}
+
+Dali::InputMethodContext::State InputMethodContextX::GetInputPanelState()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelState\n" );
+
+  if( mIMFContext )
+  {
+    int value;
+    value = ecore_imf_context_input_panel_state_get( mIMFContext );
+
+    switch (value)
+    {
+      case ECORE_IMF_INPUT_PANEL_STATE_SHOW:
+      {
+        return Dali::InputMethodContext::SHOW;
+        break;
+      }
+
+      case ECORE_IMF_INPUT_PANEL_STATE_HIDE:
+      {
+        return Dali::InputMethodContext::HIDE;
+        break;
+      }
+
+      case ECORE_IMF_INPUT_PANEL_STATE_WILL_SHOW:
+      {
+        return Dali::InputMethodContext::WILL_SHOW;
+        break;
+      }
+
+      default:
+      {
+        return Dali::InputMethodContext::DEFAULT;
+      }
+    }
+  }
+  return Dali::InputMethodContext::DEFAULT;
+}
+
+void InputMethodContextX::SetReturnKeyState( bool visible )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetReturnKeyState\n" );
+
+  if( mIMFContext )
+  {
+    ecore_imf_context_input_panel_return_key_disabled_set( mIMFContext, !visible );
+  }
+}
+
+void InputMethodContextX::AutoEnableInputPanel( bool enabled )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::AutoEnableInputPanel\n" );
+
+  if( mIMFContext )
+  {
+    ecore_imf_context_input_panel_enabled_set( mIMFContext, enabled );
+  }
+}
+
+void InputMethodContextX::ShowInputPanel()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::ShowInputPanel\n" );
+
+  if( mIMFContext )
+  {
+    ecore_imf_context_input_panel_show( mIMFContext );
+  }
+}
+
+void InputMethodContextX::HideInputPanel()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::HideInputPanel\n" );
+
+  if( mIMFContext )
+  {
+    ecore_imf_context_input_panel_hide( mIMFContext );
+  }
+}
+
+Dali::InputMethodContext::KeyboardType InputMethodContextX::GetKeyboardType()
+{
+  return Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD;
+}
+
+std::string InputMethodContextX::GetInputPanelLocale()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelLocale\n" );
+
+  std::string locale = "";
+
+  if( mIMFContext )
+  {
+    char* value = NULL;
+    ecore_imf_context_input_panel_language_locale_get( mIMFContext, &value );
+
+    if( value )
+    {
+      std::string valueCopy( value );
+      locale = valueCopy;
+
+      // The locale string retrieved must be freed with free().
+      free( value );
+    }
+  }
+  return locale;
+}
+
+void InputMethodContextX::SetContentMIMETypes( const std::string& mimeTypes )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetContentMIMETypes\n" );
+  // ecore_imf_context_mime_type_accept_set() is supported from ecore-imf 1.20.0 version.
+}
+
+bool InputMethodContextX::FilterEventKey( const Dali::KeyEvent& keyEvent )
+{
+  bool eventHandled( false );
+
+  // If a device key then skip ecore_imf_context_filter_event.
+  if ( ! KeyLookup::IsDeviceButton( keyEvent.keyPressedName.c_str() ))
+  {
+    //check whether it's key down or key up event
+    if ( keyEvent.state == KeyEvent::Down )
+    {
+      eventHandled = ProcessEventKeyDown( keyEvent );
+    }
+    else if ( keyEvent.state == KeyEvent::Up )
+    {
+      eventHandled = ProcessEventKeyUp( keyEvent );
+    }
+  }
+
+  return eventHandled;
+}
+
+void InputMethodContextX::AllowTextPrediction( bool prediction )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::AllowTextPrediction\n" );
+
+  if( mIMFContext )
+  {
+    ecore_imf_context_prediction_allow_set( mIMFContext, prediction );
+  }
+}
+
+bool InputMethodContextX::IsTextPredictionAllowed() const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::IsTextPredictionAllowed\n" );
+  bool prediction = false;
+  if( mIMFContext )
+  {
+    prediction = ecore_imf_context_prediction_allow_get( mIMFContext );
+  }
+  return prediction;
+}
+
+void InputMethodContextX::SetInputPanelLanguage( Dali::InputMethodContext::InputPanelLanguage language )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetInputPanelLanguage\n" );
+  if( mIMFContext )
+  {
+    switch (language)
+    {
+      case Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC:
+      {
+        ecore_imf_context_input_panel_language_set( mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC );
+        break;
+      }
+      case Dali::InputMethodContext::InputPanelLanguage::ALPHABET:
+      {
+        ecore_imf_context_input_panel_language_set( mIMFContext, ECORE_IMF_INPUT_PANEL_LANG_ALPHABET );
+        break;
+      }
+    }
+  }
+}
+
+Dali::InputMethodContext::InputPanelLanguage InputMethodContextX::GetInputPanelLanguage() const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetInputPanelLanguage\n" );
+  if( mIMFContext )
+  {
+    int value;
+    value =  ecore_imf_context_input_panel_language_get( mIMFContext );
+
+    switch (value)
+    {
+      case ECORE_IMF_INPUT_PANEL_LANG_AUTOMATIC:
+      {
+        return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
+        break;
+      }
+      case ECORE_IMF_INPUT_PANEL_LANG_ALPHABET:
+      {
+        return Dali::InputMethodContext::InputPanelLanguage::ALPHABET;
+        break;
+      }
+    }
+  }
+  return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;
+}
+
+void InputMethodContextX::SetInputPanelPosition( unsigned int x, unsigned int y )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::SetInputPanelPosition\n" );
+
+  // ecore_imf_context_input_panel_position_set() is supported from ecore-imf 1.21.0 version.
+}
+
+void InputMethodContextX::GetPreeditStyle( Dali::InputMethodContext::PreEditAttributeDataContainer& attrs ) const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextX::GetPreeditStyle\n" );
+  attrs = mPreeditAttrs;
+}
+
+bool InputMethodContextX::ProcessEventKeyDown( const KeyEvent& keyEvent )
+{
+  bool eventHandled( false );
+  if ( mIMFContext )
+  {
+    Integration::KeyEvent integKeyEvent( keyEvent );
+    std::string key = integKeyEvent.logicalKey;
+
+    std::string compose = keyEvent.GetCompose();
+
+    // We're consuming key down event so we have to pass to InputMethodContext so that it can parse it as well.
+    Ecore_IMF_Event_Key_Down ecoreKeyDownEvent;
+    ecoreKeyDownEvent.keyname = keyEvent.keyPressedName.c_str();
+    ecoreKeyDownEvent.key = key.c_str();
+    ecoreKeyDownEvent.string = keyEvent.keyPressed.c_str();
+    ecoreKeyDownEvent.compose = compose.c_str();
+    ecoreKeyDownEvent.timestamp = keyEvent.time;
+    ecoreKeyDownEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
+    ecoreKeyDownEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
+
+#if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR)
+#if (ECORE_VERSION_MINOR >= 14)
+    ecoreKeyDownEvent.dev_name  = "";
+    ecoreKeyDownEvent.dev_class = ECORE_IMF_DEVICE_CLASS_KEYBOARD;
+    ecoreKeyDownEvent.dev_subclass = ECORE_IMF_DEVICE_SUBCLASS_NONE;
+#endif // Since ecore_imf 1.14 version
+#if (ECORE_VERSION_MINOR >= 22)
+    ecoreKeyDownEvent.keycode = keyEvent.keyCode;
+#endif // Since ecore_imf 1.22 version
+#endif // Since ecore_imf Version 1
+
+    // If the device is IME and the focused key is the direction keys, then we should send a key event to move a key cursor.
+    if ((keyEvent.GetDeviceName() == "ime") && ((!strncmp(keyEvent.keyPressedName.c_str(), "Left", 4)) ||
+                                   (!strncmp(keyEvent.keyPressedName.c_str(), "Right", 5)) ||
+                                   (!strncmp(keyEvent.keyPressedName.c_str(), "Up", 2)) ||
+                                   (!strncmp(keyEvent.keyPressedName.c_str(), "Down", 4))))
+    {
+      eventHandled = 0;
+    }
+    else
+    {
+      eventHandled = ecore_imf_context_filter_event(mIMFContext,
+                                                    ECORE_IMF_EVENT_KEY_DOWN,
+                                                    reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyDownEvent ));
+    }
+
+    // If the event has not been handled by InputMethodContext then check if we should reset our IMFcontext
+    if (!eventHandled)
+    {
+      if (!strcmp(keyEvent.keyPressedName.c_str(), "Escape") ||
+          !strcmp(keyEvent.keyPressedName.c_str(), "Return") ||
+          !strcmp(keyEvent.keyPressedName.c_str(), "KP_Enter"))
+      {
+        ecore_imf_context_reset(mIMFContext);
+      }
+    }
+  }
+  return eventHandled;
+}
+
+bool InputMethodContextX::ProcessEventKeyUp( const KeyEvent& keyEvent )
+{
+  bool eventHandled( false );
+  if( mIMFContext )
+  {
+    Integration::KeyEvent integKeyEvent( keyEvent );
+    std::string key = integKeyEvent.logicalKey;
+
+    std::string compose = keyEvent.GetCompose();
+
+    // We're consuming key up event so we have to pass to InputMethodContext so that it can parse it as well.
+    Ecore_IMF_Event_Key_Up ecoreKeyUpEvent;
+    ecoreKeyUpEvent.keyname = keyEvent.keyPressedName.c_str();
+    ecoreKeyUpEvent.key = key.c_str();
+    ecoreKeyUpEvent.string = keyEvent.keyPressed.c_str();
+    ecoreKeyUpEvent.compose = compose.c_str();
+    ecoreKeyUpEvent.timestamp = keyEvent.time;
+    ecoreKeyUpEvent.modifiers = EcoreInputModifierToEcoreIMFModifier( keyEvent.keyModifier );
+    ecoreKeyUpEvent.locks = EcoreInputModifierToEcoreIMFLock( keyEvent.keyModifier );
+#if defined(ECORE_VERSION_MAJOR) && (ECORE_VERSION_MAJOR >= 1) && defined(ECORE_VERSION_MINOR)
+#if (ECORE_VERSION_MINOR >= 14)
+    ecoreKeyUpEvent.dev_name  = "";
+#endif // Since ecore_imf 1.14 version
+#if (ECORE_VERSION_MINOR >= 22)
+    ecoreKeyUpEvent.keycode = keyEvent.keyCode;
+#endif // Since ecore_imf 1.22 version
+#endif // Since ecore_imf Version 1
+
+    eventHandled = ecore_imf_context_filter_event(mIMFContext,
+                                                  ECORE_IMF_EVENT_KEY_UP,
+                                                  reinterpret_cast<Ecore_IMF_Event *>( &ecoreKeyUpEvent ));
+  }
+  return eventHandled;
+}
+
+Ecore_IMF_Keyboard_Modifiers InputMethodContextX::EcoreInputModifierToEcoreIMFModifier( unsigned int ecoreModifier )
+{
+  unsigned int modifier( ECORE_IMF_KEYBOARD_MODIFIER_NONE );  // If no other matches returns NONE.
+
+  if ( ecoreModifier & ECORE_EVENT_MODIFIER_SHIFT )  // enums from ecore_input/Ecore_Input.h
+  {
+    modifier |= ECORE_IMF_KEYBOARD_MODIFIER_SHIFT;  // enums from ecore_imf/ecore_imf.h
+  }
+
+  if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALT )
+  {
+    modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALT;
+  }
+
+  if ( ecoreModifier & ECORE_EVENT_MODIFIER_CTRL )
+  {
+    modifier |= ECORE_IMF_KEYBOARD_MODIFIER_CTRL;
+  }
+
+  if ( ecoreModifier & ECORE_EVENT_MODIFIER_WIN )
+  {
+    modifier |= ECORE_IMF_KEYBOARD_MODIFIER_WIN;
+  }
+
+  if ( ecoreModifier & ECORE_EVENT_MODIFIER_ALTGR )
+  {
+    modifier |= ECORE_IMF_KEYBOARD_MODIFIER_ALTGR;
+  }
+
+  return static_cast<Ecore_IMF_Keyboard_Modifiers>( modifier );
+}
+
+Ecore_IMF_Keyboard_Locks InputMethodContextX::EcoreInputModifierToEcoreIMFLock( unsigned int modifier )
+{
+    unsigned int lock( ECORE_IMF_KEYBOARD_LOCK_NONE ); // If no other matches, returns NONE.
+
+    if( modifier & ECORE_EVENT_LOCK_NUM )
+    {
+      lock |= ECORE_IMF_KEYBOARD_LOCK_NUM; // Num lock is active.
+    }
+
+    if( modifier & ECORE_EVENT_LOCK_CAPS )
+    {
+      lock |= ECORE_IMF_KEYBOARD_LOCK_CAPS; // Caps lock is active.
+    }
+
+    if( modifier & ECORE_EVENT_LOCK_SCROLL )
+    {
+      lock |= ECORE_IMF_KEYBOARD_LOCK_SCROLL; // Scroll lock is active.
+    }
+
+    return static_cast<Ecore_IMF_Keyboard_Locks>( lock );
+}
+
+void InputMethodContextX::OnStaged( Dali::Actor actor )
+{
+  Ecore_X_Window ecoreXwin( AnyCast< Ecore_X_Window >( Dali::Integration::SceneHolder::Get( actor ).GetNativeHandle() ) );
+
+  if( mEcoreXwin != ecoreXwin )
+  {
+    mEcoreXwin = ecoreXwin;
+
+    // Reset
+    Finalize();
+    Initialize();
+  }
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/dali/internal/input/ubuntu-x11/input-method-context-impl-x.h b/dali/internal/input/ubuntu-x11/input-method-context-impl-x.h
new file mode 100755 (executable)
index 0000000..e707386
--- /dev/null
@@ -0,0 +1,358 @@
+#ifndef DALI_INTERNAL_INPUT_METHOD_CONTEXT_IMPL_X_H
+#define DALI_INTERNAL_INPUT_METHOD_CONTEXT_IMPL_X_H
+
+/*
+ * Copyright (c) 2019 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/internal/input/linux/dali-ecore-imf.h>
+#include <dali/internal/system/linux/dali-ecore-x.h>
+
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/input-method-context.h>
+#include <dali/internal/input/common/input-method-context-impl.h>
+
+namespace Dali
+{
+
+class RenderSurface;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class InputMethodContextX : public Dali::Internal::Adaptor::InputMethodContext, public Dali::ConnectionTracker
+{
+public:
+  /**
+   * @brief Creates a new InputMethodContext handle
+   *
+   * @param[in] actor The actor that uses the new InputMethodContext instance.
+   * @return InputMethodContext pointer
+   */
+  static InputMethodContextPtr New( Dali::Actor actor );
+
+  /**
+   * Constructor
+   * @param[in] actor The actor that uses the new InputMethodContext instance.
+   */
+  explicit InputMethodContextX( Dali::Actor actor );
+
+public:
+
+  /**
+   * @brief Initializes member data.
+   */
+  void Initialize() override;
+
+  /**
+   * Connect Callbacks required for InputMethodContext.
+   * If you don't connect InputMethodContext callbacks, you can't get the key events.
+   * The events are PreeditChanged, Commit and DeleteSurrounding.
+   */
+  void ConnectCallbacks() override;
+
+  /**
+   * Disconnect Callbacks attached to input method context.
+   */
+  void DisconnectCallbacks() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::Finalize()
+   */
+  void Finalize() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::Activate()
+   */
+  void Activate() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::Deactivate()
+   */
+  void Deactivate() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::Reset()
+   */
+  void Reset() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetContext()
+   */
+  ImfContext* GetContext() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::RestoreAfterFocusLost()
+   */
+  bool RestoreAfterFocusLost() const override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetRestoreAfterFocusLost()
+   */
+  void SetRestoreAfterFocusLost( bool toggle ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::PreEditChanged()
+   */
+  void PreEditChanged( void* data, ImfContext* imfContext, void* eventInfo ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::NotifyCursorPosition()
+   */
+  void CommitReceived( void* data, ImfContext* imfContext, void* eventInfo ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::NotifyCursorPosition()
+   */
+  bool RetrieveSurrounding( void* data, ImfContext* imfContext, char** text, int* cursorPosition ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::DeleteSurrounding()
+   */
+  void DeleteSurrounding( void* data, ImfContext* imfContext, void* eventInfo ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SendPrivateCommand()
+   */
+  void SendPrivateCommand( void* data, ImfContext* imfContext, void* eventInfo ) override
+  {}
+
+  /**
+   * @copydoc Dali::InputMethodContext::SendCommitContent()
+   */
+  void SendCommitContent( void* data, ImfContext* imfContext, void* eventInfo ) override
+  {}
+
+  // Cursor related
+  /**
+   * @copydoc Dali::InputMethodContext::NotifyCursorPosition()
+   */
+  void NotifyCursorPosition() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetCursorPosition()
+   */
+  void SetCursorPosition( unsigned int cursorPosition ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetCursorPosition()
+   */
+  unsigned int GetCursorPosition() const override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetSurroundingText()
+   */
+  void SetSurroundingText( const std::string& text ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetSurroundingText()
+   */
+  const std::string& GetSurroundingText() const override;
+
+  /**
+  * @copydoc Dali::InputMethodContext::NotifyTextInputMultiLine()
+  */
+  void NotifyTextInputMultiLine( bool multiLine ) override;
+
+  /**
+  * @copydoc Dali::InputMethodContext::GetTextDirection()
+  */
+  Dali::InputMethodContext::TextDirection GetTextDirection() override;
+
+  /**
+  * @copydoc Dali::InputMethodContext::GetInputMethodArea()
+  */
+  Dali::Rect<int> GetInputMethodArea() override;
+
+  /**
+  * @copydoc Dali::InputMethodContext::ApplyOptions()
+  */
+  void ApplyOptions( const InputMethodOptions& options ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetInputPanelData()
+   */
+  void SetInputPanelData( const std::string& data ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetInputPanelData()
+   */
+  void GetInputPanelData( std::string& data ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetInputPanelState()
+   */
+  Dali::InputMethodContext::State GetInputPanelState() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetReturnKeyState()
+   */
+  void SetReturnKeyState( bool visible ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::AutoEnableInputPanel()
+   */
+  void AutoEnableInputPanel( bool enabled ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::ShowInputPanel()
+   */
+  void ShowInputPanel() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::HideInputPanel()
+   */
+  void HideInputPanel() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetKeyboardType()
+   */
+  Dali::InputMethodContext::KeyboardType GetKeyboardType() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetInputPanelLocale()
+   */
+  std::string GetInputPanelLocale() override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetContentMIMETypes()
+   */
+  void SetContentMIMETypes( const std::string& mimeTypes ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::FilterEventKey()
+   */
+  bool FilterEventKey( const Dali::KeyEvent& keyEvent ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::AllowTextPrediction()
+   */
+  void AllowTextPrediction( bool prediction ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::IsTextPredictionAllowed()
+   */
+  bool IsTextPredictionAllowed() const override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetInputPanelLanguage()
+   */
+  void SetInputPanelLanguage( Dali::InputMethodContext::InputPanelLanguage language ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetInputPanelLanguage()
+   */
+  Dali::InputMethodContext::InputPanelLanguage GetInputPanelLanguage() const override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::SetInputPanelPosition()
+   */
+  void SetInputPanelPosition( unsigned int x, unsigned int y ) override;
+
+  /**
+   * @copydoc Dali::InputMethodContext::GetPreeditStyle()
+   */
+  void GetPreeditStyle( Dali::InputMethodContext::PreEditAttributeDataContainer& attrs ) const override;
+
+private:
+  /**
+   * Context created the first time and kept until deleted.
+   */
+  void CreateContext();
+
+  /**
+   * @copydoc Dali::InputMethodContext::DeleteContext()
+   */
+  void DeleteContext();
+
+private:
+
+  /**
+   * @brief Process event key down, whether filter a key to isf.
+   *
+   * @param[in] keyEvent The event key to be handled.
+   * @return Whether the event key is handled.
+   */
+  bool ProcessEventKeyDown( const KeyEvent& keyEvent );
+
+  /**
+   * @brief Process event key up, whether filter a key to isf.
+   *
+   * @param[in] keyEvent The event key to be handled.
+   * @return Whether the event key is handled.
+   */
+  bool ProcessEventKeyUp( const KeyEvent& keyEvent );
+
+  /**
+  * Ecore_Event_Modifier enums in Ecore_Input.h do not match Ecore_IMF_Keyboard_Modifiers in Ecore_IMF.h.
+  * This function converts from Ecore_Event_Modifier to Ecore_IMF_Keyboard_Modifiers enums.
+  * @param[in] ecoreModifier the Ecore_Event_Modifier input.
+  * @return the Ecore_IMF_Keyboard_Modifiers output.
+  */
+  Ecore_IMF_Keyboard_Modifiers EcoreInputModifierToEcoreIMFModifier( unsigned int ecoreModifier );
+
+  /**
+   * EcoreInputModifierToEcoreIMFLock function converts from Ecore_Event_Modifier to Ecore_IMF_Keyboard_Locks enums.
+   * @param[in] modifier the Ecore_Event_Modifier input.
+   * @return the Ecore_IMF_Keyboard_Locks output.
+   */
+  Ecore_IMF_Keyboard_Locks EcoreInputModifierToEcoreIMFLock( unsigned int modifier );
+
+  /**
+   * Called when the binded actor is added to a window.
+   */
+  void OnStaged( Dali::Actor actor );
+
+public:
+
+  /**
+   * Destructor.
+   */
+  virtual ~InputMethodContextX();
+
+private:
+
+  // Undefined copy constructor
+  InputMethodContextX( const InputMethodContextX& inputMethodContext) = delete;
+
+  // Undefined assignment operator
+  InputMethodContextX& operator=( const InputMethodContextX& inputMethodContext ) = delete;
+
+private:
+  Ecore_IMF_Context* mIMFContext;
+  Ecore_X_Window mEcoreXwin;
+  int mIMFCursorPosition;
+  std::string mSurroundingText;
+
+  bool mRestoreAfterFocusLost:1;             ///< Whether the keyboard needs to be restored (activated ) after focus regained.
+  bool mIdleCallbackConnected:1;             ///< Whether the idle callback is already connected.
+  InputMethodOptions        mOptions;
+  Dali::InputMethodContext::PreEditAttributeDataContainer mPreeditAttrs; ///< Stores preedit attribute data
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_INPUT_METHOD_CONTEXT_IMPL_X_H
diff --git a/dali/internal/input/ubuntu-x11/key-mapping-x.cpp b/dali/internal/input/ubuntu-x11/key-mapping-x.cpp
new file mode 100644 (file)
index 0000000..a69ee10
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * 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 <dali/internal/input/common/key-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace KeyLookup
+{
+
+// matches a DALI_KEY enum, to a key name
+KeyLookup KeyLookupTable[]=
+{
+  // more than one key name can be assigned to a single dali-key code
+  // e.g. "Menu" and "XF86Menu" are both assigned to  DALI_KEY_MENU
+
+  { "Escape",                DALI_KEY_ESCAPE,                                            false },
+  { "Menu",                  DALI_KEY_MENU,                                              false },
+
+  // Now literal strings are used as key names instead of defined symbols in utilX,
+  // since these definition in utilX.h is deprecated
+  { "XF86Camera",            DALI_KEY_CAMERA,                                            false },
+  { "XF86Camera_Full",       DALI_KEY_CONFIG,                                            false },
+  { "XF86PowerOff",          DALI_KEY_POWER,                                             true  },
+  { "XF86Standby",           DALI_KEY_PAUSE,                                             false },
+  { "Cancel",                DALI_KEY_CANCEL,                                            false },
+  { "XF86AudioPlay",         DALI_KEY_PLAY_CD,                                           false },
+  { "XF86AudioStop",         DALI_KEY_STOP_CD,                                           false },
+  { "XF86AudioPause",        DALI_KEY_PAUSE_CD,                                          false },
+  { "XF86AudioNext",         DALI_KEY_NEXT_SONG,                                         false },
+  { "XF86AudioPrev",         DALI_KEY_PREVIOUS_SONG,                                     false },
+  { "XF86AudioRewind",       DALI_KEY_REWIND,                                            false },
+  { "XF86AudioForward",      DALI_KEY_FASTFORWARD,                                       false },
+  { "XF86AudioMedia",        DALI_KEY_MEDIA,                                             false },
+  { "XF86AudioPlayPause",    DALI_KEY_PLAY_PAUSE,                                        false },
+  { "XF86AudioMute",         DALI_KEY_MUTE,                                              false },
+  { "XF86Menu",              DALI_KEY_MENU,                                              true  },
+  { "XF86Home",              DALI_KEY_HOME,                                              true  },
+  { "XF86Back",              DALI_KEY_BACK,                                              true  },
+  { "XF86Send",              DALI_KEY_MENU,                                              true  },
+  { "XF86Phone",             DALI_KEY_HOME,                                              true  },
+  { "XF86Stop",              DALI_KEY_BACK,                                              true  },
+  { "XF86HomePage",          DALI_KEY_HOMEPAGE,                                          false },
+  { "XF86WWW",               DALI_KEY_WEBPAGE,                                           false },
+  { "XF86Mail",              DALI_KEY_MAIL,                                              false },
+  { "XF86ScreenSaver",       DALI_KEY_SCREENSAVER,                                       false },
+  { "XF86MonBrightnessUp",   DALI_KEY_BRIGHTNESS_UP,                                     false },
+  { "XF86MonBrightnessDown", DALI_KEY_BRIGHTNESS_DOWN,                                   false },
+  { "XF86SoftKBD",           DALI_KEY_SOFT_KBD,                                          false },
+  { "XF86QuickPanel",        DALI_KEY_QUICK_PANEL,                                       false },
+  { "XF86TaskPane",          DALI_KEY_TASK_SWITCH,                                       false },
+  { "XF86Apps",              DALI_KEY_APPS,                                              false },
+  { "XF86Search",            DALI_KEY_SEARCH,                                            false },
+  { "XF86Voice",             DALI_KEY_VOICE,                                             false },
+  { "Hangul",                DALI_KEY_LANGUAGE,                                          false },
+  { "XF86AudioRaiseVolume",  DALI_KEY_VOLUME_UP,                                         true  },
+  { "XF86AudioLowerVolume",  DALI_KEY_VOLUME_DOWN,                                       true  },
+
+  { "BackSpace",             DALI_KEY_BACKSPACE,                                         false },
+  { "Left",                  DALI_KEY_CURSOR_LEFT,                                       false },
+  { "Right",                 DALI_KEY_CURSOR_RIGHT,                                      false },
+  { "Shift_L",               DALI_KEY_SHIFT_LEFT,                                        false },
+  { "Shift_R",               DALI_KEY_SHIFT_RIGHT,                                       false },
+  { "Delete",                static_cast<Dali::KEY>( DevelKey::DALI_KEY_DELETE ),        false },
+  { "Control_L",             static_cast<Dali::KEY>( DevelKey::DALI_KEY_CONTROL_LEFT ),  false },
+  { "Control_R",             static_cast<Dali::KEY>( DevelKey::DALI_KEY_CONTROL_RIGHT ), false },
+  { "Return",                static_cast<Dali::KEY>( DevelKey::DALI_KEY_RETURN ),        false }
+};
+
+const std::size_t KEY_LOOKUP_COUNT = (sizeof( KeyLookupTable ))/ (sizeof( KeyLookup ));
+
+} // namespace KeyLookup
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/input/ubuntu-x11/virtual-keyboard-impl-x.cpp b/dali/internal/input/ubuntu-x11/virtual-keyboard-impl-x.cpp
new file mode 100755 (executable)
index 0000000..a1a46f6
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/input/common/virtual-keyboard-impl.h>
+
+// EXTERNAL INCLUDES
+#include <algorithm>
+#include <X11/Xlib.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+#include <dali/internal/input/ubuntu-x11/input-method-context-impl-x.h>
+#include <dali/internal/system/common/locale-utils.h>
+#include <dali/internal/system/linux/dali-ecore-x.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace VirtualKeyboard
+{
+
+Dali::InputMethod::ButtonAction::Type gButtonActionFunction = Dali::InputMethod::ButtonAction::DEFAULT;
+
+Ecore_IMF_Input_Panel_Return_Key_Type buttonActionMapping(Dali::InputMethod::ButtonAction::Type buttonAction )
+{
+  switch( buttonAction )
+  {
+    case InputMethod::ButtonAction::DEFAULT:     return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+    case InputMethod::ButtonAction::DONE:        return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DONE;
+    case InputMethod::ButtonAction::GO:          return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_GO;
+    case InputMethod::ButtonAction::JOIN:        return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_JOIN;
+    case InputMethod::ButtonAction::LOGIN:       return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_LOGIN;
+    case InputMethod::ButtonAction::NEXT:        return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_NEXT;
+    case InputMethod::ButtonAction::PREVIOUS:    return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+    case InputMethod::ButtonAction::SEARCH:      return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEARCH;
+    case InputMethod::ButtonAction::SEND:        return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_SEND;
+    case InputMethod::ButtonAction::SIGNIN:      return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+    case InputMethod::ButtonAction::UNSPECIFIED: return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+    case InputMethod::ButtonAction::NONE:        return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+    default:                                     return ECORE_IMF_INPUT_PANEL_RETURN_KEY_TYPE_DEFAULT;
+  }
+}
+
+void RotateTo(int angle)
+{
+  // Get focus window used by Keyboard and rotate it
+  Display* display = XOpenDisplay(0);
+  if (display)
+  {
+    ::Window focusWindow;
+    int revert;
+    // Get Focus window
+    XGetInputFocus(display, &focusWindow, &revert);
+
+    ecore_x_window_prop_property_set( static_cast<Ecore_X_Window>( focusWindow ),
+                                      ECORE_X_ATOM_E_ILLUME_ROTATE_WINDOW_ANGLE,
+                                      ECORE_X_ATOM_CARDINAL, 32, &angle, 1 );
+    XCloseDisplay(display);
+  }
+}
+
+void SetReturnKeyType( const InputMethod::ButtonAction::Type type )
+{
+}
+
+Dali::InputMethod::ButtonAction::Type GetReturnKeyType()
+{
+  return gButtonActionFunction;
+}
+
+} // namespace VirtualKeyboard
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/input/windows/input-method-context-factory-win.cpp b/dali/internal/input/windows/input-method-context-factory-win.cpp
new file mode 100755 (executable)
index 0000000..131bbb5
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 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 <memory>
+#include <dali/internal/input/common/input-method-context-factory.h>
+#include <dali/internal/input/windows/input-method-context-impl-win.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class InputMethodContext;
+
+namespace InputMethodContextFactory
+{
+
+// InputMethodContext Factory to be implemented by the platform
+InputMethodContextPtr CreateInputMethodContext( Dali::Actor actor )
+{
+  return Dali::Internal::Adaptor::InputMethodContextWin::New( actor );
+}
+
+}
+
+}
+
+
+
+}
+}
\ No newline at end of file
diff --git a/dali/internal/input/windows/input-method-context-impl-win.cpp b/dali/internal/input/windows/input-method-context-impl-win.cpp
new file mode 100755 (executable)
index 0000000..3437f02
--- /dev/null
@@ -0,0 +1,411 @@
+/*\r
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// CLASS HEADER\r
+#include <dali/internal/input/windows/input-method-context-impl-win.h>\r
+\r
+// EXTERNAL INCLUDES\r
+#include <dali/public-api/events/key-event.h>\r
+#include <dali/public-api/object/type-registry.h>\r
+#include <dali/devel-api/common/singleton-service.h>\r
+#include <dali/integration-api/debug.h>\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali/public-api/adaptor-framework/key.h>\r
+#include <dali/integration-api/adaptor-framework/adaptor.h>\r
+#include <dali/internal/adaptor/common/adaptor-impl.h>\r
+#include <dali/internal/input/common/key-impl.h>\r
+#include <dali/internal/input/common/virtual-keyboard-impl.h>\r
+#include <dali/internal/system/common/locale-utils.h>\r
+\r
+namespace Dali\r
+{\r
+\r
+namespace Internal\r
+{\r
+\r
+namespace Adaptor\r
+{\r
+\r
+namespace\r
+{\r
+#if defined(DEBUG_ENABLED)\r
+Debug::Filter* gLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_INPUT_METHOD_CONTEXT" );\r
+#endif\r
+}\r
+\r
+InputMethodContextPtr InputMethodContextWin::New( Dali::Actor actor )\r
+{\r
+  InputMethodContextPtr manager;\r
+\r
+  if ( actor && Adaptor::IsAvailable() )\r
+  {\r
+    manager = new InputMethodContextWin( actor );\r
+  }\r
+\r
+  return manager;\r
+}\r
+\r
+void InputMethodContextWin::Finalize()\r
+{\r
+}\r
+\r
+InputMethodContextWin::InputMethodContextWin( Dali::Actor actor )\r
+: mWin32Window( 0 ),\r
+  mIMFCursorPosition( 0 ),\r
+  mSurroundingText(),\r
+  mRestoreAfterFocusLost( false ),\r
+  mIdleCallbackConnected( false )\r
+{\r
+\r
+  actor.OnStageSignal().Connect( this, &InputMethodContextWin::OnStaged );\r
+}\r
+\r
+InputMethodContextWin::~InputMethodContextWin()\r
+{\r
+  Finalize();\r
+}\r
+\r
+void InputMethodContextWin::Initialize()\r
+{\r
+  CreateContext( mWin32Window );\r
+  ConnectCallbacks();\r
+}\r
+\r
+void InputMethodContextWin::CreateContext( WinWindowHandle winHandle )\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::CreateContext\n" );\r
+}\r
+\r
+void InputMethodContextWin::DeleteContext()\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::DeleteContext\n" );\r
+}\r
+\r
+// Callbacks for predicitive text support.\r
+void InputMethodContextWin::ConnectCallbacks()\r
+{\r
+}\r
+\r
+void InputMethodContextWin::DisconnectCallbacks()\r
+{\r
+}\r
+\r
+void InputMethodContextWin::Activate()\r
+{\r
+  // Reset mIdleCallbackConnected\r
+  mIdleCallbackConnected = false;\r
+}\r
+\r
+void InputMethodContextWin::Deactivate()\r
+{\r
+  mIdleCallbackConnected = false;\r
+}\r
+\r
+void InputMethodContextWin::Reset()\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::Reset\n" );\r
+}\r
+\r
+ImfContext* InputMethodContextWin::GetContext()\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::GetContext\n" );\r
+\r
+  return NULL;\r
+}\r
+\r
+bool InputMethodContextWin::RestoreAfterFocusLost() const\r
+{\r
+  return mRestoreAfterFocusLost;\r
+}\r
+\r
+void InputMethodContextWin::SetRestoreAfterFocusLost( bool toggle )\r
+{\r
+  mRestoreAfterFocusLost = toggle;\r
+}\r
+\r
+/**\r
+ * Called when an InputMethodContext Pre-Edit changed event is received.\r
+ * We are still predicting what the user is typing.  The latest string is what the InputMethodContext module thinks\r
+ * the user wants to type.\r
+ */\r
+void InputMethodContextWin::PreEditChanged( void*, ImfContext* imfContext, void* eventInfo )\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::PreEditChanged\n" );\r
+}\r
+\r
+void InputMethodContextWin::CommitReceived( void*, ImfContext* imfContext, void* eventInfo )\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::CommitReceived\n" );\r
+\r
+  if ( Dali::Adaptor::IsAvailable() )\r
+  {\r
+    const std::string keyString( static_cast<char*>( eventInfo ) );\r
+\r
+    Dali::InputMethodContext handle( this );\r
+    Dali::InputMethodContext::EventData eventData( Dali::InputMethodContext::COMMIT, keyString, 0, 0 );\r
+    Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, eventData );\r
+\r
+    if( callbackData.update )\r
+    {\r
+      mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );\r
+\r
+      NotifyCursorPosition();\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Called when an InputMethodContext retrieve surround event is received.\r
+ * Here the InputMethodContext module wishes to know the string we are working with and where within the string the cursor is\r
+ * We need to signal the application to tell us this information.\r
+ */\r
+bool InputMethodContextWin::RetrieveSurrounding( void* data, ImfContext* imfContext, char** text, int* cursorPosition )\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::RetrieveSurrounding\n" );\r
+\r
+  Dali::InputMethodContext::EventData imfData( Dali::InputMethodContext::GET_SURROUNDING, std::string(), 0, 0 );\r
+  Dali::InputMethodContext handle( this );\r
+  Dali::InputMethodContext::CallbackData callbackData = mEventSignal.Emit( handle, imfData );\r
+\r
+  if( callbackData.update )\r
+  {\r
+    if( text )\r
+    {\r
+      *text = strdup( callbackData.currentText.c_str() );\r
+    }\r
+\r
+    if( cursorPosition )\r
+    {\r
+      mIMFCursorPosition = static_cast<int>( callbackData.cursorPosition );\r
+      *cursorPosition = mIMFCursorPosition;\r
+    }\r
+  }\r
+\r
+  return true;\r
+}\r
+\r
+/**\r
+ * Called when an InputMethodContext delete surrounding event is received.\r
+ * Here we tell the application that it should delete a certain range.\r
+ */\r
+void InputMethodContextWin::DeleteSurrounding( void* data, ImfContext* imfContext, void* eventInfo )\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::DeleteSurrounding\n" );\r
+}\r
+\r
+void InputMethodContextWin::NotifyCursorPosition()\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::NotifyCursorPosition\n" );\r
+}\r
+\r
+void InputMethodContextWin::SetCursorPosition( unsigned int cursorPosition )\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::SetCursorPosition\n" );\r
+\r
+  mIMFCursorPosition = static_cast<int>( cursorPosition );\r
+}\r
+\r
+unsigned int InputMethodContextWin::GetCursorPosition() const\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::GetCursorPosition\n" );\r
+\r
+  return static_cast<unsigned int>( mIMFCursorPosition );\r
+}\r
+\r
+void InputMethodContextWin::SetSurroundingText( const std::string& text )\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::SetSurroundingText\n" );\r
+\r
+  mSurroundingText = text;\r
+}\r
+\r
+const std::string& InputMethodContextWin::GetSurroundingText() const\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::GetSurroundingText\n" );\r
+\r
+  return mSurroundingText;\r
+}\r
+\r
+void InputMethodContextWin::NotifyTextInputMultiLine( bool multiLine )\r
+{\r
+}\r
+\r
+Dali::InputMethodContext::TextDirection InputMethodContextWin::GetTextDirection()\r
+{\r
+  Dali::InputMethodContext::TextDirection direction ( Dali::InputMethodContext::LeftToRight );\r
+\r
+  return direction;\r
+}\r
+\r
+Rect<int> InputMethodContextWin::GetInputMethodArea()\r
+{\r
+  int xPos, yPos, width, height;\r
+\r
+  width = height = xPos = yPos = 0;\r
+\r
+  return Rect<int>(xPos,yPos,width,height);\r
+}\r
+\r
+void InputMethodContextWin::ApplyOptions( const InputMethodOptions& options )\r
+{\r
+  using namespace Dali::InputMethod::Category;\r
+\r
+  int index;\r
+\r
+  if ( mOptions.CompareAndSet(PANEL_LAYOUT, options, index) )\r
+  {\r
+  }\r
+  if ( mOptions.CompareAndSet(BUTTON_ACTION, options, index) )\r
+  {\r
+  }\r
+  if ( mOptions.CompareAndSet(AUTO_CAPITALIZE, options, index) )\r
+  {\r
+  }\r
+  if ( mOptions.CompareAndSet(VARIATION, options, index) )\r
+  {\r
+  }\r
+}\r
+\r
+void InputMethodContextWin::SetInputPanelData( const std::string& data )\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::SetInputPanelData\n" );\r
+}\r
+\r
+void InputMethodContextWin::GetInputPanelData( std::string& data )\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::GetInputPanelData\n" );\r
+}\r
+\r
+Dali::InputMethodContext::State InputMethodContextWin::GetInputPanelState()\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::GetInputPanelState\n" );\r
+  return Dali::InputMethodContext::DEFAULT;\r
+}\r
+\r
+void InputMethodContextWin::SetReturnKeyState( bool visible )\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::SetReturnKeyState\n" );\r
+}\r
+\r
+void InputMethodContextWin::AutoEnableInputPanel( bool enabled )\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::AutoEnableInputPanel\n" );\r
+}\r
+\r
+void InputMethodContextWin::ShowInputPanel()\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::ShowInputPanel\n" );\r
+}\r
+\r
+void InputMethodContextWin::HideInputPanel()\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::HideInputPanel\n" );\r
+}\r
+\r
+Dali::InputMethodContext::KeyboardType InputMethodContextWin::GetKeyboardType()\r
+{\r
+  return Dali::InputMethodContext::KeyboardType::SOFTWARE_KEYBOARD;\r
+}\r
+\r
+std::string InputMethodContextWin::GetInputPanelLocale()\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::GetInputPanelLocale\n" );\r
+\r
+  std::string locale = "";\r
+  return locale;\r
+}\r
+\r
+void InputMethodContextWin::SetContentMIMETypes( const std::string& mimeTypes )\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::SetContentMIMETypes\n" );\r
+}\r
+\r
+bool InputMethodContextWin::FilterEventKey( const Dali::KeyEvent& keyEvent )\r
+{\r
+  bool eventHandled( false );\r
+\r
+  if ( ! KeyLookup::IsDeviceButton( keyEvent.keyPressedName.c_str() ))\r
+  {\r
+    //check whether it's key down or key up event\r
+    if ( keyEvent.state == KeyEvent::Down )\r
+    {\r
+      eventHandled = ProcessEventKeyDown( keyEvent );\r
+    }\r
+    else if ( keyEvent.state == KeyEvent::Up )\r
+    {\r
+      eventHandled = ProcessEventKeyUp( keyEvent );\r
+    }\r
+  }\r
+\r
+  return eventHandled;\r
+}\r
+\r
+void InputMethodContextWin::SetInputPanelLanguage( Dali::InputMethodContext::InputPanelLanguage language )\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::SetInputPanelLanguage\n" );\r
+}\r
+\r
+Dali::InputMethodContext::InputPanelLanguage InputMethodContextWin::GetInputPanelLanguage() const\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::GetInputPanelLanguage\n" );\r
+  return Dali::InputMethodContext::InputPanelLanguage::AUTOMATIC;\r
+}\r
+\r
+void InputMethodContextWin::SetInputPanelPosition( unsigned int x, unsigned int y )\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::SetInputPanelPosition\n" );\r
+}\r
+\r
+void InputMethodContextWin::GetPreeditStyle( Dali::InputMethodContext::PreEditAttributeDataContainer& attrs ) const\r
+{\r
+  DALI_LOG_INFO( gLogFilter, Debug::General, "InputMethodContextWin::GetPreeditStyle\n" );\r
+  attrs = mPreeditAttrs;\r
+}\r
+\r
+bool InputMethodContextWin::ProcessEventKeyDown( const KeyEvent& keyEvent )\r
+{\r
+  bool eventHandled( false );\r
+  return eventHandled;\r
+}\r
+\r
+bool InputMethodContextWin::ProcessEventKeyUp( const KeyEvent& keyEvent )\r
+{\r
+  bool eventHandled( false );\r
+  return eventHandled;\r
+}\r
+\r
+void InputMethodContextWin::OnStaged( Dali::Actor actor )\r
+{\r
+  WinWindowHandle winWindow( AnyCast< WinWindowHandle >( Dali::Integration::SceneHolder::Get( actor ).GetNativeHandle() ) );\r
+\r
+  if( mWin32Window != winWindow )\r
+  {\r
+    mWin32Window = winWindow;\r
+\r
+    // Reset\r
+    Finalize();\r
+    Initialize();\r
+  }\r
+}\r
+\r
+} // Adaptor\r
+\r
+} // Internal\r
+\r
+} // Dali\r
+\r
diff --git a/dali/internal/input/windows/input-method-context-impl-win.h b/dali/internal/input/windows/input-method-context-impl-win.h
new file mode 100755 (executable)
index 0000000..253bc02
--- /dev/null
@@ -0,0 +1,331 @@
+#ifndef DALI_INTERNAL_INPUT_METHOD_CONTEXT_IMPL_WIN_H\r
+#define DALI_INTERNAL_INPUT_METHOD_CONTEXT_IMPL_WIN_H\r
+\r
+/*\r
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// EXTERNAL INCLUDES\r
+#include <dali/public-api/object/base-object.h>\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali/devel-api/adaptor-framework/input-method-context.h>\r
+#include <dali/internal/input/common/input-method-context-impl.h>\r
+#include <dali/internal/window-system/windows/platform-implement-win.h>\r
+\r
+namespace Dali\r
+{\r
+\r
+class RenderSurface;\r
+\r
+namespace Internal\r
+{\r
+\r
+namespace Adaptor\r
+{\r
+\r
+class InputMethodContextWin : public Dali::Internal::Adaptor::InputMethodContext, public Dali::ConnectionTracker\r
+{\r
+public:\r
+  /**\r
+   * @brief Creates a new InputMethodContext handle\r
+   *\r
+   * @param[in] actor The actor that uses the new InputMethodContext instance.\r
+   * @return InputMethodContext pointer\r
+   */\r
+  static InputMethodContextPtr New( Dali::Actor actor );\r
+\r
+  /**\r
+   * Constructor\r
+   * @param[in] win32Window, The window is created by application.\r
+   */\r
+  explicit InputMethodContextWin( Dali::Actor actor );\r
+\r
+public:\r
+\r
+  /**\r
+   * @brief Initializes member data.\r
+   */\r
+  void Initialize() override;\r
+\r
+  /**\r
+   * Connect Callbacks required for InputMethodContext.\r
+   * If you don't connect InputMethodContext callbacks, you can't get the key events.\r
+   * The events are PreeditChanged, Commit and DeleteSurrounding.\r
+   */\r
+  void ConnectCallbacks() override;\r
+\r
+  /**\r
+   * Disconnect Callbacks attached to input method context.\r
+   */\r
+  void DisconnectCallbacks() override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::Finalize()\r
+   */\r
+  void Finalize() override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::Activate()\r
+   */\r
+  void Activate() override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::Deactivate()\r
+   */\r
+  void Deactivate() override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::Reset()\r
+   */\r
+  void Reset() override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::GetContext()\r
+   */\r
+  ImfContext* GetContext() override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::RestoreAfterFocusLost()\r
+   */\r
+  bool RestoreAfterFocusLost() const override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::SetRestoreAfterFocusLost()\r
+   */\r
+  void SetRestoreAfterFocusLost( bool toggle ) override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::PreEditChanged()\r
+   */\r
+  void PreEditChanged( void* data, ImfContext* imfContext, void* eventInfo ) override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::NotifyCursorPosition()\r
+   */\r
+  void CommitReceived( void* data, ImfContext* imfContext, void* eventInfo ) override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::NotifyCursorPosition()\r
+   */\r
+  bool RetrieveSurrounding( void* data, ImfContext* imfContext, char** text, int* cursorPosition ) override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::DeleteSurrounding()\r
+   */\r
+  void DeleteSurrounding( void* data, ImfContext* imfContext, void* eventInfo ) override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::SendPrivateCommand()\r
+   */\r
+  void SendPrivateCommand( void* data, ImfContext* imfContext, void* eventInfo ) override\r
+  {}\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::SendCommitContent()\r
+   */\r
+  void SendCommitContent( void* data, ImfContext* imfContext, void* eventInfo ) override\r
+  {}\r
+\r
+  // Cursor related\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::NotifyCursorPosition()\r
+   */\r
+  void NotifyCursorPosition() override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::SetCursorPosition()\r
+   */\r
+  void SetCursorPosition( unsigned int cursorPosition ) override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::GetCursorPosition()\r
+   */\r
+  unsigned int GetCursorPosition() const override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::SetSurroundingText()\r
+   */\r
+  void SetSurroundingText( const std::string& text ) override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::GetSurroundingText()\r
+   */\r
+  const std::string& GetSurroundingText() const override;\r
+\r
+  /**\r
+  * @copydoc Dali::InputMethodContext::NotifyTextInputMultiLine()\r
+  */\r
+  void NotifyTextInputMultiLine( bool multiLine ) override;\r
+\r
+  /**\r
+  * @copydoc Dali::InputMethodContext::GetTextDirection()\r
+  */\r
+  Dali::InputMethodContext::TextDirection GetTextDirection() override;\r
+\r
+  /**\r
+  * @copydoc Dali::InputMethodContext::GetInputMethodArea()\r
+  */\r
+  Dali::Rect<int> GetInputMethodArea() override;\r
+\r
+  /**\r
+  * @copydoc Dali::InputMethodContext::ApplyOptions()\r
+  */\r
+  void ApplyOptions( const InputMethodOptions& options ) override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::SetInputPanelData()\r
+   */\r
+  void SetInputPanelData( const std::string& data ) override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::GetInputPanelData()\r
+   */\r
+  void GetInputPanelData( std::string& data ) override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::GetInputPanelState()\r
+   */\r
+  Dali::InputMethodContext::State GetInputPanelState() override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::SetReturnKeyState()\r
+   */\r
+  void SetReturnKeyState( bool visible ) override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::AutoEnableInputPanel()\r
+   */\r
+  void AutoEnableInputPanel( bool enabled ) override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::ShowInputPanel()\r
+   */\r
+  void ShowInputPanel() override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::HideInputPanel()\r
+   */\r
+  void HideInputPanel() override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::GetKeyboardType()\r
+   */\r
+  Dali::InputMethodContext::KeyboardType GetKeyboardType() override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::GetInputPanelLocale()\r
+   */\r
+  std::string GetInputPanelLocale() override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::SetContentMIMETypes()\r
+   */\r
+  void SetContentMIMETypes( const std::string& mimeTypes ) override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::FilterEventKey()\r
+   */\r
+  bool FilterEventKey( const Dali::KeyEvent& keyEvent ) override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::SetInputPanelLanguage()\r
+   */\r
+  void SetInputPanelLanguage( Dali::InputMethodContext::InputPanelLanguage language ) override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::GetInputPanelLanguage()\r
+   */\r
+  Dali::InputMethodContext::InputPanelLanguage GetInputPanelLanguage() const override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::SetInputPanelPosition()\r
+   */\r
+  void SetInputPanelPosition( unsigned int x, unsigned int y ) override;\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::GetPreeditStyle()\r
+   */\r
+  void GetPreeditStyle( Dali::InputMethodContext::PreEditAttributeDataContainer& attrs ) const override;\r
+\r
+private:\r
+  /**\r
+   * Context created the first time and kept until deleted.\r
+   * @param[in] win32Window, The window is created by application.\r
+   */\r
+  void CreateContext( WinWindowHandle win32Window );\r
+\r
+  /**\r
+   * @copydoc Dali::InputMethodContext::DeleteContext()\r
+   */\r
+  void DeleteContext();\r
+\r
+private:\r
+\r
+  /**\r
+   * @brief Process event key down, whether filter a key to isf.\r
+   *\r
+   * @param[in] keyEvent The event key to be handled.\r
+   * @return Whether the event key is handled.\r
+   */\r
+  bool ProcessEventKeyDown( const KeyEvent& keyEvent );\r
+\r
+  /**\r
+   * @brief Process event key up, whether filter a key to isf.\r
+   *\r
+   * @param[in] keyEvent The event key to be handled.\r
+   * @return Whether the event key is handled.\r
+   */\r
+  bool ProcessEventKeyUp( const KeyEvent& keyEvent );\r
+\r
+  /**\r
+   * Called when the binded actor is added to a window.\r
+   */\r
+  void OnStaged( Dali::Actor actor );\r
+\r
+public:\r
+\r
+  /**\r
+   * Destructor.\r
+   */\r
+  virtual ~InputMethodContextWin();\r
+\r
+private:\r
+\r
+  // Undefined copy constructor\r
+  InputMethodContextWin( const InputMethodContextWin& inputMethodContext) = delete;\r
+\r
+  // Undefined assignment operator\r
+  InputMethodContextWin& operator=( const InputMethodContextWin& inputMethodContext ) = delete;\r
+\r
+private:\r
+  WinWindowHandle mWin32Window;\r
+  int mIMFCursorPosition;\r
+  std::string mSurroundingText;\r
+\r
+  bool mRestoreAfterFocusLost:1;             ///< Whether the keyboard needs to be restored (activated ) after focus regained.\r
+  bool mIdleCallbackConnected:1;             ///< Whether the idle callback is already connected.\r
+  InputMethodOptions        mOptions;\r
+  Dali::InputMethodContext::PreEditAttributeDataContainer mPreeditAttrs; ///< Stores preedit attribute data\r
+};\r
+\r
+} // namespace Adaptor\r
+\r
+} // namespace Internal\r
+\r
+} // namespace Dali\r
+\r
+#endif // DALI_INTERNAL_INPUT_METHOD_CONTEXT_IMPL_WIN_H\r
diff --git a/dali/internal/input/windows/key-mapping-win.cpp b/dali/internal/input/windows/key-mapping-win.cpp
new file mode 100755 (executable)
index 0000000..9b855bd
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/input/common/key-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace KeyLookup
+{
+
+// matches a DALI_KEY enum, to key name
+KeyLookup KeyLookupTable[]=
+{
+  // more than one key name can be assigned to a single dali-key code
+  // e.g. "Menu" and "XF86Menu" are both assigned to  DALI_KEY_MENU
+
+  { "Escape",                DALI_KEY_ESCAPE,                                            false },
+  { "Menu",                  DALI_KEY_MENU,                                              false },
+  { "Cancel",                DALI_KEY_CANCEL,                                            false },
+
+  { "BackSpace",             DALI_KEY_BACKSPACE,                                         false },
+  { "Up",                    DALI_KEY_CURSOR_UP,                                         false }, // To be removed after the key name is fixed in the platform
+  { "Left",                  DALI_KEY_CURSOR_LEFT,                                       false },
+  { "Right",                 DALI_KEY_CURSOR_RIGHT,                                      false },
+  { "Down",                  DALI_KEY_CURSOR_DOWN,                                       false }, // To be removed after the key name is fixed in the platform
+  { "Shift_L",               DALI_KEY_SHIFT_LEFT,                                        false },
+  { "Shift_R",               DALI_KEY_SHIFT_RIGHT,                                       false },
+  { "Delete",                static_cast<Dali::KEY>( DevelKey::DALI_KEY_DELETE ),        false },
+  { "Control_L",             static_cast<Dali::KEY>( DevelKey::DALI_KEY_CONTROL_LEFT ),  false },
+  { "Control_R",             static_cast<Dali::KEY>( DevelKey::DALI_KEY_CONTROL_RIGHT ), false }
+};
+
+const std::size_t KEY_LOOKUP_COUNT = (sizeof( KeyLookupTable ))/ (sizeof( KeyLookup ));
+
+} // namespace KeyLookup
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/input/windows/virtual-keyboard-impl-win.cpp b/dali/internal/input/windows/virtual-keyboard-impl-win.cpp
new file mode 100755 (executable)
index 0000000..8d4eb0a
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/input/common/virtual-keyboard-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace VirtualKeyboard
+{
+void Show()
+{
+}
+
+void Hide()
+{
+
+}
+
+bool IsVisible()
+{
+  return false;
+}
+
+void ApplySettings( const Property::Map& settingsMap )
+{
+
+}
+
+void EnablePrediction( const bool enable )
+{
+
+}
+
+bool IsPredictionEnabled()
+{
+  return false;
+}
+
+Rect<int> GetSizeAndPosition()
+{
+  Rect<int> ret;
+  return ret;
+}
+
+Dali::VirtualKeyboard::StatusSignalType& StatusChangedSignal()
+{
+  Dali::VirtualKeyboard::StatusSignalType ret;
+  return ret;
+}
+
+Dali::VirtualKeyboard::KeyboardResizedSignalType& ResizedSignal()
+{
+  Dali::VirtualKeyboard::KeyboardResizedSignalType ret;
+  return ret;
+}
+
+Dali::VirtualKeyboard::LanguageChangedSignalType& LanguageChangedSignal()
+{
+  Dali::VirtualKeyboard::LanguageChangedSignalType ret;
+  return ret;
+}
+
+Dali::VirtualKeyboard::TextDirection GetTextDirection()
+{
+  return Dali::VirtualKeyboard::LeftToRight;
+}
+
+Dali::InputMethod::ActionButton gActionButtonFunction = Dali::InputMethod::ACTION_DEFAULT;
+
+
+void RotateTo(int angle)
+{
+}
+
+void SetReturnKeyType( const InputMethod::ButtonAction::Type type )
+{
+}
+
+Dali::InputMethod::ButtonAction::Type GetReturnKeyType()
+{
+  return Dali::InputMethod::ButtonAction::DEFAULT;
+}
+
+} // namespace VirtualKeyboard
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/legacy/common/tizen-platform-abstraction.cpp b/dali/internal/legacy/common/tizen-platform-abstraction.cpp
new file mode 100644 (file)
index 0000000..4d60fee
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/legacy/common/tizen-platform-abstraction.h>
+
+// EXTERNAL INCLUDES
+#include <dirent.h>
+#include <fstream>
+#include <algorithm>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/bitmap.h>
+#include <dali/integration-api/resource-types.h>
+#include <dali/public-api/signals/callback.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/imaging/common/image-loader.h>
+#include <dali/internal/system/common/file-reader.h>
+#include <dali/internal/imaging/common/pixel-buffer-impl.h>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+struct TizenPlatformAbstraction::TimerCallback : ConnectionTracker
+{
+  Dali::Timer mTimer;
+  TizenPlatformAbstraction* mOwner;
+  CallbackBase* mCallback;
+  const uint32_t mIdNumber;
+
+  static uint32_t sNextTimerId;
+
+  TimerCallback(TizenPlatformAbstraction* owner, CallbackBase* callback, uint32_t ms)
+  : mTimer(Dali::Timer::New(ms)),
+    mOwner(owner),
+    mCallback(callback),
+    mIdNumber(sNextTimerId++)
+  {
+    mTimer.TickSignal().Connect( this, &TimerCallback::Tick );
+    mTimer.Start();
+  }
+
+  bool Tick()
+  {
+    mOwner->RunTimerFunction(*this);
+    return false;
+  }
+};
+
+uint32_t TizenPlatformAbstraction::TimerCallback::sNextTimerId = 0;
+
+TizenPlatformAbstraction::TizenPlatformAbstraction()
+: mDataStoragePath( "" ),
+  mTimerPairsWaiting(),
+  mTimerPairsSpent()
+
+{
+}
+
+TizenPlatformAbstraction::~TizenPlatformAbstraction()
+{
+}
+
+ImageDimensions TizenPlatformAbstraction::GetClosestImageSize( const std::string& filename,
+                                                               ImageDimensions size,
+                                                               FittingMode::Type fittingMode,
+                                                               SamplingMode::Type samplingMode,
+                                                               bool orientationCorrection )
+{
+  return ImageLoader::GetClosestImageSize( filename, size, fittingMode, samplingMode, orientationCorrection );
+}
+
+ImageDimensions TizenPlatformAbstraction::GetClosestImageSize( Integration::ResourcePointer resourceBuffer,
+                                                               ImageDimensions size,
+                                                               FittingMode::Type fittingMode,
+                                                               SamplingMode::Type samplingMode,
+                                                               bool orientationCorrection )
+{
+  return ImageLoader::GetClosestImageSize( resourceBuffer, size, fittingMode, samplingMode, orientationCorrection );
+}
+
+Integration::ResourcePointer TizenPlatformAbstraction::LoadImageSynchronously(const Integration::BitmapResourceType& resource, const std::string& resourcePath)
+{
+  return ImageLoader::LoadImageSynchronously( resource, resourcePath );
+}
+
+Integration::BitmapPtr TizenPlatformAbstraction::DecodeBuffer( const Integration::BitmapResourceType& resource, uint8_t * buffer, size_t size )
+{
+  Integration::BitmapPtr resultBitmap;
+  Dali::Devel::PixelBuffer bitmap;
+
+  Dali::Internal::Platform::FileReader fileReader( buffer, size );
+  FILE * const fp = fileReader.GetFile();
+  if( fp )
+  {
+    bool result = ImageLoader::ConvertStreamToBitmap( resource, "", fp, bitmap );
+    if ( !result || !bitmap )
+    {
+      bitmap.Reset();
+      DALI_LOG_WARNING( "Unable to decode bitmap supplied as in-memory blob.\n" );
+    }
+    else
+    {
+      Integration::Bitmap::Profile profile{Integration::Bitmap::Profile::BITMAP_2D_PACKED_PIXELS};
+
+      // For backward compatibility the Bitmap must be created
+      auto retval = Integration::Bitmap::New(profile, Dali::ResourcePolicy::OWNED_DISCARD);
+
+      retval->GetPackedPixelsProfile()->ReserveBuffer(
+              bitmap.GetPixelFormat(),
+              bitmap.GetWidth(),
+              bitmap.GetHeight(),
+              bitmap.GetWidth(),
+              bitmap.GetHeight()
+            );
+
+      auto& impl = Dali::GetImplementation(bitmap);
+
+      std::copy( impl.GetBuffer(), impl.GetBuffer()+impl.GetBufferSize(), retval->GetBuffer());
+      resultBitmap.Reset(retval);
+    }
+  }
+
+  return resultBitmap;
+}
+
+bool TizenPlatformAbstraction::LoadShaderBinaryFile( const std::string& filename, Dali::Vector< unsigned char >& buffer ) const
+{
+  bool result = false;
+
+#ifdef SHADERBIN_CACHE_ENABLED
+  std::string path;
+
+  // First check the system location where shaders are stored at install time:
+  path = DALI_SHADERBIN_DIR;
+  path += filename;
+  result = LoadFile( path, buffer );
+
+  // Fallback to the cache of shaders stored after previous runtime compilations:
+  // On desktop this looks in the current working directory that the app was launched from.
+  if( mResourceLoader && result == false )
+  {
+    path = mDataStoragePath;
+    path += filename;
+    result = LoadFile( path, buffer );
+  }
+#endif
+
+  return result;
+}
+
+bool TizenPlatformAbstraction::SaveShaderBinaryFile( const std::string& filename, const unsigned char * buffer, unsigned int numBytes ) const
+{
+  bool result = false;
+
+#ifdef SHADERBIN_CACHE_ENABLED
+
+  // Use the cache of shaders stored after previous runtime compilations:
+  // On desktop this looks in the current working directory that the app was launched from.
+  std::string path = mDataStoragePath;
+  path += filename;
+  result = SaveFile( path, buffer, numBytes );
+
+#endif
+
+  return result;
+}
+
+void TizenPlatformAbstraction::SetDataStoragePath( const std::string& path )
+{
+  mDataStoragePath = path;
+}
+
+uint32_t TizenPlatformAbstraction::StartTimer( uint32_t milliseconds, CallbackBase* callback )
+{
+  TimerCallback* timerCallbackPtr = new TimerCallback(this, callback, milliseconds);
+
+  // Stick it in the list
+  mTimerPairsWaiting.push_back(timerCallbackPtr);
+
+  return timerCallbackPtr->mIdNumber;
+}
+
+void TizenPlatformAbstraction::CancelTimer ( uint32_t timerId )
+{
+  auto iter = std::remove_if(
+    mTimerPairsWaiting.begin(), mTimerPairsWaiting.end(),
+    [&timerId]( TimerCallback* timerCallbackPtr )
+    {
+      if( timerCallbackPtr->mIdNumber == timerId )
+      {
+        timerCallbackPtr->mTimer.Stop();
+        return true;
+      }
+      else
+      {
+        return false;
+      }
+    }
+  );
+
+  mTimerPairsWaiting.erase( iter, mTimerPairsWaiting.end() );
+}
+
+void TizenPlatformAbstraction::RunTimerFunction(TimerCallback& timerPtr)
+{
+  CallbackBase::Execute( *timerPtr.mCallback );
+
+  std::vector<TimerCallback*>::iterator timerIter = std::find( mTimerPairsWaiting.begin(), mTimerPairsWaiting.end(), &timerPtr );
+
+  if( timerIter == std::end(mTimerPairsWaiting) )
+  {
+    DALI_ASSERT_DEBUG(false);
+  }
+
+  // ...and move it
+  std::move(timerIter, timerIter+1, std::back_inserter(mTimerPairsSpent));
+
+  mTimerPairsWaiting.erase(timerIter, timerIter+1);
+
+  Dali::Adaptor::Get().AddIdle( MakeCallback( this, &TizenPlatformAbstraction::CleanupTimers ), false );
+}
+
+
+void TizenPlatformAbstraction::CleanupTimers()
+{
+  mTimerPairsSpent.clear();
+}
+
+
+TizenPlatformAbstraction* CreatePlatformAbstraction()
+{
+  return new TizenPlatformAbstraction();
+}
+
+bool SaveFile( const std::string& filename, const unsigned char * buffer, unsigned int numBytes )
+{
+  DALI_ASSERT_DEBUG( 0 != filename.length());
+
+  bool result = false;
+
+  std::filebuf buf;
+  buf.open(filename.c_str(), std::ios::out | std::ios_base::trunc | std::ios::binary);
+  if( buf.is_open() )
+  {
+    std::ostream stream(&buf);
+
+    // determine size of buffer
+    int length = static_cast<int>(numBytes);
+
+    // write contents of buffer to the file
+    stream.write(reinterpret_cast<const char*>(buffer), length);
+
+    if( !stream.bad() )
+    {
+      result = true;
+    }
+  }
+
+  return result;
+}
+
+}  // namespace TizenPlatform
+
+}  // namespace Dali
diff --git a/dali/internal/legacy/common/tizen-platform-abstraction.h b/dali/internal/legacy/common/tizen-platform-abstraction.h
new file mode 100644 (file)
index 0000000..c288cd1
--- /dev/null
@@ -0,0 +1,156 @@
+#ifndef DALI_TIZEN_PLATFORM_ABSTRACTION_H
+#define DALI_TIZEN_PLATFORM_ABSTRACTION_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/adaptor-framework/timer.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+
+// EXTERNAL INCLUDES
+#include <cstdint>
+#include <string>
+#include <dali/integration-api/platform-abstraction.h>
+
+namespace Dali
+{
+
+class CallbackBase;
+
+namespace TizenPlatform
+{
+class ResourceLoader;
+
+/**
+ * Concrete implementation of the platform abstraction class.
+ */
+class TizenPlatformAbstraction : public Integration::PlatformAbstraction
+{
+
+public: // Construction & Destruction
+
+  /**
+   * Constructor
+   */
+  TizenPlatformAbstraction();
+
+  /**
+   * Destructor
+   */
+  virtual ~TizenPlatformAbstraction();
+
+public: // PlatformAbstraction overrides
+
+  /**
+   * @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::LoadImageSynchronously()
+   */
+  virtual Integration::ResourcePointer LoadImageSynchronously(const Integration::BitmapResourceType& resource, const std::string& resourcePath);
+
+  /**
+   * @copydoc PlatformAbstraction::DecodeBuffer()
+   */
+  virtual Integration::BitmapPtr DecodeBuffer( const Integration::BitmapResourceType& resource, uint8_t * buffer, size_t size );
+
+  /**
+   * @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::StartTimer()
+   */
+  virtual uint32_t StartTimer( uint32_t milliseconds, CallbackBase* callback );
+
+  /**
+   * @copydoc PlatformAbstraction::CancelTimer()
+   */
+  virtual void CancelTimer ( uint32_t timerId );
+
+  /**
+   * Sets path for data/resource storage.
+   * @param[in] path data/resource storage path
+   */
+  void SetDataStoragePath( const std::string& path );
+
+  /**
+   * Clears the timers that have completed
+   */
+  void CleanupTimers();
+
+private:
+
+  struct TimerCallback;
+
+  /*
+   * Executes callback function and cleans up timer
+   */
+  void RunTimerFunction(TimerCallback& timerPtr);
+
+  TizenPlatformAbstraction( const TizenPlatformAbstraction& ); ///< Undefined
+  TizenPlatformAbstraction& operator=( const TizenPlatformAbstraction& ); ///< Undefined
+
+  std::string mDataStoragePath;
+
+  std::vector<TimerCallback*> mTimerPairsWaiting;
+  std::vector<TimerCallback*> mTimerPairsSpent;
+};
+
+/**
+ * Construct a platform abstraction and return it.
+ * @return TizenPlatformAbstraction instance
+ */
+TizenPlatformAbstraction* CreatePlatformAbstraction();
+
+/**
+ * Save a file to disk
+ * @param filename to create
+ * @param buffer to store
+ * @param numBytes to store
+ * @return true if successful, false otherwise
+ */
+bool SaveFile( const std::string& filename, const unsigned char * buffer, unsigned int numBytes );
+
+}  // namespace TizenPlatform
+
+}  // namespace Dali
+
+#endif // DALI_TIZEN_PLATFORM_ABSTRACTION_H
diff --git a/dali/internal/legacy/file.list b/dali/internal/legacy/file.list
new file mode 100644 (file)
index 0000000..e9c2106
--- /dev/null
@@ -0,0 +1,6 @@
+
+# module: legacy, backend: common
+SET( adaptor_legacy_common_src_files 
+    ${adaptor_legacy_dir}/common/tizen-platform-abstraction.cpp
+)
+
diff --git a/dali/internal/legacy/tizen/data-compression.cpp b/dali/internal/legacy/tizen/data-compression.cpp
new file mode 100644 (file)
index 0000000..42c2f55
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * 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.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <memory.h>
+
+namespace Dali
+{
+namespace TizenPlatform
+{
+namespace DataCompression
+{
+
+std::size_t GetMaximumRleCompressedSize(const std::size_t inputLength)
+{
+  // RLE has worst case scenerio of double the input data
+  // e.g. if data is 1,2,3,4  = 4 bytes
+  // it will be encoded as 1,1, 1,2 1,3 1,4 = 8 bytes
+
+  // we also encode the original size into the stream to check
+  // the decode buffers are big enough and for corruption
+  return (inputLength * 2) + 4;  // 4 bytes is space for size
+
+}
+
+// Run length encode a byte stream, consisting of byte values.
+// Format is one byte for run-length, one byte value.
+// e.g. 10, 15, 20, 20, 20, 5, 5
+// is represented as :
+// 1,10
+// 1,15
+// 3,20
+// 2, 5
+// First 4 bytes are the size of the decoded data
+//
+void EncodeRle( const unsigned char* input,
+                const std::size_t inputLength,
+                unsigned char* output,
+                const std::size_t outputLength,
+                std::size_t& encodedSize)
+{
+  DALI_ASSERT_DEBUG( outputLength >= GetMaximumRleCompressedSize( inputLength ));
+
+  unsigned int index(0);
+  unsigned int runLength(0);
+  encodedSize = 0;
+
+  // encode the input length in the first 4 bytes.
+  output[ encodedSize++ ] =  inputLength & 0xFF;
+  output[ encodedSize++ ] = (inputLength >> 8) & 0xFF;
+  output[ encodedSize++ ] = (inputLength >> 16) & 0xFF;
+  output[ encodedSize++ ] = (inputLength >> 24) & 0xFF;
+
+  while( index < inputLength  )
+  {
+    unsigned char curChar = input[ index ];
+    runLength = 1;
+
+    if( ( (index + 1) == inputLength )         // is more data available
+        || input[index + 1] != curChar  )      // character doesn't match
+    {
+      // we out of data, or the next character doesn't match (run of zero)
+      index++;
+    }
+    else
+    {
+      while( ( (index+1) < inputLength ) &&
+               ( input[index + 1] == curChar ) &&
+               ( runLength < 0xFF ) )
+      {
+        runLength++;
+        index++;
+      }
+      index++;
+    }
+    output[ encodedSize++ ] = runLength;
+    output[ encodedSize++ ] = curChar;
+
+  }
+}
+
+bool DecodeRle( const unsigned char* input,
+                const std::size_t inputLength,
+                unsigned char* output,
+                const std::size_t outputLength,
+                std::size_t& decodedSize)
+{
+  unsigned int index(0);
+  unsigned int outputIndex(0);
+
+  // there should be at least 4 bytes for the size field
+  if( inputLength < 4)
+  {
+    DALI_LOG_ERROR("input buffer too small\n");
+    return false;
+  }
+
+  decodedSize = input[ index++ ] ;
+  decodedSize|= input[ index++ ]<<8 ;
+  decodedSize|= input[ index++ ]<<16 ;
+  decodedSize|= input[ index++ ]<<24 ;
+
+  // check the decoded data will fit in to
+  if( outputLength < decodedSize )
+  {
+    DALI_LOG_ERROR("buffer too small, buffer size =%d, data size = %d \n",outputLength, decodedSize);
+    return false;
+  }
+
+  while( (index+1)< inputLength )
+  {
+    // read the value and the run length
+    unsigned char runLength =  input[ index++ ];
+    unsigned char value = input[ index++ ];
+
+    if( (runLength + outputIndex) > decodedSize)
+    {
+      DALI_LOG_ERROR( "corrupted RLE data\n" );
+      // corrupted
+      return false;
+    }
+    // set the value run Length times
+    memset( &output[ outputIndex ], value, runLength * sizeof( unsigned char) );
+    outputIndex+= runLength;
+  }
+  if( outputIndex != decodedSize)
+  {
+    DALI_LOG_ERROR(" RLE data size missmatch\n");
+    return false;
+  }
+
+  return true;
+}
+
+} // DataCompression
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/dali/internal/legacy/tizen/data-compression.h b/dali/internal/legacy/tizen/data-compression.h
new file mode 100644 (file)
index 0000000..ddbcf8c
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef DALI_TIZEN_PLATFORM_DATA_COMPRESSION_H
+#define DALI_TIZEN_PLATFORM_DATA_COMPRESSION_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+
+namespace Dali
+{
+namespace TizenPlatform
+{
+namespace DataCompression
+{
+
+/**
+ * Return the maximum size of a buffer required to hold a number of bytes.
+ * Required because compressing data, can end up being bigger
+ * than the original data.
+ * @return maximum buffer size required to compress inputSize
+ */
+std::size_t GetMaximumRleCompressedSize(const std::size_t inputSize);
+
+/**
+ * RLE Encodes an array of data
+ * @param input input data
+ * @param inputLength input data length in bytes
+ * @param output output data, pre-allocated by caller
+ * @param outputLength size of the output buffer in bytes
+ * @param encodedSize number of bytes written to outputBuffer
+ */
+void EncodeRle(  const unsigned char* input,
+                 const std::size_t inputLength,
+                 unsigned char* output,
+                 const std::size_t outputLength,
+                 std::size_t &encodedSize );
+
+/**
+ * RLE Decodes an array of data.
+ * @param[in] input input data
+ * @param[in] inputLength input data length in bytes
+ * @param[out] output output data, pre-allocated by caller, allocated using GetMaximumRleCompressedSize()
+ * @param[in] outputLength size of output data in bytes
+ * @param[out] decodedSize the number of bytes decoded into outputBuffer
+ */
+bool DecodeRle( const unsigned char* input,
+                const std::size_t inputLength,
+                unsigned char* output,
+                const std::size_t outputLength,
+               std::size_t& decodedSize);
+
+
+} // namespace DataCompression
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // DALI_TIZEN_PLATFORM_DATA_COMPRESSION_H
diff --git a/dali/internal/legacy/tizen/image-encoder.h b/dali/internal/legacy/tizen/image-encoder.h
new file mode 100644 (file)
index 0000000..96145ab
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef DALI_TIZEN_PLATFORM_IMAGE_ENCODER_H
+#define DALI_TIZEN_PLATFORM_IMAGE_ENCODER_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+namespace Dali
+{
+
+/**
+ * Used file format
+ */
+enum FileFormat
+{
+  PNG_FORMAT,
+  JPG_FORMAT,
+  BMP_FORMAT,
+  GIF_FORMAT,
+  ICO_FORMAT,
+  INVALID_FORMAT
+};
+
+} // namespace Dali
+
+#endif //DALI_TIZEN_PLATFORM_IMAGE_ENCODER_H
diff --git a/dali/internal/legacy/tizen/platform-capabilities.h b/dali/internal/legacy/tizen/platform-capabilities.h
new file mode 100644 (file)
index 0000000..403414e
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef DALI_TIZEN_PLATFORM_CAPABILITIES_H
+#define DALI_TIZEN_PLATFORM_CAPABILITIES_H
+
+/*
+ * Copyright (c) 2019 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/math/math-utils.h>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+/**
+ * Returns true if non power of two textures are supported.
+ */
+inline bool SupportsNonPowerOfTwoTextures()
+{
+#ifdef NON_POWER_OF_TWO_TEXTURES
+  return true; // All current devices and desktop builds have NPOT
+#else
+#error "NPOT are standard in GLES 2.0 if mipmaps are not used, they are standard with mipmaps and no restrictions in GLES 3.0, requiring them simplifies image handling code."
+  return false;
+#endif
+}
+
+/**
+ * Returns the size that a textures dimension should have for a specific image size.
+ */
+inline unsigned int GetTextureDimension( unsigned int size )
+{
+#ifdef NON_POWER_OF_TWO_TEXTURES
+  return size;
+#else
+#error "NPOT are standard in GLES 2.0 if mipmaps are not used, they are standard with mipmaps and no restrictions in GLES 3.0, requiring them simplifies image handling code."
+  return NextPowerOfTwo( size );
+#endif
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // DALI_TIZEN_PLATFORM_CAPABILITIES_H
diff --git a/dali/internal/network/common/automation.cpp b/dali/internal/network/common/automation.cpp
new file mode 100644 (file)
index 0000000..ce17605
--- /dev/null
@@ -0,0 +1,443 @@
+
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/network/common/automation.h>
+
+// EXTERNAL INCLUDES
+#include <sstream>
+#include <iomanip>
+#include <stdio.h>
+#include <dali/public-api/dali-core.h>
+#include <dali/integration-api/debug.h>
+
+using Dali::Property;
+using Dali::Matrix;
+using Dali::Matrix3;
+
+namespace  // un-named namespace
+{
+
+const unsigned int MAX_SET_PROPERTY_STRING_LENGTH = 256; ///< maximum length of a set property command
+
+class JsonPropertyValue
+{
+public:
+  JsonPropertyValue( const std::string& str )
+  {
+    std::size_t strLength = str.length();
+
+    mString.reserve( strLength );
+    for( std::size_t i = 0; i < strLength; ++i )
+    {
+      const char c = str[i];
+      if( (c != '[') && c != ']')
+      {
+        mString.push_back( c );
+      }
+    }
+
+  }
+  std::string GetString() const
+  {
+    return mString;
+  }
+  float GetFloat() const
+  {
+    return atof( mString.c_str() );
+  }
+  int GetInt()
+  {
+    return atoi( mString.c_str() );
+  }
+  bool GetBoolean()
+  {
+    return (GetInt() != 0);
+  }
+
+  Dali::Vector2 GetVector2()
+  {
+    Dali::Vector2 vec2;
+
+    int count = sscanf( mString.c_str(),"%f,%f",&vec2.x,&vec2.y );
+    if( count != 2 )
+    {
+      DALI_LOG_ERROR("Bad format\n");
+    }
+    return vec2;
+  }
+
+  Dali::Vector3 GetVector3()
+  {
+    Dali::Vector3 vec3;
+
+    int count = sscanf( mString.c_str(),"%f,%f,%f",&vec3.x,&vec3.y,&vec3.z );
+    if( count != 3 )
+    {
+      DALI_LOG_ERROR("Bad format\n");
+    }
+    return vec3;
+  }
+
+  Dali::Vector4 GetVector4()
+  {
+    Dali::Vector4 vec4;
+
+    int count = sscanf( mString.c_str(),"%f,%f,%f,%f", &vec4.x, &vec4.y, &vec4.z, &vec4.w );
+    if( count != 4 )
+    {
+      DALI_LOG_ERROR("Bad format\n");
+    }
+    return vec4;
+  }
+
+private:
+  std::string mString;
+
+};
+
+void SetProperty( Dali::Handle handle, int propertyId, JsonPropertyValue& propertyValue )
+{
+  Dali::Property::Type type = handle.GetPropertyType( propertyId );
+  switch( type )
+  {
+  case Dali::Property::FLOAT:
+  {
+    float val = propertyValue.GetFloat();
+    handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+    break;
+  }
+  case Dali::Property::INTEGER:
+  {
+    int val = propertyValue.GetInt();
+    handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+    break;
+  }
+  case Dali::Property::BOOLEAN:
+  {
+    bool val = propertyValue.GetBoolean();
+    handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+    break;
+  }
+  case Dali::Property::STRING:
+  {
+    std::string str = propertyValue.GetString();
+    handle.SetProperty( propertyId, Dali::Property::Value( str ) );
+    break;
+  }
+  case Dali::Property::VECTOR2:
+  {
+    Dali::Vector2 val = propertyValue.GetVector2();
+    handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+    break;
+  }
+  case Dali::Property::VECTOR3:
+  {
+    Dali::Vector3 val = propertyValue.GetVector3();
+    handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+    break;
+  }
+  case Dali::Property::VECTOR4:
+  {
+    Dali::Vector4 val = propertyValue.GetVector4();
+    handle.SetProperty( propertyId, Dali::Property::Value( val ) );
+    break;
+  }
+  default:
+  {
+    break;
+  }
+  }
+}
+
+int SetProperties( const std::string& setPropertyMessage )
+{
+  std::istringstream iss( setPropertyMessage );
+  std::string token;
+  getline( iss, token, '|' ); // swallow command name
+  while( getline( iss, token, '|' ) )
+  {
+    std::string actorId, propName, propValue;
+    if( token.compare( "---" ) != 0 )
+    {
+      std::istringstream propss( token );
+      getline( propss, actorId, ';' );
+      getline( propss, propName, ';' );
+      getline( propss, propValue );
+
+      Dali::Actor root = Dali::Stage::GetCurrent().GetRootLayer();
+      int id = atoi( actorId.c_str() );
+      Dali::Actor a = root.FindChildById( id );
+      if( a )
+      {
+        // lookup by name for custom properties
+        int propId = a.GetPropertyIndex( propName );
+        if( propId > 0 )
+        {
+          JsonPropertyValue pv( propValue );
+          SetProperty( a, propId, pv );
+        }
+
+      }
+    }
+  }
+
+  return 0;
+}
+
+
+void MatrixToStream( Property::Value value, std::ostream& o )
+{
+  Matrix m4(false);
+  Matrix3 m3;
+
+  if( value.Get(m4) )
+  {
+    float* matrix = m4.AsFloat();
+    o << "[ [" << matrix[0] << ", " << matrix[1] << ", " << matrix[2]  << ", " << matrix[3] << "], "
+      << "[" << matrix[4] << ", " << matrix[5] << ", " << matrix[6]  << ", " << matrix[7] << "], "
+      << "[" << matrix[8] << ", " << matrix[9] << ", " << matrix[10] << ", " << matrix[11] << "], "
+      << "[" << matrix[12] << ", " << matrix[13] << ", " << matrix[14] << ", " << matrix[15] << "] ]";
+  }
+  else if( value.Get(m3) )
+  {
+    float* matrix = m3.AsFloat();
+    o << "[ [" << matrix[0] << ", " << matrix[1] << ", " << matrix[2]  << "], "
+      << "[" << matrix[3] << ", " << matrix[4] << ", " << matrix[5]  << "], "
+      << "[" << matrix[6] << ", " << matrix[7] << ", " << matrix[8]  << "] ]";
+  }
+}
+
+
+}; //   un-named namespace
+
+inline std::string Quote( const std::string& in )
+{
+  return (std::string( "\"" ) + in + std::string( "\"" ));
+}
+
+template<class T>
+std::string ToString( T i )
+{
+  std::stringstream ss;
+  std::string s;
+  ss << i;
+  s = ss.str();
+
+  return s;
+}
+
+std::string GetPropertyValueString( Dali::Handle handle, int propertyIndex )
+{
+  std::ostringstream valueStream;
+  if( propertyIndex != Dali::Property::INVALID_INDEX )
+  {
+    Dali::Property::Value value = handle.GetProperty( propertyIndex );
+
+    if( value.GetType() == Dali::Property::STRING )
+    {
+      // Escape the string (to ensure valid json)
+      // Write out quotes, escapes and control characters using unicode syntax \uXXXX
+      std::ostringstream unescapedValue;
+      unescapedValue << value;
+      std::string valueString = unescapedValue.str();
+      std::ostringstream escapedValue;
+      for( std::string::iterator c = valueString.begin() ; c != valueString.end(); ++c )
+      {
+        if( *c == '"' )
+        {
+          escapedValue << "\\\"";
+        }
+        else if( *c == '\\' )
+        {
+          escapedValue << "\\\\";
+        }
+        else if( '\x00' <= *c && *c <= '\x1f' )
+        {
+          escapedValue << "\\u" << std::hex << std::setw(4) << std::setfill('0') << int(*c);
+        }
+        else
+        {
+          escapedValue << *c;
+        }
+      }
+      valueStream << escapedValue.str();
+    }
+    else if( value.GetType() == Dali::Property::MATRIX || value.GetType() == Dali::Property::MATRIX3 )
+    {
+      MatrixToStream( value, valueStream );
+    }
+    else
+    {
+      valueStream << value;
+    }
+  }
+  else
+  {
+    valueStream << "INVALID";
+  }
+
+  return valueStream.str();
+}
+
+// currently rotations are output in Euler format ( may change)
+void AppendPropertyNameAndValue( Dali::Handle handle, int propertyIndex, std::ostringstream& outputStream)
+{
+  // get the property name and the value as a string
+  std::string propertyName( handle.GetPropertyName( propertyIndex ) );
+
+  // Apply quotes around the property name
+  outputStream << "\"" << propertyName << "\"" << ",";
+
+  // Convert value to a string
+  std::string valueString = GetPropertyValueString( handle, propertyIndex );
+
+  outputStream << "\"" << valueString << "\"";
+}
+
+void AppendRendererPropertyNameAndValue( Dali::Renderer renderer, int rendererIndex, const std::string& name, std::ostringstream& outputStream)
+{
+  outputStream << ",[\"renderer[" << rendererIndex << "]." << name << "\"" << ",";
+  std::string valueString = GetPropertyValueString( renderer, renderer.GetPropertyIndex( name ) );
+  outputStream << "\"" << valueString << "\"]";
+}
+
+bool ExcludeProperty( int propIndex )
+{
+  return (propIndex == Dali::Actor::Property::NAME    ||
+
+      // all of these are repeat properties of values in vectors....
+      // We don't really need these in the UI
+      propIndex == Dali::Actor::Property::ANCHOR_POINT_X || propIndex == Dali::Actor::Property::ANCHOR_POINT_Y || propIndex == Dali::Actor::Property::ANCHOR_POINT_Z || propIndex == Dali::Actor::Property::PARENT_ORIGIN_X
+      || propIndex == Dali::Actor::Property::PARENT_ORIGIN_Y || propIndex == Dali::Actor::Property::PARENT_ORIGIN_Z || propIndex == Dali::Actor::Property::COLOR_RED || propIndex == Dali::Actor::Property::COLOR_GREEN
+      || propIndex == Dali::Actor::Property::COLOR_BLUE || propIndex == Dali::Actor::Property::COLOR_ALPHA|| propIndex == Dali::Actor::Property::POSITION_X || propIndex == Dali::Actor::Property::POSITION_Y
+      || propIndex == Dali::Actor::Property::POSITION_Z|| propIndex == Dali::Actor::Property::SIZE_WIDTH|| propIndex == Dali::Actor::Property::SIZE_HEIGHT || propIndex == Dali::Actor::Property::SCALE_X || propIndex == Dali::Actor::Property::SCALE_Y
+      || propIndex == Dali::Actor::Property::SCALE_Z || propIndex == Dali::Actor::Property::SIZE_DEPTH);
+}
+
+std::string DumpJson( Dali::Actor actor, int level )
+{
+  // All the information about this actor
+  std::ostringstream msg;
+  msg << "{ " << Quote( "Name" ) << " : " << Quote( actor.GetName() ) << ", " << Quote( "level" ) << " : " << level << ", " << Quote( "id" ) << " : " << actor.GetId() << ", " << Quote( "IsVisible" )
+      << " : " << actor.IsVisible() << ", " << Quote( "IsSensitive" ) << " : " << actor.IsSensitive();
+
+  msg << ", " << Quote( "properties" ) << ": [ ";
+
+  Dali::Property::IndexContainer indices;
+  actor.GetPropertyIndices( indices );
+
+  Dali::Property::IndexContainer::Iterator iter = indices.Begin();
+  int numCustom = 0;
+  for( ; iter != indices.End() ; iter++ )
+  {
+    int i = *iter;
+    if( !ExcludeProperty( i ) )
+    {
+      if( numCustom++ != 0 )
+      {
+        msg << ", ";
+      }
+      msg << "[";
+
+      AppendPropertyNameAndValue( actor, i,msg );
+
+      msg << "]";
+    }
+  }
+  if( actor.GetRendererCount() > 0 )
+  {
+    for( unsigned int i=0; i<actor.GetRendererCount(); ++i )
+    {
+      auto renderer = actor.GetRendererAt( i );
+      AppendRendererPropertyNameAndValue( renderer, i, "offset", msg );
+      AppendRendererPropertyNameAndValue( renderer, i, "size", msg );
+      AppendRendererPropertyNameAndValue( renderer, i, "offsetSizeMode", msg );
+      AppendRendererPropertyNameAndValue( renderer, i, "origin", msg );
+      AppendRendererPropertyNameAndValue( renderer, i, "anchorPoint", msg );
+    }
+  }
+
+  msg << "]";
+  msg << ", " << Quote( "children" ) << " : [ ";
+
+  // Recursively dump all the children as well
+  for( unsigned int i = 0 ; i < actor.GetChildCount() ; ++i )
+  {
+    if( i )
+    {
+      msg << " , ";
+    }
+    msg << DumpJson( actor.GetChildAt( i ), level + 1 );
+  }
+  msg << "] }";
+
+  return msg.str();
+}
+
+std::string GetActorTree()
+{
+  Dali::Actor actor = Dali::Stage::GetCurrent().GetRootLayer();
+  std::string str = DumpJson( actor, 0 );
+  return str;
+}
+
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace Automation
+{
+
+void SetProperty( const std::string& message )
+{
+  // check the set property length is within range
+  if( message.length() > MAX_SET_PROPERTY_STRING_LENGTH )
+  {
+    DALI_LOG_ERROR("SetProperty message length too long, size = %ul\n", message.length());
+    return;
+  }
+
+  SetProperties( message );
+}
+
+void DumpScene( unsigned int clientId, ClientSendDataInterface* sendData )
+{
+  char buf[32];
+  std::string json = GetActorTree();
+  int length = json.length();
+  snprintf( buf, 32, "%d\n", length );
+  std::string header( buf );
+  json = buf + json;
+  sendData->SendData( json.c_str(), json.length(), clientId );
+}
+
+} // namespace Automation
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
diff --git a/dali/internal/network/common/automation.h b/dali/internal/network/common/automation.h
new file mode 100644 (file)
index 0000000..4420153
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef DALI_INTERNAL_ADAPTOR_AUTOMATION_H
+#define DALI_INTERNAL_ADAPTOR_AUTOMATION_H
+
+/*
+ * Copyright (c) 2019 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 <dali/internal/network/common/client-send-data-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief The automation functions allow a way to control Dali via a network socket.
+ *
+ * The functions must be called from the event thread only.
+ *
+ * Any functions which require a response to be sent back to the network client
+ * use the ClientSendDataInterface interface.
+
+ * E.g.
+ * Dali network client thread            <---- "dump_scene" from network
+ * Dali main thread       "json data"    ----->   network
+ *
+ */
+namespace Automation
+{
+
+/**
+ * @brief Sets properties on an Actor.
+ * No ClientSendDataInterface required, as no response is sent back
+ * @param[in] message set property message
+ */
+void SetProperty( const std::string& message );
+
+
+/**
+ * @brief Dumps the actor tree to the client
+ * @param[in] clientId unique network client id
+ * @param[in] sendData interface to transmit data to the client
+ */
+void DumpScene( unsigned int clientId, ClientSendDataInterface* sendData );
+
+
+} // namespace Automation
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif
diff --git a/dali/internal/network/common/client-send-data-interface.h b/dali/internal/network/common/client-send-data-interface.h
new file mode 100644 (file)
index 0000000..9908bf5
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef DALI_INTERNAL_ADAPTOR_CLIENT_SEND_DATA_INTERFACE_H
+#define DALI_INTERNAL_ADAPTOR_CLIENT_SEND_DATA_INTERFACE_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief  Abstract interface used to transmit data to a client
+ */
+class ClientSendDataInterface
+{
+public:
+
+  /**
+   * @brief Sends data to the client
+   * @param[in] data pointer to some data
+   * @param[in] bufferSizeInBytes how big the buffer is in bytes
+   * @param[in] clientId unique client id to send the data to
+   */
+  virtual void SendData( const char* const data, unsigned int bufferSizeInBytes, unsigned int clientId ) = 0;
+
+
+protected:
+
+  /**
+   * @brief  Constructor
+   */
+  ClientSendDataInterface()
+  {
+  }
+
+  /**
+   * @brief Virtual Destructor
+   */
+  virtual ~ClientSendDataInterface()
+  {
+  }
+
+private:
+
+  // Undefined copy constructor.
+  ClientSendDataInterface( const ClientSendDataInterface& );
+
+  // Undefined assignment operator.
+  ClientSendDataInterface& operator=( const ClientSendDataInterface& );
+
+};
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_CLIENT_SEND_DATA_INTERFACE_H
diff --git a/dali/internal/network/common/network-performance-client.cpp b/dali/internal/network/common/network-performance-client.cpp
new file mode 100644 (file)
index 0000000..1185c95
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/network/common/network-performance-client.h>
+
+// EXTERNAL INCLUDES
+#include <stdio.h>
+#include <string>
+
+// INTERNAL INCLUDES
+#include <dali/internal/network/common/socket-interface.h>
+#include <dali/internal/network/common/network-performance-protocol.h>
+#include <dali/internal/network/common/automation.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const float MICROSECONDS_TO_SECOND = 1e-6;
+const char UNKNOWN_CMD[]= "Command or parameter invalid, type help for list of commands\n";
+
+
+/**
+ * helper class to store data along with the automation callback.
+ */
+class AutomationCallback: public CallbackBase
+{
+public:
+
+  /**
+   * instead of using templates, or having different callback classes for each callback
+   * we use a command id that decides which static function to call on the Automation class.
+   */
+  enum CommandId
+  {
+    UNKNOWN_COMMAND,
+    SET_PROPERTY,
+    DUMP_SCENE
+  };
+
+  AutomationCallback(  unsigned int clientId, ClientSendDataInterface& sendDataInterface )
+  :CallbackBase( reinterpret_cast< void* >( this ),
+                 NULL, // we get the dispatcher to call function directly
+                 reinterpret_cast< CallbackBase::Dispatcher>( &AutomationCallback::Dispatcher) ),
+  mSendDataInterface( sendDataInterface ),
+  mCommandId( UNKNOWN_COMMAND ),
+  mClientId( clientId )
+  {}
+
+  void AssignSetPropertyCommand( std::string setPropertyCommand )
+  {
+    mCommandId = SET_PROPERTY;
+    mPropertyCommand = setPropertyCommand;
+  }
+  void AssignDumpSceneCommand()
+  {
+     mCommandId = DUMP_SCENE;
+  }
+
+  void RunCallback()
+  {
+    switch( mCommandId )
+    {
+      case SET_PROPERTY:
+      {
+        Automation::SetProperty( mPropertyCommand );
+        break;
+      }
+      case DUMP_SCENE:
+      {
+        Automation::DumpScene( mClientId, &mSendDataInterface);
+        break;
+      }
+      default:
+      {
+        DALI_ASSERT_DEBUG( 0 && "Unknown command");
+        break;
+      }
+    }
+  }
+  static void Dispatcher( CallbackBase& base )
+  {
+    AutomationCallback& automationCallback( static_cast< AutomationCallback& >( base) );
+    automationCallback.RunCallback();
+  }
+
+private:
+
+  std::string mPropertyCommand;                   ///< property command
+  ClientSendDataInterface& mSendDataInterface;    ///< Abstract client send data interface
+  CommandId mCommandId;                           ///< command id
+  const unsigned int mClientId;                   ///< client id
+};
+
+} // unnamed namespace
+
+NetworkPerformanceClient::NetworkPerformanceClient(  pthread_t* thread,
+                                                     SocketInterface *socket,
+                                                     unsigned int clientId,
+                                                     ClientSendDataInterface& sendDataInterface,
+                                                     SocketFactoryInterface& socketFactory )
+: mThread( thread ),
+  mSocket( socket ),
+  mMarkerBitmask( PerformanceMarker::FILTERING_DISABLED ),
+  mSendDataInterface( sendDataInterface ),
+  mSocketFactoryInterface( socketFactory ),
+  mClientId( clientId ),
+  mConsoleClient(false)
+{
+
+}
+
+NetworkPerformanceClient::~NetworkPerformanceClient()
+{
+  if( mSocket->SocketIsOpen() )
+  {
+    mSocket->CloseSocket();
+  }
+  mSocketFactoryInterface.DestroySocket( mSocket );
+}
+
+unsigned int NetworkPerformanceClient::GetId() const
+{
+  return mClientId;
+}
+
+SocketInterface& NetworkPerformanceClient::GetSocket()
+{
+  return *mSocket;
+}
+
+bool NetworkPerformanceClient::WriteSocket( const void* buffer, unsigned int bufferSizeInBytes )
+{
+  return mSocket->Write( buffer, bufferSizeInBytes );
+}
+
+bool NetworkPerformanceClient::TransmitMarker( const PerformanceMarker& marker, const char* const description )
+{
+  if( ! marker.IsFilterEnabled( mMarkerBitmask ) )
+  {
+    return true;
+  }
+  if( mConsoleClient )
+  {
+    // write out the time stamp
+    char buffer[64];
+    double usec = marker.GetTimeStamp().microseconds;
+    int size = snprintf( buffer, sizeof(buffer),"%.6f (seconds), %s\n",
+                         usec * MICROSECONDS_TO_SECOND,
+                         description );
+
+   return mSocket->Write( buffer, size );
+
+  }
+
+
+  // todo serialize the data
+  return false;
+}
+
+void NetworkPerformanceClient::ExitSelect()
+{
+  mSocket->ExitSelect();
+}
+
+pthread_t* NetworkPerformanceClient::GetThread()
+{
+  return mThread;
+}
+
+void NetworkPerformanceClient::ProcessCommand( char* buffer, unsigned int bufferSizeInBytes )
+{
+  // if connected via console, then strip off the carriage return, and switch to console mode
+  if( buffer[ bufferSizeInBytes - 1] == '\n')
+  {
+    buffer[ bufferSizeInBytes - 1] = 0;
+    mConsoleClient = true;
+  }
+  unsigned int param(0);
+  std::string stringParam;
+  PerformanceProtocol::CommandId commandId( PerformanceProtocol::UNKNOWN_COMMAND );
+
+  bool ok =  PerformanceProtocol::GetCommandId( buffer, bufferSizeInBytes, commandId, param, stringParam );
+  if( !ok )
+  {
+    WriteSocket( UNKNOWN_CMD, sizeof(UNKNOWN_CMD) );
+    return;
+  }
+  std::string response;
+
+  switch( commandId )
+  {
+    case PerformanceProtocol::HELP_MESSAGE:
+    {
+      response = PerformanceProtocol::GetHelpMessage();
+      break;
+    }
+
+    case PerformanceProtocol::ENABLE_TIME_MARKER_BIT_MASK:
+    {
+      mMarkerBitmask  = static_cast<  PerformanceMarker::MarkerFilter >( param );
+      response = "enable time marker ";
+      break;
+    }
+
+    case PerformanceProtocol::DUMP_SCENE_GRAPH:
+    {
+      // this needs to be run on the main thread, use the trigger event....
+      AutomationCallback* callback = new AutomationCallback( mClientId, mSendDataInterface );
+      callback->AssignDumpSceneCommand();
+
+      // create a trigger event that automatically deletes itself after the callback has run in the main thread
+      TriggerEventInterface *interface = TriggerEventFactory::CreateTriggerEvent( callback, TriggerEventInterface::DELETE_AFTER_TRIGGER );
+
+      // asynchronous call, the call back will be run sometime later on the main thread
+      interface->Trigger();
+      break;
+    }
+
+    case PerformanceProtocol::SET_PROPERTIES:
+    {
+      // this needs to be run on the main thread, use the trigger event....
+      AutomationCallback* callback = new AutomationCallback( mClientId, mSendDataInterface );
+      callback->AssignSetPropertyCommand( stringParam );
+
+      // create a trigger event that automatically deletes itself after the callback has run in the main thread
+      TriggerEventInterface *interface = TriggerEventFactory::CreateTriggerEvent( callback, TriggerEventInterface::DELETE_AFTER_TRIGGER );
+
+      // asynchronous call, the call back will be run sometime later on the main thread
+      interface->Trigger();
+      break;
+    }
+
+    case PerformanceProtocol::LIST_METRICS_AVAILABLE:
+    case PerformanceProtocol::ENABLE_METRIC:
+    case PerformanceProtocol::DISABLE_METRIC:
+    {
+      response="Metrics currently not supported";
+      break;
+    }
+    default:
+    {
+      response = UNKNOWN_CMD;
+      break;
+    }
+  }
+  if( ! response.empty() )
+  {
+    // add a carriage return for console clients
+    if( mConsoleClient )
+    {
+      response+="\n";
+    }
+    WriteSocket( response.c_str(), response.length()  );
+  }
+}
+
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
diff --git a/dali/internal/network/common/network-performance-client.h b/dali/internal/network/common/network-performance-client.h
new file mode 100644 (file)
index 0000000..c196b86
--- /dev/null
@@ -0,0 +1,141 @@
+#ifndef DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_CLIENT_H
+#define DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_CLIENT_H
+
+/*
+ * Copyright (c) 2019 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 <pthread.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/performance-marker.h>
+#include <dali/internal/network/common/client-send-data-interface.h>
+#include <dali/internal/network/common/socket-factory-interface.h>
+#include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ *  @brief Network Performance client
+ *
+ *  Every time a client connects to Dali, a NetworkPerformanceClient object is created.
+ *  It is responsible for processing incoming commands, and storing the client state
+ *  (e.g. what performance markers it wants).
+ *
+ *  Certain commands such as dump-scene need to be run on the main Dali event thread.
+ *  To achieve this, a trigger event is used which executes a function on the main thread.
+ *  The sendDataInterface is then used with the client id to transmit the data to the client.
+ *  The reason for using a client id is because the client
+ *  can be deleted in between receiving a command and sending a response.
+ *  E.g.
+ *  NetworkPerformanceClient (own thread, id 5)  <---  Dump Scene Command
+ *  delete NetworkPerformanceClient              <---  Connection closed
+ *  MainThread. Send scene data to client 5. Client 5 has been deleted so don't send the data.
+ *
+ */
+class NetworkPerformanceClient
+{
+public:
+
+  /**
+   * @brief Constructor
+   * @param thread thread pointer
+   * @param socket socket interface
+   * @param clientId unique client id
+   * @param sendDataInterface used to send data to the socket from main thread
+   * @param SocketFactoryInterface used to delete the socket when the client is destroyed
+   */
+  NetworkPerformanceClient( pthread_t* thread,
+                            SocketInterface *socket,
+                            unsigned int clientId,
+                            ClientSendDataInterface& sendDataInterface,
+                            SocketFactoryInterface& socketFactory );
+
+  /**
+   * @brief Destructor
+   */
+  ~NetworkPerformanceClient();
+
+  /**
+   * @return client unique id
+   */
+  unsigned int GetId() const;
+
+  /**
+   * @return socket interface
+   */
+  SocketInterface& GetSocket();
+
+  /**
+   * @brief Write data to a socket. Can be called from any thread
+   * @copydoc Dali::SocketInterface::Send
+   */
+  bool WriteSocket( const void* buffer, unsigned int bufferSizeInBytes );
+
+  /**
+   * @brief Process a command
+   * @param buffer pointer to command data
+   * @param bufferSizeInBytes how big the buffer is in bytes
+   */
+  void ProcessCommand( char* buffer, unsigned int bufferSizeInBytes );
+
+  /**
+   * @brief Write a marker to the socket, if this client is filtering this marker.
+   * @param marker
+   */
+  bool TransmitMarker( const PerformanceMarker& marker, const char* const description );
+
+  /**
+   * @brief If the client is waiting inside a select statement, this will cause it
+   * to break out.
+   */
+  void ExitSelect();
+
+  /**
+   * @brief get the thread running the client
+   * @return thread pointer
+   */
+  pthread_t* GetThread();
+
+private:
+
+  pthread_t* mThread;                                   ///< thread for the client
+  SocketInterface* mSocket;                             ///< socket interface
+  PerformanceMarker::MarkerFilter mMarkerBitmask;       ///< What markers are currently filtered
+  ClientSendDataInterface& mSendDataInterface;          ///< used to send data to a client from the main event thread
+  SocketFactoryInterface& mSocketFactoryInterface;      ///< used to delete the socket
+  unsigned int mClientId;                               ///< unique client id
+  bool mConsoleClient;                                  ///< if connected via a console then all responses are in ASCII, not binary packed data.
+
+};
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_CLIENT_H
diff --git a/dali/internal/network/common/network-performance-protocol.cpp b/dali/internal/network/common/network-performance-protocol.cpp
new file mode 100644 (file)
index 0000000..5b28773
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2018 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
+
+// CLASS HEADER
+#include <dali/internal/network/common/network-performance-protocol.h>
+
+// EXTERNAL INCLUDES
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+namespace Dali
+{
+
+namespace PerformanceProtocol
+{
+
+namespace
+{
+
+/**
+ * Command parameter type
+ */
+enum PARAMETER_TYPE
+{
+  NO_PARAMS,
+  UNSIGNED_INT,
+  STRING
+};
+
+/**
+ * Command information structure
+ */
+struct CommandInfo
+{
+  CommandId     cmdId;
+  CommandString cmdString;
+  PARAMETER_TYPE paramType;
+};
+
+/**
+ * Command lookup table
+ */
+CommandInfo CommandLookup[]=
+{
+  {  HELP_MESSAGE               , "help"               ,NO_PARAMS     },
+  {  ENABLE_METRIC              , "enable_metric"      ,UNSIGNED_INT  },
+  {  DISABLE_METRIC             , "disable_metric"     ,UNSIGNED_INT  },
+  {  LIST_METRICS_AVAILABLE     , "list_metrics"       ,NO_PARAMS     },
+  {  ENABLE_TIME_MARKER_BIT_MASK, "set_marker",         UNSIGNED_INT  },
+  {  DUMP_SCENE_GRAPH           , "dump_scene"         ,NO_PARAMS     },
+  {  SET_PROPERTIES             , "set_properties"     ,STRING        },
+  {  UNKNOWN_COMMAND            , "unknown"            ,NO_PARAMS     }
+};
+const unsigned int CommandLookupLength = sizeof( CommandLookup ) /sizeof( CommandInfo );
+
+#define GREEN  "\033[01;32m"
+#define NORMAL  "\e[m"
+#define PARAM "\033[22;32m"
+#define YELLOW "\033[01;33m"
+
+const char* const helpMsg =
+    YELLOW
+    "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+    "  Dali performance console                           \n"
+    "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n" NORMAL
+    GREEN " list_metrics " NORMAL " - list available metrics\n"
+    GREEN " enable_metric " PARAM " metricId" NORMAL " - enable a metric \n"
+    GREEN " disable_metric " PARAM " metricId" NORMAL " - disable a metric\n\n"
+    GREEN " set_marker " PARAM " value " NORMAL "-output Dali markers\n"
+    "            : Bit 0  = V_SYNC (1)\n"
+    "            : Bit 1  = Update task (2)\n"
+    "            : Bit 2  = Render task (4) \n"
+    "            : Bit 3  = Event Processing task (8)\n"
+    "            : Bit 4  = SwapBuffers (16)\n"
+    "            : Bit 5  = Life cycle events  (32)\n"
+    "            : Bit 6  = Resource event (64)\n"
+    "\n"
+    GREEN " set_properties " NORMAL " - set an actor property command. Format:\n\n"
+    GREEN " set_properties " PARAM "|ActorIndex;Property;Value|" NORMAL ", e.g: \n"
+    GREEN " set_properties " PARAM "|178;Size;[ 144.0, 144.0, 144.0 ]|178;Color;[ 1.0, 1,0, 1.0 ]|\n"
+    "\n"
+    GREEN " dump_scene" NORMAL " - dump the current scene in json format\n";
+
+} // un-named namespace
+
+bool GetCommandId( const char* const commandString, unsigned int lengthInBytes, CommandId& commandId, unsigned int& intParam, std::string& stringParam  )
+{
+  commandId = UNKNOWN_COMMAND;
+  intParam = 0;
+
+  // the command list is small so just do a O(n) search for the commandID.
+  for( unsigned int i = 0 ; i < CommandLookupLength; ++i )
+  {
+    if( strncmp( commandString, CommandLookup[i].cmdString ,strlen(CommandLookup[i].cmdString  )) == 0 )
+    {
+      commandId = CommandLookup[i].cmdId;
+
+      // if the command has a parameter read it
+      if( CommandLookup[i].paramType ==  UNSIGNED_INT)
+      {
+        int count = sscanf(commandString,"%*s %d",&intParam);
+        if( count != 1 )
+        {
+          // missing parameter
+          return false;
+        }
+      }
+      else if (CommandLookup[i].paramType == STRING )
+      {
+        char* charParam( NULL );
+        // allocates the character array
+        int count = sscanf(commandString,"%*s %ms",&charParam);
+        if( count != 1 )
+        {
+          // missing parameter
+          return false;
+        }
+        stringParam = std::string( charParam);
+        free(charParam);
+      }
+      return true;
+    }
+  }
+  // not found
+  return false;
+}
+
+bool GetCommandString( CommandId commandId, CommandString& commandString )
+{
+  for( unsigned int i = 0; i < CommandLookupLength; ++i)
+  {
+    if( CommandLookup[ i ].cmdId == commandId )
+    {
+      strncpy( commandString,  CommandLookup[ i ].cmdString, strlen(CommandLookup[ i ].cmdString) );
+      return true;
+    }
+  }
+  strncpy( commandString, CommandLookup[ UNKNOWN_COMMAND ].cmdString, MAX_COMMAND_STRING_LENGTH);
+  return false;
+}
+
+const char* const GetHelpMessage()
+{
+  return helpMsg;
+}
+
+
+} // namespace PerformanceProtocol
+
+} // namespace Dali
diff --git a/dali/internal/network/common/network-performance-protocol.h b/dali/internal/network/common/network-performance-protocol.h
new file mode 100644 (file)
index 0000000..ce6e467
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_PROTOCOL_H
+#define DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_PROTOCOL_H
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+namespace Dali
+{
+
+namespace PerformanceProtocol
+{
+
+const unsigned int MAX_COMMAND_STRING_LENGTH = 256;  ///< maximum length of a command including null terminator
+
+/**
+ * @brief List of commands id's
+ */
+enum CommandId
+{
+  HELP_MESSAGE            = 0, ///<  help message
+  ENABLE_METRIC           = 1, ///< enable metric
+  DISABLE_METRIC          = 2, ///< disable metric
+  LIST_METRICS_AVAILABLE  = 3, ///< list  metrics that are available
+  ENABLE_TIME_MARKER_BIT_MASK = 4, ///< bit mask of time markers to enable
+  SET_PROPERTIES            = 5, ///< set property
+  DUMP_SCENE_GRAPH          = 6, ///< dump the scene graph
+  UNKNOWN_COMMAND           = 4096
+};
+
+
+typedef char CommandString[ MAX_COMMAND_STRING_LENGTH ];
+
+/**
+ * @brief given a command id, get the command string
+ * @param[in] commandId command id
+ * @param[out] commandString command string
+ * @return true on success, false on failure
+ */
+bool GetCommandString( CommandId commandId, CommandString& commandString );
+
+/**
+ * @brief given a command string, get the command id and an integer parameter if it exists
+ * @param[in] commandString command string
+ * @param[in] lengthInBytes length of the string
+ * @param[out] commandId command id
+ * @param[out] intParam integer parameter
+ * @param[out] stringParam string parameter
+ * @param true on success, false on failure
+ */
+bool GetCommandId( const char* const commandString,
+                   unsigned int lengthInBytes,
+                   CommandId& commandId,
+                   unsigned int& intParam,
+                   std::string& stringParam);
+
+/**
+ * @return the protocol help message for console users
+ */
+const char* const GetHelpMessage();
+
+} // namespace PerformanceProtocol
+
+} // namespace Dali
+
+#endif //DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_PROTOCOL_H
diff --git a/dali/internal/network/common/network-performance-server.cpp b/dali/internal/network/common/network-performance-server.cpp
new file mode 100644 (file)
index 0000000..1f048d0
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/network/common/network-performance-server.h>
+
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/performance-marker.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // un-named namespace
+{
+const unsigned int SERVER_PORT = 3031;
+const unsigned int MAXIMUM_PORTS_TO_TRY = 10; ///< if port in use, try up to SERVER_PORT + 10
+const unsigned int CONNECTION_BACKLOG = 2;   ///<  maximum length of the queue of pending connections.
+const unsigned int SOCKET_READ_BUFFER_SIZE = 4096;
+typedef Vector< NetworkPerformanceClient*> ClientList;
+
+/**
+ * POD passed to client thread on startup
+ */
+struct ClientThreadInfo
+{
+  NetworkPerformanceServer* server;
+  NetworkPerformanceClient* client;
+};
+}
+
+NetworkPerformanceServer::NetworkPerformanceServer( AdaptorInternalServices& adaptorServices,
+                                                    const EnvironmentOptions& logOptions )
+: mSocketFactory( adaptorServices.GetSocketFactoryInterface() ),
+  mLogOptions( logOptions ),
+  mServerThread( 0 ),
+  mListeningSocket( NULL ),
+  mClientUniqueId( 0 ),
+  mClientCount( 0 ),
+  mLogFunctionInstalled( false )
+{
+}
+
+NetworkPerformanceServer::~NetworkPerformanceServer()
+{
+  Stop();
+
+  if( mLogFunctionInstalled )
+  {
+    mLogOptions.UnInstallLogFunction();
+  }
+}
+
+void NetworkPerformanceServer::Start()
+{
+  // start a thread to listen for incoming connection requests
+  if (! mServerThread )
+  {
+    if( mListeningSocket )
+    {
+      mSocketFactory.DestroySocket( mListeningSocket );
+    }
+    mListeningSocket = mSocketFactory.NewSocket( SocketInterface::TCP);
+    mListeningSocket->ReuseAddress( true );
+
+    bool bound = false;
+    unsigned int basePort = 0;
+
+    // try a small range of ports, so if multiple Dali apps are running you can select
+    // which one to connect to
+    while( !bound && ( basePort <  MAXIMUM_PORTS_TO_TRY ))
+    {
+      bound = mListeningSocket->Bind( SERVER_PORT + basePort );
+      if( !bound )
+      {
+        basePort++;
+      }
+    }
+    if(!bound )
+    {
+      DALI_LOG_ERROR("Failed to bind to a port \n");
+      return;
+    }
+
+    mListeningSocket->Listen( CONNECTION_BACKLOG );
+
+    // start a thread which will block waiting for new connections
+    int error = pthread_create( &mServerThread, NULL, ConnectionListenerFunc, this );
+    DALI_ASSERT_ALWAYS( !error && "pthread create failed" );
+
+    Dali::Integration::Log::LogMessage(Integration::Log::DebugInfo, "~~~ NetworkPerformanceServer started on port %d ~~~ \n",  SERVER_PORT + basePort);
+
+  }
+}
+void NetworkPerformanceServer::Stop()
+{
+  if( !mServerThread )
+  {
+    return;
+  }
+
+  if( mListeningSocket )
+  {
+    // close the server thread to prevent any new connections
+    mListeningSocket->ExitSelect();
+  }
+
+  // wait for the thread to exit.
+  void* exitValue;
+  pthread_join( mServerThread, &exitValue );
+
+  if( mListeningSocket )
+  {
+    // close the socket
+    mListeningSocket->CloseSocket();
+  }
+
+  mSocketFactory.DestroySocket( mListeningSocket );
+
+  mListeningSocket = NULL;
+
+  // this will tell all client threads to quit
+  StopClients();
+
+}
+
+bool NetworkPerformanceServer::IsRunning() const
+{
+  if (mServerThread )
+  {
+    return true;
+  }
+  return false;
+}
+
+void NetworkPerformanceServer::ClientThread( NetworkPerformanceClient* client )
+{
+  mClientCount++;
+
+  SocketInterface& socket( client->GetSocket() );
+
+  for( ;; )
+  {
+    SocketInterface::SelectReturn ret = socket.Select();
+
+    if( ret == SocketInterface::DATA_AVAILABLE )
+    {
+     // Read
+      char buffer[ SOCKET_READ_BUFFER_SIZE ];
+      unsigned int  bytesRead;
+
+      bool ok  = socket.Read( buffer, sizeof( buffer ) , bytesRead);
+      if( ok && ( bytesRead > 0) )
+      {
+        client->ProcessCommand( buffer, bytesRead );
+      }
+      else   // if bytesRead == 0, then client closed connection, if ok == false then an error
+      {
+        DeleteClient( client );
+        return;
+      }
+    }
+    else // ret == QUIT or ERROR
+    {
+      DeleteClient( client);
+      return;
+    }
+  }
+}
+
+void NetworkPerformanceServer::ConnectionListener()
+{
+  // install Dali logging function for this thread
+  if( !mLogFunctionInstalled )
+  {
+    mLogOptions.InstallLogFunction();
+    mLogFunctionInstalled = true;
+  }
+
+  for( ;; )
+  {
+    // this will block, waiting for a client to connect
+    // or for mListeningSocket->ExitSelect() to be called
+
+    SocketInterface::SelectReturn ret = mListeningSocket->Select();
+
+    if( ret == SocketInterface::DATA_AVAILABLE )
+    {
+      SocketInterface* clientSocket = mListeningSocket->Accept();
+
+      // new connection made, spawn a thread to handle it
+      pthread_t* clientThread = new pthread_t();
+
+      NetworkPerformanceClient* client = AddClient( clientSocket, clientThread );
+
+      ClientThreadInfo* info = new ClientThreadInfo;
+      info->client = client;
+      info->server = this;
+
+      int error = pthread_create( clientThread, NULL, ClientThreadFunc, info );
+      DALI_ASSERT_ALWAYS( !error && "pthread create failed" );
+
+    }
+    else // ret == SocketInterface::QUIT or SocketInterface::ERROR
+    {
+      return;
+    }
+  }
+}
+
+void* NetworkPerformanceServer::ClientThreadFunc( void* data )
+{
+  ClientThreadInfo* info = static_cast<ClientThreadInfo*>( data );
+  info->server->ClientThread( info->client );
+  delete info;
+  return NULL;
+}
+
+NetworkPerformanceClient* NetworkPerformanceServer::AddClient( SocketInterface* clientSocket, pthread_t* clientThread )
+{
+  // This function is only called from the listening thread
+  NetworkPerformanceClient* client= new NetworkPerformanceClient( clientThread,
+                                                                  clientSocket,
+                                                                  mClientUniqueId++,
+                                                                  *this,
+                                                                  mSocketFactory);
+
+  // protect the mClients list which can be accessed from multiple threads.
+  Mutex::ScopedLock lock( mClientListMutex );
+
+  mClients.PushBack( client );
+
+  return client;
+}
+
+void NetworkPerformanceServer::DeleteClient( NetworkPerformanceClient* client )
+{
+  // protect the mClients list while modifying
+  Mutex::ScopedLock lock( mClientListMutex );
+
+  // remove from the list, and delete it
+  for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
+  {
+    if( (*iter) == client )
+    {
+      mClients.Erase( iter );
+      delete client;
+
+      // if there server is shutting down, it waits for client count to hit zero
+      mClientCount--;
+
+      return;
+    }
+  }
+}
+
+void NetworkPerformanceServer::SendData( const char* const data, unsigned int bufferSizeInBytes,unsigned int clientId )
+{
+  if( ! mClientCount )
+  {
+    return;
+  }
+
+  // prevent clients been added / deleted while transmiting data
+  Mutex::ScopedLock lock( mClientListMutex );
+
+  for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
+  {
+    NetworkPerformanceClient* client = (*iter);
+    if( client->GetId() == clientId )
+    {
+      client->WriteSocket(data ,bufferSizeInBytes);
+      return;
+    }
+  }
+}
+
+void NetworkPerformanceServer::TransmitMarker( const PerformanceMarker& marker, const char* const description )
+{
+  if( ! IsRunning() )
+  {
+    return;
+  }
+  // prevent clients been added / deleted while transmiting data
+  Mutex::ScopedLock lock( mClientListMutex );
+
+  for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
+  {
+    NetworkPerformanceClient* client = (*iter);
+    client->TransmitMarker( marker, description );
+  }
+}
+
+
+void NetworkPerformanceServer::StopClients()
+{
+  // prevent clients been added / deleted while stopping all clients
+  Mutex::ScopedLock lock( mClientListMutex );
+
+  for( ClientList::Iterator iter = mClients.Begin(); iter != mClients.End() ; ++iter )
+  {
+    NetworkPerformanceClient* client = (*iter);
+    // stop the client from waiting for new commands, and exit from it's thread
+    client->ExitSelect();
+  }
+}
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
diff --git a/dali/internal/network/common/network-performance-server.h b/dali/internal/network/common/network-performance-server.h
new file mode 100644 (file)
index 0000000..0e0d45c
--- /dev/null
@@ -0,0 +1,182 @@
+#ifndef DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_SERVER_H
+#define DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_SERVER_H
+
+/*
+ * Copyright (c) 2019 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 <pthread.h>
+#include <dali/devel-api/threading/mutex.h>
+#include <dali/public-api/common/dali-vector.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/environment-options.h>
+#include <dali/internal/network/common/network-performance-client.h>
+#include <dali/internal/adaptor/common/adaptor-internal-services.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class SocketInterface;
+class PerformanceMarker;
+
+/**
+ *  @brief  The class listens for incoming connections on a dedicated thread.
+ *
+ *  When a new connection is established a client thread is spawned to
+ *  handle that connection, along with a NetworkPerformanceClient object.
+ *  The NetworkPerformanceClient object performs processing of incoming
+ *  commands and holds the per-client state information for performance monitoring.
+ *
+ *  Server->Start()
+ *  - Open socket
+ *  - Spawns a thread to listen for incoming connections
+ *  <---- New connection
+ *  - Spawns a client thread to communicate with new client
+ *
+ *  Server->Stop()
+ *  - Stops listening thread
+ *  - Stops all client threads
+ */
+class NetworkPerformanceServer : public ClientSendDataInterface
+{
+
+public:
+
+  /**
+   * @brief Constructor
+   * @param[in] adaptorServices adaptor internal services
+   * @param[in] logOptions log options
+   */
+  NetworkPerformanceServer( AdaptorInternalServices& adaptorServices, const EnvironmentOptions& logOptions );
+
+
+  /**
+   * @brief Start the server, to be called form Dali main thread
+   * @pre Can only be called form Dali main thread
+   */
+  void Start();
+
+  /**
+   * @brief Stop the server
+   * @pre Can only be called form Dali main thread
+   */
+  void Stop();
+
+  /**
+   * @return true if the server is running
+   */
+  bool IsRunning() const;
+
+  /**
+   * @brief Transmit a marker to any clients are listening for this marker.
+   * @param[in] marker performance marker
+   * @param[in] description marker description
+   * @pre Can be called from any thread
+   *
+   */
+  void TransmitMarker( const PerformanceMarker& marker, const char* const description );
+
+  /**
+   * Destructor
+   */
+   ~NetworkPerformanceServer();
+
+protected:  // ClientSendDataInterface
+
+  /**
+   * @copydoc ClientSendDataInterface::ClientSendDataInterface()
+   */
+  virtual void SendData( const char* const data, unsigned int bufferSizeInBytes, unsigned int clientId );
+
+private:
+
+  /**
+   * Helper for the thread calling the entry function.
+   * @param[in] This A pointer to the current RenderThread object
+   */
+  static void* ConnectionListenerFunc( void* This )
+  {
+    ( static_cast<NetworkPerformanceServer*>( This ) )->ConnectionListener();
+    return NULL;
+  }
+
+  /**
+   * Helper for the thread calling the entry function.
+   * @param[in] This A pointer to the current RenderThread object
+   */
+  static void* ClientThreadFunc( void* data );
+
+  /**
+   * @brief Client thread function
+   * @param client network client object
+   */
+  void ClientThread( NetworkPerformanceClient* client );
+
+  /**
+   * @brief Stop all client threads
+   */
+  void StopClients();
+
+  /**
+   * @brief Waits for new connections to be made
+   */
+  void ConnectionListener();
+
+  /**
+   * @brief Add a new client to the client list
+   * @param clientSocket client socket
+   * @param clientThread client thread
+   * @return client
+   */
+  NetworkPerformanceClient* AddClient( SocketInterface* clientSocket, pthread_t* clientThread );
+
+  /**
+   * @brief Delete a client from the client list
+   * @param client  network client
+   */
+  void DeleteClient( NetworkPerformanceClient* client );
+
+  NetworkPerformanceServer( const NetworkPerformanceServer& );            ///< undefined copy constructor
+  NetworkPerformanceServer& operator=( const NetworkPerformanceServer& ); ///< undefined assignment operator
+
+  SocketFactoryInterface& mSocketFactory;                 ///< used to create sockets
+  const EnvironmentOptions& mLogOptions;                  ///< log options
+  Dali::Vector< NetworkPerformanceClient* > mClients;     ///< list of connected clients
+  pthread_t mServerThread;                                ///< thread that listens for new connections
+  SocketInterface* mListeningSocket;                      ///< socket used to listen for new connections
+  Dali::Mutex mClientListMutex;                           ///< mutex
+  unsigned int mClientUniqueId;                           ///< increments for every client connection
+  volatile unsigned int mClientCount;                     ///< client count
+  bool mLogFunctionInstalled;                             ///< whether the log function is installed
+
+};
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif //DALI_INTERNAL_ADAPTOR_NETWORK_PERFORMANCE_SERVER_H
diff --git a/dali/internal/network/common/socket-factory-interface.h b/dali/internal/network/common/socket-factory-interface.h
new file mode 100644 (file)
index 0000000..4819e94
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef DALI_INTERNAL_ADAPTOR_BASE_SOCKET_FACTORY_INTERFACE_H
+#define DALI_INTERNAL_ADAPTOR_BASE_SOCKET_FACTORY_INTERFACE_H
+
+/*
+ * Copyright (c) 2019 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/internal/network/common/socket-interface.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * @brief abstract class to create and destroy sockets
+ */
+class SocketFactoryInterface
+{
+public:
+
+  /**
+   * @brief Create a new socket
+   * @param protocol network protocol
+   * @return true on success, false on failure
+   */
+   virtual SocketInterface* NewSocket( SocketInterface::Protocol protocol  ) = 0;
+
+   /**
+    * @brief destroy a socket
+    * @param[in] socket socket to destroy
+    */
+   virtual void DestroySocket( SocketInterface* socket  ) = 0;
+
+protected:
+
+  /**
+   * @brief Constructor
+   */
+   SocketFactoryInterface( )
+  {
+  }
+
+  /**
+   * @brief Virtual destructor
+   */
+  virtual ~SocketFactoryInterface()
+  {
+  }
+
+private:
+
+  // Undefined copy constructor.
+  SocketFactoryInterface( const SocketFactoryInterface& );
+
+  // Undefined assignment operator.
+  SocketFactoryInterface& operator=( const SocketFactoryInterface& );
+
+};
+
+
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_BASE_SOCKET_FACTORY_INTERFACE_H
diff --git a/dali/internal/network/common/socket-factory.cpp b/dali/internal/network/common/socket-factory.cpp
new file mode 100644 (file)
index 0000000..f35ce2c
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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 <dali/internal/network/common/socket-factory.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/network/common/socket-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+SocketInterface* SocketFactory::NewSocket( SocketInterface::Protocol protocol  )
+{
+  return new Socket( protocol );
+}
+
+void SocketFactory::DestroySocket( SocketInterface* socketInterface )
+{
+  Socket* socket( static_cast<Socket* >( socketInterface ));
+  delete socket;
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/dali/internal/network/common/socket-factory.h b/dali/internal/network/common/socket-factory.h
new file mode 100644 (file)
index 0000000..2b048e6
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef DALI_INTERNAL_ADAPTOR_SOCKET_FACTORY_H
+#define DALI_INTERNAL_ADAPTOR_SOCKET_FACTORY_H
+/*
+ * Copyright (c) 2019 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/internal/network/common/socket-factory-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief concrete implementation of the socket factory interface
+ */
+class SocketFactory : public SocketFactoryInterface
+{
+public:
+
+
+  /**
+   * @brief Constructor
+   */
+  SocketFactory( )
+  {
+  }
+
+  /**
+   * @brief destructor
+   */
+  virtual ~SocketFactory()
+  {
+  }
+
+  /**
+   * @copydoc SocketFactoryInterface::NewSocket()
+   */
+  virtual SocketInterface* NewSocket( SocketInterface::Protocol protocol  );
+
+  /**
+   * @copydoc SocketFactoryInterface::DestroySocket()
+   */
+  virtual void DestroySocket( SocketInterface* socket  );
+
+};
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_SOCKET_FACTORY_H
diff --git a/dali/internal/network/common/socket-impl.cpp b/dali/internal/network/common/socket-impl.cpp
new file mode 100644 (file)
index 0000000..f2d94eb
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * 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 <dali/internal/network/common/socket-impl.h>
+
+// EXTERNAL INCLUDES
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dali/integration-api/debug.h>
+
+// Sockets enums like INADDR_ANY use C-Casts
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+namespace
+{
+const unsigned int MAX_SOCKET_DATA_WRITE_SIZE = 1024 * 1024 * 10 ; // limit maximum size to write to 10 MB
+}
+
+Socket::Socket( Protocol protocol , int fileDescriptor )
+:mSocketFileDescriptor( fileDescriptor ),
+ mBound(false),
+ mListening(false),
+ mQuitPipeCreated(false),
+ mBlocked(false)
+{
+  int addressFamily( AF_INET );
+  int netProtocol( IPPROTO_TCP );
+  int type( SOCK_STREAM );    // for TCP
+
+  if( protocol == UDP )
+  {
+    type = SOCK_DGRAM;
+    netProtocol = IPPROTO_UDP;
+  }
+  if( mSocketFileDescriptor == -1)
+  {
+    mSocketFileDescriptor = socket( addressFamily,type, netProtocol);
+    if( mSocketFileDescriptor == -1 )
+    {
+      DALI_LOG_ERROR( "Unable to create socket\n" );
+    }
+  }
+  else
+  {
+    // socket already open
+    mBound = true;
+  }
+}
+
+Socket::~Socket()
+{
+  if( SocketIsOpen() )
+  {
+    CloseSocket();
+  }
+}
+
+bool Socket::SocketIsOpen() const
+{
+  return (mSocketFileDescriptor != -1);
+}
+
+bool Socket::CloseSocket()
+{
+
+  if( ! SocketIsOpen() )
+  {
+    DALI_LOG_ERROR("Socket already closed or is invalid \n");
+    return false;
+  }
+
+  int ret = close( mSocketFileDescriptor );
+  mSocketFileDescriptor = -1;
+  mListening = false;
+  mBound = false;
+
+  if( ret == -1 )
+  {
+    DALI_LOG_ERROR("Socket close failed\n");
+    return false;
+  }
+  return true;
+}
+
+bool Socket::Bind( uint16_t port )
+{
+  if( ! SocketIsOpen() || mBound )
+  {
+     DALI_LOG_ERROR("Socket is invalid, or already bound\n");
+     return false;
+  }
+  struct sockaddr_in serverAddress;
+
+  memset( &serverAddress, 0, sizeof(serverAddress) );
+  serverAddress.sin_family = AF_INET;                             // internet
+  serverAddress.sin_port = htons( port );  //  host-to-net short (16-bit) translation
+  serverAddress.sin_addr.s_addr = htonl( INADDR_ANY ); //  binds the socket to all available interfaces
+
+  int ret = bind( mSocketFileDescriptor,
+                  reinterpret_cast< struct sockaddr* >( &serverAddress ),
+                  sizeof(serverAddress));
+
+  if( ret == -1 )
+  {
+    char buf[512];
+    DALI_LOG_ERROR( "bind failed for port %d %s \n", port, strerror_r( errno, buf, 512 ) );
+    return false;
+  }
+
+  mBound = true;
+
+  return true;
+}
+
+bool Socket::Listen( int blacklog)
+{
+  if( ! mBound || mListening )
+  {
+    DALI_LOG_ERROR("socket is not bound, or already opened for listening\n");
+    return false;
+  }
+  int ret =  listen( mSocketFileDescriptor, blacklog);
+
+  if( ret == -1 )
+  {
+    DALI_LOG_ERROR("Listen failed\n");
+    return false;
+  }
+
+  mListening = true;
+
+  return true;
+}
+
+SocketInterface* Socket::Accept() const
+{
+  if( !mListening )
+  {
+    DALI_LOG_ERROR("socket is not being listened to\n");
+    return NULL;
+  }
+
+  struct sockaddr clientAddress;
+
+  socklen_t addressLength(sizeof(sockaddr_in));
+
+  int clientFileDescriptor = accept( mSocketFileDescriptor, &clientAddress, &addressLength);
+  if( clientFileDescriptor == -1 )
+  {
+     DALI_LOG_ERROR("Accept failed\n");
+     return NULL;
+  }
+
+  // create a new socket, only TCP supports connections
+  Socket* client = new Socket( TCP, clientFileDescriptor );
+
+  return client;
+}
+
+bool Socket::CreateQuitPipe()
+{
+  if( !mQuitPipeCreated )
+  {
+    // create a pipe file descriptor to be able to break from the Select statement
+    //
+    int ret = pipe( mQuitPipe );
+    if( ret != 0)
+    {
+      DALI_LOG_ERROR("Pipe creation failed\n");
+      return false;
+    }
+    mQuitPipeCreated = true;
+  }
+  return true;
+}
+void Socket::DeleteQuitPipe()
+{
+  if( mQuitPipeCreated )
+  {
+    close( mQuitPipe[0] );
+    close( mQuitPipe[1] );
+  }
+}
+
+SocketInterface::SelectReturn Socket::Select()
+{
+  bool ok = CreateQuitPipe();
+  if( !ok )
+  {
+    return ERROR;
+  }
+
+  fd_set  readFileDescriptors, exceptFileDescriptors;
+  FD_ZERO(&readFileDescriptors);
+  FD_ZERO(&exceptFileDescriptors);
+
+  FD_SET(mSocketFileDescriptor,&readFileDescriptors );
+  FD_SET(mQuitPipe[0],&readFileDescriptors );
+
+  FD_SET(mSocketFileDescriptor,&exceptFileDescriptors);
+
+  unsigned int maxFd = mQuitPipe[0] > mSocketFileDescriptor ? mQuitPipe[0]: mSocketFileDescriptor;
+
+  for( ;; )
+  {
+    // this will block waiting for file descriptors
+    int ret = select( maxFd+1, &readFileDescriptors, NULL, &exceptFileDescriptors, NULL );
+    if( ret == -1 )
+    {
+      DALI_LOG_ERROR("select failed\n");
+      return ERROR;
+    }
+    else if ( FD_ISSET( mQuitPipe[0] , &readFileDescriptors ))
+    {
+      // ExitSelect() called
+      return QUIT;
+    }
+    else if ( FD_ISSET( mSocketFileDescriptor, &readFileDescriptors ))
+    {
+      // socket data received
+      return DATA_AVAILABLE;
+    }
+  }
+  return QUIT;
+}
+
+void Socket::ExitSelect()
+{
+  if( mQuitPipeCreated )
+  {
+    // write a single character to the pipe (can be anything)
+    char c = ' ';
+    int ret = write( mQuitPipe[1], &c, 1);
+    if( ret < 1 )
+    {
+      DALI_LOG_ERROR("ExitSelect failed!\n");
+    }
+    return;
+  }
+}
+
+bool Socket::ReuseAddress( bool reUse  )
+{
+  if( ! SocketIsOpen() | mBound )
+  {
+    DALI_LOG_ERROR("Socket is invalid or already bound \n");
+    return false;
+  }
+
+  int reUseInteger = reUse; // convert it to an int
+
+  int ret = setsockopt( mSocketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, &reUseInteger, sizeof(reUseInteger));
+  if( ret == -1 )
+  {
+    char buf[512];
+    DALI_LOG_ERROR( "SO_REUSEADDR option failed %s \n", strerror_r( errno, buf, 512 ) );
+    return false;
+  }
+  return true;
+}
+
+bool Socket::SetBufferSize( SocketInterface::BufferType type, unsigned int size )
+{
+  if( ! SocketIsOpen() || mBound )
+  {
+    DALI_LOG_ERROR("Socket is invalid or already bound \n");
+    return false;
+  }
+  int option = SO_RCVBUF;
+  if( type == SocketInterface::SEND_BUFFER )
+  {
+    option = SO_SNDBUF;
+  }
+
+  int ret = setsockopt( mSocketFileDescriptor, SOL_SOCKET,option,&size,sizeof(size));
+  if( ret == -1 )
+  {
+    DALI_LOG_ERROR("SO_RCVBUF / SO_SNDBUF  option failed \n");
+    return false;
+  }
+  return true;
+}
+
+bool Socket::Read( void* buffer, unsigned int bufferSizeInBytes, unsigned int& bytesRead )
+{
+  bytesRead = 0;
+
+  if( !SocketIsOpen() )
+  {
+    DALI_LOG_ERROR("Socket is invalid \n");
+    return false;
+  }
+
+  bytesRead = read( mSocketFileDescriptor, buffer, bufferSizeInBytes );
+
+  return true;
+}
+
+bool Socket::Write( const void* buffer, unsigned int bufferSizeInBytes )
+{
+  if( !SocketIsOpen() )
+  {
+    DALI_LOG_ERROR("Socket is invalid \n");
+    return false;
+  }
+
+  // check we don't try to write more than 10MB ( this can be increased if required)
+  if( bufferSizeInBytes > MAX_SOCKET_DATA_WRITE_SIZE )
+  {
+    DALI_LOG_ERROR("Writing %d bytes exceeds MAX_SOCKET_DATA_WRITE_SIZE of %d bytes \n", bufferSizeInBytes, MAX_SOCKET_DATA_WRITE_SIZE);
+    return false;
+  }
+
+  int bytesWritten = 0;
+
+  // write isn't guaranteed to write the entire buffer in one go
+
+  while(  bytesWritten != static_cast< int>(bufferSizeInBytes))
+  {
+    const char* byteBuffer = static_cast<const char *>( buffer );
+    byteBuffer+=bytesWritten;
+
+    int ret = write( mSocketFileDescriptor, byteBuffer, bufferSizeInBytes - bytesWritten );
+    if( ret < 1)
+    {
+      DALI_LOG_ERROR("Socket writer error \n");
+      return false;
+    }
+    else
+    {
+      bytesWritten += ret;
+    }
+  }
+  return true;
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
+
+#pragma GCC diagnostic pop
diff --git a/dali/internal/network/common/socket-impl.h b/dali/internal/network/common/socket-impl.h
new file mode 100644 (file)
index 0000000..21c8780
--- /dev/null
@@ -0,0 +1,138 @@
+#ifndef DALI_INTERNAL_ADAPTOR_SOCKET_IMPL_H
+#define DALI_INTERNAL_ADAPTOR_SOCKET_IMPL_H
+
+/*
+ * Copyright (c) 2019 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/internal/network/common/socket-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief Concrete implementation of a socket under Linux.
+ *
+ * Provides automatic closing of socket on destruction.
+ */
+class Socket : public SocketInterface
+{
+public:
+
+  /**
+   * @brief Constructor
+   * @param protocol network protocol
+   * @param fileDescriptor option file descriptor if the socket is already open
+   */
+  Socket( Protocol protocol , int fileDescriptor = -1 );
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketIsOpen()
+   */
+  virtual bool SocketIsOpen() const;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::CloseSocket
+   */
+  virtual bool CloseSocket();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::Bind
+   */
+  virtual bool Bind( uint16_t port ) ;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::Listen
+   */
+  virtual bool Listen( int blacklog);
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::Accept
+   */
+  virtual SocketInterface* Accept() const ;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::Select
+   */
+  virtual SelectReturn Select( );
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::ExitSelect
+   */
+  virtual void ExitSelect();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::Recieve
+   */
+  virtual bool Read( void* buffer, unsigned int bufferSizeInBytes, unsigned int& bytesRead );
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::Send
+   */
+  virtual bool Write( const void* buffer, unsigned int bufferLength );
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::ReuseAddress
+   */
+  virtual bool ReuseAddress( bool reUse );
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SocketInterface::SetBufferSize
+   *
+   */
+  virtual bool SetBufferSize( SocketInterface::BufferType type, unsigned int bufferSizeInBytes );
+
+  /**
+   * @brief Virtual destructor
+   */
+  virtual ~Socket();
+
+private:
+
+
+  /**
+   * @brief Helper to create the quit pipe
+   */
+  bool CreateQuitPipe();
+
+  /**
+   * @brief  Helper to delete the quit pipe
+   */
+  void DeleteQuitPipe();
+
+  int mSocketFileDescriptor; ///< file descriptor
+  int mQuitPipe[2];          ///< Pipe to inform Select to quit.
+  bool mBound:1;             ///< whether the socket is bound
+  bool mListening:1;         ///< whether the socket is being listen to
+  bool mQuitPipeCreated:1;   ///< whether the quit pipe has been created
+  bool mBlocked:1;           ///< whether the socket is blocked waiting for a connection
+};
+
+
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_SOCKET_IMPL_H
diff --git a/dali/internal/network/common/socket-interface.h b/dali/internal/network/common/socket-interface.h
new file mode 100644 (file)
index 0000000..6f0dabd
--- /dev/null
@@ -0,0 +1,200 @@
+#ifndef DALI_INTERNAL_ADAPTOR_BASE_SOCKET_INTERFACE_H
+#define DALI_INTERNAL_ADAPTOR_BASE_SOCKET_INTERFACE_H
+
+/*
+ * Copyright (c) 2019 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 <stdint.h>
+
+#undef ERROR
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * @brief Abstract socket interface.
+ * The typical usage is:
+ *
+ * @code
+ *
+ * SocketFactory::NewSocket( SocketInterface::TCP );
+ * socket->ReuseAddress( true );
+ * socket->Bind( port );
+ * socket->Listen();
+ *
+ * ret = socket->Select();     // call socket->ExitSelect to break from select from another thread
+ * if ( ret == DATA_AVAILABLE )
+ * {
+ *   socket->Read( ...);
+ * }
+ * socket->Close();
+ *
+ * @endcode
+ *
+ */
+class SocketInterface
+{
+public:
+
+  /**
+   * @brief Protocol type
+   */
+  enum Protocol
+  {
+    TCP,          ///< Reliable, connection oriented
+    UDP,          ///< Connection less, no guarantees of packet delivery, ordering
+  };
+
+  /**
+   * @brief check is a socket is open
+   * @return true if the socket is currently open
+   */
+  virtual bool SocketIsOpen() const = 0;
+
+  /**
+   * @brief CloseSocket
+   * @return true on success, false on failure
+   */
+  virtual bool CloseSocket() = 0;
+
+  /**
+   * @brief Socket bind,  associate a local address with a socket ( normally uses AF_INET + INADDR_ANY)
+   * @param[in] port network port
+   * @return true on success, false on failure
+   */
+  virtual bool Bind( uint16_t port ) = 0;
+
+  /**
+   * @brief Indicate a willingness to accept incoming connection requests
+   * @param[in] backlog maximum length of the queue of pending connections.
+   * @return true on success, false on failure
+   */
+  virtual bool Listen( int blacklog) = 0;
+
+  /**
+   * @brief Wait for connection request and make connection
+   * @return new client socket
+   */
+  virtual SocketInterface* Accept() const = 0;
+
+  /**
+   * @brief Select return values
+   */
+  enum SelectReturn
+  {
+    DATA_AVAILABLE,   ///< Data is available to read
+    QUIT,             ///< ExitSelect() has been called on the socket
+    ERROR             ///< Socket error
+  };
+
+  /**
+   * @brief Waits for an event to occur (data available / error)
+   * Returns when
+   * - data has been sent to the socket
+   * - client has closed the connection ( Read will return 0 bytes)
+   * - ExitSelect has been called (returns QUIT)
+   * - There is an error (returns ERROR)
+   * @return DATA_AVAILABLE if data is available
+   */
+  virtual SelectReturn Select() = 0;
+
+  /**
+   * @brief To be called from a separate thread to break out of select
+   */
+  virtual void ExitSelect() = 0;
+
+  /**
+   * @brief Read data from the socket
+   * @param[out] buffer data
+   * @param[in] bufferSizeInBytes buffer size in bytes
+   * @param[out] bytesRead number of bytes read
+   * @return true on success, false on failure
+   */
+  virtual bool Read( void* buffer, unsigned int bufferSizeInBytes, unsigned int& bytesRead  ) = 0;
+
+  /**
+   * @brief Send data to the socket
+   * @param[in] buffer data to write
+   * @param[in] bufferSizeInBytes buffer size in write
+   * @return true on success, false on failure
+   */
+  virtual bool Write( const void* buffer, unsigned int bufferSizeInBytes ) = 0;
+
+  //
+  // Common socket options. Please add more as required.
+  // These should be wrappers around the setsockopt API
+
+  /**
+   * @brief Whether the SO_REUSEADDR is enabled or not.
+   * @param[in] reuse flag.
+   * @return true on success, false on failure
+   */
+  virtual bool ReuseAddress( bool reUse ) = 0;
+
+  /**
+   * @brief Socket buffer type
+   */
+  enum BufferType
+  {
+    SEND_BUFFER,        ///< (SO_SNDBUF) Send buffer size
+    RECIEVE_BUFFER      ///< (SO_RCVBUF) Size of buffer allocated to hold data arriving to the socket
+  };
+
+  /**
+   * @brief Set the send and recieve buffer sizes ( SO_SNDBUF, SO_RCVBUF )
+   * @param[in] type buffer type
+   * @param[in] size buffer size
+   * @return true on success, false on failure
+   */
+  virtual bool SetBufferSize( BufferType type, unsigned int size ) = 0;
+
+protected:
+
+  /**
+   * @brief Constructor
+   */
+  SocketInterface( )
+  {
+  }
+
+  /**
+   * @brief virtual destructor
+   */
+  virtual ~SocketInterface()
+  {
+  }
+
+private:
+
+  // Undefined copy constructor.
+  SocketInterface( const SocketInterface& );
+
+  // Undefined assignment operator.
+  SocketInterface& operator=( const SocketInterface& );
+
+};
+
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_BASE_SOCKET_INTERFACE_H
diff --git a/dali/internal/network/common/trace-interface.h b/dali/internal/network/common/trace-interface.h
new file mode 100644 (file)
index 0000000..026a29a
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef DALI_INTERNAL_BASE_TRACE_INTERFACE_H
+#define DALI_INTERNAL_BASE_TRACE_INTERFACE_H
+
+/*
+ * Copyright (c) 2019 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 <dali/internal/system/common/performance-marker.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Abstract Tracing Interface.
+ * Used to log trace messages.
+ * E.g. On Linux this may use ftrace
+ *
+ */
+class TraceInterface
+{
+
+public:
+
+  /**
+   * Write a trace message
+   * @param marker performance marker
+   * @param traceMessage trace message
+   */
+  virtual void Trace( const PerformanceMarker& marker, const std::string& traceMessage ) = 0;
+
+protected:
+
+  /**
+   * Constructor
+   */
+  TraceInterface()
+  {
+  }
+
+  /**
+   * virtual destructor
+   */
+  virtual ~TraceInterface()
+  {
+  }
+
+  // Undefined copy constructor.
+  TraceInterface( const TraceInterface& );
+
+  // Undefined assignment operator.
+  TraceInterface& operator=( const TraceInterface& );
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_BASE_TRACE_INTERFACE_H
diff --git a/dali/internal/network/file.list b/dali/internal/network/file.list
new file mode 100644 (file)
index 0000000..0beeaaf
--- /dev/null
@@ -0,0 +1,15 @@
+
+# module: network, backend: common
+SET( adaptor_network_common_src_files 
+    ${adaptor_network_dir}/common/socket-factory.cpp 
+    ${adaptor_network_dir}/common/socket-impl.cpp
+)
+
+# module: network, backend: common
+SET( adaptor_performance_logging_src_files 
+    ${adaptor_network_dir}/common/network-performance-protocol.cpp 
+    ${adaptor_network_dir}/common/network-performance-client.cpp 
+    ${adaptor_network_dir}/common/network-performance-server.cpp 
+    ${adaptor_network_dir}/common/automation.cpp
+)
+
diff --git a/dali/internal/sensor/common/tilt-sensor-factory.cpp b/dali/internal/sensor/common/tilt-sensor-factory.cpp
new file mode 100644 (file)
index 0000000..f5245b3
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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/internal/sensor/common/tilt-sensor-factory.h>
+#include <dali/internal/sensor/common/tilt-sensor-impl.h>
+#include <dali/devel-api/common/singleton-service.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+namespace TiltSensorFactory
+{
+__attribute__((weak)) Dali::Internal::Adaptor::TiltSensor* Create()
+{
+  // default implementation returns 'dummy' sensor
+  return new Internal::Adaptor::TiltSensor();
+}
+
+Dali::TiltSensor Get()
+{
+  Dali::TiltSensor sensor;
+
+  Dali::SingletonService service(SingletonService::Get());
+
+  if (service)
+  {
+    // Check whether the keyboard focus manager is already created
+    Dali::BaseHandle handle = service.GetSingleton(typeid(Dali::TiltSensor));
+    if (handle)
+    {
+      // If so, downcast the handle of singleton to keyboard focus manager
+      sensor = Dali::TiltSensor(dynamic_cast< TiltSensor * >( handle.GetObjectPtr()));
+    }
+    else
+    {
+      // Create a singleton instance
+      sensor = Dali::TiltSensor(TiltSensorFactory::Create());
+      service.Register(typeid(sensor), sensor);
+      handle = sensor;
+    }
+  }
+  return sensor;
+}
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/dali/internal/sensor/common/tilt-sensor-factory.h b/dali/internal/sensor/common/tilt-sensor-factory.h
new file mode 100644 (file)
index 0000000..fe7ec28
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef DALI_SENSOR_COMMON_TILT_SENSOR_FACTORY_H
+#define DALI_SENSOR_COMMON_TILT_SENSOR_FACTORY_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/devel-api/adaptor-framework/tilt-sensor.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class TiltSensor;
+
+namespace TiltSensorFactory
+{
+
+/**
+ * Creates new instance of tilt sensor implementation
+ * @return pointer to tilt sensor implementation instance
+ */
+Dali::Internal::Adaptor::TiltSensor* Create();
+
+/**
+ * Obtains existing or creates new instance of the tilt sensor
+ * @return Tilt sensor handle
+ */
+Dali::TiltSensor Get();
+
+} // TiltSensorFactory
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_SENSOR_COMMON_TILT_SENSOR_FACTORY_H
diff --git a/dali/internal/sensor/common/tilt-sensor-impl.cpp b/dali/internal/sensor/common/tilt-sensor-impl.cpp
new file mode 100644 (file)
index 0000000..79627be
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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/internal/sensor/common/tilt-sensor-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+TiltSensor::TiltSensor() = default;
+
+TiltSensor::~TiltSensor() = default;
+
+bool TiltSensor::Start()
+{
+  return false;
+}
+
+void TiltSensor::Stop()
+{
+
+}
+
+bool TiltSensor::IsStarted() const
+{
+  return false;
+}
+
+float TiltSensor::GetRoll() const
+{
+  return 0.0f;
+}
+
+float TiltSensor::GetPitch() const
+{
+  return 0.0f;
+}
+
+Quaternion TiltSensor::GetRotation() const
+{
+  return Quaternion::IDENTITY;
+}
+
+
+TiltSensor::TiltedSignalType& TiltSensor::TiltedSignal()
+{
+  static TiltSensor::TiltedSignalType signal;
+  return signal;
+}
+
+
+void TiltSensor::SetUpdateFrequency(float frequencyHertz)
+{
+
+}
+
+float TiltSensor::GetUpdateFrequency() const
+{
+  return 0.0f;
+}
+
+void TiltSensor::SetRotationThreshold(Radian rotationThreshold)
+{
+
+}
+
+/**
+ * @copydoc Dali::TiltSensor::GetRotationThreshold()
+ */
+Radian TiltSensor::GetRotationThreshold() const
+{
+  return Radian();
+}
+
+/**
+ * Connects a callback function with the object's signals.
+ * @param[in] object The object providing the signal.
+ * @param[in] tracker Used to disconnect the signal.
+ * @param[in] signalName The signal to connect to.
+ * @param[in] functor A newly allocated FunctorDelegate.
+ * @return True if the signal was connected.
+ * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+ */
+bool TiltSensor::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  return false;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali/internal/sensor/common/tilt-sensor-impl.h b/dali/internal/sensor/common/tilt-sensor-impl.h
new file mode 100644 (file)
index 0000000..e2473f8
--- /dev/null
@@ -0,0 +1,148 @@
+#ifndef DALI_SENSOR_COMMON_TILT_SENSOR_IMPL_H
+#define DALI_SENSOR_COMMON_TILT_SENSOR_IMPL_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/timer.h>
+#include <dali/devel-api/adaptor-framework/tilt-sensor.h>
+#include <deque>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * TiltSensor provides pitch & roll values when the device is tilted.
+ */
+class TiltSensor : public Dali::BaseObject
+{
+public:
+
+  /**
+   * Constructor
+   */
+  TiltSensor();
+
+  /**
+   * Destructor
+   */
+  ~TiltSensor() override;
+
+  typedef Dali::TiltSensor::TiltedSignalType TiltedSignalType;
+
+  /**
+   * @copydoc Dali::TiltSensor::Start()
+   */
+  virtual bool Start();
+
+  /**
+   * @copydoc Dali::TiltSensor::Stop()
+   */
+  virtual void Stop();
+
+  /**
+   * @copydoc Dali::TiltSensor::IsStarted()
+   */
+  virtual bool IsStarted() const;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetRoll()
+   */
+  virtual float GetRoll() const;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetPitch()
+   */
+  virtual float GetPitch() const;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetRotation()
+   */
+  virtual Quaternion GetRotation() const;
+
+  /**
+   * @copydoc Dali::TiltSensor::TiltedSignal()
+   */
+  virtual TiltedSignalType& TiltedSignal();
+
+  /**
+   * @copydoc Dali::TiltSensor::SetUpdateFrequency()
+   */
+  virtual void SetUpdateFrequency( float frequencyHertz );
+
+  /**
+   * @copydoc Dali::TiltSensor::GetUpdateFrequency()
+   */
+  virtual float GetUpdateFrequency() const;
+
+  /**
+   * @copydoc Dali::TiltSensor::SetRotationThreshold()
+   */
+  virtual void SetRotationThreshold(Radian rotationThreshold);
+
+  /**
+   * @copydoc Dali::TiltSensor::GetRotationThreshold()
+   */
+  virtual Radian GetRotationThreshold() const;
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+inline Internal::Adaptor::TiltSensor& GetImplementation(Dali::TiltSensor& sensor)
+{
+  DALI_ASSERT_ALWAYS( sensor && "TiltSensor handle is empty" );
+
+  BaseObject& handle = sensor.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::TiltSensor&>(handle);
+}
+
+inline const Internal::Adaptor::TiltSensor& GetImplementation(const Dali::TiltSensor& sensor)
+{
+  DALI_ASSERT_ALWAYS( sensor && "TiltSensor handle is empty" );
+
+  const BaseObject& handle = sensor.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::TiltSensor&>(handle);
+}
+
+} // namespace Dali
+
+#endif // DALI_SENSOR_COMMON_TILT_SENSOR_IMPL_H
diff --git a/dali/internal/sensor/file.list b/dali/internal/sensor/file.list
new file mode 100644 (file)
index 0000000..48e1405
--- /dev/null
@@ -0,0 +1,19 @@
+
+# module: sensor, backend: common
+SET( adaptor_sensor_common_src_files 
+    ${adaptor_sensor_dir}/common/tilt-sensor-factory.cpp 
+    ${adaptor_sensor_dir}/common/tilt-sensor-impl.cpp
+)
+
+# module: sensor, backend: tizen
+SET( adaptor_sensor_tizen_src_files 
+    ${adaptor_sensor_dir}/tizen/tilt-sensor-factory-tizen.cpp 
+    ${adaptor_sensor_dir}/tizen/tilt-sensor-impl-tizen.cpp
+)
+
+# module: sensor, backend: ubuntu
+SET( adaptor_sensor_ubuntu_src_files 
+    ${adaptor_sensor_dir}/ubuntu/tilt-sensor-factory-ubuntu.cpp 
+    ${adaptor_sensor_dir}/ubuntu/tilt-sensor-impl-ubuntu.cpp
+)
+
diff --git a/dali/internal/sensor/tizen/tilt-sensor-factory-tizen.cpp b/dali/internal/sensor/tizen/tilt-sensor-factory-tizen.cpp
new file mode 100644 (file)
index 0000000..76a1dcd
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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 <dali/internal/sensor/tizen/tilt-sensor-impl-tizen.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace TiltSensorFactory
+{
+
+Dali::Internal::Adaptor::TiltSensor* Create()
+{
+  return Dali::Internal::Adaptor::TiltSensorTizen::New();
+}
+
+} // TiltSensorFactory
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
\ No newline at end of file
diff --git a/dali/internal/sensor/tizen/tilt-sensor-impl-tizen.cpp b/dali/internal/sensor/tizen/tilt-sensor-impl-tizen.cpp
new file mode 100644 (file)
index 0000000..13d3336
--- /dev/null
@@ -0,0 +1,397 @@
+/*
+ * 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 <dali/internal/sensor/tizen/tilt-sensor-impl-tizen.h>
+#include <dali/internal/sensor/common/tilt-sensor-factory.h>
+
+// EXTERNAL INCLUDES
+#include <cmath>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/integration-api/debug.h>
+
+namespace // unnamed namespace
+{
+const char* const SIGNAL_TILTED = "tilted";
+
+const float MAX_ORIENTATION_ROLL_VALUE = 90.f;
+const float MAX_ORIENTATION_PITCH_VALUE = 180.f;
+const float MAX_ACCELEROMETER_VALUE = 9.8f;
+
+// Type Registration
+Dali::BaseHandle Create()
+{
+  return Dali::Internal::Adaptor::TiltSensorFactory::Get();
+}
+
+Dali::TypeRegistration typeRegistration( typeid(Dali::TiltSensor), typeid(Dali::BaseHandle), Create );
+
+Dali::SignalConnectorType signalConnector1( typeRegistration, SIGNAL_TILTED, Dali::Internal::Adaptor::TiltSensor::DoConnectSignal );
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+#ifdef SENSOR_ENABLED
+static void sensor_changed_cb (sensor_h sensor, sensor_event_s *event, void *user_data)
+{
+  TiltSensorTizen* tiltSensor = reinterpret_cast< TiltSensorTizen* >( user_data );
+
+  if(tiltSensor)
+  {
+    tiltSensor->Update(event);
+  }
+
+  return;
+}
+
+static std::string get_sensor_error_string(int errorValue)
+{
+  std::string ret;
+
+  switch(errorValue)
+  {
+    case SENSOR_ERROR_IO_ERROR:
+      ret = "SENSOR_ERROR_IO_ERROR";
+      break;
+    case SENSOR_ERROR_INVALID_PARAMETER:
+      ret = "SENSOR_ERROR_INVALID_PARAMETER";
+      break;
+    case SENSOR_ERROR_NOT_SUPPORTED:
+      ret = "SENSOR_ERROR_NOT_SUPPORTED";
+      break;
+    case SENSOR_ERROR_PERMISSION_DENIED:
+      ret = "SENSOR_ERROR_PERMISSION_DENIED";
+      break;
+    case SENSOR_ERROR_OUT_OF_MEMORY:
+      ret = "SENSOR_ERROR_OUT_OF_MEMORY";
+      break;
+    case SENSOR_ERROR_NOT_NEED_CALIBRATION:
+      ret = "SENSOR_ERROR_NOT_NEED_CALIBRATION";
+      break;
+    case SENSOR_ERROR_OPERATION_FAILED:
+      ret = "SENSOR_ERROR_OPERATION_FAILED";
+      break;
+  }
+
+  return ret;
+}
+#endif
+
+TiltSensorTizen* TiltSensorTizen::New()
+{
+  return new TiltSensorTizen();
+}
+
+TiltSensorTizen::~TiltSensorTizen()
+{
+  Disconnect();
+}
+
+bool TiltSensorTizen::Connect()
+{
+#ifdef SENSOR_ENABLED
+  if(mState != DISCONNECTED)
+  {
+    Stop();
+    Disconnect();
+  }
+
+  const int interval = 1000/mFrequencyHertz;
+
+  int ret = 0;
+  bool isSupported = false;
+
+  // try to use Orientation sensor at first for less power consumption.
+  ret = sensor_is_supported(SENSOR_ORIENTATION, &isSupported);
+
+  if(ret < 0)
+  {
+    DALI_LOG_ERROR("sensor_is_supported() failed : %s\n", get_sensor_error_string(ret).c_str());
+    return false;
+  }
+
+  if(isSupported == true)
+  {
+    mSensorType = SENSOR_ORIENTATION;
+  }
+  else
+  {
+    DALI_LOG_ERROR("sensor does not support SENSOR_ORIENTATION\n");
+
+    ret = sensor_is_supported(SENSOR_ACCELEROMETER, &isSupported);
+
+    if(ret < 0)
+    {
+      DALI_LOG_ERROR("sensor_is_supported() failed : %s\n", get_sensor_error_string(ret).c_str());
+      return false;
+    }
+
+    if(isSupported == false)
+    {
+      DALI_LOG_ERROR("sensor does not support both SENSOR_ORIENTATION and SENSOR_ACCELEROMETER\n");
+      return false;
+    }
+
+    mSensorType = SENSOR_ACCELEROMETER;
+  }
+
+  ret = sensor_get_default_sensor(mSensorType, &mSensor); /* mSensor should not be deleted */
+
+  if(ret < 0)
+  {
+    DALI_LOG_ERROR("sensor_get_default_sensor() failed : %s\n", get_sensor_error_string(ret).c_str());
+    return false;
+  }
+
+  ret = sensor_create_listener(mSensor, &mSensorListener);
+
+  if(ret < 0)
+  {
+    DALI_LOG_ERROR("sensor_create_listener() failed : %s\n", get_sensor_error_string(ret).c_str());
+    return false;
+  }
+
+  sensor_listener_set_event_cb(mSensorListener, interval, sensor_changed_cb, this);
+  sensor_listener_set_interval(mSensorListener, interval);
+
+  sensor_listener_set_option(mSensorListener, SENSOR_OPTION_DEFAULT /* Not receive data when LCD is off and in power save mode */);
+
+  mState = CONNECTED;
+
+  return true;
+#endif
+
+  return false;
+}
+
+void TiltSensorTizen::Disconnect()
+{
+  if(mSensorListener)
+  {
+    if(mState == STARTED)
+    {
+      Stop();
+    }
+
+    if(mState == STOPPED || mState == CONNECTED)
+    {
+#ifdef SENSOR_ENABLED
+      sensor_listener_unset_event_cb(mSensorListener);
+      sensor_listener_stop(mSensorListener);
+      sensor_destroy_listener(mSensorListener);
+#endif
+      mSensor = NULL;
+      mSensorListener = NULL;
+      mState = DISCONNECTED;
+    }
+  }
+}
+
+bool TiltSensorTizen::Start()
+{
+  if( mSensorListener && ( mState == CONNECTED || mState == STOPPED ) )
+  {
+#ifdef SENSOR_ENABLED
+    int ret = 0;
+    ret = sensor_listener_start(mSensorListener);
+    if(ret != SENSOR_ERROR_NONE)
+    {
+      DALI_LOG_ERROR("sensor_listener_start() failed : %s\n", get_sensor_error_string(ret).c_str());
+      Disconnect();
+      return false;
+    }
+
+    mState = STARTED;
+    return true;
+#endif
+  }
+  else
+  {
+    if( mState == STARTED )
+    {
+      DALI_LOG_ERROR("TiltSensor is already started. Current state [%d]\n", mState);
+    }
+    else
+    {
+      // mState is DISCONNECTED
+      DALI_LOG_ERROR("TiltSensor is disconnected. Current state [%d]\n", mState);
+    }
+    return false;
+  }
+  return false;
+}
+
+void TiltSensorTizen::Stop()
+{
+#ifdef SENSOR_ENABLED
+  if(mSensorListener && mState == STARTED)
+  {
+    sensor_listener_stop( mSensorListener );
+    mState = STOPPED;
+  }
+#endif
+}
+
+bool TiltSensorTizen::IsStarted() const
+{
+  return ( mSensorListener && mState == STARTED );
+}
+
+float TiltSensorTizen::GetRoll() const
+{
+  return mRoll;
+}
+
+float TiltSensorTizen::GetPitch() const
+{
+  return mPitch;
+}
+
+Quaternion TiltSensorTizen::GetRotation() const
+{
+  return mRotation;
+}
+
+TiltSensor::TiltedSignalType& TiltSensorTizen::TiltedSignal()
+{
+  return mTiltedSignal;
+}
+
+void TiltSensorTizen::SetUpdateFrequency( float frequencyHertz )
+{
+  DALI_ASSERT_ALWAYS( frequencyHertz > 0.0f && "Frequency must have a positive value" );
+
+  if ( fabsf(mFrequencyHertz - frequencyHertz) >= GetRangedEpsilon(mFrequencyHertz, frequencyHertz) )
+  {
+    mFrequencyHertz = frequencyHertz;
+
+#ifdef SENSOR_ENABLED
+    if(mSensorListener)
+    {
+      const int interval = 1000/mFrequencyHertz;
+      sensor_listener_set_interval(mSensorListener, interval);
+    }
+#endif
+  }
+}
+
+float TiltSensorTizen::GetUpdateFrequency() const
+{
+  return mFrequencyHertz;
+}
+
+void TiltSensorTizen::SetRotationThreshold(Radian rotationThreshold)
+{
+  mRotationThreshold = rotationThreshold;
+}
+
+Radian TiltSensorTizen::GetRotationThreshold() const
+{
+  return mRotationThreshold;
+}
+
+bool TiltSensorTizen::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  bool connected( true );
+  TiltSensor* sensor = dynamic_cast<TiltSensor*>( object );
+
+  if( sensor && SIGNAL_TILTED == signalName )
+  {
+    sensor->TiltedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+TiltSensorTizen::TiltSensorTizen()
+: mState(DISCONNECTED),
+  mFrequencyHertz( Dali::TiltSensor::DEFAULT_UPDATE_FREQUENCY ),
+  mSensor( NULL ),
+  mSensorListener( NULL ),
+  mRoll( 0.0f ),
+  mPitch( 0.0f ),
+  mRotation( Radian(0.0f), Vector3::YAXIS ),
+  mRotationThreshold( 0.0f )
+{
+  // connect sensor
+  Connect();
+}
+
+#ifdef SENSOR_ENABLED
+void TiltSensorTizen::Update(sensor_event_s *event)
+{
+  Radian newRoll( 0.0f );
+  Radian newPitch( 0.0f );
+  Quaternion newRotation;
+
+  if(mSensorType == SENSOR_ORIENTATION)
+  {
+    newRoll  = Clamp( float(event->values[2]  / MAX_ORIENTATION_ROLL_VALUE)  /* -90 < roll < 90 */, -1.0f/*min*/, 1.0f/*max*/ );
+    newPitch = Clamp( float(event->values[1] / MAX_ORIENTATION_PITCH_VALUE) /* -180 < pitch < 180 */, -1.0f/*min*/, 1.0f/*max*/ );
+  }
+  else if(mSensorType == SENSOR_ACCELEROMETER)
+  {
+    newRoll  = Clamp( float(event->values[0] / MAX_ACCELEROMETER_VALUE), -1.0f/*min*/, 1.0f/*max*/ );
+    newPitch = Clamp( float(event->values[1] / MAX_ACCELEROMETER_VALUE), -1.0f/*min*/, 1.0f/*max*/ );
+  }
+  else
+  {
+    DALI_LOG_ERROR("Invalid sensor type\n");
+    return;
+  }
+
+  newRotation = Quaternion( Radian( newRoll * Math::PI * -0.5f ), Vector3::YAXIS ) *
+              Quaternion( Radian( newPitch * Math::PI * -0.5f ), Vector3::XAXIS );
+
+  Radian angle(Quaternion::AngleBetween(newRotation, mRotation));
+
+  // If the change in value is more than the threshold then emit tilted signal.
+  if( angle >= mRotationThreshold )
+  {
+    mRoll = newRoll;
+    mPitch = newPitch;
+    mRotation = newRotation;
+
+    // emit signal
+    if ( !mTiltedSignal.Empty() )
+    {
+      Dali::TiltSensor handle( this );
+      mTiltedSignal.Emit( handle );
+    }
+  }
+}
+#endif // SENSOR_ENABLED
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/sensor/tizen/tilt-sensor-impl-tizen.h b/dali/internal/sensor/tizen/tilt-sensor-impl-tizen.h
new file mode 100644 (file)
index 0000000..b2f3963
--- /dev/null
@@ -0,0 +1,199 @@
+#ifndef DALI_SENSOR_TIZEN_TILT_SENSOR_IMPL_TIZEN_H
+#define DALI_SENSOR_TIZEN_TILT_SENSOR_IMPL_TIZEN_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#ifdef CAPI_SYSTEM_SENSOR_SUPPORT
+#include <sensor/sensor.h>
+#define SENSOR_ENABLED
+#endif
+
+#include <deque>
+#include <dali/public-api/object/base-object.h>
+#include <dali/internal/sensor/common/tilt-sensor-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/timer.h>
+#include <dali/devel-api/adaptor-framework/tilt-sensor.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * TiltSensorTizen provides pitch & roll values when the device is tilted.
+ */
+class TiltSensorTizen : public Dali::Internal::Adaptor::TiltSensor
+{
+public:
+
+  typedef Dali::TiltSensor::TiltedSignalType TiltedSignalType;
+
+  /**
+   * Public constructor
+   * @return New instance of TiltSensorTizen
+   */
+  static TiltSensorTizen* New();
+
+  /**
+   * @copydoc Dali::TiltSensor::Start()
+   */
+  bool Start() override;
+
+  /**
+   * @copydoc Dali::TiltSensor::Stop()
+   */
+  void Stop() override;
+
+  /**
+   * @copydoc Dali::TiltSensor::IsStarted()
+   */
+  bool IsStarted() const override;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetRoll()
+   */
+  float GetRoll() const override;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetPitch()
+   */
+  float GetPitch() const override;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetRotation()
+   */
+  Quaternion GetRotation() const override;
+
+  /**
+   * @copydoc Dali::TiltSensor::TiltedSignal()
+   */
+  TiltedSignalType& TiltedSignal() override;
+
+  /**
+   * @copydoc Dali::TiltSensor::SetUpdateFrequency()
+   */
+  void SetUpdateFrequency( float frequencyHertz ) override;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetUpdateFrequency()
+   */
+  float GetUpdateFrequency() const override;
+
+  /**
+   * @copydoc Dali::TiltSensor::SetRotationThreshold()
+   */
+  void SetRotationThreshold(Radian rotationThreshold) override;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetRotationThreshold()
+   */
+  Radian GetRotationThreshold() const override;
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+  /**
+   * Update sensor data
+   * @note This is called by static sensor callback function
+   * @param[in] event sensor event data
+   */
+#ifdef SENSOR_ENABLED
+  void Update(sensor_event_s *event);
+#endif
+
+
+private:
+
+  enum State
+  {
+    DISCONNECTED,
+    CONNECTED,
+    STARTED,
+    STOPPED
+  };
+
+  /**
+   * Private constructor; see also TiltSensor::New()
+   */
+  TiltSensorTizen();
+
+  /**
+   * Destructor
+   */
+  virtual ~TiltSensorTizen();
+
+  /**
+   * Connect sensor device
+   */
+  bool Connect();
+  /**
+   * Disconnect sensor device
+   */
+  void Disconnect();
+
+  // Undefined
+  TiltSensorTizen(const TiltSensor&);
+
+  // Undefined
+  TiltSensorTizen& operator=(TiltSensor&);
+
+private:
+  State mState;
+  float mFrequencyHertz;
+
+#ifdef SENSOR_ENABLED
+  sensor_type_e mSensorType;
+  sensor_h mSensor;
+  sensor_listener_h mSensorListener;
+#else
+  int mSensorType;
+  int* mSensor;
+  int* mSensorListener;
+#endif
+
+  float mRoll;
+  float mPitch;
+  Quaternion mRotation;
+
+  Radian mRotationThreshold;
+
+  TiltedSignalType mTiltedSignal;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_SENSOR_TIZEN_TILT_SENSOR_IMPL_TIZEN_H
diff --git a/dali/internal/sensor/ubuntu/tilt-sensor-factory-ubuntu.cpp b/dali/internal/sensor/ubuntu/tilt-sensor-factory-ubuntu.cpp
new file mode 100644 (file)
index 0000000..3471167
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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 <dali/internal/sensor/ubuntu/tilt-sensor-impl-ubuntu.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+namespace TiltSensorFactory
+{
+
+Dali::Internal::Adaptor::TiltSensor* Create()
+{
+  return Dali::Internal::Adaptor::TiltSensorUbuntu::New();
+}
+
+} // TiltSensorFactory
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
\ No newline at end of file
diff --git a/dali/internal/sensor/ubuntu/tilt-sensor-impl-ubuntu.cpp b/dali/internal/sensor/ubuntu/tilt-sensor-impl-ubuntu.cpp
new file mode 100644 (file)
index 0000000..9a2b5ea
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/sensor/ubuntu/tilt-sensor-impl-ubuntu.h>
+#include <dali/internal/sensor/common/tilt-sensor-factory.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/common/singleton-service.h>
+
+namespace // unnamed namespace
+{
+
+const char* const SIGNAL_TILTED = "tilted";
+
+const int NUMBER_OF_SAMPLES = 10;
+
+const float MAX_ACCELEROMETER_XY_VALUE = 9.8f;
+
+// Type Registration
+Dali::BaseHandle GetInstance()
+{
+  return Dali::Internal::Adaptor::TiltSensorFactory::Get();
+}
+
+Dali::TypeRegistration typeRegistration( typeid(Dali::TiltSensor), typeid(Dali::BaseHandle), GetInstance );
+
+Dali::SignalConnectorType signalConnector1( typeRegistration, SIGNAL_TILTED, Dali::Internal::Adaptor::TiltSensor::DoConnectSignal );
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+TiltSensorUbuntu* TiltSensorUbuntu::New()
+{
+  return new TiltSensorUbuntu();
+}
+
+TiltSensorUbuntu::~TiltSensorUbuntu()
+{
+  Stop();
+}
+
+bool TiltSensorUbuntu::Start()
+{
+  // Make sure sensor API is responding
+  bool success = Update();
+
+  if ( success )
+  {
+    if ( !mTimer )
+    {
+      mTimer = Dali::Timer::New( 1000.0f / mFrequencyHertz );
+      mTimer.TickSignal().Connect( mTimerSlot, &TiltSensorUbuntu::Update );
+    }
+
+    if ( mTimer &&
+         !mTimer.IsRunning() )
+    {
+      mTimer.Start();
+    }
+  }
+
+  return success;
+}
+
+void TiltSensorUbuntu::Stop()
+{
+  if ( mTimer )
+  {
+    mTimer.Stop();
+    mTimer.Reset();
+  }
+}
+
+bool TiltSensorUbuntu::IsStarted() const
+{
+  return ( mTimer && mTimer.IsRunning() );
+}
+
+float TiltSensorUbuntu::GetRoll() const
+{
+  return mRoll;
+}
+
+float TiltSensorUbuntu::GetPitch() const
+{
+  return mPitch;
+}
+
+Quaternion TiltSensorUbuntu::GetRotation() const
+{
+  return mRotation;
+}
+
+TiltSensor::TiltedSignalType& TiltSensorUbuntu::TiltedSignal()
+{
+  return mTiltedSignal;
+}
+
+void TiltSensorUbuntu::SetUpdateFrequency( float frequencyHertz )
+{
+  DALI_ASSERT_ALWAYS( frequencyHertz > 0.0f && "Frequency must have a positive value" );
+
+  if ( fabsf(mFrequencyHertz - frequencyHertz) >= GetRangedEpsilon(mFrequencyHertz, frequencyHertz) )
+  {
+    mFrequencyHertz = frequencyHertz;
+
+    if ( mTimer )
+    {
+      mTimer.SetInterval( 1000.0f / mFrequencyHertz );
+    }
+  }
+}
+
+float TiltSensorUbuntu::GetUpdateFrequency() const
+{
+  return mFrequencyHertz;
+}
+
+void TiltSensorUbuntu::SetRotationThreshold(Radian rotationThreshold)
+{
+  mRotationThreshold = rotationThreshold;
+}
+
+Radian TiltSensorUbuntu::GetRotationThreshold() const
+{
+  return mRotationThreshold;
+}
+
+bool TiltSensorUbuntu::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  bool connected( true );
+  TiltSensor* sensor = dynamic_cast<TiltSensor*>( object );
+
+  if( sensor && ( SIGNAL_TILTED == signalName ) )
+  {
+    sensor->TiltedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+TiltSensorUbuntu::TiltSensorUbuntu()
+: mFrequencyHertz( Dali::TiltSensor::DEFAULT_UPDATE_FREQUENCY ),
+  mTimerSlot( this ),
+  mSensorFrameworkHandle( -1 ),
+  mRoll( 0.0f ),
+  mPitch( 0.0f ),
+  mRotation( Dali::ANGLE_0, Vector3::YAXIS ),
+  mRotationThreshold( 0.0f )
+{
+  mRollValues.resize( NUMBER_OF_SAMPLES, 0.0f );
+  mPitchValues.resize( NUMBER_OF_SAMPLES, 0.0f );
+}
+
+bool TiltSensorUbuntu::Update()
+{
+  float newRoll = 0.0f;
+  float newPitch = 0.0f;
+  Quaternion newRotation;
+
+  Radian angle(Quaternion::AngleBetween(newRotation, mRotation));
+  // If the change in value is more than the threshold then emit tilted signal.
+  if( angle > mRotationThreshold )
+  {
+    mRoll = newRoll;
+    mPitch = newPitch;
+    mRotation = newRotation;
+
+    if ( !mTiltedSignal.Empty() )
+    {
+      Dali::TiltSensor handle( this );
+      mTiltedSignal.Emit( handle );
+    }
+  }
+
+  return true;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/sensor/ubuntu/tilt-sensor-impl-ubuntu.h b/dali/internal/sensor/ubuntu/tilt-sensor-impl-ubuntu.h
new file mode 100644 (file)
index 0000000..f516b29
--- /dev/null
@@ -0,0 +1,169 @@
+#ifndef DALI_SENSOR_UBUNTU_TILT_SENSOR_IMPL_UBUNTU_H
+#define DALI_SENSOR_UBUNTU_TILT_SENSOR_IMPL_UBUNTU_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 <deque>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/sensor/common/tilt-sensor-impl.h>
+#include <dali/devel-api/adaptor-framework/tilt-sensor.h>
+#include <dali/public-api/adaptor-framework/timer.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * TiltSensor provides pitch & roll values when the device is tilted.
+ */
+class TiltSensorUbuntu : public Dali::Internal::Adaptor::TiltSensor
+{
+public:
+
+  typedef Dali::TiltSensor::TiltedSignalType TiltedSignalType;
+
+  /**
+ * Public constructor
+ * @return New instance of TiltSensorUbuntu
+ */
+  static TiltSensorUbuntu* New();
+
+  /**
+   * @copydoc Dali::TiltSensor::Start()
+   */
+  bool Start() override;
+
+  /**
+   * @copydoc Dali::TiltSensor::Stop()
+   */
+  void Stop() override;
+
+  /**
+   * @copydoc Dali::TiltSensor::IsStarted()
+   */
+  bool IsStarted() const override;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetRoll()
+   */
+  float GetRoll() const override;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetPitch()
+   */
+  float GetPitch() const override;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetRotation()
+   */
+  Quaternion GetRotation() const override;
+
+  /**
+   * @copydoc Dali::TiltSensor::TiltedSignal()
+   */
+  TiltedSignalType& TiltedSignal() override;
+
+  /**
+   * @copydoc Dali::TiltSensor::SetUpdateFrequency()
+   */
+  void SetUpdateFrequency( float frequencyHertz ) override;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetUpdateFrequency()
+   */
+  float GetUpdateFrequency() const override;
+
+  /**
+   * @copydoc Dali::TiltSensor::SetRotationThreshold()
+   */
+  void SetRotationThreshold(Radian rotationThreshold) override;
+
+  /**
+   * @copydoc Dali::TiltSensor::GetRotationThreshold()
+   */
+  Radian GetRotationThreshold() const override;
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+private:
+
+  /**
+ * Private constructor; see also TiltSensor::New()
+ */
+  TiltSensorUbuntu();
+
+  /**
+   * Destructor
+   */
+  virtual ~TiltSensorUbuntu() override;
+
+  /**
+   * Timer callback to update the tilt values
+   */
+  bool Update();
+
+  // Undefined
+  TiltSensorUbuntu(const TiltSensorUbuntu&) = delete;
+
+  // Undefined
+  TiltSensorUbuntu& operator=(TiltSensorUbuntu&) = delete;
+
+private:
+
+  float mFrequencyHertz;
+  Dali::Timer mTimer;
+  SlotDelegate< TiltSensorUbuntu > mTimerSlot;
+
+  int mSensorFrameworkHandle;
+
+  float mRoll;
+  float mPitch;
+  Quaternion mRotation;
+
+  Radian mRotationThreshold;
+
+  std::deque<float> mRollValues;
+  std::deque<float> mPitchValues;
+
+  TiltedSignalType mTiltedSignal;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_SENSOR_UBUNTU_TILT_SENSOR_IMPL_UBUNTU_H
diff --git a/dali/internal/styling/common/style-monitor-impl.cpp b/dali/internal/styling/common/style-monitor-impl.cpp
new file mode 100644 (file)
index 0000000..8e93285
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/styling/common/style-monitor-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/file-loader.h>
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_STYLE_MONITOR");
+#endif
+
+/**
+ * Use font client to get the system default font family
+ * @param[in] fontClient handle to font client
+ * @param[out] fontFamily string representing font family
+ */
+void GetSystemDefaultFontFamily( TextAbstraction::FontClient& fontClient, std::string& fontFamily )
+{
+  TextAbstraction::FontDescription defaultFontDescription;
+  if ( fontClient )
+  {
+    fontClient.GetDefaultPlatformFontDescription( defaultFontDescription );
+    fontFamily = defaultFontDescription.family;
+  }
+}
+
+} // unnamed namespace
+
+Dali::StyleMonitor StyleMonitor::Get()
+{
+  Dali::StyleMonitor styleMonitor;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::StyleMonitor ) );
+    if( handle )
+    {
+      // If so, downcast the handle
+      styleMonitor = Dali::StyleMonitor( dynamic_cast< StyleMonitor* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      styleMonitor = Dali::StyleMonitor( new StyleMonitor() );
+      service.Register( typeid( styleMonitor ), styleMonitor );
+    }
+  }
+
+  return styleMonitor;
+}
+
+StyleMonitor::StyleMonitor()
+: mDefaultFontSize(-1)
+{
+  mFontClient = TextAbstraction::FontClient::Get();
+  GetSystemDefaultFontFamily( mFontClient, mDefaultFontFamily );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "StyleMonitor::StyleMonitor::DefaultFontFamily(%s)\n", mDefaultFontFamily.c_str() );
+  mDefaultFontSize = mFontClient.GetDefaultFontSize();
+}
+
+StyleMonitor::~StyleMonitor()
+{
+}
+
+void StyleMonitor::StyleChanged( StyleChange::Type styleChange )
+{
+  switch ( styleChange )
+  {
+    case StyleChange::DEFAULT_FONT_CHANGE:
+    {
+      if ( mFontClient )
+      {
+        mFontClient.ResetSystemDefaults();
+        GetSystemDefaultFontFamily( mFontClient, mDefaultFontFamily );
+      }
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "StyleMonitor::StyleChanged::DefaultFontFamily(%s)\n", mDefaultFontFamily.c_str() );
+      break;
+    }
+
+    case StyleChange::DEFAULT_FONT_SIZE_CHANGE:
+    {
+      mDefaultFontSize = mFontClient.GetDefaultFontSize();
+      break;
+    }
+
+    case StyleChange::THEME_CHANGE:
+    {
+      break;
+    }
+  }
+
+  EmitStyleChangeSignal(styleChange);
+}
+
+std::string StyleMonitor::GetDefaultFontFamily() const
+{
+  return mDefaultFontFamily;
+}
+
+std::string StyleMonitor::GetDefaultFontStyle() const
+{
+  return mDefaultFontStyle;
+}
+
+int StyleMonitor::GetDefaultFontSize() const
+{
+  return mDefaultFontSize;
+}
+
+const std::string& StyleMonitor::GetTheme() const
+{
+  return mUserDefinedThemeFilePath;
+}
+
+void StyleMonitor::SetTheme(const std::string& path)
+{
+  mUserDefinedThemeFilePath = path;
+  EmitStyleChangeSignal( StyleChange::THEME_CHANGE );
+}
+
+bool StyleMonitor::LoadThemeFile( const std::string& filename, std::string& output )
+{
+  bool retval( false );
+
+  std::streampos bufferSize = 0;
+  Dali::Vector<char> fileBuffer;
+  if( Dali::FileLoader::ReadFile( filename, bufferSize, fileBuffer, FileLoader::FileType::BINARY ) )
+  {
+    output.assign( &fileBuffer[0], bufferSize );
+    retval = true;
+  }
+
+  return retval;
+}
+
+Dali::StyleMonitor::StyleChangeSignalType& StyleMonitor::StyleChangeSignal()
+{
+  return mStyleChangeSignal;
+}
+
+void StyleMonitor::EmitStyleChangeSignal( StyleChange::Type styleChange )
+{
+  if( !mStyleChangeSignal.Empty() )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "StyleMonitor::EmitStyleChangeSignal\n" );
+    Dali::StyleMonitor handle( this );
+    mStyleChangeSignal.Emit( handle, styleChange );
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/styling/common/style-monitor-impl.h b/dali/internal/styling/common/style-monitor-impl.h
new file mode 100644 (file)
index 0000000..638863d
--- /dev/null
@@ -0,0 +1,154 @@
+#ifndef DALI_INTERNAL_STYLE_MONITOR_H
+#define DALI_INTERNAL_STYLE_MONITOR_H
+
+/*
+ * Copyright (c) 2019 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/object/ref-object.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/style-monitor.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * This holds the platform's style information.
+ * It provides a signal when any aspect of the default style changes on the device.
+ */
+class StyleMonitor : public BaseObject
+{
+public:
+
+  // Creation & Destruction
+
+  /**
+   * Constructor.
+   */
+  StyleMonitor();
+
+  /**
+   * Retrieve the initialized instance of the StyleMonitor.
+   * @return Handle to StyleMonitor.
+   */
+  static Dali::StyleMonitor Get();
+
+  // Style Change Notifications
+
+  /**
+   * Informs the Style Monitor that the style has changed.
+   * @param[in]  styleChange  The details of the change.
+   */
+  void StyleChanged( StyleChange::Type styleChange );
+
+  // Style Information
+
+  /**
+   * @copydoc Dali::StyleMonitor::GetDefaultFontFamily() const
+   */
+  std::string GetDefaultFontFamily() const;
+
+  /**
+   * @copydoc Dali::StyleMonitor::GetDefaultFontStyle() const
+   */
+  std::string GetDefaultFontStyle() const;
+
+  /**
+   * @copydoc Dali::StyleMonitor::GetDefaultFontSize() const
+   */
+  int GetDefaultFontSize() const;
+
+  /**
+   * @copydoc Dali::StyleMonitor::GetTheme() const
+   */
+  const std::string& GetTheme() const;
+
+  /**
+   * @copydoc Dali::StyleMonitor::SetTheme()
+   */
+  void SetTheme(const std::string& themeFilePath);
+
+  /**
+   * @copydoc Dali::StyleMonitor::LoadThemeFile()
+   */
+  bool LoadThemeFile( const std::string& filename, std::string& output );
+
+  // Signals
+
+  /**
+   * @copydoc Dali::StyleMonitor::StyleChangeSignal()
+   */
+  Dali::StyleMonitor::StyleChangeSignalType& StyleChangeSignal();
+
+protected:
+
+  /**
+   * Virtual Destructor.
+   */
+  virtual ~StyleMonitor();
+
+private:
+
+  /**
+   * Emit the style change signal.
+   * @param[in]  styleChange  The details of the style change
+   */
+  inline void EmitStyleChangeSignal( StyleChange::Type styleChange );
+
+private:
+
+  Dali::StyleMonitor::StyleChangeSignalType mStyleChangeSignal; ///< Emitted when the style changes
+
+  TextAbstraction::FontClient mFontClient;
+  std::string mDefaultFontFamily;        ///< The system default font family
+  std::string mDefaultFontStyle;         ///< The default font style
+  std::string mUserDefinedThemeFilePath; ///< String containing the user defined theme file path
+  int mDefaultFontSize;                  ///< The default accessibility font size e.g. 0 is smallest
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Additional Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::StyleMonitor& GetImplementation(Dali::StyleMonitor& monitor)
+{
+  DALI_ASSERT_ALWAYS(monitor && "Monitor handle is empty");
+  BaseObject& handle = monitor.GetBaseObject();
+  return static_cast<Internal::Adaptor::StyleMonitor&>(handle);
+}
+
+inline const Internal::Adaptor::StyleMonitor& GetImplementation(const Dali::StyleMonitor& monitor)
+{
+  DALI_ASSERT_ALWAYS(monitor && "Monitor handle is empty");
+  const BaseObject& handle = monitor.GetBaseObject();
+  return static_cast<const Internal::Adaptor::StyleMonitor&>(handle);
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_STYLE_MONITOR_H
diff --git a/dali/internal/styling/file.list b/dali/internal/styling/file.list
new file mode 100644 (file)
index 0000000..6ce4b3b
--- /dev/null
@@ -0,0 +1,6 @@
+
+# module: styling, backend: common
+SET( adaptor_styling_common_src_files 
+    ${adaptor_styling_dir}/common/style-monitor-impl.cpp
+)
+
diff --git a/dali/internal/system/android/callback-manager-android.cpp b/dali/internal/system/android/callback-manager-android.cpp
new file mode 100644 (file)
index 0000000..7cb1952
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/android/callback-manager-android.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/adaptor-framework/android/android-framework.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/framework.h>
+#include <dali/internal/adaptor/android/android-framework-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Structure contains the callback function and control options
+ */
+struct CallbackData
+{
+
+  /**
+   * Constructor
+   */
+  CallbackData( CallbackBase* callback, bool hasReturnValue )
+  : mIdleId( 0 ),
+    mCallback( callback ),
+    mRemoveFromContainerFunction( NULL ),
+    mHasReturnValue( hasReturnValue )
+  {
+  }
+  /**
+   * Destructor
+   */
+  ~CallbackData()
+  {
+    delete mCallback;
+    delete mRemoveFromContainerFunction;
+  }
+
+  unsigned int                    mIdleId;
+  CallbackBase*                   mCallback;       ///< call back
+  CallbackBase*                   mRemoveFromContainerFunction; ///< Called to remove the callbackdata from the callback container
+  bool                            mHasReturnValue; ///< true if the callback function has a return value.
+};
+
+namespace
+{
+
+/**
+ * Called from the main thread while idle.
+ */
+bool IdleCallback(void *data)
+{
+  bool ret = false;
+  CallbackData *callbackData = static_cast< CallbackData * >( data );
+
+  if( callbackData->mHasReturnValue )
+  {
+    // run the function
+    bool retValue = CallbackBase::ExecuteReturn< bool >( *callbackData->mCallback );
+    if( retValue )
+    {
+      // keep the callback
+      ret = true;
+    }
+    else
+    {
+      // remove callback data from the container
+      CallbackBase::Execute( *callbackData->mRemoveFromContainerFunction, callbackData );
+
+      // delete our data
+      delete callbackData;
+    }
+  }
+  else
+  {
+    // remove callback data from the container
+    CallbackBase::Execute( *callbackData->mRemoveFromContainerFunction, callbackData );
+
+    // run the function
+    CallbackBase::Execute( *callbackData->mCallback );
+
+    // delete our data
+    delete callbackData;
+  }
+
+  return ret;
+}
+
+} // unnamed namespace
+
+AndroidCallbackManager::AndroidCallbackManager()
+  : mRunning( false )
+{
+}
+
+
+void AndroidCallbackManager::Start()
+{
+  DALI_ASSERT_DEBUG( mRunning == false );
+
+  mRunning = true;
+}
+
+void AndroidCallbackManager::Stop()
+{
+  // make sure we're not called twice
+  DALI_ASSERT_DEBUG( mRunning == true );
+
+  RemoveAllCallbacks();
+
+  mRunning = false;
+
+}
+
+bool AndroidCallbackManager::AddIdleCallback( CallbackBase* callback, bool hasReturnValue )
+{
+  if( !mRunning )
+  {
+    return false;
+  }
+
+  CallbackData* callbackData = new CallbackData( callback, hasReturnValue );
+  callbackData->mRemoveFromContainerFunction = MakeCallback( this, &AndroidCallbackManager::RemoveCallbackFromContainer );
+  callbackData->mIdleId = AndroidFramework::GetFramework( Dali::Integration::AndroidFramework::Get() ).AddIdle( 0, callbackData, IdleCallback );
+
+  // add the call back to the container
+  mCallbackContainer.push_front( callbackData );
+  return true;
+}
+
+void AndroidCallbackManager::RemoveIdleCallback( CallbackBase* callback )
+{
+  for( CallbackList::iterator it = mCallbackContainer.begin(),
+         endIt = mCallbackContainer.end();
+       it != endIt;
+       ++it )
+  {
+    CallbackData* data = *it;
+
+    if( data->mCallback == callback )
+    {
+      // remove callback data from the container.
+      CallbackBase::Execute( *data->mRemoveFromContainerFunction, data );
+      AndroidFramework::GetFramework( AndroidFramework::Get() ).RemoveIdle( data->mIdleId );
+      return;
+    }
+  }
+}
+
+bool AndroidCallbackManager::ProcessIdle()
+{
+  // @todo To be implemented.
+  return false;
+}
+
+void AndroidCallbackManager::ClearIdleCallbacks()
+{
+  // @todo To be implemented.
+}
+
+bool AndroidCallbackManager::AddIdleEntererCallback( CallbackBase* callback )
+{
+  if( !mRunning )
+  {
+    return false;
+  }
+
+  CallbackData* callbackData = new CallbackData( callback, true );
+
+  callbackData->mRemoveFromContainerFunction = MakeCallback( this, &AndroidCallbackManager::RemoveCallbackFromContainer );
+  callbackData->mIdleId = AndroidFramework::GetFramework( Dali::Integration::AndroidFramework::Get() ).AddIdle( 0, callbackData, IdleCallback );
+
+  // add the call back to the container
+  mCallbackContainer.push_front( callbackData );
+  return true;
+}
+
+void AndroidCallbackManager::RemoveIdleEntererCallback( CallbackBase* callback )
+{
+  for( CallbackList::iterator it = mCallbackContainer.begin(),
+         endIt = mCallbackContainer.end();
+       it != endIt;
+       ++it )
+  {
+    CallbackData* data = *it;
+
+    if( data->mCallback == callback )
+    {
+      // remove callback data from the container.
+      CallbackBase::Execute( *data->mRemoveFromContainerFunction, data );
+      AndroidFramework::GetFramework( Dali::Integration::AndroidFramework::Get() ).RemoveIdle( data->mIdleId );
+      return;
+    }
+  }
+}
+
+void AndroidCallbackManager::RemoveCallbackFromContainer( CallbackData *callbackData )
+{
+  mCallbackContainer.remove( callbackData );
+}
+
+void AndroidCallbackManager::RemoveAllCallbacks()
+{
+  // always called from main thread
+  for( CallbackList::iterator  iter =  mCallbackContainer.begin(); iter != mCallbackContainer.end(); ++iter )
+  {
+    CallbackData* data = (*iter);
+    AndroidFramework::GetFramework( Dali::Integration::AndroidFramework::Get() ).RemoveIdle( data->mIdleId );
+    delete data;
+  }
+  mCallbackContainer.clear();
+}
+
+// Creates a concrete interface for CallbackManager
+CallbackManager* CallbackManager::New()
+{
+  return new AndroidCallbackManager;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+
diff --git a/dali/internal/system/android/callback-manager-android.h b/dali/internal/system/android/callback-manager-android.h
new file mode 100644 (file)
index 0000000..71017c5
--- /dev/null
@@ -0,0 +1,133 @@
+#ifndef __DALI_ANDROID_CALLBACK_MANAGER_H__
+#define __DALI_ANDROID_CALLBACK_MANAGER_H__
+
+/*
+ * Copyright (c) 2019 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 <list>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/callback-manager.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+struct CallbackData;
+
+/**
+ * Ecore interface to install call backs in the applications main loop.
+ */
+class AndroidCallbackManager : public CallbackManager
+{
+
+public:
+
+    /**
+     * @brief constructor
+     */
+    AndroidCallbackManager();
+
+    /**
+     * @brief destructor
+     */
+    ~AndroidCallbackManager() = default;
+
+    /**
+     * @copydoc CallbackManager::AddIdleCallback()
+     */
+    virtual bool AddIdleCallback( CallbackBase* callback, bool hasReturnValue );
+
+    /**
+     * @copydoc CallbackManager::RemoveIdleCallback()
+     */
+    virtual void RemoveIdleCallback( CallbackBase* callback );
+
+    /**
+     * @copydoc CallbackManager::ProcessIdle()
+     */
+    virtual bool ProcessIdle();
+
+    /**
+     * @copydoc CallbackManager::ProcessIdle()
+     */
+    virtual void ClearIdleCallbacks();
+
+    /**
+     * @copydoc CallbackManager::AddIdleEntererCallback()
+     */
+    virtual bool AddIdleEntererCallback( CallbackBase* callback );
+
+    /**
+     * @copydoc CallbackManager::RemoveIdleEntererCallback()
+     */
+    virtual void RemoveIdleEntererCallback( CallbackBase* callback );
+
+    /**
+     * @copydoc CallbackManager::Start()
+     */
+    virtual void Start();
+
+    /**
+     * @copydoc CallbackManager::Stop()
+     */
+    virtual void Stop();
+
+private:
+
+    /**
+     * @brief Remove all idle call backs that are pending
+     * Called by Stop()
+     * Always called from the main thread
+     */
+    void RemoveAllCallbacks();
+
+    /**
+     * @brief Removes a single call back from the container
+     * Always called from main thread
+     * @param callbackData callback data
+     */
+    void RemoveCallbackFromContainer(CallbackData *callbackData);
+
+    /**
+     * @brief Remove a standard call back from ecore
+     * Always called from main thread
+     * @param callbackData callback data
+     */
+    void RemoveStandardCallback(CallbackData *callbackData);
+
+
+    typedef std::list<CallbackData *>  CallbackList;
+
+    bool                           mRunning;            ///< flag is set to true if when running
+    CallbackList                   mCallbackContainer;  ///< container of live idle callbacks
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // __DALI_ANDROID_CALLBACK_MANAGER_H__
diff --git a/dali/internal/system/android/file-descriptor-monitor-android.cpp b/dali/internal/system/android/file-descriptor-monitor-android.cpp
new file mode 100644 (file)
index 0000000..9bbfb01
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * 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 <dali/internal/system/common/file-descriptor-monitor.h>
+
+// EXTERNAL INCLUDES
+#include <looper.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Using Impl to hide away Android specific members
+ */
+struct FileDescriptorMonitor::Impl
+{
+  // Construction
+  Impl( int fileDescriptor, CallbackBase* callback, int eventBitmask )
+  : mCallback( callback ),
+    mFileDescriptor( fileDescriptor ),
+    mEventsToMonitor( eventBitmask )
+  {
+  }
+
+  ~Impl()
+  {
+    delete mCallback;
+  }
+
+  // Data
+  CallbackBase* mCallback;
+  int mFileDescriptor;
+  int mEventsToMonitor;
+
+  // Static Methods
+
+  /**
+   * Called when the file descriptor receives an event.
+   */
+  static int EventDispatch( int fd, int events, void* data )
+  {
+    Impl* impl = reinterpret_cast<Impl*>(data);
+
+    // if we want read events, check to see if a read event is available
+    int type = FileDescriptorMonitor::FD_NO_EVENT;
+
+    if( impl->mEventsToMonitor & ALOOPER_EVENT_INPUT )
+    {
+
+      type = FileDescriptorMonitor::FD_READABLE;
+
+    }
+    // check if we want write events
+    if( impl->mEventsToMonitor & ALOOPER_EVENT_OUTPUT )
+    {
+
+      type |= FileDescriptorMonitor::FD_WRITABLE;
+
+    }
+
+    // if there is an event, execute the callback
+    if( type != FileDescriptorMonitor::FD_NO_EVENT )
+    {
+      CallbackBase::Execute( *impl->mCallback, static_cast< FileDescriptorMonitor::EventType >( type ) );
+    }
+
+    return 1; // Continue receiving callbacks
+  }
+};
+
+FileDescriptorMonitor::FileDescriptorMonitor( int fileDescriptor, CallbackBase* callback, int eventBitmask )
+{
+  mImpl = new Impl(fileDescriptor, callback, eventBitmask);
+
+  if (fileDescriptor >= 0)
+  {
+    int events = 0;
+    if( eventBitmask & FD_READABLE)
+    {
+      events = ALOOPER_EVENT_INPUT;
+    }
+    if( eventBitmask & FD_WRITABLE)
+    {
+      events |= ALOOPER_EVENT_OUTPUT;
+    }
+
+    mImpl->mEventsToMonitor = events;
+
+    ALooper* looper = ALooper_forThread();
+    if( looper )
+    {
+      ALooper_addFd( looper, fileDescriptor, ALOOPER_POLL_CALLBACK, events, &Impl::EventDispatch, mImpl );
+    }
+  }
+}
+
+FileDescriptorMonitor::~FileDescriptorMonitor()
+{
+  if( mImpl->mFileDescriptor )
+  {
+    ALooper* looper = ALooper_forThread();
+    if( looper )
+    {
+      ALooper_removeFd( looper, mImpl->mFileDescriptor );
+    }
+  }
+
+  delete mImpl;
+  mImpl = NULL;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
diff --git a/dali/internal/system/android/logging-android.cpp b/dali/internal/system/android/logging-android.cpp
new file mode 100644 (file)
index 0000000..0518c51
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// FUNCTION HEADER
+#include <dali/internal/system/common/logging.h>
+
+// EXTERNAL INCLUDES
+#include <log.h>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+void LogMessage(Dali::Integration::Log::DebugPriority level, std::string& message)
+{
+  const char* DALI_TAG = "DALI";
+
+  switch(level)
+  {
+    case Dali::Integration::Log::DebugInfo:
+      __android_log_print(ANDROID_LOG_INFO, DALI_TAG, "%s", message.c_str());
+      break;
+    case Dali::Integration::Log::DebugWarning:
+      __android_log_print(ANDROID_LOG_WARN, DALI_TAG, "%s", message.c_str());
+      break;
+    case Dali::Integration::Log::DebugError:
+      __android_log_print(ANDROID_LOG_DEBUG, DALI_TAG, "%s", message.c_str());
+      break;
+    default:
+      __android_log_print(ANDROID_LOG_DEBUG, DALI_TAG, "%s", message.c_str());
+      break;
+  }
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/dali/internal/system/android/shared-file-operations-android.cpp b/dali/internal/system/android/shared-file-operations-android.cpp
new file mode 100644 (file)
index 0000000..763b7bb
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/shared-file.h>
+
+// EXTERNAL INCLUDES
+#include <fcntl.h>
+#include <bits/ioctl.h>
+#include <include/linux/ashmem.h>
+#include <sys/mman.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+int SharedFile::Open( const char* filename, int size, int oflag, mode_t mode )
+{
+  int fileDescriptor = open( ASHMEM_NAME_DEF, oflag );
+  if( mFileDescriptor >= 0 )
+  {
+    ioctl( mFileDescriptor, ASHMEM_SET_NAME, filename );
+    ioctl( mFileDescriptor, ASHMEM_SET_SIZE, size );
+  }
+
+  return mFileDescriptor;
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/dali/internal/system/android/system-settings-android.cpp b/dali/internal/system/android/system-settings-android.cpp
new file mode 100644 (file)
index 0000000..3eb6045
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019 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
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/system-settings.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+int GetElmAccessActionOver()
+{
+  return 0;
+}
+
+int GetLongPressTime( int defaultTime )
+{
+  return defaultTime;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/android/timer-impl-android.cpp b/dali/internal/system/android/timer-impl-android.cpp
new file mode 100644 (file)
index 0000000..62f06d3
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/timer-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/android/android-framework.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/adaptor/common/framework.h>
+#include <dali/internal/adaptor/android/android-framework-impl.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+// Copied from x server
+static unsigned int GetCurrentMilliSeconds()
+{
+  struct timeval tv;
+
+  struct timespec tp;
+  static clockid_t clockid;
+
+  if (!clockid)
+  {
+#ifdef CLOCK_MONOTONIC_COARSE
+    if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
+      (tp.tv_nsec / 1000) <= 1000 && clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
+    {
+      clockid = CLOCK_MONOTONIC_COARSE;
+    }
+    else
+#endif
+    if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
+    {
+      clockid = CLOCK_MONOTONIC;
+    }
+    else
+    {
+      clockid = ~0L;
+    }
+  }
+  if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
+  {
+    return (tp.tv_sec * 1000) + (tp.tv_nsec / 1000000L);
+  }
+
+  gettimeofday(&tv, NULL);
+  return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+}
+
+}
+
+struct Timer::Impl
+{
+  Impl( unsigned int milliSec )
+  : mInterval( milliSec ),
+    mStartTimestamp( 0 ),
+    mPauseTimestamp( 0 ),
+    mRunning( false ),
+    mId( 0 )
+  {
+  }
+
+  unsigned int mInterval;
+  unsigned int mStartTimestamp;
+  unsigned int mPauseTimestamp;
+  bool mRunning;
+  unsigned int mId;
+};
+
+TimerPtr Timer::New( unsigned int milliSec )
+{
+  TimerPtr timer( new Timer( milliSec ) );
+  return timer;
+}
+
+Timer::Timer( unsigned int milliSec )
+: mImpl( new Impl( milliSec ) )
+{
+}
+
+Timer::~Timer()
+{
+  Stop();
+  delete mImpl;
+}
+
+bool TimerCallback( void *data )
+{
+  Timer* timer = static_cast<Timer*>( data );
+  if( timer->IsRunning() )
+  {
+    return timer->Tick();
+  }
+
+  return false;
+}
+
+void Timer::Start()
+{
+  // Timer should be used in the event thread
+  DALI_ASSERT_DEBUG( Adaptor::IsAvailable() );
+
+  if( mImpl->mRunning )
+  {
+    Stop();
+  }
+
+  mImpl->mId = AndroidFramework::GetFramework( Dali::Integration::AndroidFramework::Get() ).AddIdle( mImpl->mInterval, this, TimerCallback );
+  mImpl->mRunning = true;
+  mImpl->mStartTimestamp = GetCurrentMilliSeconds();
+}
+
+void Timer::Stop()
+{
+  // Timer should be used in the event thread
+  DALI_ASSERT_DEBUG( Adaptor::IsAvailable() );
+
+  if( mImpl->mId != 0 )
+  {
+    AndroidFramework::GetFramework( Dali::Integration::AndroidFramework::Get() ).RemoveIdle( mImpl->mId );
+    mImpl->mStartTimestamp = 0;
+    mImpl->mPauseTimestamp = 0;
+  }
+
+  ResetTimerData();
+}
+
+void Timer::Pause()
+{
+  // Timer should be used in the event thread
+  DALI_ASSERT_DEBUG( Adaptor::IsAvailable() );
+
+  if( mImpl->mRunning )
+  {
+    mImpl->mPauseTimestamp = GetCurrentMilliSeconds();
+    AndroidFramework::GetFramework( Dali::Integration::AndroidFramework::Get() ).RemoveIdle( mImpl->mId );
+    mImpl->mId = 0;
+  }
+}
+
+void Timer::Resume()
+{
+  // Timer should be used in the event thread
+  DALI_ASSERT_DEBUG( Adaptor::IsAvailable() );
+
+  if( mImpl->mRunning && mImpl->mId == 0 )
+  {
+    unsigned int newInterval = 0;
+    unsigned int runningTime = mImpl->mPauseTimestamp - mImpl->mStartTimestamp;
+    if( mImpl->mInterval > runningTime )
+    {
+      newInterval = mImpl->mInterval - runningTime;
+    }
+
+    mImpl->mStartTimestamp = GetCurrentMilliSeconds() - runningTime;
+    mImpl->mPauseTimestamp = 0;
+    mImpl->mId = AndroidFramework::GetFramework( Dali::Integration::AndroidFramework::Get() ).AddIdle( newInterval, this, TimerCallback );
+  }
+}
+
+void Timer::SetInterval( unsigned int interval, bool restart )
+{
+  // stop existing timer
+  Stop();
+  mImpl->mInterval = interval;
+
+  if( restart )
+  {
+    // start new tick
+    Start();
+  }
+}
+
+unsigned int Timer::GetInterval() const
+{
+  return mImpl->mInterval;
+}
+
+bool Timer::Tick()
+{
+  // Guard against destruction during signal emission
+  Dali::Timer handle( this );
+
+  bool retVal( false );
+
+  // Override with new signal if used
+  if( !mTickSignal.Empty() )
+  {
+    retVal = mTickSignal.Emit();
+
+    // Timer stops if return value is false
+    if (retVal == false)
+    {
+      Stop();
+    }
+    else
+    {
+      retVal = true;   // continue emission
+    }
+  }
+  else // no callbacks registered
+  {
+    // periodic timer is started but nobody listens, continue
+    retVal = true;
+  }
+
+  return retVal;
+}
+
+Dali::Timer::TimerSignalType& Timer::TickSignal()
+{
+  return mTickSignal;
+}
+
+void Timer::ResetTimerData()
+{
+  mImpl->mRunning = false;
+  mImpl->mId = 0;
+}
+
+bool Timer::IsRunning() const
+{
+  return mImpl->mRunning;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/android/widget-application-impl-android.cpp b/dali/internal/system/android/widget-application-impl-android.cpp
new file mode 100644 (file)
index 0000000..be5da40
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/android/widget-application-impl-android.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+WidgetApplicationPtr WidgetApplicationAndroid::New(
+  int* argc,
+  char **argv[],
+  const std::string& stylesheet)
+{
+  return new WidgetApplicationAndroid(argc, argv, stylesheet );
+}
+
+WidgetApplicationAndroid::WidgetApplicationAndroid( int* argc, char** argv[], const std::string& stylesheet )
+: WidgetApplication(argc, argv, stylesheet)
+{
+  DALI_LOG_ERROR("WidgetApplication is not implemented in Android profile.\n");
+}
+
+WidgetApplicationAndroid::~WidgetApplicationAndroid() = default;
+
+void WidgetApplicationAndroid::RegisterWidgetCreatingFunction( const std::string& widgetName, Dali::WidgetApplication::CreateWidgetFunction createFunction )
+{
+}
+
+// factory function, must be implemented
+namespace WidgetApplicationFactory
+{
+/**
+ * Create a new widget 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
+ */
+WidgetApplicationPtr Create( int* argc, char **argv[], const std::string& stylesheet )
+{
+  return WidgetApplicationAndroid::New( argc, argv, stylesheet );
+}
+
+} // namespace Factory
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/android/widget-application-impl-android.h b/dali/internal/system/android/widget-application-impl-android.h
new file mode 100644 (file)
index 0000000..ffb4e87
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef DALI_INTERNAL_WIDGET_APPLICATION_IMPL_ANDROID_H
+#define DALI_INTERNAL_WIDGET_APPLICATION_IMPL_ANDROID_H
+
+/*
+ * Copyright (c) 2019 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 <dali/internal/adaptor/common/application-impl.h>
+#include <dali/internal/system/common/widget-application-impl.h>
+#include <dali/public-api/adaptor-framework/widget-application.h>
+
+namespace Dali
+{
+class Widget;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Implementation of the WidgetApplicationAndroid class.
+ */
+class WidgetApplicationAndroid : public WidgetApplication
+{
+public:
+
+  typedef std::pair<const std::string, Dali::WidgetApplication::CreateWidgetFunction >  CreateWidgetFunctionPair;
+  typedef std::vector< CreateWidgetFunctionPair >   CreateWidgetFunctionContainer;
+
+  /**
+   * Create a new widget 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
+   */
+  static WidgetApplicationPtr New( int* argc, char **argv[], const std::string& stylesheet );
+
+public:
+
+  /**
+   * @copydoc Dali::WidgetApplication::RegisterWidgetCreator()
+   */
+  void RegisterWidgetCreatingFunction( const std::string& widgetName, Dali::WidgetApplication::CreateWidgetFunction createFunction ) override;
+
+protected:
+
+  /**
+   * 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
+   */
+  WidgetApplicationAndroid( int* argc, char **argv[], const std::string& stylesheet );
+
+  /**
+   * Destructor
+   */
+  virtual ~WidgetApplicationAndroid();
+
+  WidgetApplicationAndroid(const Application&) = delete;
+  WidgetApplicationAndroid& operator=(Application&) = delete;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WIDGET_APPLICATION_IMPL_ANDROID_H
diff --git a/dali/internal/system/common/abort-handler.cpp b/dali/internal/system/common/abort-handler.cpp
new file mode 100644 (file)
index 0000000..696570e
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/abort-handler.h>
+
+// EXTERNAL INCLUDES
+#include <cstring>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+AbortHandler* AbortHandler::gInstance(NULL);
+
+AbortHandler::AbortHandler( CallbackBase* callback )
+: mSignalMask( 0 ),
+  mCallback( callback )
+{
+  DALI_ASSERT_ALWAYS( gInstance == NULL && "Only one instance of abort handler allowed" );
+  gInstance = this;
+
+  memset( mSignalOldHandlers, 0, sizeof(SignalHandlerFuncPtr) * (_NSIG-1));
+}
+
+AbortHandler::~AbortHandler()
+{
+  delete mCallback;
+
+  int signum;
+  for ( signum = 1; signum < _NSIG; signum++ )
+  {
+    if ( mSignalMask & (1ULL << (signum-1) ) )
+    {
+      // set signals back to default handling
+      signal( signum, mSignalOldHandlers[signum-1] );
+    }
+  }
+  gInstance = NULL;
+}
+
+bool AbortHandler::AbortOnSignal( int signum )
+{
+  bool status = false;
+
+  if ( signum < _NSIG )
+  {
+    SignalHandlerFuncPtr signalHandlerPrevious = signal( signum, &AbortHandler::SignalHandler );
+
+// SIG_ERR is a macro with C cast
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+  if ( SIG_ERR != signalHandlerPrevious )
+    {
+      mSignalOldHandlers[signum-1] = signalHandlerPrevious;
+      mSignalMask |= ( 1ULL << (signum-1) );
+      status = true;
+    }
+  }
+#pragma GCC diagnostic pop
+  return status;
+}
+
+void AbortHandler::SignalHandler( int signum )
+{
+  if( gInstance )
+  {
+    if( gInstance->mCallback )
+    {
+      CallbackBase::Execute( *gInstance->mCallback );
+    }
+  }
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/dali/internal/system/common/abort-handler.h b/dali/internal/system/common/abort-handler.h
new file mode 100755 (executable)
index 0000000..2910693
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef DALI_INTERNAL_ADAPTOR_ABORT_HANDLER_H
+#define DALI_INTERNAL_ADAPTOR_ABORT_HANDLER_H
+
+/*
+ * Copyright (c) 2019 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 <signal.h>
+#include <dali/public-api/signals/callback.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/application.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * Class to listen to system signals and trigger an abort callback
+ * when they occur.
+ *
+ * This class maintains a process wide singleton, as the signal(2) system
+ * call is process specific, not thread specific.
+ *
+ * Currently, this precludes having multiple DALi instances in the same process.
+ */
+class AbortHandler
+{
+public:
+  /**
+   * Constructor
+   * @param[in] callback The function to call when abort signals occur
+   * @note The ownership of callback is passed onto this class.
+   */
+  AbortHandler( CallbackBase* callback );
+
+  /**
+   * Destructor
+   */
+  ~AbortHandler();
+
+  /**
+   * Add a signal you want to be handled by this abort handler.
+   * @param[in] signum The signal number (from signum.h)
+   * @return true if the signal handler was installed ok
+   */
+  bool AbortOnSignal( int signum );
+
+private:
+  /**
+   * Signal handler - Called when signal is received.
+   * Stops the application.
+   */
+  static void SignalHandler( int signum );
+
+  /**
+   * Default constructor - undefined
+   */
+  AbortHandler();
+
+  /**
+   * Copy constructor - undefined
+   */
+  AbortHandler(const AbortHandler& rhs);
+
+  /**
+   * Assignment operator - undefined
+   */
+  AbortHandler& operator=(const AbortHandler& rhs);
+
+private:
+  using SignalHandlerFuncPtr = void( * )( int );
+
+  // _NSIG comes from the signal.h linux system header, defining the number of signals.
+  SignalHandlerFuncPtr        mSignalOldHandlers[_NSIG-1];
+  unsigned long long          mSignalMask;
+
+  CallbackBase*               mCallback;
+
+  static AbortHandler*        gInstance;
+};
+
+} // Namespace Adaptor
+} // Namespace Internal
+} // Namespace Dali
+
+#endif //  DALI_INTERNAL_ADAPTOR_ABORT_HANDLER_H
diff --git a/dali/internal/system/common/atomics.h b/dali/internal/system/common/atomics.h
new file mode 100644 (file)
index 0000000..9462c8d
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef _DALI_INTERNAL_PLATFORM_ATOMICS_H_
+#define _DALI_INTERNAL_PLATFORM_ATOMICS_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 <cstddef>
+
+/*
+ * atomics.h
+ *
+ * Interface for atomic memory operations.
+ * There may be platform-specific versions of this file in other directories.
+ */
+
+namespace Dali
+{
+namespace Internal
+{
+
+/**
+ * @brief Atomic write to an aligned memory location in cacheable memory.
+ *
+ * For common platforms with coherent caches such as ARM mpcore and Intel CPUs,
+ * a cacheline can be in a writeable state in the L1 cache of exactly one core
+ * at a time. Therefore, a write to a location that does not require a read /
+ * modify / write cycle or cross a cacheline boundary is  automatically
+ * atomic.
+ *
+ * @param address A pointer to a location in a cacheable memory region that is
+ *        aligned to a 4 byte boundary.
+ * @param value A value to assign to the memory location in address.
+ */
+inline void AtomicWriteToCacheableAlignedAddress( volatile uint32_t * const address, const uint32_t value )
+{
+  DALI_ASSERT_DEBUG( ptrdiff_t(address) % 4 == 0 && "Address must be 32 bit aligned" );
+  *address = value;
+}
+
+/**
+ * @brief Atomic read from an aligned memory location in cacheable memory.
+ *
+ * For common platforms with coherent caches such as ARM mpcore and Intel CPUs,
+ * a cacheline can be in a writeable state in the L1 cache of exactly one core
+ * at a time. Therefore, a read a location that does not cross a cacheline
+ * boundary is automatically atomic.
+ *
+ * @param  address A pointer to a location in a cacheable memory region that is
+ *         aligned to a 4 byte boundary.
+ * @return The value stored at the memory location in address.
+ */
+inline uint32_t AtomicReadFromCacheableAlignedAddress( const volatile uint32_t * const address )
+{
+  DALI_ASSERT_DEBUG( ptrdiff_t(address) % 4 == 0 && "Address must be 32 bit aligned" );
+  return *address;
+}
+
+} /* namespace Internal */
+} /* namespace Dali */
+
+#endif /* _DALI_INTERNAL_PLATFORM_ATOMICS_H_ */
diff --git a/dali/internal/system/common/callback-manager.h b/dali/internal/system/common/callback-manager.h
new file mode 100644 (file)
index 0000000..a368d49
--- /dev/null
@@ -0,0 +1,159 @@
+#ifndef DALI_INTERNAL_CALLBACK_MANAGER_H
+#define DALI_INTERNAL_CALLBACK_MANAGER_H
+
+/*
+ * Copyright (c) 2019 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/signals/callback.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Abstract interface to install call backs in to an applications main loop.
+ */
+class CallbackManager
+{
+
+public:
+
+    /**
+     * Create a new call back interface
+     */
+    static CallbackManager* New();
+
+    /**
+     * Virtual destructor
+     */
+    virtual ~CallbackManager() {}
+
+    /**
+     * @brief Adds a @p callback to be run on idle.
+     * @note Must be called from the main thread only.
+     *
+     * Callbacks of the following types may be used:
+     * @code
+     *   void MyFunction();
+     * @endcode
+     * This callback will be deleted once it is called.
+     *
+     * @code
+     *   bool MyFunction();
+     * @endcode
+     * This callback will be called repeatedly as long as it returns true. A return of 0 deletes this callback.
+     *
+     * @param[in] callback custom callback function.
+     * @param[in] hasReturnValue Sould be set to true if the callback function has a return value.
+     *
+     * @return true on success
+     */
+    virtual bool AddIdleCallback( CallbackBase* callback, bool hasReturnValue ) = 0;
+
+    /**
+     * @brief Removes a previously added @p callback.
+     * @note Must be called from main thread only.
+     *
+     * Does nothing if the @p callback doesn't exist.
+     *
+     * @param[in] callback The callback to be removed.
+     */
+    virtual void RemoveIdleCallback( CallbackBase* callback ) = 0;
+
+    /**
+     * @brief Processes the idle callbacks.
+     *
+     * @return whether a DALi callback has been processed.
+     */
+    virtual bool ProcessIdle() = 0;
+
+    /**
+     * @brief Clears the container of callbacks.
+     */
+    virtual void ClearIdleCallbacks() = 0;
+
+    /**
+     * @brief Adds a @p callback to be run when entering an idle state.
+     * @note Must be called from the main thread only.
+     *
+     * A callback of the following type should be used:
+     * @code
+     *   bool MyFunction();
+     * @endcode
+     * This callback will be called repeatedly as long as it returns true. A return of 0 deletes this callback.
+     *
+     * @param[in] callback custom callback function.
+     *
+     * @return true on success
+     */
+    virtual bool AddIdleEntererCallback( CallbackBase* callback ) = 0;
+
+    /**
+     * @brief Removes a previously added the idle enterer callback.
+     * @note Must be called from main thread only.
+     *
+     * Does nothing if the @p callback doesn't exist.
+     *
+     * @param[in] callback The callback to be removed.
+     */
+    virtual void RemoveIdleEntererCallback( CallbackBase* callback ) = 0;
+
+    /**
+     * Starts the callback manager.
+     */
+    virtual void Start() = 0;
+
+    /**
+     * Stop the callback manager and can remove all pending callbacks synchronously.
+     * This call will synchronise with the main loop and not return
+     * until all call backs have been deleted.
+     */
+    virtual void Stop() = 0;
+
+protected:
+
+    /**
+     * constructor
+     */
+    CallbackManager() {}
+
+private:
+
+    // Undefined copy constructor.
+    CallbackManager( const CallbackManager& );
+
+    // Undefined assignment operator.
+    CallbackManager& operator=( const CallbackManager& );
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_CALLBACK_MANAGER_H
diff --git a/dali/internal/system/common/color-controller-impl.cpp b/dali/internal/system/common/color-controller-impl.cpp
new file mode 100644 (file)
index 0000000..c7630b2
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/color-controller-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dlfcn.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/common/singleton-service.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // unnamed namespace
+{
+const char* COLOR_CONTROLLER_PLUGIN_SO( "libdali-color-controller-plugin.so" );
+}
+
+Dali::ColorController ColorController::Get()
+{
+  Dali::ColorController colorController;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::ColorController ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      colorController = Dali::ColorController( dynamic_cast< ColorController* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      colorController = Dali::ColorController( new ColorController( ) );
+      service.Register( typeid( colorController ), colorController );
+    }
+  }
+
+  return colorController;
+}
+
+ColorController::ColorController()
+: mLibHandle( NULL ),
+  mPlugin( NULL ),
+  mCreateColorControllerPtr( NULL )
+{
+  Initialize();
+}
+
+ColorController::~ColorController()
+{
+  if( mPlugin )
+  {
+    delete mPlugin;
+    mPlugin = NULL;
+
+    if( mLibHandle && dlclose( mLibHandle ) )
+    {
+      DALI_LOG_ERROR( "Error closing color controller plugin library: %s\n", dlerror() );
+    }
+  }
+}
+
+void ColorController::Initialize()
+{
+  mLibHandle = dlopen( COLOR_CONTROLLER_PLUGIN_SO, RTLD_LAZY );
+
+  char* error = dlerror();
+  if( mLibHandle == NULL || error != NULL )
+  {
+    DALI_LOG_ERROR( "ColorController::Initialize: dlopen error [%s]\n", error );
+    return;
+  }
+
+  // load plugin
+  mCreateColorControllerPtr = reinterpret_cast< CreateColorControllerFunction >( dlsym( mLibHandle, "CreateColorControllerPlugin" ) );
+
+  error = dlerror();
+  if( mCreateColorControllerPtr == NULL || error != NULL )
+  {
+    DALI_LOG_ERROR( "ColorController::Initialize: Cannot load symbol CreateColorControllerPlugin(): %s\n", error );
+    return;
+  }
+
+  mPlugin = mCreateColorControllerPtr();
+  if( !mPlugin )
+  {
+    DALI_LOG_ERROR("ColorController::Initialize: Plugin creation failed\n");
+    return;
+  }
+}
+
+bool ColorController::RetrieveColor( const std::string& colorCode, Vector4& colorValue )
+{
+  if( mPlugin )
+  {
+    return mPlugin->RetrieveColor( colorCode, colorValue );
+  }
+  return false;
+}
+
+bool ColorController::RetrieveColor( const std::string& colorCode , Vector4& textColor, Vector4& textOutlineColor, Vector4& textShadowColor)
+{
+  if( mPlugin )
+  {
+    return mPlugin->RetrieveColor( colorCode, textColor, textOutlineColor, textShadowColor );
+  }
+  return false;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/common/color-controller-impl.h b/dali/internal/system/common/color-controller-impl.h
new file mode 100644 (file)
index 0000000..58de395
--- /dev/null
@@ -0,0 +1,109 @@
+#ifndef DALI_INTERNAL_COLOR_CONTROLLER_H
+#define DALI_INTERNAL_COLOR_CONTROLLER_H
+
+/*
+ * Copyright (c) 2019 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/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/color-controller.h>
+#include <dali/devel-api/adaptor-framework/color-controller-plugin.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Implementation of ColorController
+ */
+class ColorController : public BaseObject
+{
+public:
+
+  /**
+   * Constructor.
+   */
+  ColorController();
+
+  /**
+   * @copydoc Dali::ColorController::Get()
+   */
+  static Dali::ColorController Get();
+
+  /**
+   * @copydoc Dali::ColorController::RetrieveColor(const std::string&, Vector4&)
+   */
+  bool RetrieveColor( const std::string& colorCode, Vector4& colorValue );
+
+  /**
+   * @copydoc Dali::ColorController::RetrieveColor(const std::string&, Vector4&, Vector4&, Vector4&)
+   */
+  bool RetrieveColor( const std::string& colorCode , Vector4& textColor, Vector4& textOutlineColor, Vector4& textShadowColor);
+
+private:
+
+ /**
+  * @brief Initialize
+  */
+  void Initialize();
+
+protected:
+  /**
+   * @brief Destructor.
+   */
+  virtual ~ColorController();
+
+private:
+
+  using CreateColorControllerFunction = Dali::ColorControllerPlugin* (*)();
+
+  void*                                  mLibHandle;          ///< Handle for the loaded library
+  Dali::ColorControllerPlugin*           mPlugin;             ///< Plugin handle
+
+  CreateColorControllerFunction          mCreateColorControllerPtr;   ///< Function pointer called in adaptor to create a plugin instance
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+// Additional Helpers for public-api forwarding methods
+inline Internal::Adaptor::ColorController& GetImplementation(Dali::ColorController& controller)
+{
+  DALI_ASSERT_ALWAYS(controller && "ColorController handle is empty");
+  BaseObject& handle = controller.GetBaseObject();
+  return static_cast<Internal::Adaptor::ColorController&>(handle);
+}
+
+inline const Internal::Adaptor::ColorController& GetImplementation(const Dali::ColorController& controller)
+{
+  DALI_ASSERT_ALWAYS(controller && "ColorController handle is empty");
+  const BaseObject& handle = controller.GetBaseObject();
+  return static_cast<const Internal::Adaptor::ColorController&>(handle);
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_COLOR_CONTROLLER_H
diff --git a/dali/internal/system/common/command-line-options.cpp b/dali/internal/system/common/command-line-options.cpp
new file mode 100644 (file)
index 0000000..7270a23
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/command-line-options.h>
+
+// EXTERNAL INCLUDES
+#include <getopt.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+
+#include <dali/public-api/common/dali-vector.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+struct Argument
+{
+  const char * const opt;
+  const char * const optDescription;
+
+  void Print()
+  {
+    const std::ios_base::fmtflags flags = std::cout.flags();
+    std::cout << std::left << "  --";
+    std::cout.width( 18 );
+    std::cout << opt;
+    std::cout << optDescription;
+    std::cout << std::endl;
+    std::cout.flags( flags );
+  }
+};
+
+Argument EXPECTED_ARGS[] =
+{
+  { "width",       "Stage Width"             },
+  { "height",      "Stage Height"            },
+  { "dpi",         "Emulated DPI"            },
+  { "help",        "Help"                    },
+  { NULL,          NULL                      }
+};
+
+enum Option
+{
+  OPTION_STAGE_WIDTH = 0,
+  OPTION_STAGE_HEIGHT,
+  OPTION_DPI,
+  OPTION_HELP
+};
+
+typedef Dali::Vector< int32_t > UnhandledContainer;
+
+void ShowHelp()
+{
+  std::cout << "Available options:" << std::endl;
+  Argument* arg = EXPECTED_ARGS;
+  while ( arg->opt )
+  {
+    arg->Print();
+    ++arg;
+  }
+}
+
+} // unnamed namespace
+
+CommandLineOptions::CommandLineOptions(int32_t *argc, char **argv[])
+: stageWidth(0),
+  stageHeight(0)
+{
+  // Exit gracefully if no arguments provided
+  if ( !argc || !argv )
+  {
+    return;
+  }
+
+  if ( *argc > 1 )
+  {
+    // We do not want to print out errors.
+    int32_t origOptErrValue( opterr );
+    opterr = 0;
+
+    int32_t help( 0 );
+
+    const struct option options[]=
+    {
+      { EXPECTED_ARGS[OPTION_STAGE_WIDTH].opt,  required_argument, NULL,             'w' },  // "--width"
+      { EXPECTED_ARGS[OPTION_STAGE_HEIGHT].opt, required_argument, NULL,             'h' },  // "--height"
+      { EXPECTED_ARGS[OPTION_DPI].opt,          required_argument, NULL,             'd' },  // "--dpi"
+      { EXPECTED_ARGS[OPTION_HELP].opt,         no_argument,       &help,            '?' },  // "--help"
+      { 0, 0, 0, 0 } // end of options
+    };
+
+    int32_t shortOption( 0 );
+    int32_t optionIndex( 0 );
+
+    const char* optString = "-w:h:d:"; // The '-' ensures that argv is NOT permuted
+    bool optionProcessed( false );
+
+    UnhandledContainer unhandledOptions; // We store indices of options we do not handle here
+
+    do
+    {
+      shortOption = getopt_long( *argc, *argv, optString, options, &optionIndex );
+
+      switch ( shortOption )
+      {
+        case 0:
+        {
+          // Check if we want help
+          if ( help )
+          {
+            ShowHelp();
+            optionProcessed = true;
+          }
+          break;
+        }
+
+        case 'w':
+        {
+          if ( optarg )
+          {
+            stageWidth = atoi( optarg );
+            optionProcessed = true;
+          }
+          break;
+        }
+
+        case 'h':
+        {
+          if ( optarg )
+          {
+            stageHeight = atoi( optarg );
+            optionProcessed = true;
+          }
+          break;
+        }
+
+        case 'd':
+        {
+          if ( optarg )
+          {
+            stageDPI.assign( optarg );
+            optionProcessed = true;
+          }
+          break;
+        }
+
+        case -1:
+        {
+          // All command-line options have been parsed.
+          break;
+        }
+
+        default:
+        {
+          unhandledOptions.PushBack( optind - 1 );
+          break;
+        }
+      }
+    } while ( shortOption != -1 );
+
+    // Take out the options we have processed
+    if ( optionProcessed )
+    {
+      if ( unhandledOptions.Count() > 0 )
+      {
+        int32_t index( 1 );
+
+        // Overwrite the argv with the values from the unhandled indices
+        const UnhandledContainer::ConstIterator endIter = unhandledOptions.End();
+        for ( UnhandledContainer::Iterator iter = unhandledOptions.Begin(); iter != endIter; ++iter )
+        {
+          (*argv)[ index++ ] = (*argv)[ *iter ];
+        }
+        *argc = unhandledOptions.Count() + 1; // +1 for the program name
+      }
+      else
+      {
+        // There are no unhandled options, so we should just have the program name
+        *argc = 1;
+      }
+
+      optind = 1; // Reset to start
+    }
+
+    opterr = origOptErrValue; // Reset opterr value.
+  }
+}
+
+CommandLineOptions::~CommandLineOptions()
+{
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/common/command-line-options.h b/dali/internal/system/common/command-line-options.h
new file mode 100644 (file)
index 0000000..5277ffd
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef DALI_INTERNAL_COMMAND_LINE_OPTIONS_H
+#define DALI_INTERNAL_COMMAND_LINE_OPTIONS_H
+
+/*
+ * Copyright (c) 2019 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 <cstdint> // int32_t
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Parses the passed command line arguments and sets the values stored within this
+ * class appropriately.
+ *
+ * The following options are supported:
+ *
+ * @code
+ *  -w|--width          Stage Width
+ *  -h|--height         Stage Height
+ *  -d|--dpi            Emulated DPI
+ *     --help           Help
+ * @endcode
+ *
+ * When the above options are found, they are stripped from argv, and argc is updated appropriately.
+ */
+struct CommandLineOptions
+{
+public:
+
+  /**
+   * Constructor
+   * @param[in,out]  argc  The number of arguments
+   * @param[in,out]  argv  The argument list
+   * @note Supported options are stripped from argv, and argc is updated appropriately.
+   */
+  CommandLineOptions( int32_t *argc, char **argv[] );
+
+  /**
+   * Destructor
+   */
+  ~CommandLineOptions();
+
+public: // Command line parsed values
+
+  int32_t stageWidth;      ///< The width of the stage required.  0 if not set.
+  int32_t stageHeight;     ///< The height of the stage required.   0 if not set.
+  std::string stageDPI;    ///< DPI stored as hxv, where h is horizontal DPI and v is vertical DPI
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_COMMAND_LINE_OPTIONS_H
diff --git a/dali/internal/system/common/configuration-manager.cpp b/dali/internal/system/common/configuration-manager.cpp
new file mode 100644 (file)
index 0000000..63b62dc
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/configuration-manager.h>
+
+// EXTERNAL INCLUDES
+#include <fstream>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/file-stream.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+#include <dali/internal/system/common/environment-options.h>
+#include <dali/internal/system/common/environment-variables.h>
+#include <dali/internal/system/common/thread-controller.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+const std::string SYSTEM_CACHE_FILE = "gpu-environment.conf";
+const std::string DALI_ENV_MULTIPLE_WINDOW_SUPPORT = "DALI_ENV_MULTIPLE_WINDOW_SUPPORT";
+
+bool RetrieveKeyFromConfigFile( std::iostream& stream, const std::string& key, std::string& value )
+{
+  bool keyFound = false;
+
+  std::string line;
+  while( std::getline( stream, line ) )
+  {
+    line.erase( line.find_last_not_of( " \t\r\n" ) + 1 );
+    line.erase( 0, line.find_first_not_of( " \t\r\n" ) );
+    if( '#' == *( line.cbegin() ) || line == "" )
+    {
+      continue;
+    }
+
+    std::istringstream stream( line );
+    std::string name;
+    std::getline(stream, name, ' ');
+    if( name == key )
+    {
+      std::getline(stream, value);
+      keyFound = true;
+      break;
+    }
+  }
+
+  return keyFound;
+}
+
+
+} // unnamed namespace
+
+ConfigurationManager::ConfigurationManager( std::string systemCachePath, EglGraphics* eglGraphics, ThreadController* threadController )
+: mSystemCacheFilePath( systemCachePath + SYSTEM_CACHE_FILE ),
+  mEglGraphics( eglGraphics ),
+  mThreadController( threadController ),
+  mMaxTextureSize( 0u ),
+  mIsMultipleWindowSupported( true ),
+  mMaxTextureSizeCached( false ) ,
+  mIsMultipleWindowSupportedCached( false )
+{
+}
+
+ConfigurationManager::~ConfigurationManager()
+{
+}
+
+void ConfigurationManager::RetrieveKeysFromConfigFile( const std::string& configFilePath )
+{
+  Dali::FileStream configFile( configFilePath, Dali::FileStream::READ | Dali::FileStream::TEXT );
+  std::iostream& stream = configFile.GetStream();
+  if( stream.rdbuf()->in_avail() )
+  {
+    std::string value;
+    if( !mMaxTextureSizeCached &&
+        RetrieveKeyFromConfigFile( stream, DALI_ENV_MAX_TEXTURE_SIZE, value ) )
+    {
+      mMaxTextureSize = std::atoi( value.c_str() );
+      mMaxTextureSizeCached = true;
+    }
+
+    if( !mIsMultipleWindowSupportedCached &&
+        RetrieveKeyFromConfigFile( stream, DALI_ENV_MULTIPLE_WINDOW_SUPPORT, value ) )
+    {
+      mIsMultipleWindowSupported = std::atoi( value.c_str() );
+      mIsMultipleWindowSupportedCached = true;
+    }
+  }
+}
+
+unsigned int ConfigurationManager::GetMaxTextureSize()
+{
+  if( !mMaxTextureSizeCached )
+  {
+    RetrieveKeysFromConfigFile( mSystemCacheFilePath );
+
+    if( !mMaxTextureSizeCached )
+    {
+      GlImplementation& mGLES = mEglGraphics->GetGlesInterface();
+      mMaxTextureSize = mGLES.GetMaxTextureSize();
+      mMaxTextureSizeCached = true;
+
+      Dali::FileStream configFile( mSystemCacheFilePath, Dali::FileStream::READ | Dali::FileStream::APPEND | Dali::FileStream::TEXT );
+      std::fstream& stream = dynamic_cast<std::fstream&>( configFile.GetStream() );
+      if( stream.is_open() )
+      {
+        stream << DALI_ENV_MAX_TEXTURE_SIZE << " " << mMaxTextureSize << std::endl;
+      }
+      else
+      {
+        DALI_LOG_ERROR( "Fail to open file : %s\n", mSystemCacheFilePath.c_str() );
+      }
+    }
+  }
+
+  return mMaxTextureSize;
+}
+
+bool ConfigurationManager::IsMultipleWindowSupported()
+{
+  if ( !mIsMultipleWindowSupportedCached )
+  {
+    RetrieveKeysFromConfigFile( mSystemCacheFilePath );
+
+    if ( !mIsMultipleWindowSupportedCached )
+    {
+      EglImplementation& eglImpl = mEglGraphics->GetEglImplementation();
+      if ( !eglImpl.IsGlesInitialized() )
+      {
+        // Wait until GLES is initialised, but this will happen once.
+        // This method blocks until the render thread has initialised the graphics.
+        mThreadController->WaitForGraphicsInitialization();
+      }
+
+      // Query from GLES and save the cache
+      mIsMultipleWindowSupported = eglImpl.IsSurfacelessContextSupported();
+      mIsMultipleWindowSupportedCached = true;
+
+      Dali::FileStream configFile( mSystemCacheFilePath, Dali::FileStream::READ | Dali::FileStream::APPEND | Dali::FileStream::TEXT );
+      std::fstream& stream = dynamic_cast<std::fstream&>( configFile.GetStream() );
+      if ( stream.is_open() )
+      {
+        stream << DALI_ENV_MULTIPLE_WINDOW_SUPPORT << " " << mIsMultipleWindowSupported << std::endl;
+      }
+      else
+      {
+        DALI_LOG_ERROR( "Fail to open file : %s\n", mSystemCacheFilePath.c_str() );
+      }
+    }
+  }
+
+  return mIsMultipleWindowSupported;
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/dali/internal/system/common/configuration-manager.h b/dali/internal/system/common/configuration-manager.h
new file mode 100644 (file)
index 0000000..a6721ee
--- /dev/null
@@ -0,0 +1,100 @@
+#ifndef DALI_INTERNAL_ENVIRONMENT_CONFIGURATION_MANAGER_H
+#define DALI_INTERNAL_ENVIRONMENT_CONFIGURATION_MANAGER_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <memory>
+#include <string>
+
+namespace Dali
+{
+
+class FileStream;
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+class EglGraphics;
+class ThreadController;
+
+/**
+ * This class retrieves and caches the system configuration.
+ *
+ */
+class ConfigurationManager
+{
+public:
+
+  /**
+   * @brief Constructor
+   */
+  ConfigurationManager( std::string systemCachePath, EglGraphics* eglGraphics, ThreadController* threadController );
+
+  /**
+   * @brief Virtual Destructor for interface cleanup
+   */
+  virtual ~ConfigurationManager();
+
+  /**
+   * @brief Retrieve all keys from the config file if the file exists.
+   */
+  void RetrieveKeysFromConfigFile( const std::string& configFilePath );
+
+  /**
+   * @brief Get the maximum texture size.
+   * @return The maximum texture size
+   */
+  unsigned int GetMaxTextureSize();
+
+  /**
+   * @brief Check whether multiple window is supported
+   * @return Whether multiple window is supported
+   */
+  bool IsMultipleWindowSupported();
+
+  // Deleted copy constructor.
+  ConfigurationManager( const ConfigurationManager& ) = delete;
+
+  // Deleted move constructor.
+  ConfigurationManager( const ConfigurationManager&& ) = delete;
+
+  // Deleted assignment operator.
+  ConfigurationManager& operator=( const ConfigurationManager& ) = delete;
+
+  // Deleted move assignment operator.
+  ConfigurationManager& operator=( const ConfigurationManager&& ) = delete;
+
+private: // Data
+
+  std::string mSystemCacheFilePath;              ///< The path of system cache file
+  EglGraphics* mEglGraphics;                     ///< EGL graphics
+  ThreadController* mThreadController;           ///< The thread controller
+  unsigned int mMaxTextureSize;                  ///< The largest texture that the GL can handle
+  bool mIsMultipleWindowSupported:1;             ///< Whether multiple window is supported by the GLES
+  bool mMaxTextureSizeCached:1;                  ///< Whether we have checked the maximum texture size
+  bool mIsMultipleWindowSupportedCached:1;       ///< Whether we have checked the support of multiple window
+};
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // DALI_INTERNAL_ENVIRONMENT_CONFIGURATION_MANAGER_H
diff --git a/dali/internal/system/common/core-event-interface.h b/dali/internal/system/common/core-event-interface.h
new file mode 100644 (file)
index 0000000..d2240e1
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef DALI_INTERNAL_ADAPTOR_CORE_EVENT_INTERFACE_H
+#define DALI_INTERNAL_ADAPTOR_CORE_EVENT_INTERFACE_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Integration
+{
+struct Event;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * This interface should be used by adaptor components to send events to Core.
+ * This is preferable to using Core directly i.e. so there is a common place for measuring performance.
+ */
+class CoreEventInterface
+{
+public:
+
+  /**
+   * Queue an event with Core.
+   * @param[in] event The new event.
+   */
+  virtual void QueueCoreEvent(const Dali::Integration::Event& event) = 0;
+
+  /**
+   * Process the events queued with QueueEvent().
+   */
+  virtual void ProcessCoreEvents() = 0;
+
+protected:
+
+  /**
+   * Protected virtual destructor
+   */
+  virtual ~CoreEventInterface() {}
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_CORE_EVENT_INTERFACE_H
diff --git a/dali/internal/system/common/environment-options.cpp b/dali/internal/system/common/environment-options.cpp
new file mode 100644 (file)
index 0000000..7fea428
--- /dev/null
@@ -0,0 +1,669 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/environment-options.h>
+
+// EXTERNAL INCLUDES
+#include <cstdlib>
+#include <dali/integration-api/render-controller.h>
+#include <dali/public-api/math/math-utils.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/trace/common/trace-factory.h>
+#include <dali/internal/system/common/environment-variables.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const unsigned int DEFAULT_STATISTICS_LOG_FREQUENCY = 2;
+const int DEFAULT_MULTI_SAMPLING_LEVEL = -1;
+const bool DEFAULT_DEPTH_BUFFER_REQUIRED_SETTING = true;
+const bool DEFAULT_STENCIL_BUFFER_REQUIRED_SETTING = true;
+
+unsigned int GetIntegerEnvironmentVariable( const char* variable, unsigned int defaultValue )
+{
+  const char* variableParameter = std::getenv(variable);
+
+  // if the parameter exists convert it to an integer, else return the default value
+  unsigned int intValue = variableParameter ? std::atoi(variableParameter) : defaultValue;
+  return intValue;
+}
+
+bool GetIntegerEnvironmentVariable( const char* variable, int& intValue )
+{
+  const char* variableParameter = std::getenv(variable);
+
+  if( !variableParameter )
+  {
+    return false;
+  }
+  // if the parameter exists convert it to an integer, else return the default value
+  intValue = std::atoi(variableParameter);
+  return true;
+}
+
+bool GetFloatEnvironmentVariable( const char* variable, float& floatValue )
+{
+  const char* variableParameter = std::getenv(variable);
+
+  if( !variableParameter )
+  {
+    return false;
+  }
+  // if the parameter exists convert it to an integer, else return the default value
+  floatValue = std::atof(variableParameter);
+  return true;
+}
+
+const char * GetCharEnvironmentVariable( const char * variable )
+{
+  return std::getenv( variable );
+}
+
+} // unnamed namespace
+
+EnvironmentOptions::EnvironmentOptions()
+: mLogFunction( NULL ),
+  mWindowName(),
+  mWindowClassName(),
+  mNetworkControl( 0 ),
+  mFpsFrequency( 0 ),
+  mUpdateStatusFrequency( 0 ),
+  mObjectProfilerInterval( 0 ),
+  mPerformanceStatsLevel( 0 ),
+  mPerformanceStatsFrequency( DEFAULT_STATISTICS_LOG_FREQUENCY ),
+  mPerformanceTimeStampOutput( 0 ),
+  mPanGestureLoggingLevel( 0 ),
+  mWindowWidth( 0u ),
+  mWindowHeight( 0u ),
+  mRenderRefreshRate( 1u ),
+  mMaxTextureSize( 0 ),
+  mRenderToFboInterval( 0u ),
+  mPanGesturePredictionMode( -1 ),
+  mPanGesturePredictionAmount( -1 ), ///< only sets value in pan gesture if greater than 0
+  mPanGestureMaxPredictionAmount( -1 ),
+  mPanGestureMinPredictionAmount( -1 ),
+  mPanGesturePredictionAmountAdjustment( -1 ),
+  mPanGestureSmoothingMode( -1 ),
+  mPanGestureSmoothingAmount( -1.0f ),
+  mPanGestureUseActualTimes( -1 ),
+  mPanGestureInterpolationTimeRange( -1 ),
+  mPanGestureScalarOnlyPredictionEnabled( -1 ),
+  mPanGestureTwoPointPredictionEnabled( -1 ),
+  mPanGestureTwoPointInterpolatePastTime( -1 ),
+  mPanGestureTwoPointVelocityBias( -1.0f ),
+  mPanGestureTwoPointAccelerationBias( -1.0f ),
+  mPanGestureMultitapSmoothingRange( -1 ),
+  mPanMinimumDistance( -1 ),
+  mPanMinimumEvents( -1 ),
+  mPinchMinimumDistance( -1.0f ),
+  mPinchMinimumTouchEvents( -1 ),
+  mPinchMinimumTouchEventsAfterStart( -1 ),
+  mRotationMinimumTouchEvents( -1 ),
+  mRotationMinimumTouchEventsAfterStart( -1 ),
+  mLongPressMinimumHoldingTime( -1 ),
+  mGlesCallTime( 0 ),
+  mMultiSamplingLevel( DEFAULT_MULTI_SAMPLING_LEVEL ),
+  mThreadingMode( ThreadingMode::COMBINED_UPDATE_RENDER ),
+  mGlesCallAccumulate( false ),
+  mDepthBufferRequired( DEFAULT_DEPTH_BUFFER_REQUIRED_SETTING ),
+  mStencilBufferRequired( DEFAULT_STENCIL_BUFFER_REQUIRED_SETTING )
+{
+  ParseEnvironmentOptions();
+}
+
+EnvironmentOptions::~EnvironmentOptions()
+{
+}
+
+void EnvironmentOptions::CreateTraceManager( PerformanceInterface* performanceInterface )
+{
+  mTraceManager = TraceManagerFactory::CreateTraceFactory( performanceInterface );
+}
+
+void EnvironmentOptions::InstallTraceFunction() const
+{
+  if( mTraceManager )
+  {
+    mTraceManager->Initialise();
+  }
+}
+
+void EnvironmentOptions::SetLogFunction( const Dali::Integration::Log::LogFunction& logFunction )
+{
+  mLogFunction = logFunction;
+}
+
+void EnvironmentOptions::InstallLogFunction() const
+{
+  Dali::Integration::Log::InstallLogFunction( mLogFunction );
+}
+
+void EnvironmentOptions::UnInstallLogFunction() const
+{
+  Dali::Integration::Log::UninstallLogFunction();
+}
+
+unsigned int EnvironmentOptions::GetNetworkControlMode() const
+{
+  return mNetworkControl;
+}
+unsigned int EnvironmentOptions::GetFrameRateLoggingFrequency() const
+{
+  return mFpsFrequency;
+}
+
+unsigned int EnvironmentOptions::GetUpdateStatusLoggingFrequency() const
+{
+  return mUpdateStatusFrequency;
+}
+
+unsigned int EnvironmentOptions::GetObjectProfilerInterval() const
+{
+  return mObjectProfilerInterval;
+}
+
+unsigned int EnvironmentOptions::GetPerformanceStatsLoggingOptions() const
+{
+  return mPerformanceStatsLevel;
+}
+unsigned int EnvironmentOptions::GetPerformanceStatsLoggingFrequency() const
+{
+  return mPerformanceStatsFrequency;
+}
+unsigned int EnvironmentOptions::GetPerformanceTimeStampOutput() const
+{
+  return mPerformanceTimeStampOutput;
+}
+
+unsigned int EnvironmentOptions::GetPanGestureLoggingLevel() const
+{
+  return mPanGestureLoggingLevel;
+}
+
+int EnvironmentOptions::GetPanGesturePredictionMode() const
+{
+  return mPanGesturePredictionMode;
+}
+
+int EnvironmentOptions::GetPanGesturePredictionAmount() const
+{
+  return mPanGesturePredictionAmount;
+}
+
+int EnvironmentOptions::GetPanGestureMaximumPredictionAmount() const
+{
+  return mPanGestureMaxPredictionAmount;
+}
+
+int EnvironmentOptions::GetPanGestureMinimumPredictionAmount() const
+{
+  return mPanGestureMinPredictionAmount;
+}
+
+int EnvironmentOptions::GetPanGesturePredictionAmountAdjustment() const
+{
+  return mPanGesturePredictionAmountAdjustment;
+}
+
+int EnvironmentOptions::GetPanGestureSmoothingMode() const
+{
+  return mPanGestureSmoothingMode;
+}
+
+float EnvironmentOptions::GetPanGestureSmoothingAmount() const
+{
+  return mPanGestureSmoothingAmount;
+}
+
+int EnvironmentOptions::GetPanGestureUseActualTimes() const
+{
+  return mPanGestureUseActualTimes;
+}
+
+int EnvironmentOptions::GetPanGestureInterpolationTimeRange() const
+{
+  return mPanGestureInterpolationTimeRange;
+}
+
+int EnvironmentOptions::GetPanGestureScalarOnlyPredictionEnabled() const
+{
+  return mPanGestureScalarOnlyPredictionEnabled;
+}
+
+int EnvironmentOptions::GetPanGestureTwoPointPredictionEnabled() const
+{
+  return mPanGestureTwoPointPredictionEnabled;
+}
+
+int EnvironmentOptions::GetPanGestureTwoPointInterpolatePastTime() const
+{
+  return mPanGestureTwoPointInterpolatePastTime;
+}
+
+float EnvironmentOptions::GetPanGestureTwoPointVelocityBias() const
+{
+  return mPanGestureTwoPointVelocityBias;
+}
+
+float EnvironmentOptions::GetPanGestureTwoPointAccelerationBias() const
+{
+  return mPanGestureTwoPointAccelerationBias;
+}
+
+int EnvironmentOptions::GetPanGestureMultitapSmoothingRange() const
+{
+  return mPanGestureMultitapSmoothingRange;
+}
+
+int EnvironmentOptions::GetMinimumPanDistance() const
+{
+  return mPanMinimumDistance;
+}
+
+int EnvironmentOptions::GetMinimumPanEvents() const
+{
+  return mPanMinimumEvents;
+}
+
+float EnvironmentOptions::GetMinimumPinchDistance() const
+{
+  return mPinchMinimumDistance;
+}
+
+int EnvironmentOptions::GetMinimumPinchTouchEvents() const
+{
+  return mPinchMinimumTouchEvents;
+}
+
+int EnvironmentOptions::GetMinimumPinchTouchEventsAfterStart() const
+{
+  return mPinchMinimumTouchEventsAfterStart;
+}
+
+int EnvironmentOptions::GetMinimumRotationTouchEvents() const
+{
+  return mRotationMinimumTouchEvents;
+}
+
+int EnvironmentOptions::GetMinimumRotationTouchEventsAfterStart() const
+{
+  return mRotationMinimumTouchEventsAfterStart;
+}
+
+int EnvironmentOptions::GetLongPressMinimumHoldingTime() const
+{
+  return mLongPressMinimumHoldingTime;
+}
+
+unsigned int EnvironmentOptions::GetWindowWidth() const
+{
+  return mWindowWidth;
+}
+
+unsigned int EnvironmentOptions::GetWindowHeight() const
+{
+  return mWindowHeight;
+}
+
+int EnvironmentOptions::GetGlesCallTime() const
+{
+  return mGlesCallTime;
+}
+
+bool EnvironmentOptions::GetGlesCallAccumulate() const
+{
+  return mGlesCallAccumulate;
+}
+
+const std::string& EnvironmentOptions::GetWindowName() const
+{
+  return mWindowName;
+}
+
+const std::string& EnvironmentOptions::GetWindowClassName() const
+{
+  return mWindowClassName;
+}
+
+ThreadingMode::Type EnvironmentOptions::GetThreadingMode() const
+{
+  return mThreadingMode;
+}
+
+unsigned int EnvironmentOptions::GetRenderRefreshRate() const
+{
+  return mRenderRefreshRate;
+}
+
+int EnvironmentOptions::GetMultiSamplingLevel() const
+{
+  return mMultiSamplingLevel;
+}
+
+unsigned int EnvironmentOptions::GetMaxTextureSize() const
+{
+  return mMaxTextureSize;
+}
+
+unsigned int EnvironmentOptions::GetRenderToFboInterval() const
+{
+  return mRenderToFboInterval;
+}
+
+bool EnvironmentOptions::PerformanceServerRequired() const
+{
+  return ( ( GetPerformanceStatsLoggingOptions() > 0) ||
+           ( GetPerformanceTimeStampOutput() > 0 ) ||
+           ( GetNetworkControlMode() > 0) );
+}
+
+bool EnvironmentOptions::DepthBufferRequired() const
+{
+  return mDepthBufferRequired;
+}
+
+bool EnvironmentOptions::StencilBufferRequired() const
+{
+  return mStencilBufferRequired;
+}
+
+void EnvironmentOptions::ParseEnvironmentOptions()
+{
+  // get logging options
+  mFpsFrequency = GetIntegerEnvironmentVariable( DALI_ENV_FPS_TRACKING, 0 );
+  mUpdateStatusFrequency = GetIntegerEnvironmentVariable( DALI_ENV_UPDATE_STATUS_INTERVAL, 0 );
+  mObjectProfilerInterval = GetIntegerEnvironmentVariable( DALI_ENV_OBJECT_PROFILER_INTERVAL, 0 );
+  mPerformanceStatsLevel = GetIntegerEnvironmentVariable( DALI_ENV_LOG_PERFORMANCE_STATS, 0 );
+  mPerformanceStatsFrequency = GetIntegerEnvironmentVariable( DALI_ENV_LOG_PERFORMANCE_STATS_FREQUENCY, 0 );
+  mPerformanceTimeStampOutput = GetIntegerEnvironmentVariable( DALI_ENV_PERFORMANCE_TIMESTAMP_OUTPUT, 0 );
+  mNetworkControl = GetIntegerEnvironmentVariable( DALI_ENV_NETWORK_CONTROL, 0 );
+  mPanGestureLoggingLevel = GetIntegerEnvironmentVariable( DALI_ENV_LOG_PAN_GESTURE, 0 );
+
+  int predictionMode;
+  if( GetIntegerEnvironmentVariable(DALI_ENV_PAN_PREDICTION_MODE, predictionMode) )
+  {
+    mPanGesturePredictionMode = predictionMode;
+  }
+  int predictionAmount(-1);
+  if( GetIntegerEnvironmentVariable(DALI_ENV_PAN_PREDICTION_AMOUNT, predictionAmount) )
+  {
+    if( predictionAmount < 0 )
+    {
+      // do not support times in the past
+      predictionAmount = 0;
+    }
+    mPanGesturePredictionAmount = predictionAmount;
+  }
+  int minPredictionAmount(-1);
+  if( GetIntegerEnvironmentVariable(DALI_ENV_PAN_MIN_PREDICTION_AMOUNT, minPredictionAmount) )
+  {
+    if( minPredictionAmount < 0 )
+    {
+      // do not support times in the past
+      minPredictionAmount = 0;
+    }
+    mPanGestureMinPredictionAmount = minPredictionAmount;
+  }
+  int maxPredictionAmount(-1);
+  if( GetIntegerEnvironmentVariable(DALI_ENV_PAN_MAX_PREDICTION_AMOUNT, maxPredictionAmount) )
+  {
+    if( minPredictionAmount > -1 && maxPredictionAmount < minPredictionAmount )
+    {
+      // maximum amount should not be smaller than minimum amount
+      maxPredictionAmount = minPredictionAmount;
+    }
+    mPanGestureMaxPredictionAmount = maxPredictionAmount;
+  }
+  int predictionAmountAdjustment(-1);
+  if( GetIntegerEnvironmentVariable(DALI_ENV_PAN_PREDICTION_AMOUNT_ADJUSTMENT, predictionAmountAdjustment) )
+  {
+    if( predictionAmountAdjustment < 0 )
+    {
+      // negative amount doesn't make sense
+      predictionAmountAdjustment = 0;
+    }
+    mPanGesturePredictionAmountAdjustment = predictionAmountAdjustment;
+  }
+  int smoothingMode;
+  if( GetIntegerEnvironmentVariable(DALI_ENV_PAN_SMOOTHING_MODE, smoothingMode) )
+  {
+    mPanGestureSmoothingMode = smoothingMode;
+  }
+  float smoothingAmount = 1.0f;
+  if( GetFloatEnvironmentVariable(DALI_ENV_PAN_SMOOTHING_AMOUNT, smoothingAmount) )
+  {
+    smoothingAmount = Clamp(smoothingAmount, 0.0f, 1.0f);
+    mPanGestureSmoothingAmount = smoothingAmount;
+  }
+
+  int useActualTimes( -1 );
+  if( GetIntegerEnvironmentVariable( DALI_ENV_PAN_USE_ACTUAL_TIMES, useActualTimes ) )
+  {
+    mPanGestureUseActualTimes = useActualTimes == 0 ? 0 : 1;
+  }
+
+  int interpolationTimeRange( -1 );
+  if( GetIntegerEnvironmentVariable( DALI_ENV_PAN_INTERPOLATION_TIME_RANGE, interpolationTimeRange ) )
+  {
+    if( interpolationTimeRange < 0 )
+    {
+      interpolationTimeRange = 0;
+    }
+    mPanGestureInterpolationTimeRange = interpolationTimeRange;
+  }
+
+  int scalarOnlyPredictionEnabled( -1 );
+  if( GetIntegerEnvironmentVariable( DALI_ENV_PAN_SCALAR_ONLY_PREDICTION_ENABLED, scalarOnlyPredictionEnabled ) )
+  {
+    mPanGestureScalarOnlyPredictionEnabled = scalarOnlyPredictionEnabled == 0 ? 0 : 1;
+  }
+
+  int twoPointPredictionEnabled( -1 );
+  if( GetIntegerEnvironmentVariable( DALI_ENV_PAN_TWO_POINT_PREDICTION_ENABLED, twoPointPredictionEnabled ) )
+  {
+    mPanGestureTwoPointPredictionEnabled = twoPointPredictionEnabled == 0 ? 0 : 1;
+  }
+
+  int twoPointPastInterpolateTime( -1 );
+  if( GetIntegerEnvironmentVariable( DALI_ENV_PAN_TWO_POINT_PAST_INTERPOLATE_TIME, twoPointPastInterpolateTime ) )
+  {
+    if( twoPointPastInterpolateTime < 0 )
+    {
+      twoPointPastInterpolateTime = 0;
+    }
+    mPanGestureTwoPointInterpolatePastTime = twoPointPastInterpolateTime;
+  }
+
+  float twoPointVelocityBias = -1.0f;
+  if( GetFloatEnvironmentVariable( DALI_ENV_PAN_TWO_POINT_VELOCITY_BIAS, twoPointVelocityBias ) )
+  {
+    twoPointVelocityBias = Clamp( twoPointVelocityBias, 0.0f, 1.0f );
+    mPanGestureTwoPointVelocityBias = twoPointVelocityBias;
+  }
+
+  float twoPointAccelerationBias = -1.0f;
+  if( GetFloatEnvironmentVariable( DALI_ENV_PAN_TWO_POINT_ACCELERATION_BIAS, twoPointAccelerationBias ) )
+  {
+    twoPointAccelerationBias = Clamp( twoPointAccelerationBias, 0.0f, 1.0f );
+    mPanGestureTwoPointAccelerationBias = twoPointAccelerationBias;
+  }
+
+  int multitapSmoothingRange( -1 );
+  if( GetIntegerEnvironmentVariable( DALI_ENV_PAN_MULTITAP_SMOOTHING_RANGE, multitapSmoothingRange ) )
+  {
+    if( multitapSmoothingRange < 0 )
+    {
+      multitapSmoothingRange = 0;
+    }
+    mPanGestureMultitapSmoothingRange = multitapSmoothingRange;
+  }
+
+  int minimumDistance(-1);
+  if ( GetIntegerEnvironmentVariable(DALI_ENV_PAN_MINIMUM_DISTANCE, minimumDistance ))
+  {
+    mPanMinimumDistance = minimumDistance;
+  }
+
+  int minimumEvents(-1);
+  if ( GetIntegerEnvironmentVariable(DALI_ENV_PAN_MINIMUM_EVENTS, minimumEvents ))
+  {
+    mPanMinimumEvents = minimumEvents;
+  }
+
+  float pinchMinimumDistance = -1.0f;
+  if( GetFloatEnvironmentVariable( DALI_ENV_PINCH_MINIMUM_DISTANCE, pinchMinimumDistance ) )
+  {
+    mPinchMinimumDistance = pinchMinimumDistance;
+  }
+
+  int pinchMinimumTouchEvents = -1;
+  if( GetIntegerEnvironmentVariable( DALI_ENV_PINCH_MINIMUM_TOUCH_EVENTS, pinchMinimumTouchEvents ) )
+  {
+    mPinchMinimumTouchEvents = pinchMinimumTouchEvents;
+  }
+
+  int pinchMinimumTouchEventsAfterStart = -1;
+  if( GetIntegerEnvironmentVariable( DALI_ENV_PINCH_MINIMUM_TOUCH_EVENTS_AFTER_START, pinchMinimumTouchEventsAfterStart ) )
+  {
+    mPinchMinimumTouchEventsAfterStart = pinchMinimumTouchEventsAfterStart;
+  }
+
+  int rotationMinimumTouchEvents = -1;
+  if( GetIntegerEnvironmentVariable( DALI_ENV_ROTATION_MINIMUM_TOUCH_EVENTS, rotationMinimumTouchEvents ) )
+  {
+    mRotationMinimumTouchEvents = rotationMinimumTouchEvents;
+  }
+
+  int rotationMinimumTouchEventsAfterStart = -1;
+  if( GetIntegerEnvironmentVariable( DALI_ENV_ROTATION_MINIMUM_TOUCH_EVENTS_AFTER_START, rotationMinimumTouchEventsAfterStart ) )
+  {
+    mRotationMinimumTouchEventsAfterStart = rotationMinimumTouchEventsAfterStart;
+  }
+
+  int longPressMinimumHoldingTime = -1;
+  if( GetIntegerEnvironmentVariable( DALI_ENV_LONG_PRESS_MINIMUM_HOLDING_TIME, longPressMinimumHoldingTime ) )
+  {
+    mLongPressMinimumHoldingTime = longPressMinimumHoldingTime;
+  }
+
+  int glesCallTime(0);
+  if ( GetIntegerEnvironmentVariable(DALI_GLES_CALL_TIME, glesCallTime ))
+  {
+    mGlesCallTime = glesCallTime;
+  }
+
+  int glesCallAccumulate( 0 );
+  if ( GetIntegerEnvironmentVariable( DALI_GLES_CALL_ACCUMULATE, glesCallAccumulate ) )
+  {
+    mGlesCallAccumulate = glesCallAccumulate != 0;
+  }
+
+  int windowWidth(0), windowHeight(0);
+  if ( GetIntegerEnvironmentVariable( DALI_WINDOW_WIDTH, windowWidth ) && GetIntegerEnvironmentVariable( DALI_WINDOW_HEIGHT, windowHeight ) )
+  {
+    mWindowWidth = windowWidth;
+    mWindowHeight = windowHeight;
+  }
+
+  const char * windowName = GetCharEnvironmentVariable( DALI_WINDOW_NAME );
+  if ( windowName )
+  {
+    mWindowName = windowName;
+  }
+
+  const char * windowClassName = GetCharEnvironmentVariable( DALI_WINDOW_CLASS_NAME );
+  if ( windowClassName )
+  {
+    mWindowClassName = windowClassName;
+  }
+
+  int threadingMode(0);
+  if ( GetIntegerEnvironmentVariable( DALI_THREADING_MODE, threadingMode ) )
+  {
+    switch( threadingMode )
+    {
+      case ThreadingMode::COMBINED_UPDATE_RENDER:
+      {
+        mThreadingMode = static_cast< ThreadingMode::Type >( threadingMode );
+        break;
+      }
+    }
+  }
+
+  int renderRefreshRate(0);
+  if ( GetIntegerEnvironmentVariable( DALI_REFRESH_RATE, renderRefreshRate ) )
+  {
+    // Only change it if it's valid
+    if( renderRefreshRate > 1 )
+    {
+      mRenderRefreshRate = renderRefreshRate;
+    }
+  }
+
+  int multiSamplingLevel( 0 );
+  if( GetIntegerEnvironmentVariable( DALI_ENV_MULTI_SAMPLING_LEVEL, multiSamplingLevel ) )
+  {
+    mMultiSamplingLevel = multiSamplingLevel;
+  }
+
+  int maxTextureSize( 0 );
+  if( GetIntegerEnvironmentVariable( DALI_ENV_MAX_TEXTURE_SIZE, maxTextureSize ) )
+  {
+    if( maxTextureSize > 0 )
+    {
+      mMaxTextureSize = maxTextureSize;
+    }
+  }
+
+  mRenderToFboInterval = GetIntegerEnvironmentVariable( DALI_RENDER_TO_FBO, 0u );
+
+
+  int depthBufferRequired( -1 );
+  if( GetIntegerEnvironmentVariable( DALI_ENV_DISABLE_DEPTH_BUFFER, depthBufferRequired ) )
+  {
+    if( depthBufferRequired > 0 )
+    {
+      mDepthBufferRequired = false;
+      mStencilBufferRequired = false; // Disable stencil buffer as well
+    }
+  }
+
+  int stencilBufferRequired( -1 );
+  if( GetIntegerEnvironmentVariable( DALI_ENV_DISABLE_STENCIL_BUFFER, stencilBufferRequired ) )
+  {
+    if( stencilBufferRequired > 0 )
+    {
+      mStencilBufferRequired = false;
+    }
+  }
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/dali/internal/system/common/environment-options.h b/dali/internal/system/common/environment-options.h
new file mode 100644 (file)
index 0000000..f72ebdd
--- /dev/null
@@ -0,0 +1,393 @@
+#ifndef DALI_INTERNAL_ADAPTOR_ENVIRONMENT_OPTIONS_H
+#define DALI_INTERNAL_ADAPTOR_ENVIRONMENT_OPTIONS_H
+
+/*
+ * Copyright (c) 2019 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 <memory>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/log-factory-interface.h>
+#include <dali/internal/adaptor/common/threading-mode.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class TraceManager;
+class PerformanceInterface;
+
+/**
+ * This class provides the environment options which define settings as well as
+ * the ability to install a log function.
+ *
+ */
+class EnvironmentOptions : public Dali::LogFactoryInterface
+{
+public:
+
+  /**
+   * Constructor
+   */
+  EnvironmentOptions();
+
+  /**
+   * Virtual Destructor for interface cleanup
+   */
+  virtual ~EnvironmentOptions();
+
+  /**
+   * Create a TraceManager which is used for tracing.
+   * @param PerformanceInterface for using network logging for tracing on Ubuntu
+   */
+  void CreateTraceManager( PerformanceInterface* performanceInterface );
+
+  /**
+   * Initialize TraceManager by installing Trace function.
+   */
+  void InstallTraceFunction() const;
+
+  /**
+   * @param logFunction logging function
+   */
+  void SetLogFunction( const Dali::Integration::Log::LogFunction& logFunction );
+
+  /**
+   * Install the log function for the current thread.
+   */
+  virtual void InstallLogFunction() const;
+
+  /**
+   * Un-install the log function for the current thread.
+   */
+  void UnInstallLogFunction() const;
+
+  /**
+   * @return whether network control is enabled or not ( 0 = off, 1 = on )
+   */
+  unsigned int GetNetworkControlMode() const;
+
+  /**
+   * @return frequency of how often FPS is logged out (e.g. 0 = off, 2 = every 2 seconds).
+   */
+  unsigned int GetFrameRateLoggingFrequency() const;
+
+  /**
+   * @return frequency of how often Update Status is logged out (e.g. 0 = off, 60 = log every 60 frames = 1 second @ 60FPS).
+   */
+  unsigned int GetUpdateStatusLoggingFrequency() const;
+
+  /**
+   * @return object profiler status interval ( 0 == off )
+   */
+  unsigned int GetObjectProfilerInterval() const;
+
+  /**
+   * @return performance statistics log level ( 0 == off )
+   */
+  unsigned int GetPerformanceStatsLoggingOptions() const;
+
+  /**
+   * @return performance statistics log frequency in seconds
+   */
+  unsigned int GetPerformanceStatsLoggingFrequency() const;
+
+  /**
+   * @return performance time stamp output ( 0 == off)
+   */
+  unsigned int GetPerformanceTimeStampOutput() const;
+
+  /**
+   * @return pan-gesture logging level ( 0 == off )
+   */
+  unsigned int GetPanGestureLoggingLevel() const;
+
+  /**
+   * @return pan-gesture prediction mode ( -1 means not set so no prediction, 0 = no prediction )
+   */
+  int GetPanGesturePredictionMode() const;
+
+  /**
+   * @return pan-gesture prediction amount
+   */
+  int GetPanGesturePredictionAmount() const;
+
+  /**
+   * @return maximum pan-gesture prediction amount
+   */
+  int GetPanGestureMaximumPredictionAmount() const;
+
+  /**
+   * @return minimum pan-gesture prediction amount
+   */
+  int GetPanGestureMinimumPredictionAmount() const;
+
+  /**
+   * @brief Gets the prediction amount to adjust when the pan velocity is changed.
+   *
+   * If the pan velocity is accelerating, the prediction amount will be increased
+   * by the specified amount until it reaches the upper bound. If the pan velocity
+   * is decelerating, the prediction amount will be decreased by the specified
+   * amount until it reaches the lower bound.
+   *
+   * @return pan-gesture prediction amount adjustment
+   */
+  int GetPanGesturePredictionAmountAdjustment() const;
+
+  /**
+   * @return pan-gesture smoothing mode ( -1 means not set so no smoothing, 0 = no smoothing )
+   */
+  int GetPanGestureSmoothingMode() const;
+
+  /**
+   * @return pan-gesture smoothing amount
+   */
+  float GetPanGestureSmoothingAmount() const;
+
+  /**
+   * @return pan-gesture use actual times is true if real gesture and frame times are to be used.
+   */
+  int GetPanGestureUseActualTimes() const;
+
+  /**
+   * @return pan-gesture interpolation time range is the time range (ms) of past points to use (with weights) when interpolating.
+   */
+  int GetPanGestureInterpolationTimeRange() const;
+
+  /**
+   * @return pan-gesture scalar only prediction, when enabled, ignores acceleration.
+   */
+  int GetPanGestureScalarOnlyPredictionEnabled() const;
+
+  /**
+   * @return pan-gesture two point prediction combines two interpolated points to get more steady acceleration and velocity values.
+   */
+  int GetPanGestureTwoPointPredictionEnabled() const;
+
+  /**
+   * @return pan-gesture two point interpolate past time is the time delta (ms) in the past to interpolate the second point.
+   */
+  int GetPanGestureTwoPointInterpolatePastTime() const;
+
+  /**
+   * @return pan-gesture two point velocity bias is the ratio of first and second points to use for velocity.
+   * 0.0f = 100% of first point. 1.0f = 100% of second point.
+   */
+  float GetPanGestureTwoPointVelocityBias() const;
+
+  /**
+   * @return pan-gesture two point acceleration bias is the ratio of first and second points to use for acceleration.
+   * 0.0f = 100% of first point. 1.0f = 100% of second point.
+   */
+  float GetPanGestureTwoPointAccelerationBias() const;
+
+  /**
+   * @return pan-gesture multitap smoothing range is the range in time (ms) of points in the history to smooth the final output against.
+   */
+  int GetPanGestureMultitapSmoothingRange() const;
+
+  /**
+   * @return The minimum distance before a pan can be started (-1 means it's not set)
+   */
+  int GetMinimumPanDistance() const;
+
+  /**
+   * @return The minimum events before a pan can be started (-1 means it's not set)
+   */
+  int GetMinimumPanEvents() const;
+
+  /**
+   * @return The minimum pixels before a pinch can be started (-1 means it's not set)
+   */
+  float GetMinimumPinchDistance() const;
+
+  /**
+   * @return The minimum touch events required before a pinch can be started (-1 means it's not set)
+   */
+  int GetMinimumPinchTouchEvents() const;
+
+  /**
+   * @return The minimum touch events required after a pinch started (-1 means it's not set)
+   */
+  int GetMinimumPinchTouchEventsAfterStart() const;
+
+  /**
+   * @return The minimum touch events required before a rotation can be started (-1 means it's not set)
+   */
+  int GetMinimumRotationTouchEvents() const;
+
+  /**
+   * @return The minimum touch events required after a rotation started (-1 means it's not set)
+   */
+  int GetMinimumRotationTouchEventsAfterStart() const;
+
+  /**
+   * @return The minimum holding time required to be recognized as a long press gesture (milliseconds)
+   */
+  int GetLongPressMinimumHoldingTime() const;
+
+  /**
+   * @return The width of the window
+   */
+  unsigned int GetWindowWidth() const;
+
+  /**
+   * @return The height of the window
+   */
+  unsigned int GetWindowHeight() const;
+
+  /**
+   * @brief Get the graphics status time
+   */
+  int GetGlesCallTime() const;
+
+  /**
+   * @brief Get whether or not to accumulate gles call statistics
+   */
+  bool GetGlesCallAccumulate() const;
+
+  /**
+   * @return true if performance server is required
+   */
+  bool PerformanceServerRequired() const;
+
+  /**
+   * @return Gets the window name.
+   */
+  const std::string& GetWindowName() const;
+
+  /**
+   * @return Gets the window class.
+   */
+  const std::string& GetWindowClassName() const;
+
+  /**
+   * @return The thread mode that DALi should use.
+   */
+  ThreadingMode::Type GetThreadingMode() const;
+
+  /**
+   * @return The render refresh rate.
+   */
+  unsigned int GetRenderRefreshRate() const;
+
+  /**
+   * @return The number of samples required in multisample buffers
+   */
+  int GetMultiSamplingLevel() const;
+
+  /**
+   * @return The maximum texture size
+   */
+  unsigned int GetMaxTextureSize() const;
+
+  /**
+   * @brief Retrieves the interval of frames to be rendered into the Frame Buffer Object and the Frame Buffer.
+   *
+   * @return The number of frames that are going to be rendered into the Frame Buffer Object but the last one which is going to be rendered into the Frame Buffer.
+   */
+  unsigned int GetRenderToFboInterval() const;
+
+  /**
+   * @return Whether the depth buffer is required.
+   */
+  bool DepthBufferRequired() const;
+
+  /**
+   * @return Whether the stencil buffer is required.
+   */
+  bool StencilBufferRequired() const;
+
+  /// Deleted copy constructor.
+  EnvironmentOptions( const EnvironmentOptions& ) = delete;
+
+  /// Deleted move constructor.
+  EnvironmentOptions( const EnvironmentOptions&& ) = delete;
+
+  /// Deleted assignment operator.
+  EnvironmentOptions& operator=( const EnvironmentOptions& ) = delete;
+
+  /// Deleted move assignment operator.
+  EnvironmentOptions& operator=( const EnvironmentOptions&& ) = delete;
+
+private: // Internal
+
+  /**
+   * Parses the environment options.
+   * Called from the constructor
+   */
+  void ParseEnvironmentOptions();
+
+private: // Data
+
+  Dali::Integration::Log::LogFunction mLogFunction;
+  std::string mWindowName;                        ///< name of the window
+  std::string mWindowClassName;                   ///< name of the class the window belongs to
+  unsigned int mNetworkControl;                   ///< whether network control is enabled
+  unsigned int mFpsFrequency;                     ///< how often fps is logged out in seconds
+  unsigned int mUpdateStatusFrequency;            ///< how often update status is logged out in frames
+  unsigned int mObjectProfilerInterval;           ///< how often object counts are logged out in seconds
+  unsigned int mPerformanceStatsLevel;            ///< performance statistics logging bitmask
+  unsigned int mPerformanceStatsFrequency;        ///< performance statistics logging frequency (seconds)
+  unsigned int mPerformanceTimeStampOutput;       ///< performance time stamp output ( bitmask)
+  unsigned int mPanGestureLoggingLevel;           ///< pan-gesture log level
+  unsigned int mWindowWidth;                      ///< width of the window
+  unsigned int mWindowHeight;                     ///< height of the window
+  unsigned int mRenderRefreshRate;                ///< render refresh rate
+  unsigned int mMaxTextureSize;                   ///< The maximum texture size that GL can handle
+  unsigned int mRenderToFboInterval;              ///< The number of frames that are going to be rendered into the Frame Buffer Object but the last one which is going to be rendered into the Frame Buffer.
+  int mPanGesturePredictionMode;                  ///< prediction mode for pan gestures
+  int mPanGesturePredictionAmount;                ///< prediction amount for pan gestures
+  int mPanGestureMaxPredictionAmount;             ///< maximum prediction amount for pan gestures
+  int mPanGestureMinPredictionAmount;             ///< minimum prediction amount for pan gestures
+  int mPanGesturePredictionAmountAdjustment;      ///< adjustment of prediction amount for pan gestures
+  int mPanGestureSmoothingMode;                   ///< prediction mode for pan gestures
+  float mPanGestureSmoothingAmount;               ///< prediction amount for pan gestures
+  int mPanGestureUseActualTimes;                  ///< Disable to optionally override actual times if they make results worse.
+  int mPanGestureInterpolationTimeRange;          ///< Time into past history (ms) to use points to interpolate the first point.
+  int mPanGestureScalarOnlyPredictionEnabled;     ///< If enabled, prediction is done using velocity alone (no integration or acceleration).
+  int mPanGestureTwoPointPredictionEnabled;       ///< If enabled, a second interpolated point is predicted and combined with the first to get more stable values.
+  int mPanGestureTwoPointInterpolatePastTime;     ///< The target time in the past to generate the second interpolated point.
+  float mPanGestureTwoPointVelocityBias;          ///< The ratio of first and second interpolated points to use for velocity. 0.0f = 100% of first point. 1.0f = 100% of second point.
+  float mPanGestureTwoPointAccelerationBias;      ///< The ratio of first and second interpolated points to use for acceleration. 0.0f = 100% of first point. 1.0f = 100% of second point.
+  int mPanGestureMultitapSmoothingRange;          ///< The range in time (ms) of points in the history to smooth the final output against.
+  int mPanMinimumDistance;                        ///< minimum distance required before pan starts
+  int mPanMinimumEvents;                          ///< minimum events required before pan starts
+  float mPinchMinimumDistance;                    ///< minimum number of pixels moved before a pinch starts
+  int mPinchMinimumTouchEvents;                   ///< minimum events required before a pinch starts
+  int mPinchMinimumTouchEventsAfterStart;         ///< minimum events required after a pinch started
+  int mRotationMinimumTouchEvents;                ///< minimum events required before a rotation starts
+  int mRotationMinimumTouchEventsAfterStart;      ///< minimum events required after a rotation started
+  int mLongPressMinimumHoldingTime;               ///< minimum holding time required to be recognized as a long press gesture (millisecond)
+  int mGlesCallTime;                              ///< time in seconds between status updates
+  int mMultiSamplingLevel;                        ///< The number of samples required in multisample buffers
+  ThreadingMode::Type mThreadingMode;             ///< threading mode
+  bool mGlesCallAccumulate;                       ///< Whether or not to accumulate gles call statistics
+  bool mDepthBufferRequired;                      ///< Whether the depth buffer is required
+  bool mStencilBufferRequired;                    ///< Whether the stencil buffer is required
+  std::unique_ptr<TraceManager> mTraceManager;    ///< TraceManager
+};
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_ENVIRONMENT_OPTIONS_H
diff --git a/dali/internal/system/common/environment-variables.h b/dali/internal/system/common/environment-variables.h
new file mode 100644 (file)
index 0000000..ca1a9c8
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef DALI_INTERNAL_ADAPTOR_ENVIRONMENT_VARIABLES_H
+#define DALI_INTERNAL_ADAPTOR_ENVIRONMENT_VARIABLES_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * What performance statistics are logged out to dlog
+ * see StatisticsLogOptions in performance-interface.h for values
+ */
+#define DALI_ENV_LOG_PERFORMANCE_STATS "DALI_LOG_PERFORMANCE_STATS"
+
+/**
+ * How frequent in seconds to log out performance statistics
+ */
+#define DALI_ENV_LOG_PERFORMANCE_STATS_FREQUENCY "DALI_LOG_PERFORMANCE_STATS_FREQ"
+
+/**
+ * Where timestamped events for update/render/event and custom events
+ * are output.
+ * see TimeStampOutput in performance-interface.h for values
+ */
+#define DALI_ENV_PERFORMANCE_TIMESTAMP_OUTPUT "DALI_PERFORMANCE_TIMESTAMP_OUTPUT"
+
+/**
+ * Allow control and monitoring of DALi via the network
+ */
+#define DALI_ENV_NETWORK_CONTROL "DALI_NETWORK_CONTROL"
+
+// environment variable for enabling/disabling fps tracking
+#define DALI_ENV_FPS_TRACKING "DALI_FPS_TRACKING"
+
+#define DALI_ENV_UPDATE_STATUS_INTERVAL "DALI_UPDATE_STATUS_INTERVAL"
+
+#define DALI_ENV_OBJECT_PROFILER_INTERVAL "DALI_OBJECT_PROFILER_INTERVAL"
+
+// Pan-Gesture configuration:
+// Prediction Modes 1 & 2:
+#define DALI_ENV_PAN_PREDICTION_MODE                  "DALI_PAN_PREDICTION_MODE"
+#define DALI_ENV_PAN_PREDICTION_AMOUNT                "DALI_PAN_PREDICTION_AMOUNT"
+#define DALI_ENV_PAN_SMOOTHING_MODE                   "DALI_PAN_SMOOTHING_MODE"
+
+// Prediction Mode 1:
+#define DALI_ENV_PAN_MAX_PREDICTION_AMOUNT            "DALI_PAN_MAX_PREDICTION_AMOUNT"
+#define DALI_ENV_PAN_MIN_PREDICTION_AMOUNT            "DALI_PAN_MIN_PREDICTION_AMOUNT"
+#define DALI_ENV_PAN_PREDICTION_AMOUNT_ADJUSTMENT     "DALI_PAN_PREDICTION_AMOUNT_ADJUSTMENT"
+#define DALI_ENV_PAN_SMOOTHING_AMOUNT                 "DALI_PAN_SMOOTHING_AMOUNT"
+
+// Prediction Mode 2:
+#define DALI_ENV_PAN_USE_ACTUAL_TIMES                 "DALI_PAN_USE_ACTUAL_TIMES"
+#define DALI_ENV_PAN_INTERPOLATION_TIME_RANGE         "DALI_PAN_INTERPOLATION_TIME_RANGE"
+#define DALI_ENV_PAN_SCALAR_ONLY_PREDICTION_ENABLED   "DALI_PAN_SCALAR_ONLY_PREDICTION_ENABLED"
+#define DALI_ENV_PAN_TWO_POINT_PREDICTION_ENABLED     "DALI_PAN_TWO_POINT_PREDICTION_ENABLED"
+#define DALI_ENV_PAN_TWO_POINT_PAST_INTERPOLATE_TIME  "DALI_PAN_TWO_POINT_PAST_INTERPOLATE_TIME"
+#define DALI_ENV_PAN_TWO_POINT_VELOCITY_BIAS          "DALI_PAN_TWO_POINT_VELOCITY_BIAS"
+#define DALI_ENV_PAN_TWO_POINT_ACCELERATION_BIAS      "DALI_PAN_TWO_POINT_ACCELERATION_BIAS"
+#define DALI_ENV_PAN_MULTITAP_SMOOTHING_RANGE         "DALI_PAN_MULTITAP_SMOOTHING_RANGE"
+
+// Pan-Gesture miscellaneous:
+#define DALI_ENV_LOG_PAN_GESTURE                      "DALI_LOG_PAN_GESTURE"
+#define DALI_ENV_PAN_MINIMUM_DISTANCE                 "DALI_PAN_MINIMUM_DISTANCE"
+#define DALI_ENV_PAN_MINIMUM_EVENTS                   "DALI_PAN_MINIMUM_EVENTS"
+
+// Pinch-Gesture
+#define DALI_ENV_PINCH_MINIMUM_DISTANCE                     "DALI_PINCH_MINIMUM_DISTANCE"
+#define DALI_ENV_PINCH_MINIMUM_TOUCH_EVENTS                 "DALI_PINCH_MINIMUM_TOUCH_EVENTS"
+#define DALI_ENV_PINCH_MINIMUM_TOUCH_EVENTS_AFTER_START     "DALI_PINCH_MINIMUM_TOUCH_EVENTS_AFTER_START"
+
+// Rotation-Gesture
+#define DALI_ENV_ROTATION_MINIMUM_TOUCH_EVENTS              "DALI_ROTATION_MINIMUM_TOUCH_EVENTS"
+#define DALI_ENV_ROTATION_MINIMUM_TOUCH_EVENTS_AFTER_START  "DALI_ROTATION_MINIMUM_TOUCH_EVENTS_AFTER_START"
+
+/**
+ * The minimum holding time required to be recognized as a long press gesture (milliseconds)
+ */
+#define DALI_ENV_LONG_PRESS_MINIMUM_HOLDING_TIME      "DALI_LONG_PRESS_MINIMUM_HOLDING_TIME"
+
+#define DALI_GLES_CALL_TIME "DALI_GLES_CALL_TIME"
+
+#define DALI_GLES_CALL_ACCUMULATE "DALI_GLES_CALL_ACCUMULATE"
+
+#define DALI_WINDOW_WIDTH "DALI_WINDOW_WIDTH"
+
+#define DALI_WINDOW_HEIGHT "DALI_WINDOW_HEIGHT"
+
+#define DALI_WINDOW_NAME "DALI_WINDOW_NAME"
+
+#define DALI_WINDOW_CLASS_NAME "DALI_WINDOW_CLASS_NAME"
+
+#define DALI_THREADING_MODE "DALI_THREADING_MODE"
+
+#define DALI_REFRESH_RATE "DALI_REFRESH_RATE"
+
+#define DALI_WATCH_REFRESH_RATE "DALI_WATCH_REFRESH_RATE"
+
+#define DALI_WIDGET_REFRESH_RATE "DALI_WIDGET_REFRESH_RATE"
+
+#define DALI_ENV_MULTI_SAMPLING_LEVEL "DALI_MULTI_SAMPLING_LEVEL"
+
+#define DALI_ENV_MAX_TEXTURE_SIZE "DALI_MAX_TEXTURE_SIZE"
+
+#define DALI_RENDER_TO_FBO "DALI_RENDER_TO_FBO"
+
+#define DALI_ENV_DISABLE_DEPTH_BUFFER "DALI_DISABLE_DEPTH_BUFFER"
+
+#define DALI_ENV_DISABLE_STENCIL_BUFFER "DALI_DISABLE_STENCIL_BUFFER"
+
+#define DALI_ENV_WEB_ENGINE_NAME "DALI_WEB_ENGINE_NAME"
+
+#define DALI_ENV_DPI_HORIZONTAL "DALI_DPI_HORIZONTAL"
+
+#define DALI_ENV_DPI_VERTICAL "DALI_DPI_VERTICAL"
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_ENVIRONMENT_VARIABLES_H
diff --git a/dali/internal/system/common/file-closer.h b/dali/internal/system/common/file-closer.h
new file mode 100755 (executable)
index 0000000..27c30ac
--- /dev/null
@@ -0,0 +1,161 @@
+#ifndef DALI_INTERNAL_PLATFORM_FILECLOSER_H
+#define DALI_INTERNAL_PLATFORM_FILECLOSER_H
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/adaptor-framework/file-loader.h>
+
+// EXTERNAL INCLUDES
+#include <cstdio>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Platform
+{
+
+/**
+ * Opens files and closes them later even if an exception is thrown.
+ */
+class FileCloser
+{
+protected: // prevent this class being directly instantiated
+
+  /**
+   * @brief Construct a FileCloser guarding a new FILE* for accessing the path passed in.
+   */
+  FileCloser( const char* const filename, const char* const mode )
+  {
+    DALI_ASSERT_DEBUG( filename != 0 && "Can't open a null filename." );
+    DALI_ASSERT_DEBUG( mode != 0 && "Null mode is undefined behaviour in spec." );
+
+    Dali::FileLoader::FileType fileType = Dali::FileLoader::FileType::TEXT;
+
+    const char* modeStr = mode;
+    while( *modeStr )
+    {
+      switch ( *modeStr )
+      {
+      case 'r':
+        break;
+      case 'b':
+        fileType = FileLoader::FileType::BINARY;
+        break;
+      // Still has to use fopen for append and write modes
+      case 'a':
+      case 'w':
+      case '+':
+        mFile = fopen( filename, mode );
+        return;
+      default:
+        break;
+      }
+
+      ++modeStr;
+    }
+
+    std::streampos bufferSize = 0;
+    if( !Dali::FileLoader::ReadFile( filename, bufferSize, mFileBuffer, fileType ) )
+    {
+      mFile = nullptr;
+    }
+    else
+    {
+      mFile = fmemopen( &mFileBuffer[0], bufferSize, mode );
+    }
+  }
+
+  /**
+   * @brief Construct a FileCloser guarding a FILE* for reading out of the memory buffer passed in.
+   */
+  FileCloser( uint8_t* buffer, size_t dataSize, const char* const mode )
+  : mFile( fmemopen( buffer, dataSize, mode) )
+  {
+  }
+
+  FileCloser( Dali::Vector<uint8_t>& vector, size_t dataSize, const char * const mode )
+  {
+    // Resize the buffer to ensure any null that gets written by
+    // fmemopen is written past the end of any data that is written to the buffer.
+    // (Workaround for a bug in Ubuntu that overwrites null to the last byte of the
+    // data block regardless of whether binary mode was specified. Tizen doesn't write
+    // null if binary mode is specified).
+    size_t bufferSize = dataSize;
+    ++bufferSize;
+    vector.Resize( bufferSize );
+
+    void * const buffer = &vector[0];
+    mFile = fmemopen( buffer, bufferSize, mode );
+
+    DALI_ASSERT_DEBUG( buffer != 0 && "Cant open file on null buffer." );
+    DALI_ASSERT_DEBUG( dataSize > 0 && "Pointless to open file on empty buffer." );
+    DALI_ASSERT_DEBUG( mode != 0 && "Null mode is undefined behaviour in spec." );
+
+    if( mFile == 0 )
+    {
+      DALI_LOG_WARNING( "File open failed for memory buffer at location: \"%p\", of size: \"%u\", in mode: \"%s\".\n", static_cast<void*>(buffer), static_cast<unsigned>(dataSize), mode );
+    }
+  }
+
+   /**
+    * @brief Destroy the FileCloser and clean up its FILE*.
+    */
+  ~FileCloser()
+  {
+    if( mFile != 0 )
+    {
+      const int closeFailed = fclose( mFile );
+
+      if ( closeFailed )
+      {
+        DALI_LOG_WARNING( "File close failed for FILE: \"%p\".\n", static_cast<void*>(mFile) );
+      }
+      mFile = 0;
+    }
+  }
+
+public:
+  /**
+   * @return The FILE* guarded by this object.
+   */
+  FILE* GetFile()
+  {
+    return mFile;
+  }
+
+private:
+
+  // Undefined
+  FileCloser( const FileCloser& fileCloser );
+
+  // Undefined
+  FileCloser& operator=( const FileCloser& fileCloser );
+
+private:
+  FILE* mFile;
+  Dali::Vector<char> mFileBuffer;
+};
+
+} // namespace Platform
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_PLATFORM_FILECLOSER_H
diff --git a/dali/internal/system/common/file-descriptor-monitor.h b/dali/internal/system/common/file-descriptor-monitor.h
new file mode 100644 (file)
index 0000000..dafd064
--- /dev/null
@@ -0,0 +1,116 @@
+#ifndef DALI_INTERNAL_FILE_DESCRIPTOR_MONITOR_H
+#define DALI_INTERNAL_FILE_DESCRIPTOR_MONITOR_H
+
+/*
+ * Copyright (c) 2019 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/signals/callback.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+class Core;
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief Monitors the given file descriptor and whenever anything is written to it, the provided
+ * callback is called
+ */
+class FileDescriptorMonitor
+{
+public:
+
+  /**
+   * @brief Bitmask of file descriptor event types
+   */
+  enum EventType
+  {
+    FD_NO_EVENT = 0x0,
+    FD_READABLE = 0x1, // For example when monitoring a socket, data is available to read from the socket receive buffer
+    FD_WRITABLE = 0x2, // For example when monitoring a socket space is available in socket send buffer
+    FD_ERROR    = 0x4,
+  };
+
+  /**
+   * @brief Constructor.
+   *
+   * The callback will be passed a EventType bitmask to signal what type of events occured on the file
+   * descriptor.
+   * Example:
+   *
+   * MyClass::MyClass()
+   * {
+   *    mFileDescriptorMonitor = new FileDescriptorMonitor( myFd, MakeCallback( this, &MyClass::FdCallback ), FileDescriptorMonitor::FD_READABLE );
+   * }
+   *
+   * void MyClass::FdCallback( EventType event )
+   * {
+   *    if( event & FileDescriptorMonitor::FD_ERROR)
+   *    {
+   *      LOG_ERROR("...)
+   *    }
+   *    if( event & FileDescriptorMonitor::FD_READABLE )
+   *    {
+   *      // read from FD
+   *    }
+   *
+   * }
+   *
+   * @param[in] fileDescriptor  The file descriptor to monitor
+   * @param[in] callback Called when anything is written to the file descriptor
+   * @param[in] eventBitmask Bitmask of what to monitor on the file descriptor ( readable / writable ).
+   * @note The ownership of callback is taken by this class.
+   * @note Under Linux it is possible the file descriptor monitor will signal a fd is
+   * readable or writable even when it isn’t. The developer should check for handle EAGAIN or equivalent
+   * when reading from or write to the fd.
+   */
+  FileDescriptorMonitor( int fileDescriptor, CallbackBase* callback, int eventBitmask );
+
+  /**
+   * Destructor
+   */
+  ~FileDescriptorMonitor();
+
+private:
+
+  // Undefined
+  FileDescriptorMonitor( const FileDescriptorMonitor& fileDescriptorMonitor );
+
+  // Undefined
+  FileDescriptorMonitor& operator=( const FileDescriptorMonitor& fileDescriptorMonitor );
+
+private:
+  struct Impl;
+  Impl* mImpl;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_FILE_DESCRIPTOR_MONITOR_H
diff --git a/dali/internal/system/common/file-reader.h b/dali/internal/system/common/file-reader.h
new file mode 100644 (file)
index 0000000..0b87fe3
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef DALI_INTERNAL_PORTABLE_FILE_READER_H
+#define DALI_INTERNAL_PORTABLE_FILE_READER_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 <dali/devel-api/adaptor-framework/file-stream.h>
+
+// EXTERNAL INCLUDES
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Platform
+{
+
+class FileReader : public FileStream
+{
+public:
+  FileReader( const std::string& filename )
+  : FileStream( filename, FileStream::READ | FileStream::BINARY )
+  {
+  }
+
+  FileReader( Dali::Vector<uint8_t>& vector )
+  : FileStream( &vector[0], vector.Size(), FileStream::READ | FileStream::BINARY )
+  {
+  }
+
+  FileReader( Dali::Vector<uint8_t>& vector, size_t dataSize )
+  : FileStream( &vector[0], dataSize, FileStream::READ | FileStream::BINARY )
+  {
+  }
+
+  FileReader( uint8_t* data, size_t dataSize )
+  : FileStream( data, dataSize, FileStream::READ | FileStream::BINARY )
+  {
+  }
+};
+
+} /* namespace Platform */
+} /* namespace Internal */
+} /* namespace Dali */
+
+#endif // DALI_INTERNAL_PORTABLE_FILE_READER_H
diff --git a/dali/internal/system/common/file-writer.h b/dali/internal/system/common/file-writer.h
new file mode 100644 (file)
index 0000000..6bc0c0c
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef DALI_INTERNAL_PORTABLE_FILE_WRITER_H
+#define DALI_INTERNAL_PORTABLE_FILE_WRITER_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 <dali/devel-api/adaptor-framework/file-stream.h>
+
+// EXTERNAL INCLUDES
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Platform
+{
+
+class FileWriter : public FileStream
+{
+public:
+  /**
+   * Opens a file pointer onto the memory for writing to.
+   * Note, in some implementations, the vector may be resized to be larger than dataSize.
+   * @param[in,out] vector The vector to write to
+   * @param[in] dataSize the amount of data to be written
+   */
+  FileWriter( Dali::Vector<uint8_t>& vector, size_t dataSize )
+  : FileStream( vector, dataSize, FileStream::WRITE | FileStream::BINARY )
+  {
+  }
+};
+
+} /* namespace Platform */
+} /* namespace Internal */
+} /* namespace Dali */
+
+#endif // DALI_INTERNAL_PORTABLE_FILE_WRITER_H
diff --git a/dali/internal/system/common/fps-tracker.cpp b/dali/internal/system/common/fps-tracker.cpp
new file mode 100644 (file)
index 0000000..a146d3e
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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 <dali/internal/system/common/fps-tracker.h>
+
+// EXTERNAL INCLUDES
+#include <cstdio>
+#include <cmath>
+#include <sys/stat.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/environment-options.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const char* DALI_TEMP_UPDATE_FPS_FILE( "/tmp/dalifps.txt" );
+} // unnamed namespace
+
+FpsTracker::FpsTracker( const EnvironmentOptions& environmentOptions )
+: mFpsTrackingSeconds( fabsf( environmentOptions.GetFrameRateLoggingFrequency() ) ),
+  mFrameCount( 0.0f ),
+  mElapsedTime( 0.0f )
+{
+}
+
+FpsTracker::~FpsTracker()
+{
+  if( mFpsTrackingSeconds > 0.f )
+  {
+    OutputFPSRecord();
+  }
+}
+
+void FpsTracker::Track( float secondsFromLastFrame )
+{
+  if( mFpsTrackingSeconds > 0.f )
+  {
+    if ( mElapsedTime < mFpsTrackingSeconds )
+    {
+      mElapsedTime += secondsFromLastFrame;
+      mFrameCount += 1.f;
+    }
+    else
+    {
+      OutputFPSRecord();
+      mFrameCount = 0.f;
+      mElapsedTime = 0.f;
+    }
+  }
+}
+
+bool FpsTracker::Enabled() const
+{
+  return mFpsTrackingSeconds > 0.0f;
+}
+
+void FpsTracker::OutputFPSRecord()
+{
+  float fps = mFrameCount / mElapsedTime;
+  DALI_LOG_FPS("Frame count %.0f, elapsed time %.1fs, FPS: %.2f\n", mFrameCount, mElapsedTime, fps );
+
+  struct stat fileStat;
+
+  // Check file path
+  if( lstat( DALI_TEMP_UPDATE_FPS_FILE, &fileStat ) != 0 )
+  {
+    return;
+  }
+
+  if( !S_ISREG( fileStat.st_mode ) )
+  {
+    return;
+  }
+
+  // Dumps out the frame rate.
+  FILE* outfile = fopen( DALI_TEMP_UPDATE_FPS_FILE, "w" );
+  if( outfile )
+  {
+    char fpsString[10];
+    snprintf(fpsString,sizeof(fpsString),"%.2f \n", fps );
+    fputs( fpsString, outfile ); // ignore the error on purpose
+    fclose( outfile );
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/common/fps-tracker.h b/dali/internal/system/common/fps-tracker.h
new file mode 100644 (file)
index 0000000..c943247
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef DALI_INTERNAL_FPS_TRACKER_H
+#define DALI_INTERNAL_FPS_TRACKER_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class EnvironmentOptions;
+
+/**
+ * Tracks the frames per second.
+ *
+ * Can also output the FPS to a file if required.
+ */
+class FpsTracker
+{
+public:
+
+  /**
+   * Create the FPS Tracker.
+   * @param[in] environmentOptions environment options
+   */
+  FpsTracker( const EnvironmentOptions& environmentOptions );
+
+  /**
+   * Non-virtual destructor; UpdateThread is not suitable as a base class.
+   */
+  ~FpsTracker();
+
+  /**
+   * When DALI_FPS_TRACKING is enabled, this method calculates the frame rates for the specified time period
+   *
+   * @param[in] secondsFromLastFrame The time (in seconds) that has elapsed since the last frame.
+   */
+  void Track(float secondsFromLastFrame);
+
+  /**
+   * @return Whether FPS tracking is enabled.
+   */
+  bool Enabled() const;
+
+private:
+
+  /**
+   * Output the FPS information
+   * when the FSP tracking is enabled,
+   * it is called when the specified tracking period is elapsed or in the destructor when the process finished beforehand
+   */
+  void OutputFPSRecord();
+
+private: // Data
+
+  float mFpsTrackingSeconds;  ///< fps tracking time length in seconds
+  float mFrameCount;          ///< how many frames occurred during tracking period
+  float mElapsedTime;         ///< time elapsed from previous fps tracking output
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_FPS_TRACKER_H
diff --git a/dali/internal/system/common/frame-time-stamp.cpp b/dali/internal/system/common/frame-time-stamp.cpp
new file mode 100644 (file)
index 0000000..47ccce8
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/frame-time-stamp.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+FrameTimeStamp::FrameTimeStamp()
+: frame(0),
+  microseconds(0),
+  bufferIndex(0)
+{
+}
+
+FrameTimeStamp::FrameTimeStamp(unsigned int frame,
+                               uint64_t     microseconds,
+                               unsigned int bufferIndex)
+: frame( frame ),
+  microseconds( microseconds ),
+  bufferIndex( bufferIndex )
+{
+}
+
+FrameTimeStamp::FrameTimeStamp( unsigned int bufferIndex )
+: frame( 0 ),
+  microseconds( 0 ),
+  bufferIndex( bufferIndex )
+{
+}
+
+unsigned int FrameTimeStamp::MicrosecondDiff( const FrameTimeStamp& start,const FrameTimeStamp& end )
+{
+  return end.microseconds - start.microseconds;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
diff --git a/dali/internal/system/common/frame-time-stamp.h b/dali/internal/system/common/frame-time-stamp.h
new file mode 100644 (file)
index 0000000..0fa2397
--- /dev/null
@@ -0,0 +1,79 @@
+#ifndef DALI_INTERNAL_ADAPTOR_FRAME_TIME_STAMP_H
+#define DALI_INTERNAL_ADAPTOR_FRAME_TIME_STAMP_H
+
+/*
+ * Copyright (c) 2019 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 <stdint.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Simple structure to hold information about an event in time
+ * within Dali. For example when rendering started.
+ */
+struct FrameTimeStamp
+{
+
+  static const unsigned int BUFFER_NOT_USED = 2;  ///< no index buffer was used
+
+    /**
+     * Constructor
+     */
+    FrameTimeStamp();
+
+    /**
+     * Constructor
+     * @param frame the frame number
+     * @param microseconds the time from a monotonic clock
+     * @param bufferIndex  double buffered index used for performing an update / render
+     */
+    FrameTimeStamp( unsigned int frame, uint64_t microseconds, unsigned int bufferIndex = BUFFER_NOT_USED );
+
+    /**
+     * Constructor
+     * @param bufferIndex  double buffered index used for performing an update / render
+     */
+    FrameTimeStamp( unsigned int bufferIndex );
+
+    /**
+     * @param start start time
+     * @param end end time
+     * @return difference in microseconds between two time stamps
+     */
+    static unsigned int MicrosecondDiff( const FrameTimeStamp& start,const FrameTimeStamp& end );
+
+    unsigned int frame;            ///< Frame number ( not always available)
+    uint64_t     microseconds;     ///< Microsecond time stamp
+    unsigned int bufferIndex;      ///< The double buffered index used for performing an update / render
+  };
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_FRAME_TIME_STAMP_H
+
diff --git a/dali/internal/system/common/frame-time-stats.cpp b/dali/internal/system/common/frame-time-stats.cpp
new file mode 100644 (file)
index 0000000..115e124
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * 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.
+ *
+ */
+
+// STRUCT HEADER
+#include <dali/internal/system/common/frame-time-stats.h>
+
+// EXTERNAL INCLUDES
+#include <cmath>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const float EPSILON = 0.9f; // rolling average = (average * epsilon) + (current * epsilon)
+const float ONE_OVER_MICROSECONDS_TO_SECONDS = 1.f / 1000000.f; ///< microseconds per second
+}
+
+FrameTimeStats::FrameTimeStats()
+: mTotal( 0.f)
+{
+  mSamples.Reserve( 16 );   // Fill out a little to avoid early reallocations
+
+  Reset();
+}
+
+FrameTimeStats::~FrameTimeStats()
+{
+}
+
+void FrameTimeStats::StartTime( const FrameTimeStamp& timeStamp )
+{
+  // check to make sure we don't get 2 start times in a row
+  if( mTimeState != WAITING_FOR_START_TIME )
+  {
+    Reset();
+  }
+
+  mStart = timeStamp;
+  mTimeState = WAITING_FOR_END_TIME;
+}
+
+void FrameTimeStats::EndTime( const FrameTimeStamp& timeStamp )
+{
+  if( mTimeState != WAITING_FOR_END_TIME )
+  {
+    Reset();
+    return;
+  }
+
+  mTimeState = WAITING_FOR_START_TIME;
+  mRunCount++;
+
+  // frame time in seconds
+  unsigned int elapsedTime = FrameTimeStamp::MicrosecondDiff( mStart, timeStamp);
+
+  mSamples.PushBack( elapsedTime );
+
+  // if the min and max times haven't been set, do that now.
+  if( !mMinMaxTimeSet )
+  {
+    mMin = elapsedTime;
+    mMax = elapsedTime;
+    mMinMaxTimeSet = true;
+  }
+  else
+  {
+    if (elapsedTime < mMin)
+    {
+      mMin= elapsedTime;
+    }
+    else if (elapsedTime > mMax)
+    {
+      mMax = elapsedTime;
+    }
+  }
+
+  mTotal += elapsedTime;
+}
+
+void FrameTimeStats::Reset()
+{
+  mTimeState = WAITING_FOR_START_TIME;
+  mMinMaxTimeSet = false;
+  mMin = 0.f;
+  mMax = 0.f;
+  mRunCount = 0;
+  mStart = FrameTimeStamp();
+  mSamples.Clear();
+}
+
+float FrameTimeStats::GetMaxTime() const
+{
+  return mMax * ONE_OVER_MICROSECONDS_TO_SECONDS;
+}
+
+float FrameTimeStats::GetMinTime() const
+{
+  return mMin * ONE_OVER_MICROSECONDS_TO_SECONDS;
+}
+
+float FrameTimeStats::GetTotalTime() const
+{
+  return mTotal * ONE_OVER_MICROSECONDS_TO_SECONDS;
+}
+
+unsigned int FrameTimeStats::GetRunCount() const
+{
+  return mRunCount;
+}
+
+void FrameTimeStats::CalculateMean( float& meanOut, float& standardDeviationOut ) const
+{
+  if( mSamples.Size() > 0 )
+  {
+    // Mean
+    unsigned int sum = 0;
+    for( Samples::ConstIterator it = mSamples.Begin(), itEnd = mSamples.End(); it != itEnd; ++it )
+    {
+      unsigned int value = *it;
+
+      sum += value;
+    }
+
+    meanOut = static_cast<float>(sum) / mSamples.Size();
+
+    // Variance
+    float variance = 0.0f;
+    for( Samples::ConstIterator it = mSamples.Begin(), itEnd = mSamples.End(); it != itEnd; ++it )
+    {
+      unsigned int value = *it;
+
+      float difference = static_cast<float>(value) - meanOut;
+
+      variance += difference * difference;
+    }
+
+    variance /= mSamples.Size();
+
+    // Standard deviation
+    standardDeviationOut = sqrtf( variance );
+
+    meanOut *= ONE_OVER_MICROSECONDS_TO_SECONDS;
+    standardDeviationOut *= ONE_OVER_MICROSECONDS_TO_SECONDS;
+  }
+  else
+  {
+    meanOut = 0.0f;
+    standardDeviationOut = 0.0f;
+  }
+}
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/common/frame-time-stats.h b/dali/internal/system/common/frame-time-stats.h
new file mode 100644 (file)
index 0000000..5d15c1e
--- /dev/null
@@ -0,0 +1,128 @@
+#ifndef DALI_INTERNAL_ADAPTOR_FRAME_TIME_STATS_H
+#define DALI_INTERNAL_ADAPTOR_FRAME_TIME_STATS_H
+
+/*
+ * Copyright (c) 2019 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 <dali/internal/system/common/frame-time-stamp.h>
+#include <dali/public-api/common/dali-vector.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Used to get statistics about time stamps over a period of time.
+ * E.g. the min, max, total and average time spent inside two markers,
+ * such as UPDATE_START and UPDATE_END
+ */
+struct FrameTimeStats
+{
+  /**
+   * Constructor
+   */
+  FrameTimeStats();
+
+  /**
+   * Destructor, not intended as a base class
+   */
+  ~FrameTimeStats();
+
+  /**
+   * Timer start time
+   * @param timeStamp time stamp
+   */
+   void StartTime( const FrameTimeStamp& timeStamp );
+
+   /**
+    * Timer end time
+    * @param timeStamp time stamp
+    */
+   void EndTime( const FrameTimeStamp& timeStamp );
+
+   /**
+    * Reset all internal counters / state except total time.
+    */
+   void Reset();
+
+   /**
+    * @return maximum time in seconds
+    */
+   float GetMaxTime() const;
+
+   /**
+    * @return minimum time in seconds
+    */
+   float GetMinTime() const;
+
+   /**
+    * @return total time in second
+    */
+   float GetTotalTime() const;
+
+   /**
+    * Get how many times the timer has been started /stopped
+    */
+   unsigned int GetRunCount() const;
+
+   /**
+    * Calculate the mean and standard deviation
+    *
+    * @param[out] mean The return mean value
+    * @param[out] standardDeviation The return standard deviation value
+    */
+   void CalculateMean( float& meanOut, float& standardDeviationOut ) const;
+
+private:
+
+   /**
+    * internal time state.
+    */
+   enum TimeState
+   {
+     WAITING_FOR_START_TIME,    ///< waiting for start time marker
+     WAITING_FOR_END_TIME       ///< waiting for end time marker
+   };
+
+   typedef Dali::Vector< unsigned int > Samples;
+   Samples mSamples;
+
+   unsigned int mMin;                  ///< current minimum value in microseconds
+   unsigned int mMax;                  ///< current maximum value in microseconds
+   unsigned int mTotal;                ///< current total in in microseconds
+   unsigned int mRunCount;      ///< how many times the timer has been start / stopped
+   FrameTimeStamp mStart;       ///< start time stamp, to calculate the diff
+   TimeState mTimeState:1;      ///< time state
+   bool mMinMaxTimeSet:1;       ///< whether the min-max values have been configured
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_FRAME_TIME_STATS_H
+
diff --git a/dali/internal/system/common/kernel-trace.cpp b/dali/internal/system/common/kernel-trace.cpp
new file mode 100644 (file)
index 0000000..baa7039
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/kernel-trace.h>
+
+// EXTERNAL HEADERS
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+
+// INTERNAL HEADERS
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const char* TRACE_MARKER_FILE = "/sys/kernel/debug/tracing/trace_marker";
+const char* SPI_PREFIX = "SPI_EV_DALI_"; ///< prefix to let the SPI tool know it should read the trace
+}// un-named name space
+
+KernelTrace::KernelTrace()
+: mFileDescriptor( 0 ),
+  mLoggedError( false )
+{
+}
+
+KernelTrace::~KernelTrace()
+{
+  if( mFileDescriptor )
+  {
+    close( mFileDescriptor );
+  }
+}
+
+// If this function doesn't appear to work, you can test manually on the device.
+// $ cd /sys/kernel/debug/tracing
+//
+// If the folder doesn't exist then the kernel needs to be re-built with ftrace enabled
+// If it does exist, then you can continue to test ftrace is working:
+//
+// $ echo 1 > tracing_enabled
+// $ echo "test" > trace_marker
+// $ cat trace
+// should print out test message
+// If the message did not get added to the trace, then check you have write permissions to the trace_marker file.
+//
+//
+void KernelTrace::Trace( const PerformanceMarker& marker, const std::string& traceMessage )
+{
+  // Open the trace_marker file
+  if( mFileDescriptor == 0 )
+  {
+    mFileDescriptor = open( TRACE_MARKER_FILE , O_WRONLY);
+    if( mFileDescriptor == -1 )
+    {
+      // we want to keep trying to open it, so it will start working if someone fixes
+      // the permissions on the trace marker
+      mFileDescriptor = 0;
+
+      // first time we fail to open the file, log an error
+      if( !mLoggedError )
+      {
+        mLoggedError = true;
+        DALI_LOG_ERROR("Failed to open /sys/kernel/debug/tracing/trace_marker for writing please check file permissions.\n");
+      }
+
+    }
+  }
+
+  if( mFileDescriptor > 0 )
+  {
+      std::string msg( SPI_PREFIX );
+      msg+=traceMessage;
+
+      int ret = write( mFileDescriptor, msg.c_str(), msg.length() );
+          // if it failed then close the file description and try again next time we trace
+      if( ret < 0 )
+      {
+        close( mFileDescriptor );
+        mFileDescriptor = 0;
+      }
+  }
+}
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
diff --git a/dali/internal/system/common/kernel-trace.h b/dali/internal/system/common/kernel-trace.h
new file mode 100644 (file)
index 0000000..07c017d
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef DALI_INTERNAL_ADAPTOR_KERNEL_TRACE_H
+#define DALI_INTERNAL_ADAPTOR_KERNEL_TRACE_H
+
+/*
+ * Copyright (c) 2019 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/internal/network/common/trace-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Concrete Kernel Tracing Interface.
+ * Used to log trace messages to the kernel using ftrace.
+ *
+ */
+class KernelTrace : public TraceInterface
+{
+public:
+
+  /**
+   * Constructor
+   */
+  KernelTrace();
+
+  /**
+   * Destructor
+   */
+  virtual ~KernelTrace();
+
+  /**
+   * @copydoc KernelTracerInterface::KernelTrace()
+   */
+  virtual void Trace( const PerformanceMarker& marker, const std::string& traceMessage );
+
+private:
+
+  int mFileDescriptor;
+  bool mLoggedError:1;
+
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_KERNEL_TRACE_H
diff --git a/dali/internal/system/common/locale-utils.cpp b/dali/internal/system/common/locale-utils.cpp
new file mode 100755 (executable)
index 0000000..1979e2e
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/locale-utils.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace Locale
+{
+
+namespace
+{
+
+struct LocaleDirectionInfo
+{
+  const char * locale;
+  const char * name;
+  Locale::Direction direction;
+};
+
+const LocaleDirectionInfo LOCALE_DIRECTION_LOOKUP_TABLE[] =
+{
+  { "af", "Afrikaans",          Locale::LeftToRight },
+  { "am", "Amharic",            Locale::LeftToRight },
+  { "ar", "Arabic",             Locale::RightToLeft },
+  { "as", "Assamese",           Locale::LeftToRight },
+  { "az", "Azerbaijani",        Locale::LeftToRight },
+  { "be", "Belarusian",         Locale::LeftToRight },
+  { "bg", "Bulgarian",          Locale::LeftToRight },
+  { "bn", "Bengali",            Locale::LeftToRight },
+  { "bo", "Tibetan",            Locale::LeftToRight },
+  { "bs", "Bosnian",            Locale::LeftToRight },
+  { "ca", "Catalan",            Locale::LeftToRight },
+  { "ck", "Iraq",               Locale::RightToLeft },
+  { "cs", "Czech",              Locale::LeftToRight },
+  { "cy", "Welsh",              Locale::LeftToRight },
+  { "da", "Danish",             Locale::LeftToRight },
+  { "de", "German",             Locale::LeftToRight },
+  { "dv", "Divehi",             Locale::RightToLeft },
+  { "el", "Greek",              Locale::LeftToRight },
+  { "en", "English",            Locale::LeftToRight },
+  { "es", "Spanish",            Locale::LeftToRight },
+  { "et", "Estonian",           Locale::LeftToRight },
+  { "eu", "Basque",             Locale::LeftToRight },
+  { "fa", "Farsi",              Locale::RightToLeft },
+  { "fi", "Finnish",            Locale::LeftToRight },
+  { "fo", "Faroese",            Locale::LeftToRight },
+  { "fr", "French",             Locale::LeftToRight },
+  { "gd", "Gaelic",             Locale::LeftToRight },
+  { "gl", "Galician",           Locale::LeftToRight },
+  { "gn", "Guarani",            Locale::LeftToRight },
+  { "gu", "Gujarati",           Locale::LeftToRight },
+  { "ha", "Hausa",              Locale::LeftToRight },
+  { "he", "Hebrew",             Locale::RightToLeft },
+  { "hi", "Hindi",              Locale::LeftToRight },
+  { "hr", "Croatian",           Locale::LeftToRight },
+  { "hu", "Hungarian",          Locale::LeftToRight },
+  { "hy", "Armenian",           Locale::LeftToRight },
+  { "id", "Indonesian",         Locale::LeftToRight },
+  { "is", "Icelandic",          Locale::LeftToRight },
+  { "it", "Italian",            Locale::LeftToRight },
+  { "ja", "Japanese",           Locale::LeftToRight },
+  { "ka", "Georgian",           Locale::LeftToRight },
+  { "kk", "Kazakh",             Locale::LeftToRight },
+  { "km", "Khmer",              Locale::LeftToRight },
+  { "kn", "Kannada",            Locale::LeftToRight },
+  { "ko", "Korean",             Locale::LeftToRight },
+  { "ks", "Kashmiri",           Locale::LeftToRight },
+  { "la", "Latin",              Locale::LeftToRight },
+  { "lo", "Lao",                Locale::LeftToRight },
+  { "lt", "Lithuanian",         Locale::LeftToRight },
+  { "lv", "Latvian",            Locale::LeftToRight },
+  { "mi", "Maori",              Locale::LeftToRight },
+  { "mk", "FYRO Macedonia",     Locale::LeftToRight },
+  { "ml", "Malayalam",          Locale::LeftToRight },
+  { "mn", "Mongolian",          Locale::LeftToRight },
+  { "mr", "Marathi",            Locale::LeftToRight },
+  { "ms", "Malay",              Locale::LeftToRight },
+  { "mt", "Maltese",            Locale::LeftToRight },
+  { "my", "Burmese",            Locale::LeftToRight },
+  { "nb", "Norwegian: Bokml",   Locale::LeftToRight },
+  { "ne", "Nepali",             Locale::LeftToRight },
+  { "nl", "Dutch",              Locale::LeftToRight },
+  { "nn", "Norwegian: Nynorsk", Locale::LeftToRight },
+  { "or", "Oriya",              Locale::LeftToRight },
+  { "pa", "Punjabi",            Locale::LeftToRight },
+  { "pl", "Polish",             Locale::LeftToRight },
+  { "pt", "Portuguese",         Locale::LeftToRight },
+  { "rm", "Raeto-Romance",      Locale::LeftToRight },
+  { "ro", "Romanian",           Locale::LeftToRight },
+  { "ru", "Russian",            Locale::LeftToRight },
+  { "sa", "Sanskrit",           Locale::LeftToRight },
+  { "sb", "Sorbian",            Locale::LeftToRight },
+  { "sd", "Sindhi",             Locale::LeftToRight },
+  { "si", "Sinhala",            Locale::LeftToRight },
+  { "sk", "Slovak",             Locale::LeftToRight },
+  { "sl", "Slovenian",          Locale::LeftToRight },
+  { "so", "Somali",             Locale::LeftToRight },
+  { "sq", "Albanian",           Locale::LeftToRight },
+  { "sr", "Serbian",            Locale::LeftToRight },
+  { "sv", "Swedish",            Locale::LeftToRight },
+  { "sw", "Swahili",            Locale::LeftToRight },
+  { "ta", "Tamil",              Locale::LeftToRight },
+  { "te", "Telugu",             Locale::LeftToRight },
+  { "tg", "Tajik",              Locale::LeftToRight },
+  { "th", "Thai",               Locale::LeftToRight },
+  { "tk", "Turkmen",            Locale::LeftToRight },
+  { "tn", "Setsuana",           Locale::LeftToRight },
+  { "tr", "Turkish",            Locale::LeftToRight },
+  { "ts", "Tsonga",             Locale::LeftToRight },
+  { "tt", "Tatar",              Locale::LeftToRight },
+  { "uk", "Ukrainian",          Locale::LeftToRight },
+  { "ur", "Urdu",               Locale::RightToLeft },
+  { "uz", "Uzbek",              Locale::LeftToRight },
+  { "vi", "Vietnamese",         Locale::LeftToRight },
+  { "xh", "Xhosa",              Locale::LeftToRight },
+  { "yi", "Yiddish",            Locale::RightToLeft },
+  { "zh", "Chinese",            Locale::LeftToRight },
+  { "zu", "Zulu",               Locale::LeftToRight },
+
+  { NULL, NULL, Locale::LeftToRight }
+};
+
+} // unnamed namespace
+
+Locale::Direction GetDirection( const std::string& locale )
+{
+  Locale::Direction direction( Locale::LeftToRight );
+
+  if ( !locale.empty() && locale.size() > 2 )
+  {
+    for ( const LocaleDirectionInfo* iter = &LOCALE_DIRECTION_LOOKUP_TABLE[0]; iter->locale; ++iter )
+    {
+      if ( !locale.compare( 0, 2, iter->locale ) )
+      {
+        direction = iter->direction;
+        break;
+      }
+    }
+  }
+
+  return direction;
+}
+
+} // namespace Locale
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/common/locale-utils.h b/dali/internal/system/common/locale-utils.h
new file mode 100644 (file)
index 0000000..fcfbd07
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef DALI_INTERNAL_LOCALE_UTILS_H
+#define DALI_INTERNAL_LOCALE_UTILS_H
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <string>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace Locale
+{
+
+enum Direction
+{
+  LeftToRight,
+  RightToLeft,
+};
+
+Locale::Direction GetDirection( const std::string& locale );
+
+} // namespace Locale
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_LOCALE_UTILS_H
diff --git a/dali/internal/system/common/logging.h b/dali/internal/system/common/logging.h
new file mode 100644 (file)
index 0000000..6f07e2a
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef DALI_TIZEN_LOGGING_H
+#define DALI_TIZEN_LOGGING_H
+
+/*
+ * Copyright (c) 2019 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/integration-api/debug.h>
+
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+/**
+ * @copydoc Dali::Integration::Log:LogMessage
+ */
+void LogMessage(Dali::Integration::Log::DebugPriority level, std::string& message);
+
+} // namespace TizenPlatform
+
+} // namespace Dali
+
+#endif // DALI_TIZEN_LOGGING_H
diff --git a/dali/internal/system/common/object-profiler.cpp b/dali/internal/system/common/object-profiler.cpp
new file mode 100644 (file)
index 0000000..6ddc44b
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 20187 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/object-profiler.h>
+
+// EXTERNAL INCLUDES
+#include <stdlib.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/profiling.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/object/type-registry.h>
+
+using std::string;
+using namespace Dali::Integration::Profiling;
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+ObjectProfiler::ObjectProfiler( uint32_t timeInterval )
+{
+  // This class must be created after the Stage; this means it doesn't count the initial objects
+  // that are created by the stage (base layer, default camera actor)
+  mObjectRegistry = Dali::Stage::GetCurrent().GetObjectRegistry();
+
+  mTimer = Dali::Timer::New( timeInterval * 1000 );
+  mTimer.TickSignal().Connect( this, &ObjectProfiler::OnTimeout );
+  mTimer.Start();
+
+  mObjectRegistry.ObjectCreatedSignal().Connect( this, &ObjectProfiler::OnObjectCreated );
+  mObjectRegistry.ObjectDestroyedSignal().Connect( this, &ObjectProfiler::OnObjectDestroyed );
+}
+
+ObjectProfiler::~ObjectProfiler()
+{
+}
+
+void ObjectProfiler::DisplayInstanceCounts()
+{
+  for( auto&& element : mInstanceCountContainer )
+  {
+    std::size_t memorySize = GetMemorySize( element.first, element.second );
+    if( memorySize > 0 )
+    {
+      LogMessage( Debug::DebugInfo, "%-30s: % 4d  Memory MemorySize: ~% 6.1f kB\n",
+                  element.first.c_str(), element.second, memorySize / 1024.0f );
+    }
+    else
+    {
+      LogMessage( Debug::DebugInfo, "%-30s: % 4d\n",
+                  element.first.c_str(), element.second );
+    }
+  }
+  LogMessage(Debug::DebugInfo, "\n");
+}
+
+bool ObjectProfiler::OnTimeout()
+{
+  DisplayInstanceCounts();
+  return true;
+}
+
+void ObjectProfiler::OnObjectCreated(BaseHandle handle)
+{
+  string theType = handle.GetTypeName();
+  if( theType.empty() )
+  {
+    DALI_LOG_ERROR("Object created from an unregistered type\n");
+    theType = "<Unregistered>";
+  }
+
+  mInstanceTypes.push_back(InstanceTypePair(&handle.GetBaseObject(), theType));
+
+  bool found = false;
+  for( auto&& element : mInstanceCountContainer )
+  {
+    if( element.first == theType )
+    {
+      element.second++;
+      found = true;
+    }
+  }
+  if( !found )
+  {
+    InstanceCountPair instanceCount( theType, 1 );
+    mInstanceCountContainer.emplace_back( instanceCount );
+  }
+}
+
+void ObjectProfiler::OnObjectDestroyed(const Dali::RefObject* object)
+{
+  const BaseObject* baseObject = static_cast<const BaseObject*>(object);
+
+  const auto end = mInstanceTypes.end();
+  for( auto iter = mInstanceTypes.begin(); iter != end; ++iter )
+  {
+    if( iter->first == baseObject )
+    {
+      const auto& theType = iter->second;
+      if( !theType.empty() )
+      {
+        auto&& countIter = std::find_if( mInstanceCountContainer.begin(),
+                                         mInstanceCountContainer.end(),
+                                         [theType] ( const InstanceCountPair& instance )
+                                                   { return instance.first == theType; } );
+        if( countIter != mInstanceCountContainer.end() )
+        {
+          (*countIter).second--;
+        }
+      }
+      mInstanceTypes.erase( iter );
+      return;
+    }
+  }
+}
+
+std::size_t ObjectProfiler::GetMemorySize( const std::string& name, uint32_t count )
+{
+  struct MemoryMemorySize
+  {
+    std::string name;
+    std::size_t memorySize;
+  };
+  MemoryMemorySize memoryMemorySizes[] =
+    {
+      { "Animation", ANIMATION_MEMORY_SIZE },
+      { "Constraint", CONSTRAINT_MEMORY_SIZE },
+      { "Actor", ACTOR_MEMORY_SIZE },
+      { "Layer", LAYER_MEMORY_SIZE },
+      { "CameraActor", CAMERA_ACTOR_MEMORY_SIZE },
+      { "Image", IMAGE_MEMORY_SIZE },
+      { "Renderer", RENDERER_MEMORY_SIZE },
+      { "Geometry", GEOMETRY_MEMORY_SIZE },
+      { "PropertyBuffer", PROPERTY_BUFFER_MEMORY_SIZE },
+      { "TextureSet", TEXTURE_SET_MEMORY_SIZE },
+      { "Sampler", SAMPLER_MEMORY_SIZE },
+      { "Shader", SHADER_MEMORY_SIZE },
+    };
+
+  for( size_t i=0; i<sizeof(memoryMemorySizes)/sizeof(MemoryMemorySize); i++ )
+  {
+    if( memoryMemorySizes[i].name.compare(name) == 0 )
+    {
+      return count * memoryMemorySizes[i].memorySize;
+    }
+  }
+  return 0;
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/dali/internal/system/common/object-profiler.h b/dali/internal/system/common/object-profiler.h
new file mode 100644 (file)
index 0000000..14b92b0
--- /dev/null
@@ -0,0 +1,100 @@
+#ifndef DALI_ADAPTOR_OBJECT_PROFILER_H
+#define DALI_ADAPTOR_OBJECT_PROFILER_H
+
+/*
+ * Copyright (c) 2019 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 <cstdint> // uint32_t
+#include <cstddef> // size_t
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/object/object-registry.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/signals/connection-tracker.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/timer.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * Class to profile the number of instances of Objects in the system
+ */
+class ObjectProfiler : public ConnectionTracker
+{
+public:
+
+  /**
+   * Constructor
+   * @param timeInterval to specify the frequency of reporting
+   */
+  ObjectProfiler( uint32_t timeInterval );
+
+  /**
+   * Destructor
+   */
+  ~ObjectProfiler();
+
+  /**
+   * Display a list of types with the current number of instances in the system
+   */
+  void DisplayInstanceCounts();
+
+private:
+  /**
+   * If timer is running, display the instance counts
+   */
+  bool OnTimeout();
+
+  /**
+   * Callback used when objects are created. Increases instance count for that object type
+   * @param[in] handle of the created object
+   */
+  void OnObjectCreated( BaseHandle handle );
+
+  /**
+   * Callback used when objects are created. Decreases instance count for that object type
+   * @param[in] object The object being destroyed
+   */
+  void OnObjectDestroyed( const Dali::RefObject* object );
+
+  /**
+   * Get the memory size of the given object
+   */
+  std::size_t GetMemorySize( const std::string& name, uint32_t count );
+
+private:
+
+  using InstanceCountPair = std::pair< const std::string, uint32_t >;
+  using InstanceTypePair = std::pair< BaseObject*, std::string >;
+
+  Dali::ObjectRegistry    mObjectRegistry;
+  Dali::Timer             mTimer;
+  std::vector< InstanceCountPair > mInstanceCountContainer;
+  std::vector< InstanceTypePair >  mInstanceTypes;
+};
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // DALI_ADAPTOR_OBJECT_PROFILER_H
diff --git a/dali/internal/system/common/performance-interface-factory.cpp b/dali/internal/system/common/performance-interface-factory.cpp
new file mode 100644 (file)
index 0000000..80426ee
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/performance-interface-factory.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/performance-server.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+PerformanceInterface* PerformanceInterfaceFactory::CreateInterface(
+                                 AdaptorInternalServices& adaptorServices,
+                                 const EnvironmentOptions& environmentOptions  )
+{
+  return new PerformanceServer( adaptorServices, environmentOptions );
+}
+
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/common/performance-interface-factory.h b/dali/internal/system/common/performance-interface-factory.h
new file mode 100644 (file)
index 0000000..85e63ac
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef DALI_INTERNAL_BASE_PERFORMANCE_INTERFACE_FACTORY_H
+#define DALI_INTERNAL_BASE_PERFORMANCE_INTERFACE_FACTORY_H
+
+/*
+ * Copyright (c) 2019 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/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/adaptor-internal-services.h>
+#include <dali/internal/system/common/environment-options.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Performance interface factory class
+ *
+ */
+class PerformanceInterfaceFactory
+{
+public:
+
+  /**
+   * Create a new concrete implementation of the performance interface.
+   * @param adaptorServices adaptor internal services
+   * @param environmentOptions environment options
+   * @return pointer to a new performance interface
+   */
+  static PerformanceInterface* CreateInterface( AdaptorInternalServices& adaptorServices,
+                                                const EnvironmentOptions& environmentOptions );
+
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_BASE_PERFORMANCE_INTERFACE_FACTORY_H
diff --git a/dali/internal/system/common/performance-interface.h b/dali/internal/system/common/performance-interface.h
new file mode 100644 (file)
index 0000000..d1db387
--- /dev/null
@@ -0,0 +1,184 @@
+#ifndef DALI_INTERNAL_BASE_PERFORMANCE_INTERFACE_H
+#define DALI_INTERNAL_BASE_PERFORMANCE_INTERFACE_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Abstract Performance Interface.
+ * Used by the Adaptor to store performance metrics.
+ *
+ */
+class PerformanceInterface
+{
+public:
+
+  typedef unsigned short ContextId;   ///< Type to represent a context ID
+
+  /**
+   * bitmask of statistics logging options.
+   * Used for output data like min/max/average time spent in event, update,render and custom tasks.
+   * E.g.
+   * Event, min 0.04 ms, max 5.27 ms, total (0.1 secs), avg 0.28 ms, std dev 0.73 ms
+   * Update, min 0.29 ms, max 0.91 ms, total (0.5 secs), avg 0.68 ms, std dev 0.15 ms
+   * Render, min 0.33 ms, max 0.97 ms, total (0.6 secs), avg 0.73 ms, std dev 0.17 ms
+   * TableViewInit, min 76.55 ms, max 76.55 ms, total (0.1 secs), avg 76.55 ms, std dev 0.00 ms
+   */
+  enum StatisticsLogOptions
+  {
+    DISABLED             = 0,
+    LOG_EVERYTHING       = 1 << 0, ///< Bit 0 (1), log all statistics to the DALi log
+    LOG_UPDATE_RENDER    = 1 << 1, ///< Bit 1 (2), log update and render statistics to the DALi log
+    LOG_EVENT_PROCESS    = 1 << 2, ///< Bit 2 (4), log event task statistics to the DALi log
+    LOG_CUSTOM_MARKERS   = 1 << 3, ///< Bit 3 (8), log custom marker statistics to the DALi log
+  };
+
+  /**
+   * bitmask of time stamp output options.
+   * E.g. DALI_PERFORMANCE_TIMESTAMP_OUTPUT = 1 dali-demo
+   * Used for logging out time stamped markers for detailed analysis (see MarkerType, for the markers logged)
+   * Typical output would look like:
+   *   379.059025 (seconds), V_SYNC
+   *   379.059066 (seconds), UPDATE_START
+   *   379.059747 (seconds), UPDATE_END
+   *   379.059820 (seconds), RENDER_START
+   *   379.060708 (seconds), RENDER_END
+   *   379.075795 (seconds), V_SYNC
+   *   379.076444 (seconds), MY_CUSTOM_MARKER_START  ( customer marker using PerformanceLogger public API).
+   *   379.077353 (seconds), MY_CUSTOM_MARKER_END  ( customer marker using PerformanceLogger public API).
+   */
+  enum TimeStampOutput
+  {
+    NO_TIME_STAMP_OUTPUT         = 0,
+    OUTPUT_DALI_LOG              = 1 << 0, ///< Bit 0 (1), log markers to DALi log
+    OUTPUT_KERNEL_TRACE          = 1 << 1, ///< Bit 1 (2), log makers to kernel trace
+    OUTPUT_SYSTEM_TRACE          = 1 << 2, ///< Bit 2 (4), log markers to system trace
+    OUTPUT_NETWORK               = 1 << 3, ///< Bit 3 (8), log markers to network client
+  };
+
+  /**
+   * enum for difference performance markers.
+   * Please modify the name lookup table in performance-interface.cpp
+   * file if adding new markers (the order must match one to one).
+   */
+  enum MarkerType
+  {
+    VSYNC     = 0,        ///< V-Sync
+    UPDATE_START ,        ///< Update start
+    UPDATE_END   ,        ///< Update end
+    RENDER_START ,        ///< Render start
+    RENDER_END   ,        ///< Render end
+    SWAP_START   ,        ///< SwapBuffers Start
+    SWAP_END     ,        ///< SwapBuffers End
+    PROCESS_EVENTS_START, ///< Process events start (e.g. touch event)
+    PROCESS_EVENTS_END,   ///< Process events end
+    PAUSED       ,        ///< Pause start
+    RESUME       ,        ///< Resume start
+    START        ,        ///< The start of custom tracking
+    END                   ///< The end of custom tracking
+  };
+
+  /**
+   * Constructor.
+   */
+  PerformanceInterface() {}
+
+  /**
+   * Virtual destructor
+   */
+  virtual ~PerformanceInterface() {};
+
+  /**
+   * @brief Add a new context with a given name
+   *
+   * @param[in] name The name of the context
+   * @return Return the unique id for this context
+   */
+  virtual ContextId AddContext( const char* name ) = 0;
+
+  /**
+   * @brief Remove a context from use
+   *
+   * @param[in] contextId The ID of the context to remove
+   */
+  virtual void RemoveContext( ContextId contextId ) = 0;
+
+  /**
+   * @brief Add a performance marker
+   * This function can be called from ANY THREAD.
+   * The default context 0 Event/Update/Render is assumed.
+   * @param[in] markerType performance marker type
+   */
+  virtual void AddMarker( MarkerType markerType ) = 0;
+
+  /**
+   * @brief Add a performance marker for a used defined context
+   * This function can be called from ANY THREAD.
+   * @param[in] markerType performance marker type
+   * @param[in] contextId The context of the marker. This must be one generated by AddContext.
+   */
+  virtual void AddMarker( MarkerType markerType, ContextId contextId ) = 0;
+
+  /**
+   * @brief Set the logging level and frequency
+   * @param[in] StatisticsLogOptions  0 = disabled, >0 bitmask of StatisticsLogOptions
+   * @param[in] timeStampOutput 0 = disabled, > 0 bitmask of TimeStampOutput options.
+   * @param[in] logFrequency how often to log out in seconds
+   */
+  virtual void SetLogging( unsigned int statisticsLogOptions, unsigned int timeStampOutput, unsigned int logFrequency) = 0;
+
+  /**
+   * @brief Set the logging frequency for an individual context
+   *
+   * @param[in] logFrequency how often to log out in seconds
+   */
+  virtual void SetLoggingFrequency( unsigned int logFrequency, ContextId contextId ) = 0;
+
+  /**
+   * @brief Set logging on or off for a particular context
+   *
+   * @param[in] enable Enable logging or not
+   * @param[in] contextId The id of the context to log. This must be one generated by AddContext.
+   */
+  virtual void EnableLogging( bool enable, ContextId contextId ) = 0;
+
+private:
+
+  // Undefined copy constructor.
+  PerformanceInterface( const PerformanceInterface& );
+
+  // Undefined assignment operator.
+  PerformanceInterface& operator=( const PerformanceInterface& );
+
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif
diff --git a/dali/internal/system/common/performance-logger-impl.cpp b/dali/internal/system/common/performance-logger-impl.cpp
new file mode 100644 (file)
index 0000000..adb4283
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/performance-logger-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+PerformanceInterface* GetPerformanceInterface()
+{
+  if( Adaptor::IsAvailable() )
+  {
+    return Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).GetPerformanceInterface();
+  }
+
+  return NULL;
+}
+
+} // Anonymous namespace
+
+PerformanceLoggerPtr PerformanceLogger::New( const char* name )
+{
+  PerformanceLoggerPtr logger = new PerformanceLogger( name );
+  return logger;
+}
+
+PerformanceLogger::PerformanceLogger( const char* name )
+: mContext( 0 )
+{
+  PerformanceInterface* performance = GetPerformanceInterface();
+  if( performance )
+  {
+    mContext = performance->AddContext( name );
+  }
+}
+
+PerformanceLogger::~PerformanceLogger()
+{
+  PerformanceInterface* performance = GetPerformanceInterface();
+  if( performance )
+  {
+    performance->RemoveContext( mContext );
+  }
+}
+
+void PerformanceLogger::AddMarker( Dali::PerformanceLogger::Marker markerType )
+{
+  PerformanceInterface* performance = GetPerformanceInterface();
+  if( performance )
+  {
+    PerformanceInterface::MarkerType newMarkerType = PerformanceInterface::START;
+    switch( markerType )
+    {
+      case Dali::PerformanceLogger::START_EVENT:
+      {
+        newMarkerType = PerformanceInterface::START;
+        break;
+      }
+      case Dali::PerformanceLogger::END_EVENT:
+      {
+        newMarkerType = PerformanceInterface::END;
+        break;
+      }
+    }
+
+    performance->AddMarker( newMarkerType, mContext );
+  }
+}
+
+void PerformanceLogger::SetLoggingFrequency( unsigned int logFrequency)
+{
+  PerformanceInterface* performance = GetPerformanceInterface();
+  if( performance )
+  {
+    performance->SetLoggingFrequency( logFrequency, mContext );
+  }
+}
+
+void PerformanceLogger::EnableLogging( bool enable )
+{
+  PerformanceInterface* performance = GetPerformanceInterface();
+  if( performance )
+  {
+    performance->EnableLogging( enable, mContext );
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/common/performance-logger-impl.h b/dali/internal/system/common/performance-logger-impl.h
new file mode 100644 (file)
index 0000000..461a3b1
--- /dev/null
@@ -0,0 +1,126 @@
+#ifndef DALI_INTERNAL_PERFORMANCE_LOGGER_H
+#define DALI_INTERNAL_PERFORMANCE_LOGGER_H
+
+/*
+ * Copyright (c) 2019 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/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/performance-interface.h>
+#include <dali/devel-api/adaptor-framework/performance-logger.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class PerformanceLogger;
+
+typedef IntrusivePtr<PerformanceLogger> PerformanceLoggerPtr;
+
+/**
+ * @brief Interface for the performance logger
+ */
+class PerformanceLogger : public BaseObject
+{
+public:
+
+  /**
+   * @brief Create a new logger
+   *
+   * @param[in] name The name of the logger. This needs to be a compile-time literal and alive for the whole lifetime of the performance logger.
+   * @return a new logger
+   */
+  static PerformanceLoggerPtr New( const char* name );
+
+  /**
+   * Constructor
+   * @param[in] name The name to assing to the logger
+   */
+  PerformanceLogger( const char* name );
+
+  /**
+   * Destructor.
+   */
+  virtual ~PerformanceLogger();
+
+  /**
+   * Add a performance marker
+   *
+   * @param markerType Performance marker type
+   */
+  void AddMarker( Dali::PerformanceLogger::Marker markerType );
+
+  /**
+   * Set the logging frequency
+   *
+   * @param logFrequency how often to log out in seconds
+   */
+  void SetLoggingFrequency( unsigned int logFrequency);
+
+  /**
+   * Set logging on or off for this logger
+   *
+   * @param[in] enable Enable logging or not
+   */
+  void EnableLogging( bool enable );
+
+private: // Implementation
+
+  // not implemented
+  PerformanceLogger( const PerformanceLogger& );
+  PerformanceLogger& operator=( const PerformanceLogger& );
+
+private:
+
+  PerformanceInterface::ContextId mContext;   ///< Context of this logger
+
+};
+
+// Helpers for public-api forwarding methods
+
+inline static Internal::Adaptor::PerformanceLogger& GetImplementation( Dali::PerformanceLogger& logger )
+{
+  DALI_ASSERT_ALWAYS( logger && "PerformanceLogger handle is empty" );
+
+  BaseObject& handle = logger.GetBaseObject();
+
+  return static_cast< Internal::Adaptor::PerformanceLogger& >( handle );
+}
+
+inline static const  Internal::Adaptor::PerformanceLogger& GetImplementation( const Dali::PerformanceLogger& logger )
+{
+  DALI_ASSERT_ALWAYS( logger && "PerformanceLogger handle is empty" );
+
+  const BaseObject& handle = logger.GetBaseObject();
+
+  return static_cast< const Internal::Adaptor::PerformanceLogger& >( handle );
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_PERFORMANCE_LOGGER_H
diff --git a/dali/internal/system/common/performance-marker.cpp b/dali/internal/system/common/performance-marker.cpp
new file mode 100644 (file)
index 0000000..e5e0cdd
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/performance-marker.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+struct NamePair
+{
+  PerformanceInterface::MarkerType type;
+  const char* const name;
+  PerformanceMarker::MarkerFilter group;
+  PerformanceMarker::MarkerEventType eventType;
+};
+
+const NamePair MARKER_LOOKUP[] =
+{
+    // timed event names must be postfixed with with _START and _END
+    // this is to allow tracers to extract the event name by removing the _START, _END strings
+    //
+    { PerformanceInterface::VSYNC       ,         "V_SYNC"               , PerformanceMarker::V_SYNC_EVENTS, PerformanceMarker::SINGLE_EVENT      },
+    { PerformanceInterface::UPDATE_START ,        "UPDATE_START"         , PerformanceMarker::UPDATE,        PerformanceMarker::START_TIMED_EVENT },
+    { PerformanceInterface::UPDATE_END   ,        "UPDATE_END"           , PerformanceMarker::UPDATE,        PerformanceMarker::END_TIMED_EVENT   },
+    { PerformanceInterface::RENDER_START ,        "RENDER_START"         , PerformanceMarker::RENDER,        PerformanceMarker::START_TIMED_EVENT },
+    { PerformanceInterface::RENDER_END   ,        "RENDER_END"           , PerformanceMarker::RENDER,        PerformanceMarker::END_TIMED_EVENT   },
+    { PerformanceInterface::SWAP_START   ,        "SWAP_START"           , PerformanceMarker::SWAP_BUFFERS,  PerformanceMarker::START_TIMED_EVENT },
+    { PerformanceInterface::SWAP_END     ,        "SWAP_END"             , PerformanceMarker::SWAP_BUFFERS,  PerformanceMarker::END_TIMED_EVENT   },
+    { PerformanceInterface::PROCESS_EVENTS_START, "PROCESS_EVENT_START"  , PerformanceMarker::EVENT_PROCESS, PerformanceMarker::START_TIMED_EVENT },
+    { PerformanceInterface::PROCESS_EVENTS_END,   "PROCESS_EVENT_END"    , PerformanceMarker::EVENT_PROCESS, PerformanceMarker::END_TIMED_EVENT   },
+    { PerformanceInterface::PAUSED       ,        "PAUSED"               , PerformanceMarker::LIFE_CYCLE_EVENTS, PerformanceMarker::SINGLE_EVENT  },
+    { PerformanceInterface::RESUME       ,        "RESUMED"              , PerformanceMarker::LIFE_CYCLE_EVENTS, PerformanceMarker::SINGLE_EVENT  },
+    { PerformanceInterface::START        ,        "START"                , PerformanceMarker::CUSTOM_EVENTS, PerformanceMarker::START_TIMED_EVENT  },
+    { PerformanceInterface::END          ,        "END"                  , PerformanceMarker::CUSTOM_EVENTS, PerformanceMarker::END_TIMED_EVENT  }
+};
+} // un-named namespace
+
+
+
+PerformanceMarker::PerformanceMarker( PerformanceInterface::MarkerType type )
+:mType(type)
+{
+}
+
+PerformanceMarker::PerformanceMarker( PerformanceInterface::MarkerType type, FrameTimeStamp frameInfo )
+:mType(type),
+ mTimeStamp(frameInfo)
+{
+}
+
+const char* PerformanceMarker::GetName( ) const
+{
+  return MARKER_LOOKUP[ mType ].name;
+}
+
+PerformanceMarker::MarkerEventType PerformanceMarker::GetEventType() const
+{
+  return MARKER_LOOKUP[ mType ].eventType;
+}
+
+PerformanceMarker::MarkerFilter PerformanceMarker::GetFilterType() const
+{
+  return MARKER_LOOKUP[ mType ].group;
+}
+
+unsigned int PerformanceMarker::MicrosecondDiff( const PerformanceMarker& start,const PerformanceMarker& end )
+{
+  return FrameTimeStamp::MicrosecondDiff( start.mTimeStamp, end.mTimeStamp );
+}
+
+bool PerformanceMarker::IsFilterEnabled( MarkerFilter filter ) const
+{
+  return  (filter & MARKER_LOOKUP[ mType ].group);
+}
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
diff --git a/dali/internal/system/common/performance-marker.h b/dali/internal/system/common/performance-marker.h
new file mode 100644 (file)
index 0000000..e4cae4a
--- /dev/null
@@ -0,0 +1,140 @@
+#ifndef DALI_INTERNAL_ADAPTOR_PERFORMANCE_MARKER_H
+#define DALI_INTERNAL_ADAPTOR_PERFORMANCE_MARKER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/internal/system/common/performance-interface.h>
+#include <dali/internal/system/common/frame-time-stamp.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Marker used to record an event with a time stamp in Dali
+ */
+class PerformanceMarker
+{
+public:
+
+
+  /**
+   * Bitmask used to filter different types of markers based
+   * on what group they belong to.
+   */
+  enum MarkerFilter
+  {
+    FILTERING_DISABLED   = 0,      ///< disabled
+    V_SYNC_EVENTS        = 1 << 0, ///< v-sync
+    UPDATE               = 1 << 1, ///< update start / end
+    RENDER               = 1 << 2, ///< render start / end
+    EVENT_PROCESS        = 1 << 3, ///< process events start / end
+    SWAP_BUFFERS         = 1 << 4, ///< swap buffers start / end
+    LIFE_CYCLE_EVENTS    = 1 << 5, ///< pause / resume
+    RESOURCE_EVENTS      = 1 << 6, ///< resource events
+    CUSTOM_EVENTS        = 1 << 7
+  };
+
+  /**
+   * Marker event type
+   */
+  enum MarkerEventType
+  {
+    SINGLE_EVENT,           ///< event is something that has no duration associated with it
+    START_TIMED_EVENT,      ///< start of a timed event
+    END_TIMED_EVENT         ///< end of a timed event
+
+  };
+
+
+  /**
+   * @brief Constructor
+   * @param[in] type marker type
+   */
+  PerformanceMarker( PerformanceInterface::MarkerType type );
+
+  /**
+   * @brief Constructor
+   * @param[in] type marker type
+   * @param[in] time time stamp
+   */
+  PerformanceMarker( PerformanceInterface::MarkerType type,  FrameTimeStamp time );
+
+  /**
+   * @return the time stamp
+   */
+  const FrameTimeStamp& GetTimeStamp() const
+  {
+    return mTimeStamp;
+  }
+
+  /**
+   * @return the type of marker
+   */
+  PerformanceInterface::MarkerType GetType() const
+  {
+    return mType;
+  }
+
+  /**
+   * @return the event type of marker
+   */
+  MarkerEventType GetEventType() const;
+
+  /**
+   * @return the filter type of marker
+   */
+  MarkerFilter GetFilterType() const;
+
+
+  /**
+   * @return marker name
+   */
+  const char* GetName( ) const;
+
+  /**
+   * @param start the start marker
+   * @param end the end marker
+   * @return difference in microseconds between two markers
+   */
+  static unsigned int MicrosecondDiff( const PerformanceMarker& start, const PerformanceMarker& end  );
+
+  /**
+   * @return if a marker is enabled as part of a group
+   */
+  bool IsFilterEnabled( MarkerFilter filter ) const;
+private:
+
+  PerformanceInterface::MarkerType mType;         ///< marker type
+  FrameTimeStamp mTimeStamp;                      ///< frame time stamp
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_PERFORMANCE_MARKER_H
diff --git a/dali/internal/system/common/performance-server.cpp b/dali/internal/system/common/performance-server.cpp
new file mode 100644 (file)
index 0000000..6b73864
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * 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 <dali/internal/system/common/performance-server.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/platform-abstraction.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/environment-options.h>
+#include <dali/internal/system/common/time-service.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const unsigned int NANOSECONDS_PER_MICROSECOND = 1000u;
+const float        MICROSECONDS_TO_SECOND = 1e-6;
+} // unnamed namespace
+
+PerformanceServer::PerformanceServer( AdaptorInternalServices& adaptorServices,
+                                      const EnvironmentOptions& environmentOptions)
+: mEnvironmentOptions( environmentOptions ),
+  mKernelTrace( adaptorServices.GetKernelTraceInterface() ),
+  mSystemTrace( adaptorServices.GetSystemTraceInterface() ),
+  mLogMutex(),
+#if defined(NETWORK_LOGGING_ENABLED)
+  mNetworkServer( adaptorServices, environmentOptions ),
+  mNetworkControlEnabled( mEnvironmentOptions.GetNetworkControlMode()),
+#endif
+  mStatContextManager( *this ),
+  mStatisticsLogBitmask( 0 ),
+  mPerformanceOutputBitmask( 0 ),
+  mLoggingEnabled( false ),
+  mLogFunctionInstalled( false )
+{
+  SetLogging( mEnvironmentOptions.GetPerformanceStatsLoggingOptions(),
+              mEnvironmentOptions.GetPerformanceTimeStampOutput(),
+              mEnvironmentOptions.GetPerformanceStatsLoggingFrequency());
+
+#if defined(NETWORK_LOGGING_ENABLED)
+  if( mNetworkControlEnabled )
+  {
+    mLoggingEnabled  = true;
+    mNetworkServer.Start();
+  }
+#endif
+}
+
+PerformanceServer::~PerformanceServer()
+{
+#if defined(NETWORK_LOGGING_ENABLED)
+  if( mNetworkControlEnabled )
+  {
+    mNetworkServer.Stop();
+  }
+#endif
+
+  if( mLogFunctionInstalled )
+  {
+    mEnvironmentOptions.UnInstallLogFunction();
+  }
+}
+
+void PerformanceServer::SetLogging( unsigned int statisticsLogOptions,
+                                    unsigned int timeStampOutput,
+                                    unsigned int logFrequency )
+{
+  mStatisticsLogBitmask = statisticsLogOptions;
+  mPerformanceOutputBitmask = timeStampOutput;
+
+  mStatContextManager.SetLoggingLevel( mStatisticsLogBitmask, logFrequency);
+
+  if( ( mStatisticsLogBitmask == 0) && ( mPerformanceOutputBitmask == 0 ))
+  {
+    mLoggingEnabled = false;
+  }
+  else
+  {
+    mLoggingEnabled = true;
+  }
+}
+
+void PerformanceServer::SetLoggingFrequency( unsigned int logFrequency, ContextId contextId )
+{
+  mStatContextManager.SetLoggingFrequency( logFrequency, contextId );
+}
+
+void PerformanceServer::EnableLogging( bool enable, ContextId contextId )
+{
+  mStatContextManager.EnableLogging( enable, contextId );
+}
+
+PerformanceInterface::ContextId PerformanceServer::AddContext( const char* name )
+{
+  // for adding custom contexts
+  return mStatContextManager.AddContext( name, PerformanceMarker::CUSTOM_EVENTS );
+}
+
+void PerformanceServer::RemoveContext( ContextId contextId )
+{
+  mStatContextManager.RemoveContext( contextId );
+}
+
+void PerformanceServer::AddMarker( MarkerType markerType, ContextId contextId )
+{
+  // called only for custom markers
+
+  if( !mLoggingEnabled )
+  {
+    return;
+  }
+
+  // Get the time stamp
+  uint64_t timeStamp = 0;
+  TimeService::GetNanoseconds( timeStamp );
+  timeStamp /= NANOSECONDS_PER_MICROSECOND; // Convert to microseconds
+
+  // Create a marker
+  PerformanceMarker marker( markerType, FrameTimeStamp( 0, timeStamp ) );
+
+  // get the marker description for this context, e.g SIZE_NEGOTIATION_START
+  const char* const description = mStatContextManager.GetMarkerDescription( markerType, contextId );
+
+  // log it
+  LogMarker( marker, description );
+
+  // Add custom marker to statistics context manager
+  mStatContextManager.AddCustomMarker( marker, contextId );
+}
+
+void PerformanceServer::AddMarker( MarkerType markerType )
+{
+  // called only for internal markers
+
+  if( !mLoggingEnabled )
+  {
+    return;
+  }
+
+  if( markerType == VSYNC )
+  {
+    // make sure log function is installed, note this will be called only from v-sync thread
+    // if the v-sync thread has already installed one, it won't make any difference.
+    if( ! mLogFunctionInstalled )
+    {
+      mEnvironmentOptions.InstallLogFunction();
+      mLogFunctionInstalled = true;
+    }
+  }
+
+  // Get the time
+  uint64_t timeStamp = 0;
+  TimeService::GetNanoseconds( timeStamp );
+  timeStamp /= NANOSECONDS_PER_MICROSECOND; // Convert to microseconds
+
+  // Create a marker
+  PerformanceMarker marker( markerType, FrameTimeStamp( 0, timeStamp ) );
+
+  // log it
+  LogMarker(marker, marker.GetName() );
+
+  // Add internal marker to statistics context manager
+  mStatContextManager.AddInternalMarker( marker );
+
+}
+
+void PerformanceServer::LogContextStatistics( const char* const text )
+{
+  Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo, text );
+}
+
+void PerformanceServer::LogMarker( const PerformanceMarker& marker, const char* const description )
+{
+#if defined(NETWORK_LOGGING_ENABLED)
+  // log to the network ( this is thread safe )
+  if( mNetworkControlEnabled )
+  {
+    mNetworkServer.TransmitMarker( marker, description );
+  }
+#endif
+
+  // log to kernel trace
+  if( mPerformanceOutputBitmask & OUTPUT_KERNEL_TRACE )
+  {
+    // Kernel tracing implementation may not be thread safe
+    Mutex::ScopedLock lock( mLogMutex );
+    // description will be something like UPDATE_START or UPDATE_END
+    mKernelTrace.Trace( marker, description );
+  }
+
+  // log to system trace
+  if( mPerformanceOutputBitmask & OUTPUT_SYSTEM_TRACE )
+  {
+    // System  tracing implementation may not be thread safe
+    Mutex::ScopedLock lock( mLogMutex );
+
+    mSystemTrace.Trace( marker, description );
+  }
+
+  // log to Dali log ( this is thread safe )
+  if ( mPerformanceOutputBitmask & OUTPUT_DALI_LOG )
+  {
+    Integration::Log::LogMessage( Dali::Integration::Log::DebugInfo,
+                                    "%.6f (seconds), %s\n",
+                                    float( marker.GetTimeStamp().microseconds ) * MICROSECONDS_TO_SECOND,
+                                    description );
+
+  }
+}
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
diff --git a/dali/internal/system/common/performance-server.h b/dali/internal/system/common/performance-server.h
new file mode 100644 (file)
index 0000000..1362f9b
--- /dev/null
@@ -0,0 +1,145 @@
+#ifndef DALI_INTERNAL_ADAPTOR_PERFORMANCE_SERVER_H
+#define DALI_INTERNAL_ADAPTOR_PERFORMANCE_SERVER_H
+
+/*
+ * Copyright (c) 2019 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 INCLDUES
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/devel-api/threading/mutex.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/frame-time-stats.h>
+#include <dali/internal/network/common/network-performance-server.h>
+#include <dali/internal/adaptor/common/adaptor-internal-services.h>
+#include <dali/internal/system/common/performance-marker.h>
+#include <dali/internal/system/common/stat-context-manager.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class EnvironmentOptions;
+class StatContext;
+/**
+ * Concrete implementation of performance interface.
+ * Adaptor classes should never include this file, they
+ * just need to include the abstract class performance-interface.h
+ */
+class PerformanceServer : public PerformanceInterface, public StatContextLogInterface
+{
+public:
+
+  /**
+   * @brief Constructor
+   * @param[in] adaptorServices adaptor internal services
+   * @param[in] environmentOptions environment options
+   */
+  PerformanceServer( AdaptorInternalServices& adaptorServices,
+                     const EnvironmentOptions& environmentOptions );
+
+  /**
+   * Destructor
+   */
+  virtual ~PerformanceServer();
+
+  /**
+   * @copydoc PerformanceLogger::AddContext()
+   */
+  virtual ContextId AddContext( const char* name );
+
+  /**
+   * @copydoc PerformanceLogger::RemoveContext()
+   */
+  virtual void RemoveContext( ContextId contextId );
+
+  /**
+   * @copydoc PerformanceInterface::AddMarker( MarkerType markerType )
+   */
+  virtual void AddMarker( MarkerType markerType );
+
+  /**
+   * @copydoc PerformanceLogger::AddMarker( MarkerType markerType, ContextId contextId )
+   */
+  virtual void AddMarker( MarkerType markerType, ContextId contextId );
+
+  /**
+   * @copydoc PerformanceInterface::SetLogging()
+   */
+  virtual void SetLogging( unsigned int statisticsLogOptions,
+                           unsigned int timeStampOutput,
+                           unsigned int logFrequency );
+
+  /**
+   * @copydoc PerformanceLogger::SetLoggingFrequency()
+   */
+  virtual void SetLoggingFrequency( unsigned int logFrequency, ContextId contextId );
+
+  /**
+   * @copydoc PerformanceLogger::EnableLogging()
+   */
+  virtual void EnableLogging( bool enable, ContextId contextId );
+
+public: //StatLogInterface
+
+  /**
+   * @copydoc StatLogInterface::LogContextStatistics()
+   */
+  virtual void LogContextStatistics( const char* const text );
+
+private:
+
+  /**
+   * @brief log the marker out to kernel/ DALi log
+   * @param[in] marker performance marker
+   * @param[in] description marker description
+   */
+  void LogMarker( const PerformanceMarker& marker, const char* const description );
+
+private:
+
+  const EnvironmentOptions& mEnvironmentOptions;          ///< environment options
+  TraceInterface& mKernelTrace;                           ///< kernel trace interface
+  TraceInterface& mSystemTrace;                           ///< system trace interface
+  Dali::Mutex mLogMutex;                                  ///< mutex
+
+#if defined(NETWORK_LOGGING_ENABLED)
+  NetworkPerformanceServer mNetworkServer;                ///< network server
+  bool mNetworkControlEnabled;                            ///< Whether network control is enabled
+#endif
+
+  StatContextManager mStatContextManager;                 ///< Stat context manager
+  unsigned int mStatisticsLogBitmask;                     ///< statistics log level
+  unsigned int mPerformanceOutputBitmask;                 ///< performance marker output
+
+  bool mLoggingEnabled:1;                                 ///< whether logging update / render to a log is enabled
+  bool mLogFunctionInstalled:1;                           ///< whether the log function is installed
+};
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_PERFORMANCE_SERVER_H
diff --git a/dali/internal/system/common/shared-file.cpp b/dali/internal/system/common/shared-file.cpp
new file mode 100644 (file)
index 0000000..32613d8
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/shared-file.h>
+
+// EXTERNAL INCLUDES
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/file.h>
+#include <sys/mman.h>
+#include <cstring>
+
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+SharedFile* SharedFile::New(const char* filename, int size, bool isSystem)
+{
+  SharedFile *sf = NULL;
+
+  sf = new SharedFile;
+
+  bool opened = sf->OpenFile( filename, size, isSystem );
+  if( !opened )
+  {
+    delete sf;
+    sf = NULL;
+  }
+  return sf;
+}
+
+SharedFile::SharedFile()
+: mFileDescriptor(-1),
+  mSize(0),
+  mAddress(NULL),
+  mFilename()
+{
+}
+
+SharedFile::~SharedFile()
+{
+  Close();
+}
+
+void SharedFile::Close()
+{
+  if( mAddress != NULL )
+  {
+    munmap( mAddress, mSize );
+    mAddress = NULL;
+  }
+
+  if( mFileDescriptor >= 0 )
+  {
+    close( mFileDescriptor );
+    mFileDescriptor = -1;
+  }
+}
+
+unsigned char* SharedFile::GetAddress()
+{
+  return static_cast<unsigned char *>( mAddress );
+}
+
+bool SharedFile::OpenFile(const char* filename, int size, bool isSystem)
+{
+  bool opened = false;
+
+  mode_t mode;
+
+  mode = S_IRUSR | S_IWUSR;
+  if( isSystem )
+  {
+    mode |= S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+  }
+
+  mFileDescriptor = Open( filename, size, O_RDONLY, mode );
+
+  if( mFileDescriptor >= 0 )
+  {
+    mFilename = filename;
+
+    mSize = size;
+    mAddress = mmap( NULL, mSize, PROT_READ, MAP_SHARED, mFileDescriptor, 0 );
+
+// MAP_FAILED is a macro with C cast
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+    if( mAddress != MAP_FAILED )
+    {
+      opened = true;
+    }
+#pragma GCC diagnostic pop
+  }
+  return opened;
+}
+
+} // Adaptor
+} // Internal
+} // Dali
diff --git a/dali/internal/system/common/shared-file.h b/dali/internal/system/common/shared-file.h
new file mode 100644 (file)
index 0000000..7abe53a
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef DALI_INTERNAL_ADAPTOR_SHARED_FILE_H
+#define DALI_INTERNAL_ADAPTOR_SHARED_FILE_H
+
+/*
+ * Copyright (c) 2019 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 <sys/types.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class SharedFile
+{
+public:
+  /**
+   * Open an existing shared file for read/write
+   * @return The shared file, or NULL if a file could not be opened and mapped.
+   */
+  static SharedFile* New( const char* filename, int size, bool isSystem );
+
+  /**
+   * Constructor
+   */
+  SharedFile();
+
+  /**
+   * Destructor
+   */
+  virtual ~SharedFile();
+
+  /**
+   * Opens a file descriptor to shared memory segment
+   * @return The file descriptor
+   */
+  int Open( const char* filename, int size, int oflag, mode_t mode );
+
+  /**
+   * Opens a file for read/write
+   * @return true if opened, false on error.
+   */
+  bool OpenFile( const char* filename, int size, bool isSystem );
+
+  /**
+   * Close the shared file
+   */
+  void Close();
+
+  /**
+   * Get the memory address of the shared file
+   * @return the memory address
+   */
+  unsigned char* GetAddress();
+
+private:
+  int         mFileDescriptor;
+  int         mSize;
+  void*       mAddress;
+  std::string mFilename;
+};
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_SHARED_FILE_H
diff --git a/dali/internal/system/common/sound-player-impl.cpp b/dali/internal/system/common/sound-player-impl.cpp
new file mode 100644 (file)
index 0000000..572747d
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/sound-player-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+#include <dali/devel-api/common/singleton-service.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // unnamed namespace
+{
+
+const char* const SIGNAL_SOUND_PLAY_FINISHED = "soundPlayFinished";
+
+// Type Registration
+Dali::BaseHandle GetInstance()
+{
+  return SoundPlayer::Get();
+}
+
+Dali::TypeRegistration SOUND_PLAYER_TYPE( typeid(Dali::SoundPlayer), typeid(Dali::BaseHandle), GetInstance );
+
+Dali::SignalConnectorType SIGNAL_CONNECTOR_1( SOUND_PLAYER_TYPE, SIGNAL_SOUND_PLAY_FINISHED, Dali::Internal::Adaptor::SoundPlayer::DoConnectSignal );
+
+} // unnamed namespace
+
+Dali::SoundPlayer SoundPlayer::New()
+{
+  Dali::SoundPlayer player = Dali::SoundPlayer( new SoundPlayer() );
+  return player;
+}
+
+Dali::SoundPlayer SoundPlayer::Get()
+{
+  Dali::SoundPlayer player;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::SoundPlayer ) );
+    if ( handle )
+    {
+      // If so, downcast the handle
+      player = Dali::SoundPlayer( dynamic_cast< SoundPlayer* >( handle.GetObjectPtr() ) );
+    }
+    else
+    {
+      player = Dali::SoundPlayer( New() );
+      service.Register( typeid( player ), player );
+    }
+  }
+
+  return player;
+}
+
+int SoundPlayer::PlaySound( const std::string fileName )
+{
+  return mPlugin.PlaySound( fileName );
+}
+
+void SoundPlayer::Stop( int handle )
+{
+  mPlugin.StopSound( handle );
+}
+
+SoundPlayer::SoundPlayFinishedSignalType& SoundPlayer::SoundPlayFinishedSignal()
+{
+  return mSoundPlayFinishedSignal;
+}
+
+bool SoundPlayer::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+  bool connected( true );
+  SoundPlayer* player = dynamic_cast<SoundPlayer*>( object );
+
+  if( player && ( SIGNAL_SOUND_PLAY_FINISHED == signalName ) )
+  {
+    player->SoundPlayFinishedSignal().Connect( tracker, functor );
+  }
+  else
+  {
+    // signalName does not match any signal
+    connected = false;
+  }
+
+  return connected;
+}
+
+SoundPlayer::SoundPlayer()
+: mPlugin( FeedbackPluginProxy::DEFAULT_OBJECT_NAME )
+{
+}
+
+SoundPlayer::~SoundPlayer()
+{
+}
+
+void SoundPlayer::EmitSoundPlayFinishedSignal()
+{
+  // Emit SoundPlayFinished signal
+
+  if ( !mSoundPlayFinishedSignal.Empty() )
+  {
+    Dali::SoundPlayer handle( this );
+    mSoundPlayFinishedSignal.Emit( handle );
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/common/sound-player-impl.h b/dali/internal/system/common/sound-player-impl.h
new file mode 100644 (file)
index 0000000..514d4f0
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef DALI_INTERNAL_SOUND_PLAYER_H
+#define DALI_INTERNAL_SOUND_PLAYER_H
+
+/*
+ * Copyright (c) 2019 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/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/sound-player.h>
+#include <dali/internal/haptics/common/feedback-plugin-proxy.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Plays haptic effects.
+ */
+class SoundPlayer : public Dali::BaseObject
+{
+
+public:
+
+  typedef Dali::SoundPlayer::SoundPlayFinishedSignalType SoundPlayFinishedSignalType;
+
+  /**
+   * Create a SoundPlayer.
+   * @return A newly created SoundPlayer.
+   */
+  static Dali::SoundPlayer New();
+
+  /**
+   * Retrieve a handle to the SoundPlayer. This creates an instance if none has been created.
+   * @return A handle to the SoundPlayer.
+   */
+  static Dali::SoundPlayer Get();
+
+  /**
+   * @copydoc Dali::SoundPlayer::PlaySound()
+   */
+  int PlaySound(const std::string fileName);
+
+  /**
+   * @copydoc Dali::SoundPlayer::Stop()
+   */
+  void Stop(int handle);
+
+  /**
+   * @copydoc Dali::SoundPlayer::SoundPlayFinishedSignal()
+   */
+  SoundPlayFinishedSignalType& SoundPlayFinishedSignal();
+
+  /**
+   * Connects a callback function with the object's signals.
+   * @param[in] object The object providing the signal.
+   * @param[in] tracker Used to disconnect the signal.
+   * @param[in] signalName The signal to connect to.
+   * @param[in] functor A newly allocated FunctorDelegate.
+   * @return True if the signal was connected.
+   * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+   */
+  static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+private:
+
+  /**
+   * Private Constructor; see also soundPlayer::New()
+   * @param[in]  soundPlayer  The public sound player class
+   */
+  SoundPlayer();
+
+  /**
+   * Destructor
+   */
+  virtual ~SoundPlayer();
+
+  /**
+   * Emits the SoundPlayFinished signal.
+   */
+  void EmitSoundPlayFinishedSignal();
+
+  // Undefined
+  SoundPlayer(const SoundPlayer&);
+
+  // Undefined
+  SoundPlayer& operator=(SoundPlayer&);
+
+private:
+
+  FeedbackPluginProxy mPlugin;
+  SoundPlayFinishedSignalType mSoundPlayFinishedSignal;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+
+// Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::SoundPlayer& GetImplementation(Dali::SoundPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "SoundPlayer handle is empty" );
+
+  BaseObject& handle = player.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::SoundPlayer&>(handle);
+}
+
+inline const Internal::Adaptor::SoundPlayer& GetImplementation(const Dali::SoundPlayer& player)
+{
+  DALI_ASSERT_ALWAYS( player && "SoundPlayer handle is empty" );
+
+  const BaseObject& handle = player.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::SoundPlayer&>(handle);
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_SOUND_PLAYER_H
diff --git a/dali/internal/system/common/stat-context-log-interface.h b/dali/internal/system/common/stat-context-log-interface.h
new file mode 100644 (file)
index 0000000..0da1345
--- /dev/null
@@ -0,0 +1,77 @@
+#ifndef DALI_INTERNAL_ADAPTOR_STATISTICS_STAT_CONTEXT_LOG_INTERFACE_H
+#define DALI_INTERNAL_ADAPTOR_STATISTICS_STAT_CONTEXT_LOG_INTERFACE_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief  Abstract interface used to log statistics data
+ */
+class StatContextLogInterface
+{
+public:
+
+  /**
+   * @brief Used to log statistics out
+   * @param[in] text log the text
+   */
+  virtual void LogContextStatistics( const char* const text) = 0;
+
+
+protected:
+
+  /**
+   * @brief  Constructor
+   */
+  StatContextLogInterface()
+  {
+  }
+
+  /**
+   * @brief Virtual Destructor
+   */
+  virtual ~StatContextLogInterface()
+  {
+  }
+
+private:
+
+  // Undefined copy constructor.
+  StatContextLogInterface( const StatContextLogInterface& );
+
+  // Undefined assignment operator.
+  StatContextLogInterface& operator=( const StatContextLogInterface& );
+
+};
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_STATISTICS_STAT_CONTEXT_LOG_INTERFACE_H
diff --git a/dali/internal/system/common/stat-context-manager.cpp b/dali/internal/system/common/stat-context-manager.cpp
new file mode 100644 (file)
index 0000000..c6972e2
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * 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 <dali/internal/system/common/stat-context-manager.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+const char* const UPDATE_CONTEXT_NAME = "Update";
+const char* const RENDER_CONTEXT_NAME = "Render";
+const char* const EVENT_CONTEXT_NAME = "Event";
+const unsigned int DEFAULT_LOG_FREQUENCY = 2;
+}
+
+StatContextManager::StatContextManager( StatContextLogInterface& logInterface )
+: mLogInterface( logInterface ),
+  mNextContextId( 0 ),
+  mStatisticsLogBitmask(0),
+  mLogFrequency( DEFAULT_LOG_FREQUENCY )
+{
+
+  mStatContexts.Reserve(4); // intially reserve enough for 3 internal + 1 custom
+
+  // Add defaults
+  mUpdateStats = AddContext( UPDATE_CONTEXT_NAME, PerformanceMarker::UPDATE );
+  mRenderStats = AddContext( RENDER_CONTEXT_NAME, PerformanceMarker::RENDER );
+  mEventStats = AddContext( EVENT_CONTEXT_NAME,   PerformanceMarker::EVENT_PROCESS );
+
+}
+
+StatContextManager::~StatContextManager()
+{
+  for( StatContexts::Iterator it = mStatContexts.Begin(), itEnd = mStatContexts.End(); it != itEnd; ++it )
+  {
+    StatContext* context = *it;
+    delete context;
+  }
+  mStatContexts.Clear();
+}
+PerformanceInterface::ContextId StatContextManager::AddContext( const char* const name,
+                                                                PerformanceMarker::MarkerFilter type  )
+{
+  unsigned int contextId = mNextContextId++;
+
+  DALI_ASSERT_DEBUG( NULL == GetContext( contextId ) );
+
+  // logging enabled by default
+  StatContext* statContext = new StatContext( contextId, name, type,  mLogFrequency , mLogInterface );
+
+  // check to see if custom markers are enabled
+  if( ! ( mStatisticsLogBitmask & PerformanceInterface::LOG_CUSTOM_MARKERS ) )
+  {
+    statContext->EnableLogging( false );
+  }
+
+  mStatContexts.PushBack( statContext );
+
+  return contextId;
+}
+
+void StatContextManager::AddInternalMarker( const PerformanceMarker& marker )
+{
+  // log to the stat contexts, can be called from multiple threads so we
+  // protect the data
+  Mutex::ScopedLock lock( mDataMutex );
+  for( StatContexts::Iterator it = mStatContexts.Begin(), itEnd = mStatContexts.End(); it != itEnd; ++it )
+  {
+    StatContext* context = *it;
+    context->ProcessInternalMarker( marker );
+  }
+}
+
+void StatContextManager::AddCustomMarker( const PerformanceMarker& marker, PerformanceInterface::ContextId contextId )
+{
+  // log to the stat contexts, can be called from multiple threads so we
+  // protect the data
+  Mutex::ScopedLock lock( mDataMutex );
+  StatContext* context = GetContext( contextId );
+  if( context )
+  {
+    context->ProcessCustomMarker( marker );
+  }
+}
+
+void StatContextManager::RemoveContext(PerformanceInterface::ContextId contextId )
+{
+  for( StatContexts::Iterator it = mStatContexts.Begin(), itEnd = mStatContexts.End(); it != itEnd; ++it )
+  {
+    StatContext* context = *it;
+
+    if( context->GetId() == contextId )
+    {
+      delete context;
+      mStatContexts.Erase( it );
+      return;
+    }
+  }
+}
+
+
+void StatContextManager::EnableLogging( bool enable, PerformanceInterface::ContextId contextId )
+{
+  StatContext* context = GetContext( contextId );
+  if( context )
+  {
+    context->EnableLogging( enable );
+  }
+}
+
+void StatContextManager::SetLoggingLevel(  unsigned int statisticsLogOptions, unsigned int logFrequency)
+{
+  mStatisticsLogBitmask = statisticsLogOptions;
+
+  if( mStatisticsLogBitmask == PerformanceInterface::LOG_EVERYTHING )
+  {
+    mStatisticsLogBitmask = 0xFFFFFFFF; // enable everything
+  }
+
+  mLogFrequency = logFrequency;
+
+  // currently uses DALI_LOG_PERFORMANCE_STATS_FREQ environment variable to determine to log frequency
+  // if it's not set it will be zero
+  if( mLogFrequency == 0 )
+  {
+    mLogFrequency = DEFAULT_LOG_FREQUENCY;
+  }
+  EnableLogging( mStatisticsLogBitmask & PerformanceInterface::LOG_UPDATE_RENDER, mUpdateStats );
+  EnableLogging( mStatisticsLogBitmask & PerformanceInterface::LOG_UPDATE_RENDER, mRenderStats );
+  EnableLogging( mStatisticsLogBitmask & PerformanceInterface::LOG_EVENT_PROCESS, mEventStats );
+
+  for( StatContexts::Iterator it = mStatContexts.Begin(), itEnd = mStatContexts.End(); it != itEnd; ++it )
+  {
+     StatContext* context = *it;
+     context->SetLogFrequency( mLogFrequency );
+  }
+}
+
+void StatContextManager::SetLoggingFrequency( unsigned int logFrequency,
+                                              PerformanceInterface::ContextId contextId  )
+{
+  StatContext* context = GetContext( contextId );
+  if( context )
+  {
+    if( logFrequency == 0 )
+    {
+      logFrequency = DEFAULT_LOG_FREQUENCY;
+    }
+    context->SetLogFrequency( logFrequency );
+  }
+}
+const char* StatContextManager::GetContextName(PerformanceInterface::ContextId contextId) const
+{
+  StatContext* context = GetContext(contextId);
+  if( context )
+  {
+    return context->GetName();
+  }
+  return "context not found";
+}
+
+const char* StatContextManager::GetMarkerDescription( PerformanceInterface::MarkerType type, PerformanceInterface::ContextId contextId ) const
+{
+  StatContext* context = GetContext(contextId);
+  if( context )
+  {
+    return context->GetMarkerDescription( type );
+  }
+  return "context not found";
+}
+
+
+StatContext* StatContextManager::GetContext( PerformanceInterface::ContextId contextId ) const
+{
+  for( StatContexts::Iterator it = mStatContexts.Begin(), itEnd = mStatContexts.End(); it != itEnd; ++it )
+  {
+    StatContext* context = *it;
+
+    if( context->GetId() == contextId )
+    {
+      return context;
+    }
+  }
+
+  return NULL;
+}
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+
diff --git a/dali/internal/system/common/stat-context-manager.h b/dali/internal/system/common/stat-context-manager.h
new file mode 100644 (file)
index 0000000..e1521a3
--- /dev/null
@@ -0,0 +1,170 @@
+#ifndef DALI_INTERNAL_ADAPTOR_STAT_CONTEXT_MANAGER_H
+#define DALI_INTERNAL_ADAPTOR_STAT_CONTEXT_MANAGER_H
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/threading/mutex.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/performance-marker.h>
+#include <dali/internal/system/common/stat-context.h>
+#include <dali/internal/system/common/performance-interface.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Class to manage StatContext objects.
+ *
+ * Contains 3 built in contexts for event, update, render.
+ * The application developer can add more using the PerformanceLogger public API
+ *
+ * Example output of 4 contexts ( event, update, render and a custom one):
+ *
+ * Event, min 0.04 ms, max 5.27 ms, total (0.1 secs), avg 0.28 ms, std dev 0.73 ms
+ * Update, min 0.29 ms, max 0.91 ms, total (0.5 secs), avg 0.68 ms, std dev 0.15 ms
+ * Render, min 0.33 ms, max 0.97 ms, total (0.6 secs), avg 0.73 ms, std dev 0.17 ms
+ * MyAppTask, min 76.55 ms, max 76.55 ms, total (0.1 secs), avg 76.55 ms, std dev 0.00 ms  (CUSTOM CONTEXT)
+ *
+ */
+class StatContextManager
+{
+
+public:
+
+    /**
+     * @brief Constructor
+     * @param[in] logInterface interface to log statistics to
+     */
+    StatContextManager( StatContextLogInterface& logInterface );
+
+    /**
+     * @brief destructor, not intended as a bass class
+     */
+    ~StatContextManager();
+
+    /**
+     * @brief Add a context
+     * @param[in] name Name of the context to print in console
+     * @param[in] type the type of events to filter ( e.g. event, update, render or custom)
+     * @return The ID to give the context
+     */
+    PerformanceInterface::ContextId AddContext( const char* const name, PerformanceMarker::MarkerFilter type );
+
+    /**
+     * @brief Remove a context
+     * @param[in] contextId id of the context to remove
+     */
+    void RemoveContext(PerformanceInterface::ContextId contextId );
+
+    /**
+     * @brief Add an internal marker (e.g. v-sync, update, render markers)
+     * @param[in] marker the marker to add
+     */
+    void AddInternalMarker( const PerformanceMarker& marker );
+
+    /**
+     * @brief Add a custom marker defined by the application
+     * @param[in] marker the marker to add
+     * @param[in] contextId the context the custom marker is designed for
+     */
+    void AddCustomMarker( const PerformanceMarker& marker , PerformanceInterface::ContextId contextId );
+
+    /**
+     * @brief Get the nane of a context
+     * @param[in] contextId id of the context to get the name
+     * @return context name
+     */
+    const char* GetContextName( PerformanceInterface::ContextId contextId ) const;
+
+    /**
+     * @brief Get the full description of a marker for this context
+     * @param[in] type marker type, for a customer marker this will be either START or END
+     * @param[in] contextId id of the context to get the name
+     * @return marker description in relation to this context
+     */
+    const char* GetMarkerDescription( PerformanceInterface::MarkerType type, PerformanceInterface::ContextId contextId ) const;
+
+
+    /**
+     * @brief enable / disable logging for a context
+     * @param[in] enable whether to enable logging
+     * @param[in] contextId the context to configure
+     */
+    void EnableLogging( bool enable, PerformanceInterface::ContextId contextId );
+
+    /**
+     * @brief set global logging level and frequency.
+     * @param[in] statisticsLogOptions  log options
+     * @param[in] logFrequency frequency in seconds
+     */
+    void SetLoggingLevel( unsigned int statisticsLogOptions, unsigned int logFrequency);
+
+    /**
+     * @brief Set the frequency of logging for an individual context
+     * @param[in] logFrequency log frequency in seconds
+     * @param[in] contextId the context to configure
+     */
+    void SetLoggingFrequency( unsigned int logFrequency, PerformanceInterface::ContextId contextId  );
+
+  private:
+
+    StatContextManager( const StatContextManager& ); ///< Undefined
+    StatContextManager& operator=( const StatContextManager& ); ///< Undefined
+
+    typedef Dali::Vector< StatContext* > StatContexts;
+
+    /**
+     * @brief helper
+     * @param[in] contextId the context to get
+     * @return context
+     */
+    StatContext* GetContext( PerformanceInterface::ContextId contextId ) const;
+
+    Dali::Mutex mDataMutex;                            ///< mutex
+    StatContexts mStatContexts;                        ///< The list of stat contexts
+    StatContextLogInterface& mLogInterface;            ///< Log interface
+
+    PerformanceInterface::ContextId mNextContextId;    ///< The next valid context ID
+
+    // Some defaults contexts
+    PerformanceInterface::ContextId mUpdateStats;    ///< update time statistics
+    PerformanceInterface::ContextId mRenderStats;    ///< render time statistics
+    PerformanceInterface::ContextId mEventStats;     ///< event time statistics
+
+    unsigned int mStatisticsLogBitmask;              ///< statistics log bitmask
+    unsigned int mLogFrequency;                      ///< log frequency
+};
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_STAT_CONTEXT_MANAGER_H
+
diff --git a/dali/internal/system/common/stat-context.cpp b/dali/internal/system/common/stat-context.cpp
new file mode 100644 (file)
index 0000000..7a7a674
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * 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 <dali/internal/system/common/stat-context.h>
+
+// EXTERNAL INCLUDES
+#include <cstdio>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/platform-abstraction.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+#define TIME_FMT "%0.2f ms"         // 2 decimal places, e.g. 5.34 ms
+#define TOTAL_TIME_FMT "%0.1f secs" // 1 decimal place, e.g. 4.5 seconds
+
+namespace
+{
+const unsigned int MILLISECONDS_PER_SECOND = 1000;    ///< 1000 milliseconds per second
+const char* const UNKNOWN_CONTEXT_NAME = "UNKNOWN_CONTEXT_NAME";
+const unsigned int MICROSECONDS_PER_SECOND = 1000000; ///< 1000000 microseconds per second
+const unsigned int CONTEXT_LOG_SIZE = 120;
+
+}
+
+StatContext::StatContext( unsigned int id,
+                          const char* const contextName,
+                          PerformanceMarker::MarkerFilter contextType,
+                          unsigned int logFrequencySeconds,
+                          StatContextLogInterface& logInterface )
+: mInitialMarker(PerformanceInterface::VSYNC),
+  mName( contextName ),
+  mLogInterface( logInterface ),
+  mNamePlusStart( std::string(contextName) + "_START" ),
+  mNamePlusEnd( std::string(contextName) + "_END" ),
+  mId( id ),
+  mLogFrequencyMicroseconds( logFrequencySeconds * MICROSECONDS_PER_SECOND ),
+  mFilterType( contextType ),
+  mLoggingEnabled( true ),
+  mInitialMarkerSet( false )
+{
+  mTempLogBuffer = new char[ CONTEXT_LOG_SIZE ];
+}
+
+StatContext::~StatContext()
+{
+  delete []mTempLogBuffer;
+}
+unsigned int StatContext::GetId() const
+{
+  return mId;
+}
+
+const char* StatContext::GetName() const
+{
+  return mName;
+}
+
+const char* StatContext::GetMarkerDescription( PerformanceInterface::MarkerType type ) const
+{
+  if( type == PerformanceInterface::START )
+  {
+    return mNamePlusStart.c_str();
+  }
+  else if( type == PerformanceInterface::END )
+  {
+    return mNamePlusEnd.c_str();
+  }
+  return UNKNOWN_CONTEXT_NAME;
+}
+void StatContext::SetLogFrequency( unsigned int logFrequencySeconds )
+{
+  mLogFrequencyMicroseconds = logFrequencySeconds * MICROSECONDS_PER_SECOND;
+}
+
+void StatContext::EnableLogging( bool enableLogging )
+{
+  mLoggingEnabled = enableLogging;
+}
+
+void StatContext::ProcessCustomMarker( const PerformanceMarker& marker )
+{
+  // this marker has come from the application PerformanceLogger API
+  RecordMarker( marker);
+}
+
+void StatContext::ProcessInternalMarker( const PerformanceMarker& marker )
+{
+  // this marker has come from DALi internal not the application
+  // see if this context is for update, render or event
+ if( marker.IsFilterEnabled( mFilterType ))
+ {
+   RecordMarker( marker );
+ }
+ // V_SYNC is always processed
+ if( marker.GetType() == PerformanceInterface::VSYNC )
+ {
+   FrameTick( marker );
+ }
+}
+
+void StatContext::RecordMarker( const PerformanceMarker& marker )
+{
+  if( marker.GetEventType() == PerformanceMarker::START_TIMED_EVENT )
+  {
+    mStats.StartTime( marker.GetTimeStamp() );
+  }
+  else if( marker.GetEventType() == PerformanceMarker::END_TIMED_EVENT )
+  {
+    mStats.EndTime( marker.GetTimeStamp() );
+  }
+}
+
+void StatContext::FrameTick( const PerformanceMarker& marker )
+{
+  // wait until we've got some data
+  if( ! mInitialMarkerSet )
+  {
+    mInitialMarker = marker;
+    mInitialMarkerSet = true;
+    return;
+  }
+  // log out every mLogFrequency.
+  // check difference between first and last frame
+  unsigned int microseconds = PerformanceMarker::MicrosecondDiff( mInitialMarker, marker );
+
+  if( microseconds < mLogFrequencyMicroseconds )
+  {
+    return;
+  }
+
+  if( mLoggingEnabled )
+  {
+    LogMarker();
+  }
+  mStats.Reset();             // reset data for statistics
+  mInitialMarkerSet = false;  // need to restart the timer
+
+}
+
+void StatContext::LogMarker()
+{
+  float mean, standardDeviation;
+  mStats.CalculateMean( mean, standardDeviation );
+
+  snprintf( mTempLogBuffer, CONTEXT_LOG_SIZE, "%s, min " TIME_FMT ", max " TIME_FMT ", total (" TOTAL_TIME_FMT "), avg " TIME_FMT ", std dev " TIME_FMT "\n",
+     mName ? mName : UNKNOWN_CONTEXT_NAME,
+     mStats.GetMinTime() * MILLISECONDS_PER_SECOND,
+     mStats.GetMaxTime() * MILLISECONDS_PER_SECOND,
+     mStats.GetTotalTime(),
+     mean * MILLISECONDS_PER_SECOND,
+     standardDeviation * MILLISECONDS_PER_SECOND );
+
+    mLogInterface.LogContextStatistics( mTempLogBuffer );
+
+}
+
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
diff --git a/dali/internal/system/common/stat-context.h b/dali/internal/system/common/stat-context.h
new file mode 100644 (file)
index 0000000..2209b25
--- /dev/null
@@ -0,0 +1,170 @@
+#ifndef DALI_INTERNAL_ADAPTOR_STAT_CONTEXT_H
+#define DALI_INTERNAL_ADAPTOR_STAT_CONTEXT_H
+
+/*
+ * Copyright (c) 2019 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 <dali/internal/system/common/performance-marker.h>
+#include <dali/internal/system/common/frame-time-stats.h>
+#include <dali/internal/system/common/performance-interface.h>
+#include <dali/internal/system/common/stat-context-log-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Stores and prints statistics for a particular logging context.
+ *
+ */
+class StatContext
+{
+
+public:
+
+    /**
+     * @brief Constructor
+     *
+     * @param[in] id The ID to give the context
+     * @param[in] contextName Name of the context to print in console
+     * @param[in] contextType the type of events to filter ( e.g. event, update, render or custom)
+     * @param[in] logFrequencySeconds frequency to log in seconds
+     * @param[in] logInterface interface to log out to
+     *
+     */
+    StatContext( unsigned int id,
+                 const char* const contextName,
+                 PerformanceMarker::MarkerFilter contextType,
+                 unsigned int logFrequencySeconds,
+                 StatContextLogInterface& logInterface );
+
+
+    /**
+     * @brief Non-virtual destructor, not intended as a base class
+     */
+    ~StatContext();
+
+    /**
+     * @return Return the context ID
+     */
+    unsigned int GetId() const;
+
+    /**
+     * @return the context name
+     */
+    const char* GetName() const;
+
+    /**
+     *
+     * For logging we want to output the name of the context with either
+     * START / END appended to the end. E.g. MY_MARKER_START
+     * @param[in] type marker type, for a customer marker this will be either START or END
+     * @return the full description for a marker
+     */
+    const char* GetMarkerDescription( PerformanceInterface::MarkerType type ) const;
+
+    /**
+     * @brief Set the frequency for logging
+     *
+     * @param[in] logFrequencySeconds The log frequency to set in seconds
+     */
+    void SetLogFrequency( unsigned int logFrequencySeconds );
+
+    /**
+     * @brief enable/disable logging
+     *
+     * @param[in] enableLogging Flag to spePerformancecify enabling/disabling
+     */
+    void EnableLogging( bool enableLogging );
+
+    /**
+     * @brief  Process a custom marker from the application
+     *
+     * @param[in] marker The marker to log
+     */
+    void ProcessCustomMarker( const PerformanceMarker& marker );
+
+    /**
+     * @brief Process a internal marker from DALi (V_SYNC/ UPDATE /RENDER/ EVENT )
+     *
+     * @param[in] marker The marker to log
+     */
+    void ProcessInternalMarker( const PerformanceMarker& marker );
+
+  private:
+
+    /**
+     * @brief Record marker
+     *
+     * @param[in] marker to record
+     */
+    void RecordMarker( const PerformanceMarker& marker );
+
+    /**
+     * @brief Called when V-SYNC occurs to indicate a frame tick
+     * @param[in] marker the marker containing a v-sync
+     */
+    void FrameTick( const PerformanceMarker& marker );
+
+    /**
+     * @brief Helper to print to console
+     */
+    void LogMarker();
+
+
+  private:
+
+    StatContext();                                ///< undefined default constructor
+
+    StatContext( const StatContext& );            ///< undefined copy constructor
+
+    StatContext& operator=( const StatContext& ); ///< undefined assignment operator
+
+  private:
+
+    PerformanceMarker mInitialMarker;             ///< Used to store initial time
+    FrameTimeStats mStats;                        ///< Frame time stats to accumulate
+    const char* const mName;                      ///< Name of the context
+    char* mTempLogBuffer;                         ///< Temporary log buffer
+    StatContextLogInterface& mLogInterface;       ///< Log interface
+    const std::string mNamePlusStart;             ///< Name of the context + _START
+    const std::string mNamePlusEnd;                ///< Name of the context + _END
+    unsigned int mId;                             ///< The ID of the context
+    unsigned int mLogFrequencyMicroseconds;       ///< if logging is enabled, what frequency to log out at in micro-seconds
+    PerformanceMarker::MarkerFilter mFilterType;  ///< type of events the context is filtering
+    bool mLoggingEnabled:1;                       ///< Whether to print the log for this context or not
+    bool mInitialMarkerSet:1;                     ///< Whether the initial marker has been set
+
+};
+
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_STAT_CONTEXT_H
diff --git a/dali/internal/system/common/system-settings.h b/dali/internal/system/common/system-settings.h
new file mode 100644 (file)
index 0000000..174ad9b
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef DALI_INTERNAL_SYSTEM_SETTINGS_H
+#define DALI_INTERNAL_SYSTEM_SETTINGS_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+// Get SYSTEM_SETTINGS_KEY_TAP_AND_HOLD_DELAY from system setting if available
+int GetLongPressTime( int defaultTime );
+
+// Get ELM_ACCESS_ACTION_OVER from Elementary if available
+int GetElmAccessActionOver();
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_SYSTEM_SETTINGS_H
diff --git a/dali/internal/system/common/system-trace.cpp b/dali/internal/system/common/system-trace.cpp
new file mode 100644 (file)
index 0000000..73a98d2
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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 <dali/internal/system/common/system-trace.h>
+
+// EXTERNAL HEADERS
+#include <string>
+#include <dali/devel-api/common/hash.h>
+
+// INTERNAL HEADERS
+#include <dali/integration-api/debug.h>
+
+#ifdef ENABLE_TTRACE
+#include <ttrace.h>
+#else
+
+// Emulate trace calls if ttrace isn't available
+namespace
+{
+const int TTRACE_TAG_GRAPHICS = 1;
+
+void traceAsyncBegin(int tag, int cookie, const char *name, ...)
+{
+  Debug::LogMessage(Debug::DebugInfo, "AsyncBegin: %s : cookie %d\n", name, cookie );
+}
+void traceAsyncEnd(int tag, int cookie, const char *name, ...)
+{
+  Debug::LogMessage(Debug::DebugInfo, "AsyncEnd: %s : cookie %d\n", name, cookie );
+}
+void traceMark(int tag, const char *name, ...)
+{
+  Debug::LogMessage(Debug::DebugInfo, "Marker: %s \n", name);
+}
+} // un-named namespace
+#endif
+
+namespace
+{
+
+int GetCookie( const std::string& description, std::string& markerName )
+{
+  // description holds the marker name and postfix of _START or _END
+  std::size_t pos = description.find("_START");
+  if( pos == std::string::npos )
+  {
+    pos = description.find("_END");
+  }
+  if( !pos )
+  {
+    // if this asserts then check the postfix strings in StatContext.cpp for
+    // custom markers and performance-marker.cpp for built-in markers
+    DALI_ASSERT_DEBUG(0);
+  }
+  markerName = description.substr( 0, pos );
+
+  std::size_t hash =  Dali::CalculateHash( markerName.c_str() );
+  return static_cast<int>( hash );
+}
+}
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+SystemTrace::SystemTrace()
+{
+}
+SystemTrace::~SystemTrace()
+{
+}
+
+void SystemTrace::Trace( const PerformanceMarker& marker, const std::string& traceMessage )
+{
+  PerformanceMarker::MarkerEventType eventType = marker.GetEventType();
+
+  if( eventType == PerformanceMarker::SINGLE_EVENT )
+  {
+    traceMark( TTRACE_TAG_GRAPHICS, traceMessage.c_str() );
+    return;
+  }
+
+  // DALi is multi-threaded so timed events will occur asynchronously
+  std::string markerName;
+
+  int cookie = GetCookie(traceMessage, markerName );
+
+  if( eventType == PerformanceMarker::START_TIMED_EVENT )
+  {
+    traceAsyncBegin( TTRACE_TAG_GRAPHICS, cookie,  markerName.c_str() );
+  }
+  else
+  {
+    traceAsyncEnd( TTRACE_TAG_GRAPHICS, cookie,  markerName.c_str() );
+  }
+}
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
diff --git a/dali/internal/system/common/system-trace.h b/dali/internal/system/common/system-trace.h
new file mode 100644 (file)
index 0000000..7802f17
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef DALI_INTERNAL_ADAPTOR_SYSTEM_TRACE_H
+#define DALI_INTERNAL_ADAPTOR_SYSTEM_TRACE_H
+
+/*
+ * Copyright (c) 2019 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/internal/network/common/trace-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Concrete System  Tracing Interface.
+ * Used to log trace messages to the system using ttrace
+ *
+ */
+class SystemTrace : public TraceInterface
+{
+public:
+
+  /**
+   * Constructor
+   */
+  SystemTrace();
+
+  /**
+   * Destructor
+   */
+  virtual ~SystemTrace();
+
+  /**
+   * @copydoc KernelTracerInterface::KernelTrace()
+   */
+  virtual void Trace( const PerformanceMarker& marker, const std::string& traceMessage );
+
+};
+
+} // namespace Internal
+
+} // namespace Adaptor
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_SYSTEM_TRACE_H
diff --git a/dali/internal/system/common/thread-controller.cpp b/dali/internal/system/common/thread-controller.cpp
new file mode 100644 (file)
index 0000000..605c76d
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/thread-controller.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/environment-options.h>
+#include <dali/internal/adaptor/common/thread-controller-interface.h>
+#include <dali/internal/adaptor/common/combined-update-render-controller.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+ThreadController::ThreadController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions )
+: mThreadControllerInterface( NULL )
+{
+  switch( environmentOptions.GetThreadingMode() )
+  {
+    case ThreadingMode::COMBINED_UPDATE_RENDER:
+    {
+      mThreadControllerInterface = new CombinedUpdateRenderController( adaptorInterfaces, environmentOptions );
+      break;
+    }
+  }
+}
+
+ThreadController::~ThreadController()
+{
+  delete mThreadControllerInterface;
+}
+
+void ThreadController::Initialize()
+{
+  mThreadControllerInterface->Initialize();
+}
+
+void ThreadController::Start()
+{
+  mThreadControllerInterface->Start();
+}
+
+void ThreadController::Pause()
+{
+  mThreadControllerInterface->Pause();
+}
+
+void ThreadController::Resume()
+{
+  mThreadControllerInterface->Resume();
+}
+
+void ThreadController::Stop()
+{
+  mThreadControllerInterface->Stop();
+}
+
+void ThreadController::RequestUpdate()
+{
+  mThreadControllerInterface->RequestUpdate();
+}
+
+void ThreadController::RequestUpdateOnce(   UpdateMode updateMode )
+{
+  mThreadControllerInterface->RequestUpdateOnce( updateMode );
+}
+
+void ThreadController::ReplaceSurface( Dali::RenderSurfaceInterface* newSurface )
+{
+  mThreadControllerInterface->ReplaceSurface( newSurface );
+}
+
+void ThreadController::ResizeSurface()
+{
+  mThreadControllerInterface->ResizeSurface();
+}
+
+void ThreadController::WaitForGraphicsInitialization()
+{
+  mThreadControllerInterface->WaitForGraphicsInitialization();
+}
+
+void ThreadController::SetRenderRefreshRate(unsigned int numberOfVSyncsPerRender )
+{
+  mThreadControllerInterface->SetRenderRefreshRate( numberOfVSyncsPerRender );
+}
+
+void ThreadController::SetPreRenderCallback( CallbackBase* callback )
+{
+  mThreadControllerInterface->SetPreRenderCallback( callback );
+}
+
+void ThreadController::AddSurface( Dali::RenderSurfaceInterface* newSurface )
+{
+  mThreadControllerInterface->AddSurface( newSurface );
+}
+
+bool ThreadController::IsRenderingWindows() const
+{
+  return mThreadControllerInterface->IsRenderingWindows();
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/common/thread-controller.h b/dali/internal/system/common/thread-controller.h
new file mode 100644 (file)
index 0000000..471a5f9
--- /dev/null
@@ -0,0 +1,165 @@
+#ifndef DALI_INTERNAL_THREAD_CONTROLLER_H
+#define DALI_INTERNAL_THREAD_CONTROLLER_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <dali/public-api/signals/callback.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/window-system/common/display-connection.h>
+
+namespace Dali
+{
+
+class RenderSurfaceInterface;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+enum class UpdateMode;
+
+class AdaptorInternalServices;
+class EnvironmentOptions;
+class ThreadControllerInterface;
+
+/**
+ * Class to control all the threads.
+ */
+class ThreadController
+{
+public:
+
+  /**
+   * Constructor
+   */
+  ThreadController( AdaptorInternalServices& adaptorInterfaces, const EnvironmentOptions& environmentOptions );
+
+  /**
+   * Non virtual destructor. Not intended as base class.
+   */
+  ~ThreadController();
+
+  /**
+   * @brief Initializes the thread controller
+   *
+   * Will do any required initialiszation, e.g. initialize EGL, create threads (if required), etc.
+   *
+   * @note When this function returns, the application Init signal should be emitted
+   */
+  void Initialize();
+
+  /**
+   * @brief Called AFTER the Init signal has been emitted.
+   *
+   * In other words, should be called AFTER the Init signal has been emitted and all messages for the first scene
+   * have been queued for update to process.
+   */
+  void Start();
+
+  /**
+   * @brief When called, update and rendering is paused.
+   */
+  void Pause();
+
+  /**
+   * @brief Resumes update/rendering after a previous pause.
+   */
+  void Resume();
+
+  /**
+   * @brief Stops update/rendering altogether.
+   *
+   * Will shutdown EGL, destroy threads (if required) etc.
+   */
+  void Stop();
+
+  /**
+   * @brief Called by the adaptor when core requires another update
+   */
+  void RequestUpdate();
+
+  /**
+   * @brief Called by the adaptor when core requires one update
+   *
+   * @note If Adaptor is paused, we do one update/render only
+   *
+   * @param updateMode The update mode (i.e. either update and render, or update and upload without rendering)
+   */
+  void RequestUpdateOnce( UpdateMode updateMode );
+
+  /**
+   * @brief Replaces the surface.
+   *
+   * @param surface new surface
+   */
+  void ReplaceSurface( Dali::RenderSurfaceInterface* surface );
+
+  /**
+   * Resize the surface.
+   */
+  void ResizeSurface();
+
+  /**
+   * Wait until the graphics is initialised.
+   */
+  void WaitForGraphicsInitialization();
+
+  /**
+   * @copydoc Dali::Adaptor::SetRenderRefreshRate()
+   */
+  void SetRenderRefreshRate( unsigned int numberOfVSyncsPerRender );
+
+  /**
+   * @copydoc Dali::Adaptor::SetPreRenderCallback
+   */
+  void SetPreRenderCallback( CallbackBase* callback );
+
+  /**
+   * @brief Adds the new surface.
+   *
+   * @param surface new surface
+   */
+  void AddSurface( Dali::RenderSurfaceInterface* surface );
+
+  /**
+   * @copydoc Dali::Adaptor::IsRenderingWindows()
+   */
+  bool IsRenderingWindows() const;
+
+private:
+
+  // Undefined copy constructor.
+  ThreadController( const ThreadController& ) = delete;
+
+  // Undefined assignment operator.
+  ThreadController& operator=( const ThreadController& ) = delete;
+
+private:
+
+  ThreadControllerInterface* mThreadControllerInterface;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_THREAD_CONTROLLER_H
diff --git a/dali/internal/system/common/time-service.cpp b/dali/internal/system/common/time-service.cpp
new file mode 100644 (file)
index 0000000..aa310b7
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ *
+ */
+
+// HEADER
+#include <dali/internal/system/common/time-service.h>
+
+// EXTERNAL INCLUDES
+#include <ctime>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace TimeService
+{
+
+namespace
+{
+const uint64_t NANOSECONDS_PER_SECOND = 1e+9;
+}
+
+void GetNanoseconds( uint64_t& timeInNanoseconds )
+{
+  timespec timeSpec;
+  if( clock_gettime( CLOCK_MONOTONIC, &timeSpec ) == 0 )
+  {
+    // Convert all values to uint64_t to match our return type
+    timeInNanoseconds = ( static_cast< uint64_t >( timeSpec.tv_sec ) * NANOSECONDS_PER_SECOND ) + static_cast< uint64_t >( timeSpec.tv_nsec );
+  }
+  else
+  {
+    timeInNanoseconds = 0;
+  }
+}
+
+void SleepUntil( uint64_t timeInNanoseconds )
+{
+  timespec timeSpec;
+  timeSpec.tv_sec  = timeInNanoseconds / NANOSECONDS_PER_SECOND;
+  timeSpec.tv_nsec = timeInNanoseconds % NANOSECONDS_PER_SECOND;
+
+  // clock_nanosleep returns 0 if it sleeps for the period specified, otherwise it returns an error value
+  // If an error value is returned, just sleep again till the absolute time specified
+  while( clock_nanosleep( CLOCK_MONOTONIC, TIMER_ABSTIME, &timeSpec, NULL ) )
+  {
+  }
+}
+
+} // namespace TimeService
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/common/time-service.h b/dali/internal/system/common/time-service.h
new file mode 100644 (file)
index 0000000..094aeba
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef DALI_INTERNAL_TIME_SERVICE_H
+#define DALI_INTERNAL_TIME_SERVICE_H
+
+/*
+ * Copyright (c) 2019 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 <stdint.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace TimeService
+{
+
+/**
+ * @brief Get the monotonic time since some unspecified starting point (usually the boot time).
+ *
+ * @param[out]  timeInNanoseconds  The time in nanoseconds since the reference point.
+ *
+ * @note The maximum value timeInNanoseconds can hold is 0xFFFFFFFFFFFFFFFF which is 1.844674407e+19. Therefore, this can overflow after approximately 584 years.
+ */
+void GetNanoseconds( uint64_t& timeInNanoseconds );
+
+/**
+ * @brief Sleeps until the monotonic time specified since some unspecified starting point (usually the boot time).
+ *
+ * If the time specified has already passed, then it returns immediately.
+ *
+ * @param[in]  timeInNanoseconds  The time to sleep until
+ *
+ * @note The maximum value timeInNanoseconds can hold is 0xFFFFFFFFFFFFFFFF which is 1.844674407e+19. Therefore, this can overflow after approximately 584 years.
+ */
+void SleepUntil( uint64_t timeInNanoseconds );
+
+} // namespace TimeService
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TIME_SERVICE_H
diff --git a/dali/internal/system/common/timer-impl.h b/dali/internal/system/common/timer-impl.h
new file mode 100644 (file)
index 0000000..4f1b1c6
--- /dev/null
@@ -0,0 +1,150 @@
+#ifndef DALI_INTERNAL_TIMER_H
+#define DALI_INTERNAL_TIMER_H
+
+/*
+ * Copyright (c) 2019 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/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/internal/system/common/timer-interface.h>
+#include <dali/public-api/adaptor-framework/timer.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class Timer;
+
+typedef IntrusivePtr<Timer> TimerPtr;
+
+/**
+ * Implementation of the timer
+ */
+class Timer : public BaseObject, public TimerInterface
+{
+public:
+  static TimerPtr New( unsigned int milliSec );
+
+  /**
+   * Constructor
+   * @param[in]  milliSec  Interval in milliseconds.
+   */
+  Timer( unsigned int milliSec );
+
+  /**
+   * Destructor.
+   */
+  virtual ~Timer();
+
+public:
+
+  /**
+   * @copydoc Dali::Timer::Start()
+   */
+  virtual void Start();
+
+  /**
+   * @copydoc Dali::Timer::Stop()
+   */
+  virtual void Stop();
+
+  /**
+   * @copydoc Dali::Timer::Pause()
+   */
+  virtual void Pause();
+
+  /**
+   * @copydoc Dali::Timer::Resume()
+   */
+  virtual void Resume();
+
+  /**
+   * @copydoc Dali::Timer::SetInterval()
+   */
+  virtual void SetInterval( unsigned int interval, bool restart );
+
+  /**
+   * @copydoc Dali::Timer::GetInterval()
+   */
+  virtual unsigned int GetInterval() const;
+
+  /**
+   * @copydoc Dali::Timer::IsRunning()
+   */
+  virtual bool IsRunning() const;
+
+  /**
+   * Tick
+   */
+  bool Tick();
+
+public: // Signals
+
+  Dali::Timer::TimerSignalType& TickSignal();
+
+private: // Implementation
+
+  // not implemented
+  Timer( const Timer& );
+  Timer& operator=( const Timer& );
+
+  /**
+   * Resets any stored timer data.
+   */
+  void ResetTimerData();
+
+private: // Data
+
+  Dali::Timer::TimerSignalType mTickSignal;
+
+  // To hide away implementation details
+  struct Impl;
+  Impl* mImpl;
+};
+
+inline Timer& GetImplementation(Dali::Timer& timer)
+{
+  DALI_ASSERT_ALWAYS(timer && "Timer handle is empty");
+
+  BaseObject& handle = timer.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::Timer&>(handle);
+}
+
+inline const Timer& GetImplementation(const Dali::Timer& timer)
+{
+  DALI_ASSERT_ALWAYS(timer && "Timer handle is empty");
+
+  const BaseObject& handle = timer.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::Timer&>(handle);
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TIMER_H
diff --git a/dali/internal/system/common/timer-interface.h b/dali/internal/system/common/timer-interface.h
new file mode 100644 (file)
index 0000000..f75afdf
--- /dev/null
@@ -0,0 +1,81 @@
+#ifndef DALI_INTERNAL_ADAPTOR_BASE_TIMER_INTERFACE_H
+#define DALI_INTERNAL_ADAPTOR_BASE_TIMER_INTERFACE_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * Interface for a timer class
+ */
+class TimerInterface
+{
+public:
+  /**
+   * @copydoc Dali::Timer::Start()
+   */
+  virtual void Start() = 0;
+
+  /**
+   * @copydoc Dali::Timer::Stop()
+   */
+  virtual void Stop() = 0;
+
+  /**
+   * @copydoc Dali::Timer::Pause()
+   */
+  virtual void Pause() = 0;
+
+  /**
+   * @copydoc Dali::Timer::Resume()
+   */
+  virtual void Resume() = 0;
+
+  /**
+   * @copydoc Dali::Timer::SetInterval()
+   */
+  virtual void SetInterval( unsigned int intervalInMilliseconds, bool restart ) = 0;
+
+  /**
+   * @copydoc Dali::Timer::GetInterval()
+   */
+  virtual unsigned int GetInterval() const = 0;
+
+  /**
+   * @copydoc Dali::Timer::IsRunning()
+   */
+  virtual bool IsRunning() const = 0;
+
+protected:
+  /**
+   * Virtual protected destructor, no deletion through this interface
+   */
+  virtual ~TimerInterface() { }
+};
+
+
+} // Adaptor
+} // Internal
+} // Dali
+
+#endif // DALI_INTERNAL_ADAPTOR_BASE_TIMER_INTERFACE_H
diff --git a/dali/internal/system/common/trigger-event-factory.cpp b/dali/internal/system/common/trigger-event-factory.cpp
new file mode 100644 (file)
index 0000000..242be5d
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/trigger-event.h>
+
+namespace Dali
+{
+
+TriggerEventInterface* TriggerEventFactory::CreateTriggerEvent( CallbackBase* callback,  TriggerEventInterface::Options options )
+{
+  return new Internal::Adaptor::TriggerEvent( callback, options );
+}
+
+void TriggerEventFactory::DestroyTriggerEvent( TriggerEventInterface* triggerEventInterface )
+{
+  Internal::Adaptor::TriggerEvent* triggerEvent( static_cast<Internal::Adaptor::TriggerEvent *>(triggerEventInterface) );
+  delete triggerEvent;
+}
+
+} // namespace Dali
diff --git a/dali/internal/system/common/trigger-event.cpp b/dali/internal/system/common/trigger-event.cpp
new file mode 100644 (file)
index 0000000..005f5ec
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/trigger-event.h>
+
+// EXTERNAL INCLUDES
+#include <sys/eventfd.h>
+#include <unistd.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+
+#include <dali/internal/system/common/file-descriptor-monitor.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+TriggerEvent::TriggerEvent( CallbackBase* callback, TriggerEventInterface::Options options )
+: mFileDescriptorMonitor( NULL ),
+  mCallback( callback ),
+  mFileDescriptor( -1 ),
+  mOptions( options )
+{
+  // Create accompanying file descriptor.
+  mFileDescriptor = eventfd(0, EFD_NONBLOCK);
+  if (mFileDescriptor >= 0)
+  {
+    // Now Monitor the created event file descriptor
+    mFileDescriptorMonitor = new FileDescriptorMonitor( mFileDescriptor, MakeCallback( this, &TriggerEvent::Triggered ), FileDescriptorMonitor::FD_READABLE );
+  }
+  else
+  {
+    DALI_LOG_ERROR("Unable to create TriggerEvent File descriptor\n");
+  }
+}
+
+TriggerEvent::~TriggerEvent()
+{
+  delete mFileDescriptorMonitor;
+  delete mCallback;
+
+  if (mFileDescriptor >= 0)
+  {
+    close(mFileDescriptor);
+    mFileDescriptor = 0;
+  }
+}
+
+void TriggerEvent::Trigger()
+{
+  if (mFileDescriptor >= 0)
+  {
+    // Increment event counter by 1.
+    // Writing to the file descriptor triggers the Dispatch() method in the other thread
+    // (if in multi-threaded environment).
+
+    uint64_t data = 1;
+    int size = write(mFileDescriptor, &data, sizeof(uint64_t));
+
+    if (size != sizeof(uint64_t))
+    {
+      DALI_LOG_ERROR("Unable to write to UpdateEvent File descriptor\n");
+    }
+  }
+  else
+  {
+    DALI_LOG_WARNING("Attempting to write to an invalid file descriptor\n");
+  }
+}
+
+void TriggerEvent::Triggered( FileDescriptorMonitor::EventType eventBitMask )
+{
+  if( !( eventBitMask & FileDescriptorMonitor::FD_READABLE ) )
+  {
+    DALI_ASSERT_ALWAYS( 0 && "Trigger event file descriptor error");
+    return;
+  }
+
+  // Reading from the file descriptor resets the event counter, we can ignore the count.
+  uint64_t receivedData;
+  size_t size;
+  size = read(mFileDescriptor, &receivedData, sizeof(uint64_t));
+  if (size != sizeof(uint64_t))
+  {
+    DALI_LOG_WARNING("Unable to read to UpdateEvent File descriptor\n");
+  }
+
+  // Call the connected callback
+  CallbackBase::Execute( *mCallback );
+
+  //check if we should delete ourselves after the trigger
+  if( mOptions == TriggerEventInterface::DELETE_AFTER_TRIGGER )
+  {
+    delete this;
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/common/trigger-event.h b/dali/internal/system/common/trigger-event.h
new file mode 100644 (file)
index 0000000..09ef23d
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef DALI_INTERNAL_TRIGGER_EVENT_H
+#define DALI_INTERNAL_TRIGGER_EVENT_H
+
+/*
+ * Copyright (c) 2019 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/signals/callback.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/integration-api/adaptor-framework/trigger-event-interface.h>
+#include <dali/internal/system/common/file-descriptor-monitor.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+
+/**
+ * The TriggerEvent class is used to send events between threads.  For example, this can be used
+ * to wake up one thread from another thread.
+ *
+ * Typically, these should be created in the application thread.
+ *
+ * The observer will be informed whenever the event is triggered.
+ *
+ * The implementation of TriggerEvent uses an event file descriptor.
+ */
+class TriggerEvent : public TriggerEventInterface
+{
+public:
+
+  /**
+   * Constructor
+   * Creates an event file descriptor and starts a GSource which reads from the file
+   * descriptor when there is data.
+   *
+   * @param[in] callback The callback to call
+   * @param[in] options Trigger event options.
+   * @note The ownership of callback is taken by this class.
+   */
+  TriggerEvent( CallbackBase* callback, TriggerEventInterface::Options options );
+
+  /**
+   * Destructor
+   */
+  ~TriggerEvent();
+
+public:
+
+  /**
+   * Triggers the event.
+   *
+   * This can be called from one thread in order to wake up another thread.
+   */
+  void Trigger();
+
+private:
+
+  /**
+   * @brief Called when our event file descriptor has been written to.
+   * @param[in] eventBitMask bit mask of events that occured on the file descriptor
+   */
+  void Triggered( FileDescriptorMonitor::EventType eventBitMask );
+
+private:
+
+  struct Source;
+
+private:
+
+  FileDescriptorMonitor* mFileDescriptorMonitor;
+  CallbackBase* mCallback;
+  int mFileDescriptor;
+  TriggerEventInterface::Options mOptions;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TRIGGER_EVENT_H
diff --git a/dali/internal/system/common/update-status-logger.cpp b/dali/internal/system/common/update-status-logger.cpp
new file mode 100644 (file)
index 0000000..d238b0a
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * 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 <dali/internal/system/common/update-status-logger.h>
+
+// EXTERNAL INCLUDES
+#include <string>
+#include <dali/integration-api/core.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/environment-options.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+UpdateStatusLogger::UpdateStatusLogger( const EnvironmentOptions& environmentOptions )
+: mStatusLogInterval( environmentOptions.GetUpdateStatusLoggingFrequency() ),
+  mStatusLogCount( 0u )
+{
+}
+
+UpdateStatusLogger::~UpdateStatusLogger()
+{
+}
+
+void UpdateStatusLogger::Log( unsigned int keepUpdatingStatus )
+{
+  if ( mStatusLogInterval )
+  {
+    std::string oss;
+
+    if ( !(++mStatusLogCount % mStatusLogInterval) )
+    {
+      oss = "UpdateStatusLogging keepUpdating: ";
+      oss += (keepUpdatingStatus ? "true":"false");
+
+      if ( keepUpdatingStatus )
+      {
+        oss += " because: ";
+      }
+
+      if ( keepUpdatingStatus & Integration::KeepUpdating::STAGE_KEEP_RENDERING )
+      {
+        oss += "<Stage::KeepRendering() used> ";
+      }
+
+      if ( keepUpdatingStatus & Integration::KeepUpdating::ANIMATIONS_RUNNING )
+      {
+        oss  +=  "<Animations running> ";
+      }
+
+      if ( keepUpdatingStatus & Integration::KeepUpdating::MONITORING_PERFORMANCE )
+      {
+        oss += "<Monitoring performance> ";
+      }
+
+      if ( keepUpdatingStatus & Integration::KeepUpdating::RENDER_TASK_SYNC )
+      {
+        oss += "<Render task waiting for completion> ";
+      }
+
+      DALI_LOG_UPDATE_STATUS( "%s\n", oss.c_str());
+    }
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/common/update-status-logger.h b/dali/internal/system/common/update-status-logger.h
new file mode 100644 (file)
index 0000000..094a7b3
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef DALI_INTERNAL_UPDATE_STATUS_LOGGER_H
+#define DALI_INTERNAL_UPDATE_STATUS_LOGGER_H
+
+/*
+ * Copyright (c) 2019 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
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class EnvironmentOptions;
+
+/**
+ * This outputs the status of the update as required.
+ */
+class UpdateStatusLogger
+{
+public:
+
+  /**
+   * Create the update-status-logger.
+   * @param[in] environmentOptions environment options
+   */
+  UpdateStatusLogger( const EnvironmentOptions& environmentOptions );
+
+  /**
+   * Non-virtual destructor; UpdateThread is not suitable as a base class.
+   */
+  ~UpdateStatusLogger();
+
+  /**
+   * Optionally output the update thread status.
+   * @param[in] keepUpdatingStatus Whether the update-thread requested further updates.
+   */
+  void Log( unsigned int keepUpdatingStatus );
+
+private: // Data
+
+  unsigned int mStatusLogInterval;   ///< Interval in frames between status debug prints
+  unsigned int mStatusLogCount;      ///< Used to count frames between status debug prints
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_UPDATE_STATUS_LOGGER_H
diff --git a/dali/internal/system/common/widget-application-impl.cpp b/dali/internal/system/common/widget-application-impl.cpp
new file mode 100644 (file)
index 0000000..da34463
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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 <dali/internal/system/common/widget-application-impl.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+// factory function, must be implemented
+namespace WidgetApplicationFactory
+{
+/**
+ * Create a new widget 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
+ */
+WidgetApplicationPtr Create( int* argc, char **argv[], const std::string& stylesheet );
+
+} // namespace Factory
+
+WidgetApplicationPtr WidgetApplication::New(
+  int* argc,
+  char **argv[],
+  const std::string& stylesheet)
+{
+  //WidgetApplicationPtr //widgetApplication( new WidgetApplication (argc, argv, stylesheet ) );
+  return WidgetApplicationFactory::Create( argc, argv, stylesheet );
+}
+
+WidgetApplication::WidgetApplication( int* argc, char** argv[], const std::string& stylesheet )
+: Application(argc, argv, stylesheet, Dali::WidgetApplication::OPAQUE, PositionSize(), Framework::WIDGET)
+{
+  DALI_LOG_ERROR("WidgetApplication is not implemented in UBUNTU profile.\n");
+}
+
+WidgetApplication::~WidgetApplication()
+{
+}
+
+void WidgetApplication::RegisterWidgetCreatingFunction( const std::string& widgetName, Dali::WidgetApplication::CreateWidgetFunction createFunction )
+{
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/common/widget-application-impl.h b/dali/internal/system/common/widget-application-impl.h
new file mode 100644 (file)
index 0000000..d490166
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef DALI_INTERNAL_WIDGET_APPLICATION_IMPL_H
+#define DALI_INTERNAL_WIDGET_APPLICATION_IMPL_H
+
+/*
+ * Copyright (c) 2018 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 <dali/internal/adaptor/common/application-impl.h>
+#include <dali/public-api/adaptor-framework/widget-application.h>
+
+#include <memory>
+
+namespace Dali
+{
+class Widget;
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+typedef IntrusivePtr<WidgetApplication> WidgetApplicationPtr;
+
+/**
+ * Implementation of the WidgetApplication class.
+ */
+class WidgetApplication : public Application
+{
+public:
+
+  typedef std::pair<const std::string, Dali::WidgetApplication::CreateWidgetFunction >  CreateWidgetFunctionPair;
+  typedef std::vector< CreateWidgetFunctionPair >   CreateWidgetFunctionContainer;
+
+  /**
+   * Create a new widget 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
+   */
+  static WidgetApplicationPtr New( int* argc, char **argv[], const std::string& stylesheet );
+
+public:
+
+  /**
+   * @copydoc Dali::WidgetApplication::RegisterWidgetCreator()
+   */
+  virtual void RegisterWidgetCreatingFunction( const std::string& widgetName, Dali::WidgetApplication::CreateWidgetFunction createFunction );
+
+protected:
+
+  /**
+   * 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
+   */
+  WidgetApplication( int* argc, char **argv[], const std::string& stylesheet );
+
+  /**
+   * Destructor
+   */
+  virtual ~WidgetApplication();
+
+  // Undefined
+  WidgetApplication(const Application&) = delete;
+  WidgetApplication& operator=(Application&) = delete;
+};
+
+inline WidgetApplication& GetImplementation(Dali::WidgetApplication& widgetApplication)
+{
+  DALI_ASSERT_ALWAYS(widgetApplication && "widget application handle is empty");
+
+  BaseObject& handle = widgetApplication.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::WidgetApplication&>(handle);
+}
+
+inline const WidgetApplication& GetImplementation(const Dali::WidgetApplication& widgetApplication)
+{
+  DALI_ASSERT_ALWAYS(widgetApplication && "widget application handle is empty");
+
+  const BaseObject& handle = widgetApplication.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::WidgetApplication&>(handle);
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WIDGET_APPLICATION_IMPL_H
diff --git a/dali/internal/system/common/widget-controller.h b/dali/internal/system/common/widget-controller.h
new file mode 100644 (file)
index 0000000..508463a
--- /dev/null
@@ -0,0 +1,54 @@
+#ifndef DALI_WIDGET_CONTROLLER_H
+#define DALI_WIDGET_CONTROLLER_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/signals/connection-tracker.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/widget-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+/**
+ * @brief Holds the Implementation for the internal WidgetImpl class
+ */
+class Widget::Impl : public Dali::ConnectionTracker
+{
+public:
+
+  /**
+   * Set content information to widget framework
+   */
+  virtual void SetContentInfo( const std::string& contentInfo ) = 0;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_WIDGET_CONTROLLER_H
diff --git a/dali/internal/system/file.list b/dali/internal/system/file.list
new file mode 100644 (file)
index 0000000..3c5be55
--- /dev/null
@@ -0,0 +1,100 @@
+
+# module: system, backend: common
+SET( adaptor_system_common_src_files
+    ${adaptor_system_dir}/common/abort-handler.cpp
+    ${adaptor_system_dir}/common/color-controller-impl.cpp
+    ${adaptor_system_dir}/common/command-line-options.cpp
+    ${adaptor_system_dir}/common/configuration-manager.cpp
+    ${adaptor_system_dir}/common/environment-options.cpp
+    ${adaptor_system_dir}/common/fps-tracker.cpp
+    ${adaptor_system_dir}/common/frame-time-stamp.cpp
+    ${adaptor_system_dir}/common/frame-time-stats.cpp
+    ${adaptor_system_dir}/common/kernel-trace.cpp
+    ${adaptor_system_dir}/common/locale-utils.cpp
+    ${adaptor_system_dir}/common/object-profiler.cpp
+    ${adaptor_system_dir}/common/performance-interface-factory.cpp
+    ${adaptor_system_dir}/common/performance-logger-impl.cpp
+    ${adaptor_system_dir}/common/performance-marker.cpp
+    ${adaptor_system_dir}/common/performance-server.cpp
+    ${adaptor_system_dir}/common/sound-player-impl.cpp
+    ${adaptor_system_dir}/common/stat-context.cpp
+    ${adaptor_system_dir}/common/stat-context-manager.cpp
+    ${adaptor_system_dir}/common/system-trace.cpp
+    ${adaptor_system_dir}/common/thread-controller.cpp
+    ${adaptor_system_dir}/common/time-service.cpp
+    ${adaptor_system_dir}/common/update-status-logger.cpp
+    ${adaptor_system_dir}/common/widget-application-impl.cpp
+)
+
+# module: system, backend: linux
+SET( adaptor_system_linux_src_files
+    ${adaptor_system_dir}/common/shared-file.cpp
+    ${adaptor_system_dir}/common/trigger-event.cpp
+    ${adaptor_system_dir}/common/trigger-event-factory.cpp
+    ${adaptor_system_dir}/linux/callback-manager-ecore.cpp
+    ${adaptor_system_dir}/linux/file-descriptor-monitor-ecore.cpp
+    ${adaptor_system_dir}/generic/shared-file-operations-generic.cpp
+    ${adaptor_system_dir}/linux/timer-impl-ecore.cpp
+)
+
+# module: system, backend: tizen-wayland
+SET( adaptor_system_tizen_wayland_src_files
+    ${adaptor_system_dir}/common/shared-file.cpp
+    ${adaptor_system_dir}/common/trigger-event.cpp
+    ${adaptor_system_dir}/common/trigger-event-factory.cpp
+    ${adaptor_system_dir}/tizen-wayland/logging-tizen.cpp
+    ${adaptor_system_dir}/tizen-wayland/system-settings-tizen.cpp
+    ${adaptor_system_dir}/tizen-wayland/widget-application-impl-tizen.cpp
+    ${adaptor_system_dir}/tizen-wayland/widget-controller-tizen.cpp
+)
+
+# module: system, backend: tizen-wearable
+SET( adaptor_system_tizen_wearable_src_files
+    ${adaptor_system_dir}/common/shared-file.cpp
+    ${adaptor_system_dir}/common/trigger-event.cpp
+    ${adaptor_system_dir}/common/trigger-event-factory.cpp
+    ${adaptor_system_dir}/tizen-wayland/logging-tizen.cpp
+    ${adaptor_system_dir}/tizen-wayland/tizen-wearable/capture.cpp
+    ${adaptor_system_dir}/tizen-wayland/tizen-wearable/capture-impl-tizen.cpp
+    ${adaptor_system_dir}/tizen-wayland/tizen-wearable/watch-time.cpp
+    ${adaptor_system_dir}/tizen-wayland/system-settings-tizen.cpp
+    ${adaptor_system_dir}/tizen-wayland/widget-application-impl-tizen.cpp
+    ${adaptor_system_dir}/tizen-wayland/widget-controller-tizen.cpp
+)
+
+# module: system, backend: ubuntu-x11
+SET( adaptor_system_ubuntu_x11_src_files
+    ${adaptor_system_dir}/common/shared-file.cpp
+    ${adaptor_system_dir}/common/trigger-event.cpp
+    ${adaptor_system_dir}/common/trigger-event-factory.cpp
+    ${adaptor_system_dir}/ubuntu-x11/logging-x.cpp
+    ${adaptor_system_dir}/ubuntu-x11/system-settings-x.cpp
+    ${adaptor_system_dir}/ubuntu-x11/widget-application-impl-x.cpp
+    ${adaptor_system_dir}/ubuntu-x11/widget-controller-x.cpp
+)
+
+# module: system, backend: android
+SET( adaptor_system_android_src_files
+    ${adaptor_system_dir}/common/shared-file.cpp
+    ${adaptor_system_dir}/common/trigger-event.cpp
+    ${adaptor_system_dir}/common/trigger-event-factory.cpp
+    ${adaptor_system_dir}/android/callback-manager-android.cpp
+    ${adaptor_system_dir}/android/file-descriptor-monitor-android.cpp
+    ${adaptor_system_dir}/android/logging-android.cpp
+    ${adaptor_system_dir}/android/shared-file-operations-android.cpp
+    ${adaptor_system_dir}/android/system-settings-android.cpp
+    ${adaptor_system_dir}/android/timer-impl-android.cpp
+    ${adaptor_system_dir}/android/widget-application-impl-android.cpp
+)
+
+# module: system, backend: windows
+SET( adaptor_system_windows_src_files
+    ${adaptor_system_dir}/windows/callback-manager-win.cpp
+    ${adaptor_system_dir}/windows/system-settings-win.cpp
+    ${adaptor_system_dir}/windows/timer-impl-win.cpp
+    ${adaptor_system_dir}/windows/trigger-event.cpp
+    ${adaptor_system_dir}/windows/trigger-event-factory.cpp
+    ${adaptor_system_dir}/windows/logging-win.cpp
+    ${adaptor_system_dir}/windows/widget-application-impl-win.cpp
+    ${adaptor_system_dir}/windows/widget-controller-win.cpp
+)
diff --git a/dali/internal/system/generic/shared-file-operations-generic.cpp b/dali/internal/system/generic/shared-file-operations-generic.cpp
new file mode 100644 (file)
index 0000000..1a87966
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/shared-file.h>
+
+// EXTERNAL INCLUDES
+#include <sys/types.h>
+#include <sys/mman.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+int SharedFile::Open( const char* filename, int size, int oflag, mode_t mode )
+{
+  return shm_open( filename, oflag, mode );
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/dali/internal/system/linux/callback-manager-ecore.cpp b/dali/internal/system/linux/callback-manager-ecore.cpp
new file mode 100644 (file)
index 0000000..ade2f19
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/linux/callback-manager-ecore.h>
+
+// EXTERNAL INCLUDES
+#include <dali/internal/system/linux/dali-ecore.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Structure contains the callback function and control options
+ */
+struct CallbackData
+{
+
+  /**
+   * Constructor
+   */
+  CallbackData( CallbackBase* callback, bool hasReturnValue )
+  :  mCallback( callback ),
+     mRemoveFromContainerFunction( NULL ),
+     mIdler( NULL ),
+     mIdleEnterer( NULL ),
+     mHasReturnValue( hasReturnValue )
+  {
+  }
+  /**
+   * Destructor
+   */
+  ~CallbackData()
+  {
+    delete mCallback;
+    delete mRemoveFromContainerFunction;
+  }
+
+  CallbackBase*                   mCallback;       ///< call back
+  CallbackBase*                   mRemoveFromContainerFunction; ///< Called to remove the callbackdata from the callback container
+  Ecore_Idler*                    mIdler;          ///< ecore idler
+  Ecore_Idle_Enterer*             mIdleEnterer;    ///< ecore idle enterer
+  bool                            mHasReturnValue; ///< true if the callback function has a return value.
+};
+
+namespace
+{
+
+/**
+ * Called from the main thread while idle.
+ */
+Eina_Bool IdleCallback(void *data)
+{
+  Eina_Bool ret = ECORE_CALLBACK_CANCEL;    // CALLBACK Cancel will delete the idler so we don't need to call ecore_idler_del
+  CallbackData *callbackData = static_cast< CallbackData * >( data );
+
+  if( callbackData->mHasReturnValue )
+  {
+    // run the function
+    bool retValue = CallbackBase::ExecuteReturn< bool >( *callbackData->mCallback );
+    if( retValue )
+    {
+      // keep the callback
+      ret = ECORE_CALLBACK_RENEW;
+    }
+    else
+    {
+      // remove callback data from the container
+      CallbackBase::Execute( *callbackData->mRemoveFromContainerFunction, callbackData );
+
+      // delete our data
+      delete callbackData;
+    }
+  }
+  else
+  {
+    // remove callback data from the container
+    CallbackBase::Execute( *callbackData->mRemoveFromContainerFunction, callbackData );
+
+    // run the function
+    CallbackBase::Execute( *callbackData->mCallback );
+
+    // delete our data
+    delete callbackData;
+  }
+
+  return ret;
+}
+
+} // unnamed namespace
+
+EcoreCallbackManager::EcoreCallbackManager()
+:mRunning(false)
+{
+}
+
+
+void EcoreCallbackManager::Start()
+{
+  DALI_ASSERT_DEBUG( mRunning == false );
+
+  mRunning = true;
+}
+
+void EcoreCallbackManager::Stop()
+{
+  // make sure we're not called twice
+  DALI_ASSERT_DEBUG( mRunning == true );
+
+  RemoveAllCallbacks();
+
+  mRunning = false;
+
+}
+
+bool EcoreCallbackManager::AddIdleCallback( CallbackBase* callback, bool hasReturnValue )
+{
+  if( !mRunning )
+  {
+    return false;
+  }
+
+  CallbackData* callbackData = new CallbackData( callback, hasReturnValue );
+
+  callbackData->mRemoveFromContainerFunction =  MakeCallback( this, &EcoreCallbackManager::RemoveCallbackFromContainer );
+
+  // add the call back to the container
+  mCallbackContainer.push_front(callbackData);
+
+  // add the idler
+  callbackData->mIdler = ecore_idler_add( IdleCallback, callbackData);
+
+  DALI_ASSERT_ALWAYS( ( callbackData->mIdler != NULL ) && "Idle method not created" );
+
+  return true;
+}
+
+void EcoreCallbackManager::RemoveIdleCallback( CallbackBase* callback )
+{
+  for( CallbackList::iterator it = mCallbackContainer.begin(),
+         endIt = mCallbackContainer.end();
+       it != endIt;
+       ++it )
+  {
+    CallbackData* data = *it;
+
+    if( data->mCallback == callback )
+    {
+      // remove callback data from the container.
+      CallbackBase::Execute( *data->mRemoveFromContainerFunction, data );
+
+      ecore_idler_del( data->mIdler );
+
+      // delete our data
+      delete data;
+
+      return;
+    }
+  }
+}
+
+bool EcoreCallbackManager::ProcessIdle()
+{
+  // @todo To be implemented.
+  return false;
+}
+
+void EcoreCallbackManager::ClearIdleCallbacks()
+{
+  // @todo To be implemented.
+}
+
+bool EcoreCallbackManager::AddIdleEntererCallback( CallbackBase* callback )
+{
+  if( !mRunning )
+  {
+    return false;
+  }
+
+  CallbackData* callbackData = new CallbackData( callback, true );
+
+  callbackData->mRemoveFromContainerFunction = MakeCallback( this, &EcoreCallbackManager::RemoveCallbackFromContainer );
+
+  // add the call back to the container
+  mCallbackContainer.push_front( callbackData );
+
+  // add the idler
+  callbackData->mIdleEnterer = ecore_idle_enterer_add( IdleCallback, callbackData );
+
+  DALI_ASSERT_ALWAYS( ( callbackData->mIdleEnterer != NULL ) && "Idle method not created" );
+
+  return true;
+}
+
+void EcoreCallbackManager::RemoveIdleEntererCallback( CallbackBase* callback )
+{
+  for( CallbackList::iterator it = mCallbackContainer.begin(),
+         endIt = mCallbackContainer.end();
+       it != endIt;
+       ++it )
+  {
+    CallbackData* data = *it;
+
+    if( data->mCallback == callback )
+    {
+      // remove callback data from the container.
+      CallbackBase::Execute( *data->mRemoveFromContainerFunction, data );
+
+      ecore_idle_enterer_del( data->mIdleEnterer );
+
+      // delete our data
+      delete data;
+
+      return;
+    }
+  }
+}
+
+void EcoreCallbackManager::RemoveCallbackFromContainer(CallbackData *callbackData)
+{
+  mCallbackContainer.remove(callbackData);
+}
+
+void EcoreCallbackManager::RemoveAllCallbacks()
+{
+  // always called from main thread
+  for( CallbackList::iterator  iter =  mCallbackContainer.begin(); iter != mCallbackContainer.end(); ++iter)
+  {
+    CallbackData* data = (*iter);
+
+    if( data->mIdler )
+    {
+      ecore_idler_del( data->mIdler );
+    }
+    else if( data->mIdleEnterer )
+    {
+      ecore_idle_enterer_del( data->mIdleEnterer );
+    }
+
+    delete data;
+  }
+  mCallbackContainer.clear();
+}
+
+// Creates a concrete interface for CallbackManager
+CallbackManager* CallbackManager::New()
+{
+  return new EcoreCallbackManager;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/linux/callback-manager-ecore.h b/dali/internal/system/linux/callback-manager-ecore.h
new file mode 100644 (file)
index 0000000..f5fe7e3
--- /dev/null
@@ -0,0 +1,135 @@
+#ifndef DALI_ECORE_CALLBACK_MANAGER_H
+#define DALI_ECORE_CALLBACK_MANAGER_H
+
+/*
+ * Copyright (c) 2019 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 <list>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/callback-manager.h>
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+struct CallbackData;
+
+/**
+ * Ecore interface to install call backs in the applications main loop.
+ */
+class EcoreCallbackManager : public CallbackManager
+{
+
+public:
+
+    /**
+     * @brief constructor
+     */
+    EcoreCallbackManager();
+
+    /**
+     * @brief destructor
+     */
+    ~EcoreCallbackManager()
+    {
+    }
+
+    /**
+     * @copydoc CallbackManager::AddIdleCallback()
+     */
+    virtual bool AddIdleCallback( CallbackBase* callback, bool hasReturnValue );
+
+    /**
+     * @copydoc CallbackManager::RemoveIdleCallback()
+     */
+    virtual void RemoveIdleCallback( CallbackBase* callback );
+
+    /**
+     * @copydoc CallbackManager::ProcessIdle()
+     */
+    virtual bool ProcessIdle();
+
+    /**
+     * @copydoc CallbackManager::ProcessIdle()
+     */
+    virtual void ClearIdleCallbacks();
+
+    /**
+     * @copydoc CallbackManager::AddIdleEntererCallback()
+     */
+    virtual bool AddIdleEntererCallback( CallbackBase* callback );
+
+    /**
+     * @copydoc CallbackManager::RemoveIdleEntererCallback()
+     */
+    virtual void RemoveIdleEntererCallback( CallbackBase* callback );
+
+    /**
+     * @copydoc CallbackManager::Start()
+     */
+    virtual void Start();
+
+    /**
+     * @copydoc CallbackManager::Stop()
+     */
+    virtual void Stop();
+
+private:
+
+    /**
+     * @brief Remove all idle call backs that are pending
+     * Called by Stop()
+     * Always called from the main thread
+     */
+    void RemoveAllCallbacks();
+
+    /**
+     * @brief Removes a single call back from the container
+     * Always called from main thread
+     * @param callbackData callback data
+     */
+    void RemoveCallbackFromContainer(CallbackData *callbackData);
+
+    /**
+     * @brief Remove a standard call back from ecore
+     * Always called from main thread
+     * @param callbackData callback data
+     */
+    void RemoveStandardCallback(CallbackData *callbackData);
+
+
+    typedef std::list<CallbackData *>  CallbackList;
+
+    bool                           mRunning;            ///< flag is set to true if when running
+    CallbackList                   mCallbackContainer;  ///< container of live idle callbacks
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_ECORE_CALLBACK_MANAGER_H
diff --git a/dali/internal/system/linux/dali-ecore-x.h b/dali/internal/system/linux/dali-ecore-x.h
new file mode 100644 (file)
index 0000000..e9c0cd9
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef DALI_INTERNAL_SYSTEM_LINUX_DALI_ECORE_X_H
+#define DALI_INTERNAL_SYSTEM_LINUX_DALI_ECORE_X_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#pragma GCC system_header
+#include <Ecore_X.h>
+
+
+
+#endif /* DALI_INTERNAL_SYSTEM_LINUX_DALI_ECORE_X_H */
diff --git a/dali/internal/system/linux/dali-ecore.h b/dali/internal/system/linux/dali-ecore.h
new file mode 100644 (file)
index 0000000..61fb714
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef DALI_INTERNAL_SYSTEM_LINUX_DALI_ECORE_H
+#define DALI_INTERNAL_SYSTEM_LINUX_DALI_ECORE_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#pragma GCC system_header
+#include <Ecore.h>
+
+
+
+#endif /* DALI_INTERNAL_SYSTEM_LINUX_DALI_ECORE_H */
diff --git a/dali/internal/system/linux/dali-elementary.h b/dali/internal/system/linux/dali-elementary.h
new file mode 100644 (file)
index 0000000..1621aff
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef DALI_INTERNAL_SYSTEM_LINUX_DALI_ELEMENTARY_H
+#define DALI_INTERNAL_SYSTEM_LINUX_DALI_ELEMENTARY_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+#pragma GCC system_header
+#include <Elementary.h>
+
+
+
+#endif /* DALI_INTERNAL_SYSTEM_LINUX_DALI_ELEMENTARY_H */
diff --git a/dali/internal/system/linux/file-descriptor-monitor-ecore.cpp b/dali/internal/system/linux/file-descriptor-monitor-ecore.cpp
new file mode 100644 (file)
index 0000000..88e9de3
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/file-descriptor-monitor.h>
+
+// EXTERNAL INCLUDES
+#include <dali/internal/system/linux/dali-ecore.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Using Impl to hide away EFL specific members
+ */
+struct FileDescriptorMonitor::Impl
+{
+  // Construction
+  Impl( int fileDescriptor, CallbackBase* callback, int eventsToMonitor)
+  : mFileDescriptor( fileDescriptor ),
+    mEventsToMonitor( eventsToMonitor ),
+    mCallback( callback ),
+    mHandler( NULL )
+  {
+  }
+
+  ~Impl()
+  {
+    delete mCallback;
+  }
+
+  // Data
+  int mFileDescriptor;
+  int mEventsToMonitor;              ///< what file descriptor events to monitor
+  CallbackBase* mCallback;
+  Ecore_Fd_Handler* mHandler;
+
+  // Static Methods
+
+  /**
+   * Called when the file descriptor receives an event.
+   */
+  static Eina_Bool EventDispatch(void* data, Ecore_Fd_Handler *handler)
+  {
+    Impl* impl = reinterpret_cast<Impl*>(data);
+
+    // if we want read events, check to see if a read event is available
+    int type = FileDescriptorMonitor::FD_NO_EVENT;
+
+    if( ecore_main_fd_handler_active_get( handler, ECORE_FD_ERROR) )
+    {
+      CallbackBase::Execute( *impl->mCallback, FileDescriptorMonitor::FD_ERROR);
+      DALI_LOG_ERROR("ECORE_FD_ERROR occurred on %d\n", impl->mFileDescriptor);
+
+      return ECORE_CALLBACK_CANCEL;
+    }
+
+    if( impl->mEventsToMonitor & ECORE_FD_READ )
+    {
+      if (ecore_main_fd_handler_active_get( handler, ECORE_FD_READ))
+      {
+        type = FileDescriptorMonitor::FD_READABLE;
+      }
+    }
+    // check if we want write events
+    if( impl->mEventsToMonitor & ECORE_FD_WRITE )
+    {
+      if (ecore_main_fd_handler_active_get( handler, ECORE_FD_WRITE))
+      {
+        type |= FileDescriptorMonitor::FD_WRITABLE;
+      }
+    }
+
+    // if there is an event, execute the callback
+    if( type != FileDescriptorMonitor::FD_NO_EVENT )
+    {
+      CallbackBase::Execute( *impl->mCallback, static_cast< FileDescriptorMonitor::EventType >(type ) );
+    }
+
+    return ECORE_CALLBACK_RENEW;
+  }
+};
+
+FileDescriptorMonitor::FileDescriptorMonitor( int fileDescriptor, CallbackBase* callback, int eventBitmask)
+{
+  mImpl = new Impl(fileDescriptor, callback, eventBitmask);
+
+  if (fileDescriptor < 1)
+  {
+    DALI_ASSERT_ALWAYS( 0 && "Invalid File descriptor");
+    return;
+  }
+
+  int events = 0;
+  if( eventBitmask & FD_READABLE)
+  {
+    events = ECORE_FD_READ;
+  }
+  if( eventBitmask & FD_WRITABLE)
+  {
+    events |= ECORE_FD_WRITE;
+  }
+  mImpl->mEventsToMonitor = events;
+  mImpl->mHandler = ecore_main_fd_handler_add( fileDescriptor, static_cast<Ecore_Fd_Handler_Flags >( events ), &Impl::EventDispatch, mImpl, NULL, NULL );
+
+}
+
+FileDescriptorMonitor::~FileDescriptorMonitor()
+{
+  if (mImpl->mHandler)
+  {
+    ecore_main_fd_handler_del(mImpl->mHandler);
+  }
+
+  delete mImpl;
+  mImpl = NULL;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/linux/timer-impl-ecore.cpp b/dali/internal/system/linux/timer-impl-ecore.cpp
new file mode 100644 (file)
index 0000000..fde050d
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/timer-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/public-api/dali-adaptor-common.h>
+
+#include <dali/internal/system/linux/dali-ecore.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+// LOCAL STUFF
+namespace
+{
+Eina_Bool TimerSourceFunc (void *data)
+{
+  Timer* timer = static_cast<Timer*>(data);
+
+  bool keepRunning = timer->Tick();
+
+  return keepRunning ? EINA_TRUE : EINA_FALSE;
+}
+} // unnamed namespace
+
+/**
+ * Struct to hide away Ecore implementation details
+ */
+struct Timer::Impl
+{
+  Impl( unsigned int milliSec )
+  : mId(NULL),
+    mInterval(milliSec)
+  {
+  }
+
+  Ecore_Timer * mId;
+  unsigned int mInterval;
+};
+
+TimerPtr Timer::New( unsigned int milliSec )
+{
+  TimerPtr timer( new Timer( milliSec ) );
+  return timer;
+}
+
+Timer::Timer( unsigned int milliSec )
+: mImpl(new Impl(milliSec))
+{
+}
+
+Timer::~Timer()
+{
+  ResetTimerData();
+  delete mImpl;
+}
+
+void Timer::Start()
+{
+  // Timer should be used in the event thread
+  DALI_ASSERT_DEBUG( Adaptor::IsAvailable() );
+
+  if(mImpl->mId != NULL)
+  {
+    Stop();
+  }
+  double interval = static_cast<double> ( mImpl->mInterval ) / 1000.0f;
+  mImpl->mId = ecore_timer_add( interval, reinterpret_cast<Ecore_Task_Cb>( TimerSourceFunc ), this );
+}
+
+void Timer::Stop()
+{
+  // Timer should be used in the event thread
+  DALI_ASSERT_DEBUG( Adaptor::IsAvailable() );
+
+  ResetTimerData();
+}
+
+void Timer::Pause()
+{
+  // Timer should be used in the event thread
+  DALI_ASSERT_DEBUG( Adaptor::IsAvailable() );
+
+  if( mImpl->mId != NULL )
+  {
+    ecore_timer_freeze( mImpl->mId );
+  }
+}
+
+void Timer::Resume()
+{
+  // Timer should be used in the event thread
+  DALI_ASSERT_DEBUG( Adaptor::IsAvailable() );
+
+  if( mImpl->mId != NULL )
+  {
+    ecore_timer_thaw( mImpl->mId );
+  }
+}
+
+void Timer::SetInterval( unsigned int interval, bool restart )
+{
+  // stop existing timer
+  Stop();
+  mImpl->mInterval = interval;
+
+  if( restart )
+  {
+    // start new tick
+    Start();
+  }
+}
+
+unsigned int Timer::GetInterval() const
+{
+  return mImpl->mInterval;
+}
+
+bool Timer::Tick()
+{
+  // Guard against destruction during signal emission
+  Dali::Timer handle( this );
+
+  bool retVal( false );
+
+  // Override with new signal if used
+  if( !mTickSignal.Empty() )
+  {
+    retVal = mTickSignal.Emit();
+
+    // Timer stops if return value is false
+    if (retVal == false)
+    {
+      Stop();
+    }
+    else
+    {
+      retVal = true;   // continue emission
+    }
+  }
+  else // no callbacks registered
+  {
+    // periodic timer is started but nobody listens, continue
+    retVal = true;
+  }
+
+  return retVal;
+}
+
+Dali::Timer::TimerSignalType& Timer::TickSignal()
+{
+  return mTickSignal;
+}
+
+void Timer::ResetTimerData()
+{
+  if (mImpl->mId != NULL)
+  {
+    ecore_timer_del(mImpl->mId);
+    mImpl->mId = NULL;
+  }
+}
+
+bool Timer::IsRunning() const
+{
+  return mImpl->mId != NULL;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/tizen-wayland/logging-tizen.cpp b/dali/internal/system/tizen-wayland/logging-tizen.cpp
new file mode 100644 (file)
index 0000000..6638450
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// FUNCTION HEADER
+#include <dali/internal/system/common/logging.h>
+
+// EXTERNAL INCLUDES
+// Dlog uses C style casts internally
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#include <dlog.h>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+void LogMessage(Dali::Integration::Log::DebugPriority level, std::string& message)
+{
+  const char* DALI_TAG = "DALI";
+
+  switch(level)
+  {
+    case Dali::Integration::Log::DebugInfo:
+      LOG(LOG_INFO, DALI_TAG, "%s", message.c_str());
+      break;
+    case Dali::Integration::Log::DebugWarning:
+      LOG(LOG_WARN, DALI_TAG, "%s", message.c_str());
+      break;
+    case Dali::Integration::Log::DebugError:
+      LOG(LOG_ERROR, DALI_TAG, "%s", message.c_str());
+      break;
+    default:
+      LOG(LOG_DEFAULT, DALI_TAG, "%s", message.c_str());
+      break;
+  }
+#pragma GCC diagnostic pop
+
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/dali/internal/system/tizen-wayland/system-settings-tizen.cpp b/dali/internal/system/tizen-wayland/system-settings-tizen.cpp
new file mode 100644 (file)
index 0000000..aa1e48f
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018 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 <system_settings.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/system-settings.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+int GetLongPressTime( int defaultTime )
+{
+  return defaultTime;
+}
+
+int GetElmAccessActionOver()
+{
+  return 0;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/tizen-wayland/tizen-wearable/capture-impl-tizen.cpp b/dali/internal/system/tizen-wayland/tizen-wearable/capture-impl-tizen.cpp
new file mode 100755 (executable)
index 0000000..0c9487e
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/tizen-wayland/tizen-wearable/capture-impl.h>
+
+// EXTERNAL INCLUDES
+#include <fstream>
+#include <string.h>
+#include <dali/public-api/common/stage.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/adaptor.h>
+
+namespace
+{
+unsigned int TIME_OUT_DURATION = 1000;
+}
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+Capture::Capture()
+: mTimer(),
+  mPath(),
+  mNativeImageSourcePtr( NULL ),
+  mTbmSurface( NULL )
+{
+}
+
+Capture::Capture( Dali::CameraActor cameraActor )
+: mCameraActor( cameraActor ),
+  mTimer(),
+  mPath(),
+  mNativeImageSourcePtr( NULL ),
+  mTbmSurface( NULL )
+{
+}
+
+Capture::~Capture()
+{
+}
+
+CapturePtr Capture::New()
+{
+  CapturePtr pWorker = new Capture();
+
+  return pWorker;
+}
+
+CapturePtr Capture::New( Dali::CameraActor cameraActor )
+{
+  CapturePtr pWorker = new Capture( cameraActor );
+
+  return pWorker;
+}
+
+void Capture::Start( Dali::Actor source, const Dali::Vector2& size, const std::string &path, const Dali::Vector4& clearColor )
+{
+  DALI_ASSERT_ALWAYS(path.size() > 4 && "Path is invalid.");
+
+  // Increase the reference count focely to avoid application mistake.
+  Reference();
+
+  mPath = path;
+
+  DALI_ASSERT_ALWAYS(source && "Source is NULL.");
+
+  UnsetResources();
+  SetupResources( size, clearColor, source );
+}
+
+Dali::Capture::CaptureFinishedSignalType& Capture::FinishedSignal()
+{
+  return mFinishedSignal;
+}
+
+void Capture::CreateSurface( const Vector2& size )
+{
+  DALI_ASSERT_ALWAYS(!mTbmSurface && "mTbmSurface is already created.");
+
+  mTbmSurface = tbm_surface_create( size.width, size.height, TBM_FORMAT_RGBA8888 );
+}
+
+void Capture::DeleteSurface()
+{
+  DALI_ASSERT_ALWAYS(mTbmSurface && "mTbmSurface is empty.");
+
+  tbm_surface_destroy( mTbmSurface );
+  mTbmSurface = NULL;
+}
+
+void Capture::ClearSurface( const Vector2& size )
+{
+  DALI_ASSERT_ALWAYS(mTbmSurface && "mTbmSurface is empty.");
+
+  tbm_surface_info_s surface_info;
+
+  if( tbm_surface_map( mTbmSurface, TBM_SURF_OPTION_WRITE, &surface_info ) == TBM_SURFACE_ERROR_NONE )
+  {
+    //DALI_ASSERT_ALWAYS(surface_info.bpp == 32 && "unsupported tbm format");
+
+    unsigned char* ptr = surface_info.planes[0].ptr;
+    memset( ptr, 0, surface_info.size ); // TODO: support color
+
+    if( tbm_surface_unmap( mTbmSurface ) != TBM_SURFACE_ERROR_NONE )
+    {
+      DALI_LOG_ERROR( "Fail to unmap tbm_surface\n" );
+    }
+  }
+  else
+  {
+     DALI_ASSERT_ALWAYS(0 && "tbm_surface_map failed");
+  }
+}
+
+bool Capture::IsSurfaceCreated()
+{
+  return mTbmSurface != 0;
+}
+
+void Capture::CreateNativeImageSource()
+{
+  Dali::Adaptor& adaptor = Dali::Adaptor::Get();
+
+  DALI_ASSERT_ALWAYS(adaptor.IsAvailable() && "Dali::Adaptor is not available.");
+
+  DALI_ASSERT_ALWAYS(mTbmSurface && "mTbmSurface is empty.");
+
+  DALI_ASSERT_ALWAYS(!mNativeImageSourcePtr && "NativeImageSource is already created.");
+
+  // create the NativeImageSource object with our surface
+  mNativeImageSourcePtr = Dali::NativeImageSource::New( mTbmSurface );
+}
+
+void Capture::DeleteNativeImageSource()
+{
+  DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSource is NULL.");
+
+  mNativeImageSourcePtr.Reset();
+}
+
+bool Capture::IsNativeImageSourceCreated()
+{
+  return mNativeImageSourcePtr;
+}
+
+void Capture::CreateFrameBuffer()
+{
+  DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "NativeImageSource is NULL.");
+
+  DALI_ASSERT_ALWAYS(!mFrameBuffer && "FrameBuffer is already created.");
+
+  mNativeTexture = Dali::Texture::New( *mNativeImageSourcePtr );
+
+  // Create a FrameBuffer object with depth attachments.
+  mFrameBuffer = Dali::FrameBuffer::New( mNativeTexture.GetWidth(), mNativeTexture.GetHeight(), Dali::FrameBuffer::Attachment::DEPTH );
+  // Add a color attachment to the FrameBuffer object.
+  mFrameBuffer.AttachColorTexture( mNativeTexture );
+}
+
+void Capture::DeleteFrameBuffer()
+{
+  DALI_ASSERT_ALWAYS(mFrameBuffer && "FrameBuffer is NULL.");
+
+  mFrameBuffer.Reset();
+  mNativeTexture.Reset();
+}
+
+bool Capture::IsFrameBufferCreated()
+{
+  return mFrameBuffer;
+}
+
+void Capture::SetupRenderTask( Dali::Actor source, const Dali::Vector4& clearColor )
+{
+  DALI_ASSERT_ALWAYS(source && "Source is empty.");
+
+  mSource = source;
+
+  // Check the original parent about source.
+  mParent = mSource.GetParent();
+
+  Dali::Stage stage = Dali::Stage::GetCurrent();
+  Dali::Size stageSize = stage.GetSize();
+
+  // Add to stage for rendering the source. If source isn't on the stage then it never be rendered.
+  stage.Add( mSource );
+
+  if( !mCameraActor )
+  {
+    mCameraActor = Dali::CameraActor::New( stageSize );
+    mCameraActor.SetParentOrigin( ParentOrigin::CENTER );
+    mCameraActor.SetAnchorPoint( AnchorPoint::CENTER );
+  }
+
+  stage.Add( mCameraActor );
+
+  DALI_ASSERT_ALWAYS(mFrameBuffer && "Framebuffer is NULL.");
+
+  DALI_ASSERT_ALWAYS(!mRenderTask && "RenderTask is already created.");
+
+  Dali::RenderTaskList taskList = stage.GetRenderTaskList();
+  mRenderTask = taskList.CreateTask();
+  mRenderTask.SetRefreshRate( Dali::RenderTask::REFRESH_ONCE );
+  mRenderTask.SetSourceActor( source );
+  mRenderTask.SetCameraActor( mCameraActor );
+  mRenderTask.SetScreenToFrameBufferFunction( Dali::RenderTask::FULLSCREEN_FRAMEBUFFER_FUNCTION );
+  mRenderTask.SetFrameBuffer( mFrameBuffer );
+  mRenderTask.SetClearColor( clearColor );
+  mRenderTask.SetClearEnabled( true );
+  mRenderTask.SetProperty( Dali::RenderTask::Property::REQUIRES_SYNC, true );
+  mRenderTask.FinishedSignal().Connect( this, &Capture::OnRenderFinished );
+  mRenderTask.GetCameraActor().SetInvertYAxis( true );
+
+  mTimer = Dali::Timer::New( TIME_OUT_DURATION );
+  mTimer.TickSignal().Connect( this, &Capture::OnTimeOut );
+  mTimer.Start();
+}
+
+void Capture::UnsetRenderTask()
+{
+  DALI_ASSERT_ALWAYS(mCameraActor && "CameraActor is NULL.");
+
+  if( mParent )
+  {
+    // Restore the parent of source.
+    mParent.Add( mSource );
+    mParent.Reset();
+  }
+  else
+  {
+    mSource.Unparent();
+  }
+
+  mSource.Reset();
+
+  mTimer.Reset();
+
+  mCameraActor.Unparent();
+  mCameraActor.Reset();
+
+  DALI_ASSERT_ALWAYS( mRenderTask && "RenderTask is NULL." );
+
+  Dali::RenderTaskList taskList = Dali::Stage::GetCurrent().GetRenderTaskList();
+  taskList.RemoveTask( mRenderTask );
+  mRenderTask.Reset();
+}
+
+bool Capture::IsRenderTaskSetup()
+{
+  return mCameraActor && mRenderTask;
+}
+
+void Capture::SetupResources( const Dali::Vector2& size, const Dali::Vector4& clearColor, Dali::Actor source )
+{
+  CreateSurface( size );
+  ClearSurface( size );
+
+  CreateNativeImageSource();
+
+  CreateFrameBuffer();
+
+  SetupRenderTask( source, clearColor );
+}
+
+void Capture::UnsetResources()
+{
+  if( IsRenderTaskSetup() )
+  {
+    UnsetRenderTask();
+  }
+
+  if( IsFrameBufferCreated() )
+  {
+    DeleteFrameBuffer();
+  }
+
+  if( IsNativeImageSourceCreated() )
+  {
+    DeleteNativeImageSource();
+  }
+
+  if( IsSurfaceCreated() )
+  {
+    DeleteSurface();
+  }
+}
+
+void Capture::OnRenderFinished( Dali::RenderTask& task )
+{
+  Dali::Capture::FinishState state = Dali::Capture::FinishState::SUCCEEDED;
+
+  mTimer.Stop();
+
+  if( !Save() )
+  {
+    state = Dali::Capture::FinishState::FAILED;
+    DALI_LOG_ERROR("Fail to Capture mTbmSurface[%p] Path[%s]", mTbmSurface, mPath.c_str());
+  }
+
+  Dali::Capture handle( this );
+  mFinishedSignal.Emit( handle, state );
+
+  UnsetResources();
+
+  // Decrease the reference count forcely. It is increased at Start().
+  Unreference();
+}
+
+bool Capture::OnTimeOut()
+{
+  Dali::Capture::FinishState state = Dali::Capture::FinishState::FAILED;
+
+  Dali::Capture handle( this );
+  mFinishedSignal.Emit( handle, state );
+
+  UnsetResources();
+
+  // Decrease the reference count forcely. It is increased at Start().
+  Unreference();
+
+  return false;
+}
+
+bool Capture::Save()
+{
+  DALI_ASSERT_ALWAYS(mNativeImageSourcePtr && "mNativeImageSourcePtr is NULL");
+
+  return mNativeImageSourcePtr->EncodeToFile( mPath );
+}
+
+}  // End of namespace Adaptor
+
+}  // End of namespace Internal
+
+}  // End of namespace Dali
diff --git a/dali/internal/system/tizen-wayland/tizen-wearable/capture-impl.h b/dali/internal/system/tizen-wayland/tizen-wearable/capture-impl.h
new file mode 100755 (executable)
index 0000000..4eae7f6
--- /dev/null
@@ -0,0 +1,249 @@
+#ifndef DALI_INTERNAL_CAPTURE_H
+#define DALI_INTERNAL_CAPTURE_H
+
+/*
+ * Copyright (c) 2018 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 <memory>
+#include <tbm_surface.h>
+#include <dali/public-api/object/ref-object.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/render-tasks/render-task.h>
+#include <dali/public-api/rendering/texture.h>
+#include <dali/public-api/rendering/frame-buffer.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/public-api/capture/capture.h>
+#include <dali/public-api/adaptor-framework/native-image-source.h>
+#include <dali/public-api/adaptor-framework/timer.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class Capture;
+typedef IntrusivePtr<Capture> CapturePtr;
+
+class Capture : public BaseObject, public ConnectionTracker
+{
+public:
+  /**
+   * @brief Constructor.
+   */
+  Capture();
+
+  Capture( Dali::CameraActor cameraActor );
+
+  /**
+   * @copydoc Dali::Capture::New
+   */
+  static CapturePtr New();
+
+  /**
+   * @copydoc Dali::Capture::New
+   */
+  static CapturePtr New( Dali::CameraActor cameraActor );
+
+  /**
+   * @copydoc Dali::Capture::Start
+   */
+  void Start( Dali::Actor source, const Dali::Vector2& size, const std::string &path, const Dali::Vector4& clearColor );
+
+  /**
+   * @copydoc Dali::Capture::FinishedSignal
+   */
+  Dali::Capture::CaptureFinishedSignalType& FinishedSignal();
+
+protected:
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference()
+   */
+  virtual ~Capture();
+
+private:
+  /**
+   * @brief Create surface.
+   *
+   * @param[in] size of surface.
+   */
+  void CreateSurface( const Dali::Vector2& size );
+
+  /**
+   * @brief Delete surface.
+   */
+  void DeleteSurface();
+
+  /**
+   * @brief Clear surface with color.
+   *
+   * @param[in] size of clear aread.
+   */
+  void ClearSurface( const Dali::Vector2& size );
+
+  /**
+   * @brief Query whether surface is created or not.
+   *
+   * @return True is surface is created.
+   */
+  bool IsSurfaceCreated();
+
+  /**
+   * @brief Create native image source.
+   */
+  void CreateNativeImageSource();
+
+  /**
+   * @brief Delete native image source.
+   */
+  void DeleteNativeImageSource();
+
+  /**
+   * @brief Query whether native image source is created or not.
+   *
+   * @return True is native image source is created.
+   */
+  bool IsNativeImageSourceCreated();
+
+  /**
+   * @brief Create frame buffer.
+   */
+  void CreateFrameBuffer();
+
+  /**
+   * @brief Delete frame buffer.
+   */
+  void DeleteFrameBuffer();
+
+  /**
+   * @brief Query whether frame buffer is created or not.
+   *
+   * @return True is frame buffer is created.
+   */
+  bool IsFrameBufferCreated();
+
+  /**
+   * @brief Setup render task.
+   *
+   * @param[in] source is captured.
+   * @param[in] clearColor background color
+   */
+  void SetupRenderTask( Dali::Actor source, const Dali::Vector4& clearColor );
+
+  /**
+   * @brief Unset render task.
+   */
+  void UnsetRenderTask();
+
+  /**
+   * @brief Query whether render task is setup or not.
+   *
+   * @return True is render task is setup.
+   */
+  bool IsRenderTaskSetup();
+
+  /**
+   * @brief Setup resources for capture.
+   *
+   * @param[in] size is surface size.
+   * @param[in] clearColor is clear color of surface.
+   * @param[in] source is captured.
+   */
+  void SetupResources( const Dali::Vector2& size, const Dali::Vector4& clearColor, Dali::Actor source );
+
+  /**
+   * @brief Unset resources for capture.
+   */
+  void UnsetResources();
+
+  /**
+   * @brief Callback when render is finished.
+   *
+   * @param[in] task is used for capture.
+   */
+  void OnRenderFinished( Dali::RenderTask& task );
+
+  /**
+   * @brief Callback when timer is finished.
+   *
+   * @return True is timer start again.
+   */
+  bool OnTimeOut();
+
+  /**
+   * @brief Save framebuffer.
+   *
+   * @return True is success to save, false is fail.
+   */
+  bool Save();
+
+private:
+
+  // Undefined
+  Capture( const Capture& );
+
+  // Undefined
+  Capture& operator=( const Capture& rhs );
+
+private:
+  Dali::Texture                               mNativeTexture;
+  Dali::FrameBuffer                           mFrameBuffer;
+  Dali::RenderTask                            mRenderTask;
+  Dali::Actor                                 mParent;
+  Dali::Actor                                 mSource;
+  Dali::CameraActor                           mCameraActor;
+  Dali::Timer                                 mTimer;           ///< For timeout.
+  Dali::Capture::CaptureFinishedSignalType    mFinishedSignal;
+  std::string                                 mPath;
+  Dali::NativeImageSourcePtr                  mNativeImageSourcePtr;  ///< pointer to surface image
+  tbm_surface_h                               mTbmSurface;
+};
+
+}  // End of namespace Adaptor
+}  // End of namespace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::Capture& GetImpl( Dali::Capture& captureWorker)
+{
+  DALI_ASSERT_ALWAYS( captureWorker && "Capture handle is empty" );
+
+  BaseObject& handle = captureWorker.GetBaseObject();
+
+  return static_cast< Internal::Adaptor::Capture& >( handle );
+}
+
+inline const Internal::Adaptor::Capture& GetImpl( const Dali::Capture& captureWorker )
+{
+  DALI_ASSERT_ALWAYS( captureWorker && "Capture handle is empty" );
+
+  const BaseObject& handle = captureWorker.GetBaseObject();
+
+  return static_cast< const Internal::Adaptor::Capture& >( handle );
+}
+
+}  // End of namespace Dali
+
+#endif // DALI_INTERNAL_CAPTURE_H
diff --git a/dali/internal/system/tizen-wayland/tizen-wearable/capture.cpp b/dali/internal/system/tizen-wayland/tizen-wearable/capture.cpp
new file mode 100644 (file)
index 0000000..156b206
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/public-api/capture/capture.h>
+
+// INTERNAL HEADER
+#include <dali/internal/system/tizen-wayland/tizen-wearable/capture-impl.h>
+
+namespace Dali
+{
+
+Capture::Capture()
+{
+}
+
+Capture Capture::New()
+{
+  Internal::Adaptor::CapturePtr internal = Internal::Adaptor::Capture::New();
+
+  return Capture( internal.Get() );
+}
+
+Capture Capture::New( Dali::CameraActor cameraActor )
+{
+  Internal::Adaptor::CapturePtr internal = Internal::Adaptor::Capture::New( cameraActor );
+
+  return Capture( internal.Get() );
+}
+
+Capture Capture::DownCast( BaseHandle handle )
+{
+  return Capture( dynamic_cast< Internal::Adaptor::Capture* >( handle.GetObjectPtr() ) );
+}
+
+Capture::~Capture()
+{
+}
+
+Capture::Capture( const Capture& copy )
+: BaseHandle(copy)
+{
+}
+
+Capture& Capture::operator=( const Capture& rhs )
+{
+  BaseHandle::operator=( rhs );
+  return *this;
+}
+
+void Capture::Start( Actor source, const Vector2& size, const std::string &path, const Vector4& clearColor )
+{
+  GetImpl( *this ).Start( source, size, path, clearColor );
+}
+
+void Capture::Start( Actor source, const Vector2& size, const std::string &path )
+{
+  GetImpl( *this ).Start( source, size, path, Dali::Color::TRANSPARENT );
+}
+
+Capture::CaptureFinishedSignalType& Capture::FinishedSignal()
+{
+  return GetImpl( *this ).FinishedSignal();
+}
+
+Capture::Capture( Internal::Adaptor::Capture* internal )
+: BaseHandle( internal )
+{
+}
+
+} // namespace Dali
diff --git a/dali/internal/system/tizen-wayland/tizen-wearable/watch-time.cpp b/dali/internal/system/tizen-wayland/tizen-wearable/watch-time.cpp
new file mode 100644 (file)
index 0000000..345f0f4
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/public-api/watch/watch-time.h>
+
+// EXTERNAL INCLUDES
+#ifdef APPCORE_WATCH_AVAILABLE
+#include <watch_app.h>
+#include <watch_app_extension.h>
+#endif
+
+namespace Dali
+{
+
+struct WatchTime::Impl
+{
+  Impl(void *time_handle)
+  : mTimeHandle(time_handle)
+  {
+  }
+
+  void *mTimeHandle;
+};
+
+WatchTime::WatchTime(void *time_handle)
+{
+  mImpl = new Impl(time_handle);
+}
+
+WatchTime::~WatchTime()
+{
+  if( mImpl )
+  {
+    delete mImpl;
+    mImpl = NULL;
+  }
+}
+
+#ifdef APPCORE_WATCH_AVAILABLE
+
+WatchTime::WatchTime()
+{
+  watch_time_h watch_time = {0,};
+
+  watch_time_get_current_time(&watch_time);
+  mImpl = new Impl(watch_time);
+}
+
+int WatchTime::GetHour() const
+{
+  int hour;
+
+  watch_time_get_hour(reinterpret_cast<watch_time_h>(mImpl->mTimeHandle), &hour);
+  return hour;
+}
+
+int WatchTime::GetHour24() const
+{
+  int hour24;
+
+  watch_time_get_hour24(reinterpret_cast<watch_time_h>(mImpl->mTimeHandle), &hour24);
+  return hour24;
+}
+
+int WatchTime::GetMinute() const
+{
+  int minute;
+
+  watch_time_get_minute(reinterpret_cast<watch_time_h>(mImpl->mTimeHandle), &minute);
+  return minute;
+}
+
+int WatchTime::GetSecond() const
+{
+  int second;
+
+  watch_time_get_second(reinterpret_cast<watch_time_h>(mImpl->mTimeHandle), &second);
+  return second;
+}
+
+int WatchTime::GetMillisecond() const
+{
+  int millisecond;
+
+  watch_time_get_millisecond(reinterpret_cast<watch_time_h>(mImpl->mTimeHandle), &millisecond);
+  return millisecond;
+}
+
+int WatchTime::GetYear() const
+{
+  int year;
+
+  watch_time_get_year(reinterpret_cast<watch_time_h>(mImpl->mTimeHandle), &year);
+  return year;
+}
+
+int WatchTime::GetMonth() const
+{
+  int month;
+
+  watch_time_get_month(reinterpret_cast<watch_time_h>(mImpl->mTimeHandle), &month);
+  return month;
+}
+
+int WatchTime::GetDay() const
+{
+  int day;
+
+  watch_time_get_day(reinterpret_cast<watch_time_h>(mImpl->mTimeHandle), &day);
+  return day;
+}
+
+int WatchTime::GetDayOfWeek() const
+{
+  int dayOfWeek;
+
+  watch_time_get_day_of_week(reinterpret_cast<watch_time_h>(mImpl->mTimeHandle), &dayOfWeek);
+  return dayOfWeek;
+}
+
+struct tm WatchTime::GetUtcTime() const
+{
+  struct tm UtcTime;
+
+  watch_time_get_utc_time(reinterpret_cast<watch_time_h>(mImpl->mTimeHandle), &UtcTime);
+  return UtcTime;
+}
+
+time_t WatchTime::GetUtcTimeStamp() const
+{
+  time_t UtcTimeStamp;
+
+  watch_time_get_utc_timestamp(reinterpret_cast<watch_time_h>(mImpl->mTimeHandle), &UtcTimeStamp);
+  return UtcTimeStamp;
+}
+
+const char* WatchTime::GetTimeZone() const
+{
+  char* timeZone;
+
+  watch_time_get_time_zone(reinterpret_cast<watch_time_h>(mImpl->mTimeHandle), &timeZone);
+  return timeZone;
+}
+
+bool WatchTime::GetDaylightSavingTimeStatus() const
+{
+  bool daylight;
+
+  watch_time_get_daylight_time_status(reinterpret_cast<watch_time_h>(mImpl->mTimeHandle), &daylight);
+  return daylight;
+}
+
+#else
+WatchTime::WatchTime()
+  :mImpl(NULL)
+{
+}
+
+int WatchTime::GetHour() const
+{
+  return 0;
+}
+
+int WatchTime::GetHour24() const
+{
+  return 0;
+}
+
+int WatchTime::GetMinute() const
+{
+  return 0;
+}
+
+int WatchTime::GetSecond() const
+{
+  return 0;
+}
+
+int WatchTime::GetMillisecond() const
+{
+  return 0;
+}
+
+int WatchTime::GetYear() const
+{
+  return 0;
+}
+
+int WatchTime::GetMonth() const
+{
+  return 0;
+}
+
+int WatchTime::GetDay() const
+{
+  return 0;
+}
+
+int WatchTime::GetDayOfWeek() const
+{
+  return 0;
+}
+
+struct tm WatchTime::GetUtcTime() const
+{
+  time_t zero = time(0);
+  return *localtime(&zero);
+}
+
+time_t WatchTime::GetUtcTimeStamp() const
+{
+  return 0;
+}
+
+const char* WatchTime::GetTimeZone() const
+{
+  return 0;
+}
+
+bool WatchTime::GetDaylightSavingTimeStatus() const
+{
+  return 0;
+}
+
+#endif
+
+} // namespace Dali
diff --git a/dali/internal/system/tizen-wayland/widget-application-impl-tizen.cpp b/dali/internal/system/tizen-wayland/widget-application-impl-tizen.cpp
new file mode 100644 (file)
index 0000000..ff22534
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/tizen-wayland/widget-application-impl-tizen.h>
+
+// INTERNAL INCLUDE
+#include <dali/public-api/adaptor-framework/widget.h>
+#include <dali/public-api/adaptor-framework/widget-impl.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/system/common/environment-variables.h>
+#include <dali/internal/system/tizen-wayland/widget-controller-tizen.h>
+
+// EXTERNAL INCLUDES
+#include <bundle.h>
+#include <widget_base.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace
+{
+
+int OnInstanceInit(widget_base_instance_h instanceHandle, bundle *content, int w, int h, void *classData)
+{
+  char *id;
+  widget_base_context_get_id(instanceHandle, &id);
+
+  widget_base_class_on_create(instanceHandle, content, w, h);
+
+  Dali::Internal::Adaptor::WidgetApplicationTizen* application = static_cast<Dali::Internal::Adaptor::WidgetApplicationTizen*>(classData);
+
+  Dali::Window window;
+  if( application->GetWidgetCount() == 0)
+  {
+    window = application->GetWindow();
+    DALI_LOG_RELEASE_INFO("Widget Instance use default Window(win:%p), so it need to bind widget (%dx%d) (id:%s) \n",window, w, h, std::string(id).c_str());
+  }
+  else
+  {
+    window = Dali::Window::New(PositionSize(0,0,w,h) ,"", false);
+    if( window )
+    {
+      DALI_LOG_RELEASE_INFO("Widget Instance create new Window  (win:%p, cnt:%d) (%dx%d) (id:%s )\n", window, application->GetWidgetCount(), w, h, std::string(id).c_str());
+    }
+    else
+    {
+      DALI_LOG_ERROR("This device can't support Multi Widget. it means UI may not be properly drawn.");
+      window = application->GetWindow();
+    }
+  }
+
+  Any nativeHandle = window.GetNativeHandle();
+
+#ifdef ECORE_WAYLAND2
+  Ecore_Wl2_Window * wlWindow = AnyCast<Ecore_Wl2_Window*>( nativeHandle );
+#else
+  Ecore_Wl_Window * wlWindow = AnyCast<Ecore_Wl_Window*>( nativeHandle );
+#endif
+
+  widget_base_context_window_bind( instanceHandle, id, wlWindow );
+  window.SetSize( Dali::Window::WindowSize( w, h ) );
+
+  Dali::Internal::Adaptor::WidgetApplication::CreateWidgetFunctionPair pair = application->GetWidgetCreatingFunctionPair(std::string(id));
+  Dali::WidgetApplication::CreateWidgetFunction createFunction = pair.second;
+
+  Dali::Widget widgetInstance = createFunction( pair.first );
+  application->AddWidget( instanceHandle, widgetInstance , window );
+
+  Dali::Internal::Adaptor::Widget::Impl *widgetImpl = new Dali::Internal::Adaptor::WidgetImplTizen(instanceHandle);
+  Internal::Adaptor::GetImplementation(widgetInstance).SetImpl( widgetImpl );
+
+  std::string encodedContentString = "";
+
+  if( bundle_get_count( content ) )
+  {
+    bundle_raw *bundleRaw;
+    int len;
+    bundle_encode(content, &bundleRaw, &len);
+    char* encodedContent = reinterpret_cast< char* >( bundleRaw );
+    encodedContentString = std::string( encodedContent );
+    free(bundleRaw);
+  }
+
+  Internal::Adaptor::GetImplementation(widgetInstance).OnCreate( encodedContentString, window );
+
+  return 0;
+}
+
+int OnInstanceDestroy(widget_base_instance_h instanceHandle, widget_base_destroy_type_e reason, bundle *content, void *classData)
+{
+  Dali::Internal::Adaptor::WidgetApplicationTizen* application = static_cast<Dali::Internal::Adaptor::WidgetApplicationTizen*>(classData);
+
+  // Get Dali::Widget instance.
+  Dali::Widget widgetInstance = application->GetWidget( instanceHandle );
+
+  Dali::Widget::Termination destroyReason = Dali::Widget::Termination::TEMPORARY;
+
+  if(reason == WIDGET_BASE_DESTROY_TYPE_PERMANENT)
+  {
+    destroyReason = Dali::Widget::Termination::PERMANENT;
+  }
+
+  std::string encodedContentString = "";
+
+  if( bundle_get_count( content ) )
+  {
+    bundle_raw *bundleRaw;
+    int len;
+    bundle_encode(content, &bundleRaw, &len);
+    char* encodedContent = reinterpret_cast< char* >( bundleRaw );
+    encodedContentString = std::string(encodedContent);
+    free(bundleRaw);
+  }
+
+  Internal::Adaptor::GetImplementation(widgetInstance).OnTerminate( encodedContentString, destroyReason );
+
+  widget_base_class_on_destroy(instanceHandle, reason, content);
+
+  application->DeleteWidget( instanceHandle );
+
+  return 0;
+}
+
+int OnInstancePause(widget_base_instance_h instanceHandle, void *classData)
+{
+  widget_base_class_on_pause(instanceHandle);
+
+  Dali::Internal::Adaptor::WidgetApplicationTizen* application = static_cast<Dali::Internal::Adaptor::WidgetApplicationTizen*>(classData);
+
+  // Get Dali::Widget instance.
+  Dali::Widget widgetInstance = application->GetWidget( instanceHandle );
+
+  Internal::Adaptor::GetImplementation(widgetInstance).OnPause();
+
+  return 0;
+}
+
+int OnInstanceResume(widget_base_instance_h instanceHandle, void *classData)
+{
+  widget_base_class_on_resume(instanceHandle);
+
+  Dali::Internal::Adaptor::WidgetApplicationTizen* application = static_cast<Dali::Internal::Adaptor::WidgetApplicationTizen*>(classData);
+
+  // Get Dali::Widget instance.
+  Dali::Widget widgetInstance = application->GetWidget( instanceHandle );
+
+  Internal::Adaptor::GetImplementation(widgetInstance).OnResume();
+
+  return 0;
+}
+
+int OnInstanceResize(widget_base_instance_h instanceHandle, int w, int h, void *classData)
+{
+  widget_base_class_on_resize(instanceHandle, w, h);
+
+  Dali::Internal::Adaptor::WidgetApplicationTizen* application = static_cast<Dali::Internal::Adaptor::WidgetApplicationTizen*>(classData);
+
+  // Get Dali::Widget instance.
+  Dali::Widget widgetInstance = application->GetWidget( instanceHandle );
+  Dali::Window window = application->GetWindowFromWidget( instanceHandle );
+  window.SetSize( Dali::Window::WindowSize(w, h) );
+  Internal::Adaptor::GetImplementation(widgetInstance).OnResize(window);
+
+  return 0;
+}
+
+int OnInstanceUpdate(widget_base_instance_h instanceHandle, bundle *content, int force, void *classData)
+{
+  widget_base_class_on_update(instanceHandle, content, force);
+
+  Dali::Internal::Adaptor::WidgetApplicationTizen* application = static_cast<Dali::Internal::Adaptor::WidgetApplicationTizen*>(classData);
+
+  // Get Dali::Widget instance.
+  Dali::Widget widgetInstance = application->GetWidget( instanceHandle );
+
+  std::string encodedContentString = "";
+
+  if( bundle_get_count( content ) )
+  {
+    bundle_raw *bundleRaw;
+    int len;
+    bundle_encode(content, &bundleRaw, &len);
+    char* encodedContent = reinterpret_cast< char* >( bundleRaw );
+    encodedContentString = std::string(encodedContent);
+    free(bundleRaw);
+  }
+
+  Internal::Adaptor::GetImplementation(widgetInstance).OnUpdate( encodedContentString, force );
+
+  return 0;
+}
+
+unsigned int GetEnvWidgetRenderRefreshRate()
+{
+  const char* envVariable = std::getenv( DALI_WIDGET_REFRESH_RATE );
+
+  return envVariable ? std::atoi( envVariable ) : 1u; // Default 60 fps
+}
+
+} // anonymous namespace
+
+namespace Adaptor
+{
+
+WidgetApplicationPtr WidgetApplicationTizen::New(
+  int* argc,
+  char **argv[],
+  const std::string& stylesheet)
+{
+  return new WidgetApplicationTizen(argc, argv, stylesheet );
+}
+
+WidgetApplicationTizen::WidgetApplicationTizen( int* argc, char** argv[], const std::string& stylesheet )
+:WidgetApplication(argc, argv, stylesheet)
+{
+}
+
+WidgetApplicationTizen::~WidgetApplicationTizen()
+{
+}
+
+
+void WidgetApplicationTizen::RegisterWidgetCreatingFunction( const std::string& widgetName, Dali::WidgetApplication::CreateWidgetFunction createFunction )
+{
+  AddWidgetCreatingFunctionPair( CreateWidgetFunctionPair(widgetName, createFunction) );
+
+  // Register widget class to widget framework
+  widget_base_class cls = widget_base_class_get_default();
+  cls.ops.create = OnInstanceInit;
+  cls.ops.destroy = OnInstanceDestroy;
+  cls.ops.pause = OnInstancePause;
+  cls.ops.resume = OnInstanceResume;
+  cls.ops.resize = OnInstanceResize;
+  cls.ops.update = OnInstanceUpdate;
+
+  widget_base_class_add(cls, widgetName.c_str(), this);
+}
+
+void WidgetApplicationTizen::AddWidgetCreatingFunctionPair( CreateWidgetFunctionPair pair )
+{
+  mCreateWidgetFunctionContainer.push_back( pair );
+}
+
+WidgetApplicationTizen::CreateWidgetFunctionPair WidgetApplicationTizen::GetWidgetCreatingFunctionPair( const std::string& widgetName )
+{
+  int idx = widgetName.find(":");
+  std::string widgetID = widgetName.substr( idx + 1 );
+  for( CreateWidgetFunctionContainer::const_iterator iter = mCreateWidgetFunctionContainer.begin(); iter != mCreateWidgetFunctionContainer.end(); ++iter )
+  {
+    if( widgetID.compare((*iter).first) == 0)
+    {
+      return *iter;
+    }
+  }
+
+  return CreateWidgetFunctionPair( "", NULL );
+}
+
+void WidgetApplicationTizen::AddWidget( widget_base_instance_h widgetBaseInstance, Dali::Widget widget , Dali::Window window )
+{
+  mWidgetInstanceContainer.push_back( WidgetInstancePair(widgetBaseInstance, widget) );
+  mWindowInstanceContainer.push_back( WindowInstancePair(widgetBaseInstance, window) );
+}
+
+Dali::Widget WidgetApplicationTizen::GetWidget( widget_base_instance_h widgetBaseInstance ) const
+{
+  for( auto&& iter : mWidgetInstanceContainer )
+  {
+    if( (iter).first == widgetBaseInstance  )
+    {
+      return (iter).second;
+    }
+  }
+  return Dali::Widget();
+}
+
+void WidgetApplicationTizen::DeleteWidget( widget_base_instance_h widgetBaseInstance )
+{
+  // Delete WidgetInstance
+  auto widgetInstance = std::find_if( mWidgetInstanceContainer.begin(),
+                                      mWidgetInstanceContainer.end(),
+                                      [widgetBaseInstance]( WidgetInstancePair pair )
+                                      { return (pair.first == widgetBaseInstance); } );
+
+  if(widgetInstance != mWidgetInstanceContainer.end())
+  {
+    mWidgetInstanceContainer.erase(widgetInstance);
+  }
+
+  // Delete WindowInstance
+  auto windowInstance = std::find_if( mWindowInstanceContainer.begin(),
+                                      mWindowInstanceContainer.end(),
+                                      [widgetBaseInstance]( WindowInstancePair pair )
+                                      { return (pair.first == widgetBaseInstance); } );
+
+  if(windowInstance != mWindowInstanceContainer.end())
+  {
+    mWindowInstanceContainer.erase(windowInstance);
+  }
+}
+
+Dali::Window WidgetApplicationTizen::GetWindowFromWidget( widget_base_instance_h widgetBaseInstance ) const
+{
+  for( auto&& iter : mWindowInstanceContainer )
+  {
+    if( (iter).first == widgetBaseInstance  )
+    {
+      Dali::Window ret = (iter).second;
+      return ret;
+    }
+  }
+  return Dali::Window();
+}
+
+int WidgetApplicationTizen::GetWidgetCount()
+{
+  return mWidgetInstanceContainer.size();
+}
+
+void WidgetApplicationTizen::OnInit()
+{
+  WidgetApplication::OnInit();
+
+  Dali::Adaptor::Get().SetRenderRefreshRate( GetEnvWidgetRenderRefreshRate() );
+}
+
+// factory function, must be implemented
+namespace WidgetApplicationFactory
+{
+/**
+ * Create a new widget 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
+ */
+Dali::Internal::Adaptor::WidgetApplicationPtr Create( int* argc, char **argv[], const std::string& stylesheet )
+{
+  return WidgetApplicationTizen::New( argc, argv, stylesheet );
+}
+
+} // namespace Factory
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/tizen-wayland/widget-application-impl-tizen.h b/dali/internal/system/tizen-wayland/widget-application-impl-tizen.h
new file mode 100644 (file)
index 0000000..b7b12a8
--- /dev/null
@@ -0,0 +1,143 @@
+#ifndef DALI_INTERNAL_WIDGET_APPLICATION_TIZEN_H
+#define DALI_INTERNAL_WIDGET_APPLICATION_TIZEN_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <widget_base.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/application-impl.h>
+#include <dali/internal/system/common/widget-application-impl.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
+
+namespace Dali
+{
+class Widget;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class WidgetApplication;
+typedef IntrusivePtr<WidgetApplication> WidgetApplicationPtr;
+
+/**
+ * Implementation of the WidgetApplication class.
+ */
+class WidgetApplicationTizen : public WidgetApplication
+{
+public:
+
+  typedef std::pair<const std::string, Dali::WidgetApplication::CreateWidgetFunction >  CreateWidgetFunctionPair;
+  typedef std::vector< CreateWidgetFunctionPair >   CreateWidgetFunctionContainer;
+
+  /**
+   * Create a new widget 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
+   */
+  static WidgetApplicationPtr New( int* argc, char **argv[], const std::string& stylesheet );
+
+public:
+  /**
+   * @copydoc Dali::Internal::Adaptor::Application::OnInit()
+   */
+  virtual void OnInit();
+
+  /**
+   * @copydoc Dali::WidgetApplication::RegisterWidgetCreator()
+   */
+  void RegisterWidgetCreatingFunction( const std::string& widgetName, Dali::WidgetApplication::CreateWidgetFunction createFunction ) override;
+
+  /**
+   * Add widget name - CreateWidgetFunction pair to container.
+   */
+  void AddWidgetCreatingFunctionPair( CreateWidgetFunctionPair pair );
+
+  /**
+   * Find and get CreateWidgetFunctionPair in container by widget name.
+   */
+  CreateWidgetFunctionPair GetWidgetCreatingFunctionPair( const std::string& widgetName );
+
+  /**
+   * Add widget_base_instance_h - Widget instance pair to container.
+   */
+  void AddWidget( widget_base_instance_h widgetBaseInstance, Dali::Widget widget , Dali::Window window );
+
+  /**
+   * Find and get Widget instance in container by widget_base_instance_h.
+   */
+  Dali::Widget GetWidget( widget_base_instance_h widgetBaseInstance ) const;
+
+  /**
+   * Delete widget_base_instance_h - Widget instance pair in container.
+   */
+  void DeleteWidget( widget_base_instance_h widgetBaseInstance );
+
+  /**
+   * Find and get Window instance in container by widget_base_instance_h.
+   */
+  Dali::Window GetWindowFromWidget( widget_base_instance_h widgetBaseInstance ) const;
+
+  /**
+   * Get the number of created widget.
+   */
+  int32_t GetWidgetCount();
+
+protected:
+
+  /**
+   * 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
+   */
+  WidgetApplicationTizen( int* argc, char **argv[], const std::string& stylesheet );
+
+  /**
+   * Destructor
+   */
+  virtual ~WidgetApplicationTizen();
+
+  WidgetApplicationTizen(const Application&) = delete;
+  WidgetApplicationTizen& operator=(Application&) = delete;
+
+private:
+
+  typedef std::pair< widget_base_instance_h, Dali::Widget > WidgetInstancePair;
+  typedef std::vector< WidgetInstancePair >                 WidgetInstanceContainer;
+
+  CreateWidgetFunctionContainer  mCreateWidgetFunctionContainer;
+  WidgetInstanceContainer        mWidgetInstanceContainer;
+
+  typedef std::pair< widget_base_instance_h, Dali::Window >  WindowInstancePair;
+  typedef std::vector< WindowInstancePair >                 WindowInstanceContainer;
+  WindowInstanceContainer mWindowInstanceContainer;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WIDGET_APPLICATION_TIZEN_H
diff --git a/dali/internal/system/tizen-wayland/widget-controller-tizen.cpp b/dali/internal/system/tizen-wayland/widget-controller-tizen.cpp
new file mode 100644 (file)
index 0000000..b6344c2
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/tizen-wayland/widget-controller-tizen.h>
+
+// EXTERNAL INCLUDES
+#include <bundle.h>
+#include <widget_base.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+WidgetImplTizen::WidgetImplTizen( widget_base_instance_h instanceHandle )
+: Widget::Impl(), mInstanceHandle( instanceHandle )
+{
+}
+
+WidgetImplTizen::~WidgetImplTizen()
+{
+}
+
+void WidgetImplTizen::SetContentInfo( const std::string& contentInfo )
+{
+  bundle *contentBundle;
+  bundle_raw *contentBundleRaw = reinterpret_cast< bundle_raw* >( const_cast<char*>(contentInfo.c_str()) );
+  int len = contentInfo.length();
+  contentBundle = bundle_decode(contentBundleRaw, len);
+
+  widget_base_context_set_content_info( mInstanceHandle, contentBundle );
+
+  bundle_free( contentBundle );
+}
+
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/tizen-wayland/widget-controller-tizen.h b/dali/internal/system/tizen-wayland/widget-controller-tizen.h
new file mode 100644 (file)
index 0000000..c9a58d4
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef DALI_WIDGET_CONTROLLER_TIZEN_H
+#define DALI_WIDGET_CONTROLLER_TIZEN_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/signals/connection-tracker.h>
+#include <widget_base.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/widget-impl.h>
+#include <dali/internal/system/common/widget-controller.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief Holds the Implementation for the internal WidgetImpl class
+ */
+class WidgetImplTizen : public Widget::Impl
+{
+public:
+
+  /**
+   * Constructor
+   */
+  WidgetImplTizen( widget_base_instance_h instanceHandle );
+
+  /**
+   * Destructor
+   */
+  ~WidgetImplTizen() override;
+
+public:
+
+  /**
+   * Set content information to widget framework
+   */
+  void SetContentInfo( const std::string& contentInfo ) override;
+
+private:
+
+  widget_base_instance_h mInstanceHandle;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_WIDGET_CONTROLLER_TIZEN_H
diff --git a/dali/internal/system/ubuntu-x11/logging-x.cpp b/dali/internal/system/ubuntu-x11/logging-x.cpp
new file mode 100644 (file)
index 0000000..9244e99
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// FUNCTION HEADER
+#include <dali/internal/system/common/logging.h>
+
+// EXTERNAL INCLUDES
+#include <cstdio>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+void LogMessage(Dali::Integration::Log::DebugPriority level, std::string& message)
+{
+  const char* DALI_TAG = "DALI";
+
+  const char *format = NULL;
+  switch(level)
+  {
+    case Dali::Integration::Log::DebugInfo:
+      format = "\e[1;34mINFO:\e[21m %s: %s\e[0m";
+      break;
+    case Dali::Integration::Log::DebugWarning:
+      format = "\e[1;33mWARN:\e[21m %s: %s\e[0m";
+      break;
+    case Dali::Integration::Log::DebugError:
+      format = "\e[1;91mERROR:\e[21m %s: %s\e[0m";
+      break;
+    default:
+      format = ":\e[21m %s: %s\e[0m";
+      break;
+  }
+  printf(format, DALI_TAG, message.c_str());
+
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/dali/internal/system/ubuntu-x11/system-settings-x.cpp b/dali/internal/system/ubuntu-x11/system-settings-x.cpp
new file mode 100644 (file)
index 0000000..e0b9b57
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2019 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 <dali/internal/system/common/system-settings.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+int GetElmAccessActionOver()
+{
+  return 0;
+}
+
+int GetLongPressTime( int defaultTime )
+{
+  return defaultTime;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/ubuntu-x11/widget-application-impl-x.cpp b/dali/internal/system/ubuntu-x11/widget-application-impl-x.cpp
new file mode 100644 (file)
index 0000000..a9738d1
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/ubuntu-x11/widget-application-impl-x.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+WidgetApplicationPtr WidgetApplicationUbuntu::New(
+  int* argc,
+  char **argv[],
+  const std::string& stylesheet)
+{
+  return new WidgetApplicationUbuntu(argc, argv, stylesheet );
+}
+
+WidgetApplicationUbuntu::WidgetApplicationUbuntu( int* argc, char** argv[], const std::string& stylesheet )
+: WidgetApplication(argc, argv, stylesheet)
+{
+  DALI_LOG_ERROR("WidgetApplication is not implemented in UBUNTU profile.\n");
+}
+
+WidgetApplicationUbuntu::~WidgetApplicationUbuntu()
+{
+}
+
+
+void WidgetApplicationUbuntu::RegisterWidgetCreatingFunction( const std::string& widgetName, Dali::WidgetApplication::CreateWidgetFunction createFunction )
+{
+}
+
+// factory function, must be implemented
+namespace WidgetApplicationFactory
+{
+/**
+ * Create a new widget 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
+ */
+WidgetApplicationPtr Create( int* argc, char **argv[], const std::string& stylesheet )
+{
+  return WidgetApplicationUbuntu::New( argc, argv, stylesheet );
+}
+
+} // namespace Factory
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/ubuntu-x11/widget-application-impl-x.h b/dali/internal/system/ubuntu-x11/widget-application-impl-x.h
new file mode 100644 (file)
index 0000000..2154bc9
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef DALI_INTERNAL_WIDGET_APPLICATION_IMPL_UBUNTU_H
+#define DALI_INTERNAL_WIDGET_APPLICATION_IMPL_UBUNTU_H
+
+/*
+ * Copyright (c) 2018 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 <dali/internal/adaptor/common/application-impl.h>
+#include <dali/internal/system/common/widget-application-impl.h>
+#include <dali/public-api/adaptor-framework/widget-application.h>
+
+namespace Dali
+{
+class Widget;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Implementation of the WidgetApplicationUbuntu class.
+ */
+class WidgetApplicationUbuntu : public WidgetApplication
+{
+public:
+
+  typedef std::pair<const std::string, Dali::WidgetApplication::CreateWidgetFunction >  CreateWidgetFunctionPair;
+  typedef std::vector< CreateWidgetFunctionPair >   CreateWidgetFunctionContainer;
+
+  /**
+   * Create a new widget 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
+   */
+  static WidgetApplicationPtr New( int* argc, char **argv[], const std::string& stylesheet );
+
+public:
+
+  /**
+   * @copydoc Dali::WidgetApplication::RegisterWidgetCreator()
+   */
+  void RegisterWidgetCreatingFunction( const std::string& widgetName, Dali::WidgetApplication::CreateWidgetFunction createFunction ) override;
+
+protected:
+
+  /**
+   * 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
+   */
+  WidgetApplicationUbuntu( int* argc, char **argv[], const std::string& stylesheet );
+
+  /**
+   * Destructor
+   */
+  virtual ~WidgetApplicationUbuntu();
+
+  WidgetApplicationUbuntu(const Application&) = delete;
+  WidgetApplicationUbuntu& operator=(Application&) = delete;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WIDGET_APPLICATION_IMPL_UBUNTU_H
diff --git a/dali/internal/system/ubuntu-x11/widget-controller-x.cpp b/dali/internal/system/ubuntu-x11/widget-controller-x.cpp
new file mode 100644 (file)
index 0000000..3c1806a
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/ubuntu-x11/widget-controller-x.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+WidgetImplUbuntu::WidgetImplUbuntu()
+{
+}
+
+WidgetImplUbuntu::~WidgetImplUbuntu()
+{
+}
+
+void WidgetImplUbuntu::SetContentInfo( const std::string& contentInfo )
+{
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/ubuntu-x11/widget-controller-x.h b/dali/internal/system/ubuntu-x11/widget-controller-x.h
new file mode 100644 (file)
index 0000000..20eef3d
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef DALI_WIDGET_CONTROLLER_UBUNTU_H
+#define DALI_WIDGET_CONTROLLER_UBUNTU_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/signals/connection-tracker.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/widget-controller.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+/**
+ * @brief Holds the Implementation for the internal WidgetImpl class
+ */
+class WidgetImplUbuntu : public Widget::Impl
+{
+public:
+
+  /**
+   * Constructor
+   */
+  WidgetImplUbuntu();
+
+  /**
+   * Destructor
+   */
+  ~WidgetImplUbuntu() override;
+
+public:
+
+  /**
+   * Set content information to widget framework
+   */
+  void SetContentInfo( const std::string& contentInfo ) override;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_WIDGET_CONTROLLER_UBUNTU_H
diff --git a/dali/internal/system/windows/callback-manager-win.cpp b/dali/internal/system/windows/callback-manager-win.cpp
new file mode 100755 (executable)
index 0000000..b840cc5
--- /dev/null
@@ -0,0 +1,113 @@
+/*\r
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// CLASS HEADER\r
+#include <dali/internal/system/windows/callback-manager-win.h>\r
+\r
+// EXTERNAL INCLUDES\r
+#include <dali/integration-api/debug.h>\r
+#include <Windows.h>\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali/internal/window-system/windows/platform-implement-win.h>\r
+\r
+namespace Dali\r
+{\r
+\r
+namespace Internal\r
+{\r
+\r
+namespace Adaptor\r
+{\r
+\r
+WinCallbackManager::WinCallbackManager()\r
+:mRunning(false)\r
+{\r
+}\r
+\r
+void WinCallbackManager::Start()\r
+{\r
+  DALI_ASSERT_DEBUG( mRunning == false );\r
+  mRunning = true;\r
+}\r
+\r
+void WinCallbackManager::Stop()\r
+{\r
+  // make sure we're not called twice\r
+  DALI_ASSERT_DEBUG( mRunning == true );\r
+\r
+  mRunning = false;\r
+}\r
+\r
+bool WinCallbackManager::AddIdleCallback( CallbackBase* callback, bool hasReturnValue )\r
+{\r
+  if( !mRunning )\r
+  {\r
+    return false;\r
+  }\r
+\r
+  mCallbacks.insert(callback);\r
+\r
+  WindowsPlatformImplementation::PostWinThreadMessage( WIN_CALLBACK_EVENT, reinterpret_cast<uint64_t>(callback), 0 );\r
+\r
+  return true;\r
+}\r
+\r
+void WinCallbackManager::RemoveIdleCallback( CallbackBase* callback )\r
+{\r
+  //Wait for deal\r
+}\r
+\r
+bool WinCallbackManager::ProcessIdle()\r
+{\r
+  const bool idleProcessed = !mCallbacks.empty();\r
+\r
+  for (CallbackBase* cb : mCallbacks)\r
+  {\r
+    Dali::CallbackBase::Execute(*cb);\r
+  }\r
+  mCallbacks.clear();\r
+\r
+  return idleProcessed;\r
+}\r
+\r
+void WinCallbackManager::ClearIdleCallbacks()\r
+{\r
+  mCallbacks.clear();\r
+}\r
+\r
+bool WinCallbackManager::AddIdleEntererCallback( CallbackBase* callback )\r
+{\r
+  return AddIdleCallback( callback, true );\r
+}\r
+\r
+void WinCallbackManager::RemoveIdleEntererCallback( CallbackBase* callback )\r
+{\r
+\r
+}\r
+\r
+// Creates a concrete interface for CallbackManager\r
+CallbackManager* CallbackManager::New()\r
+{\r
+  return new WinCallbackManager;\r
+}\r
+\r
+} // namespace Adaptor\r
+\r
+} // namespace Internal\r
+\r
+} // namespace Dali\r
diff --git a/dali/internal/system/windows/callback-manager-win.h b/dali/internal/system/windows/callback-manager-win.h
new file mode 100755 (executable)
index 0000000..ef85501
--- /dev/null
@@ -0,0 +1,121 @@
+#ifndef DALI_WIN_CALLBACK_MANAGER_H
+#define DALI_WIN_CALLBACK_MANAGER_H
+
+/*
+ * Copyright (c) 2019 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>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/callback-manager.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+/**
+ * @brief LibUV callback manager used to install call backs in the applications main loop.
+ * The manager keeps track of all callbacks, so that if Stop() is called it can remove them.
+ */
+class WinCallbackManager : public CallbackManager
+{
+
+public:
+
+     /**
+     * @brief constructor
+     */
+    WinCallbackManager();
+
+    /**
+     * @brief destructor
+     */
+    ~WinCallbackManager(){}
+
+    /**
+     * @copydoc CallbackManager::AddIdleCallback()
+     */
+    virtual bool AddIdleCallback( CallbackBase* callback, bool hasReturnValue );
+
+    /**
+     * @copydoc CallbackManager::RemoveIdleCallback()
+     */
+    virtual void RemoveIdleCallback( CallbackBase* callback );
+
+    /**
+     * @copydoc CallbackManager::ProcessIdle()
+     */
+    virtual bool ProcessIdle();
+
+    /**
+     * @copydoc CallbackManager::ClearIdleCallbacks()
+     */
+    virtual void ClearIdleCallbacks();
+
+    /**
+    * @brief Adds a @p callback to be run when entering an idle state.
+    * @note Must be called from the main thread only.
+    *
+    * A callback of the following type should be used:
+    * @code
+    *   bool MyFunction();
+    * @endcode
+    * This callback will be called repeatedly as long as it returns true. A return of 0 deletes this callback.
+    *
+    * @param[in] callback custom callback function.
+    *
+    * @return true on success
+    */
+    virtual bool AddIdleEntererCallback( CallbackBase* callback );
+
+    /**
+    * @brief Removes a previously added the idle enterer callback.
+    * @note Must be called from main thread only.
+    *
+    * Does nothing if the @p callback doesn't exist.
+    *
+    * @param[in] callback The callback to be removed.
+    */
+    virtual void RemoveIdleEntererCallback( CallbackBase* callback );
+
+    /**
+     * @copydoc CallbackManager::Start()
+     */
+    virtual void Start();
+
+    /**
+     * @copydoc CallbackManager::Stop()
+     */
+    virtual void Stop();
+
+private:
+    std::set<CallbackBase*>        mCallbacks;
+    bool                           mRunning;            ///< flag is set to true if when running
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_WIN_CALLBACK_MANAGER_H
diff --git a/dali/internal/system/windows/logging-win.cpp b/dali/internal/system/windows/logging-win.cpp
new file mode 100644 (file)
index 0000000..9244e99
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// FUNCTION HEADER
+#include <dali/internal/system/common/logging.h>
+
+// EXTERNAL INCLUDES
+#include <cstdio>
+
+namespace Dali
+{
+
+namespace TizenPlatform
+{
+
+void LogMessage(Dali::Integration::Log::DebugPriority level, std::string& message)
+{
+  const char* DALI_TAG = "DALI";
+
+  const char *format = NULL;
+  switch(level)
+  {
+    case Dali::Integration::Log::DebugInfo:
+      format = "\e[1;34mINFO:\e[21m %s: %s\e[0m";
+      break;
+    case Dali::Integration::Log::DebugWarning:
+      format = "\e[1;33mWARN:\e[21m %s: %s\e[0m";
+      break;
+    case Dali::Integration::Log::DebugError:
+      format = "\e[1;91mERROR:\e[21m %s: %s\e[0m";
+      break;
+    default:
+      format = ":\e[21m %s: %s\e[0m";
+      break;
+  }
+  printf(format, DALI_TAG, message.c_str());
+
+}
+
+} // namespace TizenPlatform
+
+} // namespace Dali
diff --git a/dali/internal/system/windows/system-settings-win.cpp b/dali/internal/system/windows/system-settings-win.cpp
new file mode 100755 (executable)
index 0000000..3cf5f2c
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 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 <dali/internal/system/common/system-settings.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+int GetLongPressTime( int defaultTime )\r
+{\r
+  return defaultTime;\r
+}\r
+\r
+int GetElmAccessActionOver()\r
+{\r
+  return 0;\r
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/windows/timer-impl-win.cpp b/dali/internal/system/windows/timer-impl-win.cpp
new file mode 100755 (executable)
index 0000000..7691199
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/common/timer-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/window-system/windows/platform-implement-win.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+// LOCAL STUFF
+namespace
+{
+bool TimerSourceFunc (void *data)
+{
+  Timer* timer = static_cast<Timer*>(data);
+  return timer->Tick();
+}
+}
+
+/**
+ * Struct to hide away Windows implementation details
+ */
+struct Timer::Impl
+{
+  Impl( unsigned int milliSec ) :
+    mId(-1),
+    mInterval(milliSec)
+  {
+  }
+
+  int mId;
+
+  unsigned int mInterval;
+};
+
+TimerPtr Timer::New( unsigned int milliSec )
+{
+  TimerPtr timer( new Timer( milliSec ) );
+  return timer;
+}
+
+Timer::Timer( unsigned int milliSec )
+: mImpl(new Impl(milliSec))
+{
+}
+
+Timer::~Timer()
+{
+  // stop timers
+  Stop();
+
+  delete mImpl;
+  mImpl = NULL;
+}
+
+void Timer::Start()
+{
+  if( 0 > mImpl->mId )
+  {
+    mImpl->mId = WindowsPlatformImplementation::SetTimer( mImpl->mInterval, TimerSourceFunc, this );
+  }
+}
+
+void Timer::Stop()
+{
+  if( 0 <= mImpl->mId )
+  {
+    WindowsPlatformImplementation::KillTimer( mImpl->mId );
+    mImpl->mId = -1;
+  }
+}
+
+void Timer::Pause()
+{
+
+}
+
+void Timer::Resume()
+{
+
+}
+
+void Timer::SetInterval( unsigned int interval, bool restart )
+{
+  if( true == restart )
+  {
+    // stop existing timer
+    Stop();
+    mImpl->mInterval = interval;
+    // start new tick
+    Start();
+  }
+  else
+  {
+    mImpl->mInterval = interval;
+  }
+}
+
+unsigned int Timer::GetInterval() const
+{
+  return mImpl->mInterval;
+}
+
+bool Timer::Tick()
+{
+  // Guard against destruction during signal emission
+  Dali::Timer handle( this );
+
+  bool retVal( false );
+
+  // Override with new signal if used
+  if( !mTickSignal.Empty() )
+  {
+    retVal = mTickSignal.Emit();
+
+    // Timer stops if return value is false
+    if (retVal == false)
+    {
+      Stop();
+    }
+    else
+    {
+      retVal = true;   // continue emission
+    }
+  }
+  else // no callbacks registered
+  {
+    // periodic timer is started but nobody listens, continue
+    retVal = true;
+  }
+
+  return retVal;
+}
+
+Dali::Timer::TimerSignalType& Timer::TickSignal()
+{
+  return mTickSignal;
+}
+
+bool Timer::IsRunning() const
+{
+  return 0 <= mImpl->mId;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
diff --git a/dali/internal/system/windows/trigger-event-factory.cpp b/dali/internal/system/windows/trigger-event-factory.cpp
new file mode 100755 (executable)
index 0000000..2631202
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
+
+// EXTERNAL INCLUDES
+#include <dali/internal/system/windows/trigger-event.h>
+
+namespace Dali
+{
+
+TriggerEventInterface* TriggerEventFactory::CreateTriggerEvent( CallbackBase* callback,  TriggerEventInterface::Options options )
+{
+  return new Internal::Adaptor::TriggerEvent( callback, options );
+}
+
+void TriggerEventFactory::DestroyTriggerEvent( TriggerEventInterface* triggerEventInterface )
+{
+  Internal::Adaptor::TriggerEvent* triggerEvent( static_cast<Internal::Adaptor::TriggerEvent *>(triggerEventInterface) );
+  delete triggerEvent;
+}
+
+} // namespace Dali
diff --git a/dali/internal/system/windows/trigger-event.cpp b/dali/internal/system/windows/trigger-event.cpp
new file mode 100755 (executable)
index 0000000..af42ad6
--- /dev/null
@@ -0,0 +1,97 @@
+/*\r
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// CLASS HEADER\r
+#include <dali/internal/system/windows/trigger-event.h>\r
+\r
+// EXTERNAL INCLUDES\r
+#include <unistd.h>\r
+\r
+#include <dali/integration-api/debug.h>\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali/internal/system/common/file-descriptor-monitor.h>\r
+#include <dali/internal/window-system/windows/platform-implement-win.h>\r
+\r
+namespace Dali\r
+{\r
+\r
+namespace Internal\r
+{\r
+\r
+namespace Adaptor\r
+{\r
+\r
+TriggerEvent::TriggerEvent( CallbackBase* callback, TriggerEventInterface::Options options )\r
+: mCallback( callback ),\r
+  mThreadID( -1 ),\r
+  mOptions( options )\r
+{\r
+  // Create accompanying file descriptor.\r
+  mThreadID = WindowsPlatformImplementation::GetCurrentThreadId();\r
+\r
+  if ( mThreadID < 0)\r
+  {\r
+    DALI_LOG_ERROR("Unable to create TriggerEvent File descriptor\n");\r
+  }\r
+\r
+  mSelfCallback = MakeCallback( this, &TriggerEvent::Triggered );\r
+}\r
+\r
+TriggerEvent::~TriggerEvent()\r
+{\r
+  delete mCallback;\r
+  delete mSelfCallback;\r
+\r
+  if ( mThreadID >= 0)\r
+  {\r
+    mThreadID = 0;\r
+  }\r
+}\r
+\r
+void TriggerEvent::Trigger()\r
+{\r
+  if ( mThreadID >= 0)\r
+  {\r
+    // Increment event counter by 1.\r
+    // Writing to the file descriptor triggers the Dispatch() method in the other thread\r
+    // (if in multi-threaded environment).\r
+    WindowsPlatformImplementation::PostWinThreadMessage( WIN_CALLBACK_EVENT, reinterpret_cast<uint64_t>( mSelfCallback ), 0, mThreadID );\r
+  }\r
+  else\r
+  {\r
+    DALI_LOG_WARNING("Attempting to write to an invalid file descriptor\n");\r
+  }\r
+}\r
+\r
+void TriggerEvent::Triggered()\r
+{\r
+  // Call the connected callback\r
+  CallbackBase::Execute( *mCallback );\r
+\r
+  //check if we should delete ourselves after the trigger\r
+  if( mOptions == TriggerEventInterface::DELETE_AFTER_TRIGGER )\r
+  {\r
+    delete this;\r
+  }\r
+}\r
+\r
+} // namespace Adaptor\r
+\r
+} // namespace Internal\r
+\r
+} // namespace Dali\r
diff --git a/dali/internal/system/windows/trigger-event.h b/dali/internal/system/windows/trigger-event.h
new file mode 100755 (executable)
index 0000000..6bf2264
--- /dev/null
@@ -0,0 +1,88 @@
+#ifndef DALI_INTERNAL_TRIGGER_EVENT_IMPL_H
+#define DALI_INTERNAL_TRIGGER_EVENT_IMPL_H
+
+/*
+* Copyright (c) 2019 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/signals/callback.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/integration-api/adaptor-framework/trigger-event-interface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class TriggerEvent : public TriggerEventInterface
+{
+public:
+
+  /**
+   * Constructor
+   * Creates an event file descriptor and starts a GSource which reads from the file
+   * descriptor when there is data.
+   *
+   * @param[in] callback The callback to call
+   * @param[in] options Trigger event options.
+   * @note The ownership of callback is taken by this class.
+   */
+  TriggerEvent( CallbackBase* callback, TriggerEventInterface::Options options );
+
+  /**
+   * Destructor
+   */
+  ~TriggerEvent();
+
+public:
+
+  /**
+   * Triggers the event.
+   *
+   * This can be called from one thread in order to wake up another thread.
+   */
+  void Trigger();
+
+private:
+
+  /**
+   * @brief Called when our event file descriptor has been written to.
+   * @param[in] eventBitMask bit mask of events that occured on the file descriptor
+   */
+  void Triggered();
+
+private:
+
+  CallbackBase* mCallback;
+  CallbackBase* mSelfCallback;
+  int32_t mThreadID;
+  TriggerEventInterface::Options mOptions;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TRIGGER_EVENT_IMPL_H
\ No newline at end of file
diff --git a/dali/internal/system/windows/widget-application-impl-win.cpp b/dali/internal/system/windows/widget-application-impl-win.cpp
new file mode 100755 (executable)
index 0000000..57c38ee
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/system/windows/widget-application-impl-win.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+WidgetApplicationPtr WidgetApplicationWin::New(
+  int* argc,
+  char **argv[],
+  const std::string& stylesheet)
+{
+  return new WidgetApplicationWin(argc, argv, stylesheet );
+}
+
+WidgetApplicationWin::WidgetApplicationWin( int* argc, char** argv[], const std::string& stylesheet )
+: WidgetApplication(argc, argv, stylesheet)
+{
+  DALI_LOG_ERROR("WidgetApplication is not implemented in UBUNTU profile.\n");
+}
+
+WidgetApplicationWin::~WidgetApplicationWin()
+{
+}
+
+
+void WidgetApplicationWin::RegisterWidgetCreatingFunction( const std::string& widgetName, Dali::WidgetApplication::CreateWidgetFunction createFunction )
+{
+}
+
+// factory function, must be implemented
+namespace WidgetApplicationFactory
+{
+/**
+ * Create a new widget 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
+ */
+WidgetApplicationPtr Create( int* argc, char **argv[], const std::string& stylesheet )
+{
+  return WidgetApplicationWin::New( argc, argv, stylesheet );
+}
+
+} // namespace Factory
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/windows/widget-application-impl-win.h b/dali/internal/system/windows/widget-application-impl-win.h
new file mode 100755 (executable)
index 0000000..fd3b1ab
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef DALI_INTERNAL_WIDGET_APPLICATION_IMPL_WIN_H
+#define DALI_INTERNAL_WIDGET_APPLICATION_IMPL_WIN_H
+
+/*
+ * Copyright (c) 2018 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 <dali/internal/adaptor/common/application-impl.h>
+#include <dali/internal/system/common//widget-application-impl.h>
+#include <dali/public-api/adaptor-framework/widget-application.h>
+
+namespace Dali
+{
+class Widget;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Implementation of the WidgetApplicationWin class.
+ */
+class WidgetApplicationWin : public WidgetApplication
+{
+public:
+
+  typedef std::pair<const std::string, Dali::WidgetApplication::CreateWidgetFunction >  CreateWidgetFunctionPair;
+  typedef std::vector< CreateWidgetFunctionPair >   CreateWidgetFunctionContainer;
+
+  /**
+   * Create a new widget 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
+   */
+  static WidgetApplicationPtr New( int* argc, char **argv[], const std::string& stylesheet );
+
+public:
+
+  /**
+   * @copydoc Dali::WidgetApplication::RegisterWidgetCreator()
+   */
+  void RegisterWidgetCreatingFunction( const std::string& widgetName, Dali::WidgetApplication::CreateWidgetFunction createFunction ) override;
+
+protected:
+
+  /**
+   * 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
+   */
+  WidgetApplicationWin( int* argc, char **argv[], const std::string& stylesheet );
+
+  /**
+   * Destructor
+   */
+  virtual ~WidgetApplicationWin();
+
+  WidgetApplicationWin(const Application&) = delete;
+  WidgetApplicationWin& operator=(Application&) = delete;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WIDGET_APPLICATION_IMPL_UBUNTU_H
diff --git a/dali/internal/system/windows/widget-controller-win.cpp b/dali/internal/system/windows/widget-controller-win.cpp
new file mode 100755 (executable)
index 0000000..e98e29c
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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 <dali/internal/system/windows/widget-controller-win.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+WidgetImplWin::WidgetImplWin()
+{
+}
+
+WidgetImplWin::~WidgetImplWin()
+{
+}
+
+void WidgetImplWin::SetContentInfo( const std::string& contentInfo )
+{
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/system/windows/widget-controller-win.h b/dali/internal/system/windows/widget-controller-win.h
new file mode 100755 (executable)
index 0000000..c19de62
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef DALI_WIDGET_CONTROLLER_WIN_H
+#define DALI_WIDGET_CONTROLLER_WIN_H
+
+/*
+ * Copyright (c) 2018 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/signals/connection-tracker.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/widget-controller.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+/**
+ * @brief Holds the Implementation for the internal WidgetImpl class
+ */
+class WidgetImplWin : public Widget::Impl
+{
+public:
+
+  /**
+   * Constructor
+   */
+  WidgetImplWin();
+
+  /**
+   * Destructor
+   */
+  ~WidgetImplWin() override;
+
+public:
+
+  /**
+   * Set content information to widget framework
+   */
+  void SetContentInfo( const std::string& contentInfo ) override;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_WIDGET_CONTROLLER_UBUNTU_H
diff --git a/dali/internal/text/file.list b/dali/internal/text/file.list
new file mode 100644 (file)
index 0000000..8530a7b
--- /dev/null
@@ -0,0 +1,13 @@
+
+# module: text, backend: common
+SET( adaptor_text_common_src_files 
+    ${adaptor_text_dir}/text-abstraction/bidirectional-support-impl.cpp 
+    ${adaptor_text_dir}/text-abstraction/cairo-renderer.cpp 
+    ${adaptor_text_dir}/text-abstraction/font-client-helper.cpp 
+    ${adaptor_text_dir}/text-abstraction/font-client-impl.cpp 
+    ${adaptor_text_dir}/text-abstraction/font-client-plugin-impl.cpp 
+    ${adaptor_text_dir}/text-abstraction/segmentation-impl.cpp 
+    ${adaptor_text_dir}/text-abstraction/shaping-impl.cpp 
+    ${adaptor_text_dir}/text-abstraction/text-renderer-impl.cpp
+)
+
diff --git a/dali/internal/text/text-abstraction/bidirectional-support-impl.cpp b/dali/internal/text/text-abstraction/bidirectional-support-impl.cpp
new file mode 100755 (executable)
index 0000000..7142ada
--- /dev/null
@@ -0,0 +1,471 @@
+/*
+ * 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 <dali/internal/text/text-abstraction/bidirectional-support-impl.h>
+
+// EXTERNAL INCLUDES
+#include <memory.h>
+#include <fribidi/fribidi.h>
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/common/singleton-service.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+namespace
+{
+  typedef unsigned char BidiDirection;
+
+  // Internal charcter's direction.
+  const BidiDirection LEFT_TO_RIGHT = 0u;
+  const BidiDirection NEUTRAL = 1u;
+  const BidiDirection RIGHT_TO_LEFT = 2u;
+
+  /**
+   * @param[in] paragraphDirection The FriBiDi paragraph's direction.
+   *
+   * @return Whether the paragraph is right to left.
+   */
+  bool GetBidiParagraphDirection( FriBidiParType paragraphDirection )
+  {
+    switch( paragraphDirection )
+    {
+      case FRIBIDI_PAR_RTL:  // Right-To-Left paragraph.
+      case FRIBIDI_PAR_WRTL: // Weak Right To Left paragraph.
+      {
+        return true;
+      }
+      case FRIBIDI_PAR_LTR:  // Left-To-Right paragraph.
+      case FRIBIDI_PAR_ON:   // DirectiOn-Neutral paragraph.
+      case FRIBIDI_PAR_WLTR: // Weak Left To Right paragraph.
+      {
+        return false;
+      }
+    }
+
+    return false;
+  }
+
+  BidiDirection GetBidiCharacterDirection( FriBidiCharType characterDirection )
+  {
+    switch( characterDirection )
+    {
+      case FRIBIDI_TYPE_LTR: // Left-To-Right letter.
+      {
+        return LEFT_TO_RIGHT;
+      }
+      case FRIBIDI_TYPE_AL:  // Arabic Letter.
+      case FRIBIDI_TYPE_RTL: // Right-To-Left letter.
+      {
+        return RIGHT_TO_LEFT;
+      }
+      case FRIBIDI_TYPE_AN:  // Arabic Numeral.
+      case FRIBIDI_TYPE_ES:  // European number Separator.
+      case FRIBIDI_TYPE_ET:  // European number Terminator.
+      case FRIBIDI_TYPE_EN:  // European Numeral.
+      default :
+      {
+        return NEUTRAL;
+      }
+    }
+  }
+}
+
+struct BidirectionalSupport::Plugin
+{
+  /**
+   * Stores bidirectional info per paragraph.
+   */
+  struct BidirectionalInfo
+  {
+    FriBidiCharType* characterTypes;      ///< The type of each character (right, left, neutral, ...)
+    FriBidiLevel*    embeddedLevels;      ///< Embedded levels.
+    FriBidiParType   paragraphDirection;  ///< The paragraph's direction.
+  };
+
+  Plugin()
+  : mParagraphBidirectionalInfo(),
+    mFreeIndices()
+  {}
+
+  ~Plugin()
+  {
+    // free all resources.
+    for( Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin(),
+           endIt = mParagraphBidirectionalInfo.End();
+         it != endIt;
+         ++it )
+    {
+      BidirectionalInfo* info = *it;
+
+      free( info->embeddedLevels );
+      free( info->characterTypes );
+      delete info;
+    }
+  }
+
+  BidiInfoIndex CreateInfo( const Character* const paragraph,
+                            Length numberOfCharacters,
+                            bool matchSystemLanguageDirection,
+                            LayoutDirection::Type layoutDirection )
+  {
+    // Reserve memory for the paragraph's bidirectional info.
+    BidirectionalInfo* bidirectionalInfo = new BidirectionalInfo();
+
+    bidirectionalInfo->characterTypes = reinterpret_cast<FriBidiCharType*>( malloc( numberOfCharacters * sizeof( FriBidiCharType ) ) );
+    if( !bidirectionalInfo->characterTypes )
+    {
+      delete bidirectionalInfo;
+      return 0;
+    }
+
+    bidirectionalInfo->embeddedLevels = reinterpret_cast<FriBidiLevel*>( malloc( numberOfCharacters * sizeof( FriBidiLevel ) ) );
+    if( !bidirectionalInfo->embeddedLevels )
+    {
+      free( bidirectionalInfo->characterTypes );
+      delete bidirectionalInfo;
+      return 0;
+    }
+
+    // Retrieve the type of each character..
+    fribidi_get_bidi_types( paragraph, numberOfCharacters, bidirectionalInfo->characterTypes );
+
+    // Retrieve the paragraph's direction.
+    bidirectionalInfo->paragraphDirection = matchSystemLanguageDirection == true ?
+                                           ( layoutDirection == LayoutDirection::RIGHT_TO_LEFT ? FRIBIDI_PAR_RTL : FRIBIDI_PAR_LTR ) :
+                                           ( fribidi_get_par_direction( bidirectionalInfo->characterTypes, numberOfCharacters ) );
+
+    // Retrieve the embedding levels.
+    if (fribidi_get_par_embedding_levels( bidirectionalInfo->characterTypes, numberOfCharacters, &bidirectionalInfo->paragraphDirection, bidirectionalInfo->embeddedLevels ) == 0)
+    {
+      free( bidirectionalInfo->characterTypes );
+      delete bidirectionalInfo;
+      return 0;
+    }
+
+    // Store the bidirectional info and return the index.
+    BidiInfoIndex index = 0u;
+    if( 0u != mFreeIndices.Count() )
+    {
+      Vector<BidiInfoIndex>::Iterator it = mFreeIndices.End() - 1u;
+
+      index = *it;
+
+      mFreeIndices.Remove( it );
+
+      *( mParagraphBidirectionalInfo.Begin() + index ) = bidirectionalInfo;
+    }
+    else
+    {
+      index = static_cast<BidiInfoIndex>( mParagraphBidirectionalInfo.Count() );
+
+      mParagraphBidirectionalInfo.PushBack( bidirectionalInfo );
+    }
+
+    return index;
+  }
+
+  void DestroyInfo( BidiInfoIndex bidiInfoIndex )
+  {
+    if( bidiInfoIndex >= mParagraphBidirectionalInfo.Count() )
+    {
+      return;
+    }
+
+    // Retrieve the paragraph's bidirectional info.
+    Vector<BidirectionalInfo*>::Iterator it = mParagraphBidirectionalInfo.Begin() + bidiInfoIndex;
+    BidirectionalInfo* bidirectionalInfo = *it;
+
+    if( NULL != bidirectionalInfo )
+    {
+      // Free resources and destroy the container.
+      free( bidirectionalInfo->embeddedLevels );
+      free( bidirectionalInfo->characterTypes );
+      delete bidirectionalInfo;
+
+      *it = NULL;
+    }
+
+    // Add the index to the free indices vector.
+    mFreeIndices.PushBack( bidiInfoIndex );
+  }
+
+  void Reorder( BidiInfoIndex bidiInfoIndex,
+                CharacterIndex firstCharacterIndex,
+                Length numberOfCharacters,
+                CharacterIndex* visualToLogicalMap )
+  {
+    const FriBidiFlags flags = FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC;
+
+    // Retrieve the paragraph's bidirectional info.
+    const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );
+
+    // Initialize the visual to logical mapping table to the identity. Otherwise fribidi_reorder_line fails to retrieve a valid mapping table.
+    for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
+    {
+      visualToLogicalMap[ index ] = index;
+    }
+
+    // Copy embedded levels as fribidi_reorder_line() may change them.
+    const uint32_t embeddedLevelsSize = numberOfCharacters * sizeof( FriBidiLevel );
+    FriBidiLevel* embeddedLevels = reinterpret_cast<FriBidiLevel*>( malloc( embeddedLevelsSize ) );
+    if( embeddedLevels )
+    {
+      memcpy( embeddedLevels, bidirectionalInfo->embeddedLevels + firstCharacterIndex,  embeddedLevelsSize );
+
+      // Reorder the line.
+      if (fribidi_reorder_line( flags,
+                                bidirectionalInfo->characterTypes + firstCharacterIndex,
+                                numberOfCharacters,
+                                0u,
+                                bidirectionalInfo->paragraphDirection,
+                                embeddedLevels,
+                                NULL,
+                                reinterpret_cast<FriBidiStrIndex*>( visualToLogicalMap ) ) == 0)
+      {
+        DALI_LOG_ERROR("fribidi_reorder_line is failed\n");
+      }
+
+      // Free resources.
+      free( embeddedLevels );
+    }
+  }
+
+  bool GetMirroredText( Character* text,
+                        CharacterDirection* directions,
+                        Length numberOfCharacters ) const
+  {
+    bool updated = false;
+
+    for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
+    {
+      // Get a reference to the character inside the text.
+      Character& character = *( text + index );
+
+      // Retrieve the mirrored character.
+      FriBidiChar mirroredCharacter = character;
+      bool mirrored = false;
+      if( *( directions + index ) )
+      {
+        mirrored = fribidi_get_mirror_char( character, &mirroredCharacter );
+      }
+      updated = updated || mirrored;
+
+      // Update the character inside the text.
+      character = mirroredCharacter;
+    }
+
+    return updated;
+  }
+
+  bool GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const
+  {
+    // Retrieve the paragraph's bidirectional info.
+    const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );
+
+    return GetBidiParagraphDirection( bidirectionalInfo->paragraphDirection );
+  }
+
+  void GetCharactersDirection( BidiInfoIndex bidiInfoIndex,
+                               CharacterDirection* directions,
+                               Length numberOfCharacters )
+  {
+    const BidirectionalInfo* const bidirectionalInfo = *( mParagraphBidirectionalInfo.Begin() + bidiInfoIndex );
+
+    const CharacterDirection paragraphDirection = GetBidiParagraphDirection( bidirectionalInfo->paragraphDirection );
+    CharacterDirection previousDirection = paragraphDirection;
+
+    for( CharacterIndex index = 0u; index < numberOfCharacters; ++index )
+    {
+      CharacterDirection& characterDirection = *( directions + index );
+      CharacterDirection nextDirection = false;
+
+      characterDirection = false;
+
+      // Get the bidi direction.
+      const BidiDirection bidiDirection = GetBidiCharacterDirection( *( bidirectionalInfo->characterTypes + index ) );
+
+      if( RIGHT_TO_LEFT == bidiDirection )
+      {
+        characterDirection = true;
+        nextDirection = true;
+      }
+      else if( NEUTRAL == bidiDirection )
+      {
+        // For neutral characters it check's the next and previous directions.
+        // If they are equals set that direction. If they are not, sets the paragraph's direction.
+        // If there is no next, sets the paragraph's direction.
+        nextDirection = paragraphDirection;
+
+        // Look for the next non-neutral character.
+        Length nextIndex = index + 1u;
+        for( ; nextIndex < numberOfCharacters; ++nextIndex )
+        {
+          BidiDirection nextBidiDirection = GetBidiCharacterDirection( *( bidirectionalInfo->characterTypes + nextIndex ) );
+          if( nextBidiDirection != NEUTRAL )
+          {
+            nextDirection = RIGHT_TO_LEFT == nextBidiDirection;
+            break;
+          }
+        }
+
+        // Calculate the direction for all the neutral characters.
+        characterDirection = previousDirection == nextDirection ? previousDirection : paragraphDirection;
+
+        // Set the direction to all the neutral characters.
+        // The indices from currentIndex + 1u to nextIndex - 1u are neutral characters.
+        ++index;
+
+        for( ; index < nextIndex; ++index )
+        {
+          CharacterDirection& nextCharacterDirection = *( directions + index );
+          nextCharacterDirection = characterDirection;
+        }
+
+        // Set the direction of the next non-neutral character.
+        if( nextIndex < numberOfCharacters )
+        {
+          *( directions + nextIndex ) = nextDirection;
+        }
+      }
+
+      previousDirection = nextDirection;
+    }
+  }
+
+  Vector<BidirectionalInfo*> mParagraphBidirectionalInfo; ///< Stores the bidirectional info per paragraph.
+  Vector<BidiInfoIndex>      mFreeIndices;                ///< Stores indices of free positions in the bidirectional info vector.
+};
+
+BidirectionalSupport::BidirectionalSupport()
+: mPlugin( NULL )
+{
+}
+
+BidirectionalSupport::~BidirectionalSupport()
+{
+  delete mPlugin;
+}
+
+TextAbstraction::BidirectionalSupport BidirectionalSupport::Get()
+{
+  TextAbstraction::BidirectionalSupport bidirectionalSupportHandle;
+
+  SingletonService service( SingletonService::Get() );
+  if( service )
+  {
+    // Check whether the singleton is already created
+    BaseHandle handle = service.GetSingleton( typeid( TextAbstraction::BidirectionalSupport ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      BidirectionalSupport* impl = dynamic_cast< Internal::BidirectionalSupport* >( handle.GetObjectPtr() );
+      bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( impl );
+    }
+    else // create and register the object
+    {
+      bidirectionalSupportHandle = TextAbstraction::BidirectionalSupport( new BidirectionalSupport );
+      service.Register( typeid( bidirectionalSupportHandle ), bidirectionalSupportHandle );
+    }
+  }
+
+  return bidirectionalSupportHandle;
+}
+
+BidiInfoIndex BidirectionalSupport::CreateInfo( const Character* const paragraph,
+                                                Length numberOfCharacters,
+                                                bool matchSystemLanguageDirection,
+                                                Dali::LayoutDirection::Type layoutDirection )
+{
+  CreatePlugin();
+
+  return mPlugin->CreateInfo( paragraph,
+                              numberOfCharacters,
+                              matchSystemLanguageDirection,
+                              layoutDirection );
+}
+
+void BidirectionalSupport::DestroyInfo( BidiInfoIndex bidiInfoIndex )
+{
+  CreatePlugin();
+
+  mPlugin->DestroyInfo( bidiInfoIndex );
+}
+
+void BidirectionalSupport::Reorder( BidiInfoIndex bidiInfoIndex,
+                                    CharacterIndex firstCharacterIndex,
+                                    Length numberOfCharacters,
+                                    CharacterIndex* visualToLogicalMap )
+{
+  CreatePlugin();
+
+  mPlugin->Reorder( bidiInfoIndex,
+                    firstCharacterIndex,
+                    numberOfCharacters,
+                    visualToLogicalMap );
+}
+
+bool BidirectionalSupport::GetMirroredText( Character* text,
+                                            CharacterDirection* directions,
+                                            Length numberOfCharacters )
+{
+  CreatePlugin();
+
+  return mPlugin->GetMirroredText( text, directions, numberOfCharacters );
+}
+
+bool BidirectionalSupport::GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const
+{
+  if( !mPlugin )
+  {
+    return false;
+  }
+
+  return mPlugin->GetParagraphDirection( bidiInfoIndex );
+}
+
+void BidirectionalSupport::GetCharactersDirection( BidiInfoIndex bidiInfoIndex,
+                                                   CharacterDirection* directions,
+                                                   Length numberOfCharacters )
+{
+  CreatePlugin();
+
+  mPlugin->GetCharactersDirection( bidiInfoIndex,
+                                   directions,
+                                   numberOfCharacters );
+}
+
+void BidirectionalSupport::CreatePlugin()
+{
+  if( !mPlugin )
+  {
+    mPlugin = new Plugin();
+  }
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/internal/text/text-abstraction/bidirectional-support-impl.h b/dali/internal/text/text-abstraction/bidirectional-support-impl.h
new file mode 100755 (executable)
index 0000000..bfd583a
--- /dev/null
@@ -0,0 +1,141 @@
+#ifndef DALI_INTERNAL_TEXT_ABSTRACTION_BIDIRECTIONAL_SUPPORT_IMPL_H
+#define DALI_INTERNAL_TEXT_ABSTRACTION_BIDIRECTIONAL_SUPPORT_IMPL_H
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/bidirectional-support.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * Implementation of the BidirectionalSupport
+ */
+class BidirectionalSupport : public BaseObject
+{
+public:
+
+  /**
+   * Constructor
+   */
+  BidirectionalSupport();
+
+  /**
+   * Destructor
+   */
+  ~BidirectionalSupport();
+
+  /**
+   * @copydoc Dali::BidirectionalSupport::Get()
+   */
+  static TextAbstraction::BidirectionalSupport Get();
+
+  /**
+   * @copydoc Dali::BidirectionalSupport::CreateInfo()
+   */
+  BidiInfoIndex CreateInfo( const Character* const paragraph,
+                            Length numberOfCharacters,
+                            bool matchSystemLanguageDirection,
+                            LayoutDirection::Type layoutDirection );
+
+  /**
+   * @copydoc Dali::BidirectionalSupport::DestroyInfo()
+   */
+  void DestroyInfo( BidiInfoIndex bidiInfoIndex );
+
+  /**
+   * @copydoc Dali::BidirectionalSupport::Reorder()
+   */
+  void Reorder( BidiInfoIndex bidiInfoIndex,
+                CharacterIndex firstCharacterIndex,
+                Length numberOfCharacters,
+                CharacterIndex* visualToLogicalMap );
+
+  /**
+   * @copydoc Dali::BidirectionalSupport::GetMirroredText()
+   */
+  bool GetMirroredText( Character* text,
+                        CharacterDirection* directions,
+                        Length numberOfCharacters );
+
+  /**
+   * @copydoc Dali::BidirectionalSupport::GetParagraphDirection()
+   */
+  bool GetParagraphDirection( BidiInfoIndex bidiInfoIndex ) const;
+
+  /**
+   * @copydoc Dali::BidirectionalSupport::GetCharactersDirection()
+   */
+  void GetCharactersDirection( BidiInfoIndex bidiInfoIndex,
+                               CharacterDirection* directions,
+                               Length numberOfCharacters );
+
+private:
+
+  /**
+   * Helper for lazy initialization.
+   */
+  void CreatePlugin();
+
+private:
+
+  // Undefined copy constructor.
+  BidirectionalSupport( const BidirectionalSupport& );
+
+  // Undefined assignment constructor.
+  BidirectionalSupport& operator=( const BidirectionalSupport& );
+
+private:
+
+  struct Plugin;
+  Plugin* mPlugin;
+
+}; // class BidirectionalSupport
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+inline static TextAbstraction::Internal::BidirectionalSupport& GetImplementation( TextAbstraction::BidirectionalSupport& bidirectionalSupport )
+{
+  DALI_ASSERT_ALWAYS( bidirectionalSupport && "bidirectional support handle is empty" );
+  BaseObject& handle = bidirectionalSupport.GetBaseObject();
+  return static_cast<TextAbstraction::Internal::BidirectionalSupport&>(handle);
+}
+
+inline static const TextAbstraction::Internal::BidirectionalSupport& GetImplementation( const TextAbstraction::BidirectionalSupport& bidirectionalSupport )
+{
+  DALI_ASSERT_ALWAYS( bidirectionalSupport && "bidirectional support handle is empty" );
+  const BaseObject& handle = bidirectionalSupport.GetBaseObject();
+  return static_cast<const TextAbstraction::Internal::BidirectionalSupport&>(handle);
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TEXT_ABSTRACTION_BIDIRECTIONAL_SUPPORT_IMPL_H
diff --git a/dali/internal/text/text-abstraction/cairo-renderer.cpp b/dali/internal/text/text-abstraction/cairo-renderer.cpp
new file mode 100755 (executable)
index 0000000..b6d75e6
--- /dev/null
@@ -0,0 +1,898 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// FILE HEADER
+#include <dali/internal/text/text-abstraction/cairo-renderer.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/constants.h>
+#include <cairo.h>
+#include <cairo-ft.h>
+#include <cstring>
+#include <memory>
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include FT_OUTLINE_H
+#include FT_STROKER_H
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/devel-api/text-abstraction/text-renderer-layout-helper.h>
+#include <dali/integration-api/debug.h>
+#include <dali/internal/imaging/common/image-operations.h>
+#include <dali/internal/text/text-abstraction/font-client-impl.h>
+
+using namespace std;
+
+namespace
+{
+
+const float TO_FLOAT = 1.f / 255.f;
+const float TO_UCHAR = 255.f;
+const float TWO_PI = 2.f * Dali::Math::PI; ///< 360 degrees in radians
+
+/**
+ * @brief Run of glyphs that have the same style.
+ */
+struct GlyphRun
+{
+  GlyphRun()
+  : fontFace{ nullptr },
+    fontSize{ 0.0 },
+    glyphIndex{ 0u },
+    numberOfGlyphs{ 0u },
+    fontId{ 0u },
+    colorIndex{ 0u },
+    isItalicRequired{ false },
+    isBoldRequired{ false }
+  {}
+
+  FT_Face      fontFace;           ///< The font face used by the glyphs in the run.
+  double       fontSize;           ///< The font size used by the glyphs in the run. According the Cairo's documentation this is in user space units. It works if I set the size in pixels.
+  unsigned int glyphIndex;         ///< Index to the first glyph of the run.
+  unsigned int numberOfGlyphs;     ///< Number of glyphs in the run.
+  unsigned int fontId;             ///< The id of the font.
+  unsigned int colorIndex;         ///< The index to the color of the glyphs.
+  bool         isItalicRequired:1; ///< Whether the italic style is required.
+  bool         isBoldRequired:1;   ///< Whether the bold style is required.
+};
+
+/**
+ * @brief Helper struct used to destroy a bitmap buffer.
+ *
+ * The font client allocates a bitmap's buffer with the new operator.
+ * However, the PixelBuffer class allocates the buffer with the
+ * malloc() function and the Rotate() function which is intended
+ * for the PixelBuffer as well allocates memory with malloc().
+ *
+ * This struct keeps the type of allocation and uses the delete[]
+ * operator or the free() function to deallocate resources.
+ */
+struct GlyphBuffer
+{
+  enum DestructorType
+  {
+    FREE,
+    DELETE
+  };
+
+  GlyphBuffer( Dali::TextAbstraction::FontClient::GlyphBufferData& data, DestructorType type )
+  : data( data ),
+    type( type )
+  {
+  }
+
+  ~GlyphBuffer()
+  {
+    switch( type )
+    {
+      case FREE:
+      {
+        free( data.buffer );
+        break;
+      }
+      case DELETE:
+      {
+        delete[] data.buffer;
+      }
+    }
+  }
+
+  Dali::TextAbstraction::FontClient::GlyphBufferData& data;
+  DestructorType type;
+};
+
+/**
+ * @brief Creates a pixel buffer with all pixels set to transparent.
+ *
+ * @param[in] parameters Contains the width and height of the pixel buffer.
+ *
+ * @return The pixel buffer.
+ */
+Dali::Devel::PixelBuffer CreateVoidPixelBuffer( const Dali::TextAbstraction::TextRenderer::Parameters& parameters )
+{
+  Dali::Pixel::Format pixelFormat = parameters.pixelFormat == Dali::TextAbstraction::TextRenderer::Parameters::A8 ? Dali::Pixel::A8 : Dali::Pixel::RGBA8888;
+  Dali::Devel::PixelBuffer pixelBuffer = Dali::Devel::PixelBuffer::New( parameters.width,
+                                                                        parameters.height,
+                                                                        pixelFormat );
+
+  const unsigned int bufferSize = parameters.width * parameters.height * Dali::Pixel::GetBytesPerPixel( pixelFormat );
+  unsigned char* buffer = pixelBuffer.GetBuffer();
+  memset( buffer, 0, bufferSize );
+
+  return pixelBuffer;
+}
+
+/**
+ * @brief Wraps the vertices of glyphs laid out on a horizontal strainght line on a circular path.
+ *
+ * It copies the vertices from the extra cairo context created to lay out the text
+ * on a horizontal straight line to the cairo context used to render it.
+ *
+ * @param[in,out] cr The cairo context used to render the text.
+ * @param[in] circularCr The extra cairo context created to layout horizontal text.
+ * @param[in] parameters The parameters of the circular path.
+ */
+void WrapToCircularPath( cairo_t* cr, cairo_t* circularCr, const Dali::TextAbstraction::CircularTextParameters& parameters )
+{
+  bool first = true;
+
+  // Copy the path to get a cairo_path_t pointer used to iterate through all its items.
+  std::unique_ptr<cairo_path_t, void(*)(cairo_path_t*)> path( cairo_copy_path( circularCr ), cairo_path_destroy );
+
+  // Iterates through all the path items and transform each vertex to follow the circle.
+  // Transformed vertices are added to a new path in the 'cr' context (the one used to render the circular text)
+  for( int i = 0; i < path->num_data; i += path->data[i].header.length )
+  {
+    cairo_path_data_t* data = &path->data[i];
+
+    switch( data->header.type )
+    {
+      case CAIRO_PATH_MOVE_TO:
+      {
+        if( first )
+        {
+          cairo_new_path( cr );
+        }
+
+        first = false;
+        double x = data[1].point.x;
+        double y = data[1].point.y;
+        Dali::TextAbstraction::TransformToArc( parameters, x, y );
+        cairo_move_to( cr, x, y );
+        break;
+      }
+      case CAIRO_PATH_LINE_TO:
+      {
+        double x = data[1].point.x;
+        double y = data[1].point.y;
+        Dali::TextAbstraction::TransformToArc( parameters, x, y );
+        cairo_line_to( cr, x, y );
+        break;
+      }
+      case CAIRO_PATH_CURVE_TO:
+      {
+        double x1 = data[1].point.x;
+        double y1 = data[1].point.y;
+        double x2 = data[2].point.x;
+        double y2 = data[2].point.y;
+        double x3 = data[3].point.x;
+        double y3 = data[3].point.y;
+        Dali::TextAbstraction::TransformToArc( parameters, x1, y1 );
+        Dali::TextAbstraction::TransformToArc( parameters, x2, y2 );
+        Dali::TextAbstraction::TransformToArc( parameters, x3, y3 );
+        cairo_curve_to( cr, x1, y1, x2, y2, x3, y3 );
+        break;
+      }
+      case CAIRO_PATH_CLOSE_PATH:
+      {
+        cairo_close_path( cr );
+        break;
+      }
+      default:
+      {
+        DALI_LOG_WARNING( "Type of path not handled.\n" );
+        // Nothing else to do.
+        break;
+      }
+    }
+  }
+}
+
+} // namespace
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+Devel::PixelBuffer RenderTextCairo( const TextAbstraction::TextRenderer::Parameters& parameters )
+{
+  const unsigned int numberOfGlyphs = parameters.glyphs.Count();
+
+  if( 0u == numberOfGlyphs )
+  {
+    // return a pixel buffer with all pixels set to transparent.
+    return CreateVoidPixelBuffer( parameters );
+  }
+
+  // Choose the pixel format to be used.
+  //
+  // @note Behdad wrote "Upper 8 bits maps to the fourth byte in a little-endian machine like the intels."
+  //       https://lists.cairographics.org/archives/cairo/2006-March/006563.html
+  //
+  //       Here in practice Cairo's ARGB32 is like DALi's RGBA8888.
+  //
+  const bool isDstRgba = TextAbstraction::TextRenderer::Parameters::RGBA8888 == parameters.pixelFormat;
+  const Pixel::Format pixelFormat = isDstRgba ? Pixel::Format::RGBA8888 : Pixel::Format::A8;
+  const cairo_format_t cairoFormat = isDstRgba ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_A8;
+
+  const int bpp = Pixel::GetBytesPerPixel( pixelFormat );
+  if( 0u == bpp )
+  {
+    // return a pixel buffer with all pixels set to transparent.
+    return CreateVoidPixelBuffer( parameters );
+  }
+
+  // This function provides a stride value that will respect all alignment requirements of the
+  // accelerated image-rendering code within cairo.
+  const int stride = cairo_format_stride_for_width( cairoFormat,
+                                                    static_cast<int>( parameters.width ) );
+  const int strideWidth = stride / bpp;
+
+  // Convert from DALi glyphs to Cairo glyphs.
+  std::vector<cairo_glyph_t> cairoGlyphs;
+  cairoGlyphs.resize( numberOfGlyphs );
+  cairo_glyph_t* cairoGlyphsBuffer = &cairoGlyphs[0u];
+
+  const GlyphInfo* const daliGlyphsBuffer = parameters.glyphs.Begin();
+  const Vector2* const positionsBuffer = parameters.positions.Begin();
+  const ColorIndex* const colorIndicesBuffer = ( 0u == parameters.colorIndices.Count() ) ? nullptr : parameters.colorIndices.Begin();
+
+  for( unsigned index = 0u; index < numberOfGlyphs; ++index )
+  {
+    const GlyphInfo& daliGlyph = *( daliGlyphsBuffer + index );
+    const Vector2& position = *( positionsBuffer + index );
+    cairo_glyph_t& cairoGlyph = *( cairoGlyphsBuffer + index );
+
+    cairoGlyph.index = daliGlyph.index;
+    cairoGlyph.x = round( position.x );
+    cairoGlyph.y = round( position.y );
+  }
+
+  // Retrieve the FreeType fonts needed by Cairo from the font-client.
+  Dali::TextAbstraction::FontClient fontClient = Dali::TextAbstraction::FontClient::Get();
+
+  FT_Library ftLibrary;
+  auto error = FT_Init_FreeType( &ftLibrary );
+  if( error )
+  {
+    DALI_LOG_ERROR( "Error initializing FT library\n" );
+
+    // return a pixel buffer with all pixels set to transparent.
+    return CreateVoidPixelBuffer( parameters );
+  }
+
+  // Vector used to store the FreeType font faces, its size and the run of glyphs that use the font.
+  std::vector<GlyphRun> glyphRuns;
+  glyphRuns.reserve( 8u );
+
+  // The size set in Cairo and FreeType has different units.
+  // Before the size is set in Cairo it needs to be converted according the formula
+  // 'pixel_size = point_size * resolution / 72' got from the FreeType doc.
+  // https://www.freetype.org/freetype2/docs/glyphs/glyphs-2.html
+
+  unsigned int horizontalDpi = 0u;
+  unsigned int verticalDpi = 0u;
+  fontClient.GetDpi( horizontalDpi, verticalDpi );
+  const double dVerticalDpi = static_cast<double>( verticalDpi );
+
+  const double FROM_26_DOT_6_TO_PIXELS = dVerticalDpi / ( 64.0 * 72.0 );
+
+  GlyphRun currentGlyphRun;
+  currentGlyphRun.fontId = 0u;
+  currentGlyphRun.colorIndex = 0u;
+  currentGlyphRun.isItalicRequired = false;
+  currentGlyphRun.isBoldRequired = false;
+  for( unsigned index = 0u; index < numberOfGlyphs; ++index )
+  {
+    const GlyphInfo& daliGlyph = *( daliGlyphsBuffer + index );
+    const FontId fontId = daliGlyph.fontId;
+    const ColorIndex colorIndex = ( nullptr == colorIndicesBuffer ) ? 0u : *( colorIndicesBuffer + index );
+    const bool isItalicRequired = daliGlyph.isItalicRequired;
+    const bool isBoldRequired = daliGlyph.isBoldRequired;
+
+    if( ( fontId != currentGlyphRun.fontId ) ||
+        ( ( 0u == fontId ) && ( 0u != daliGlyph.index ) ) ||
+        ( colorIndex != currentGlyphRun.colorIndex ) ||
+        ( isItalicRequired != currentGlyphRun.isItalicRequired ) ||
+        ( isBoldRequired != currentGlyphRun.isBoldRequired ) )
+    {
+      // There is a new run. First set the number of glyphs of the previous run and store it.
+      currentGlyphRun.numberOfGlyphs = index - currentGlyphRun.glyphIndex;
+      if( 0u != currentGlyphRun.numberOfGlyphs )
+      {
+        glyphRuns.push_back( currentGlyphRun );
+      }
+
+      currentGlyphRun.fontFace = nullptr;
+      currentGlyphRun.fontSize = 0.0;
+      currentGlyphRun.glyphIndex = index;
+      currentGlyphRun.numberOfGlyphs = 0u;
+      currentGlyphRun.fontId = 0u;
+      currentGlyphRun.colorIndex = 0u;
+      currentGlyphRun.isItalicRequired = false;
+      currentGlyphRun.isBoldRequired = false;
+
+      if( 0u != fontId )
+      {
+        // Get the font's path file name from the font Id.
+        FontDescription fontDescription;
+        fontClient.GetDescription( fontId, fontDescription );
+
+        switch( fontDescription.type )
+        {
+          case FontDescription::FACE_FONT:
+          {
+            // Create a FreeType font's face.
+            auto error = FT_New_Face( ftLibrary, fontDescription.path.c_str(), 0u, &currentGlyphRun.fontFace );
+            if( error )
+            {
+              DALI_LOG_ERROR( "Error in FT while creating a new face\n" );
+
+              // return a pixel buffer with all pixels set to transparent.
+              return CreateVoidPixelBuffer( parameters );
+            }
+
+            // Set the font's size. It needs to be set in the Freetype font and in the Cairo's context.
+            unsigned int fontSize = fontClient.GetPointSize( fontId );
+
+            // Font's size to be set in the Cairo's context.
+            currentGlyphRun.fontSize = FROM_26_DOT_6_TO_PIXELS * static_cast<double>( fontSize );
+            break;
+          }
+          case FontDescription::BITMAP_FONT:
+          {
+            //Nothing to do.
+            break;
+          }
+          default:
+          {
+            //Nothing to do.
+            break;
+          }
+        }
+      }
+      currentGlyphRun.fontId = fontId;
+      currentGlyphRun.colorIndex = colorIndex;
+      currentGlyphRun.isItalicRequired = isItalicRequired;
+      currentGlyphRun.isBoldRequired = isBoldRequired;
+    }
+  }
+
+  // Calculate the number of glyphs of the last run and store it.
+  currentGlyphRun.numberOfGlyphs = numberOfGlyphs - currentGlyphRun.glyphIndex;
+  if( 0u != currentGlyphRun.numberOfGlyphs )
+  {
+    glyphRuns.push_back( currentGlyphRun );
+  }
+
+  // Creates the pixel buffer and retrieves the buffer pointer used to create the Cairo's surface.
+  Devel::PixelBuffer pixelBuffer = Devel::PixelBuffer::New( strideWidth, parameters.height, pixelFormat );
+
+  unsigned char* buffer = pixelBuffer.GetBuffer();
+  const unsigned int bufferSize = stride * parameters.height;
+  memset( buffer, 0, bufferSize );
+
+  std::unique_ptr<cairo_surface_t, void(*)(cairo_surface_t*)> surfacePtr( cairo_image_surface_create_for_data( buffer,
+                                                                                                               cairoFormat,
+                                                                                                               parameters.width,
+                                                                                                               parameters.height,
+                                                                                                               stride ),
+                                                                          cairo_surface_destroy );
+  cairo_surface_t* surface = surfacePtr.get();
+
+  if( ( nullptr == surface ) || ( CAIRO_STATUS_SUCCESS != cairo_surface_status( surface ) ) )
+  {
+    DALI_LOG_ERROR( "Failed to create a cairo's surface\n" );
+
+    return CreateVoidPixelBuffer( parameters );
+  }
+
+  // Whether the text is circular.
+  const bool isCircularText = 0u != parameters.radius;
+
+  // Creates a surface for circular text.
+  //
+  // The reason to create a surface for circular text is that the strategy
+  // followed is to layout the text in a straight horizontal line and apply a
+  // transform to each vertex that forms the geometry of the glyphs to place
+  // and bend the glyphs accordingly to the circular path.
+  //
+  // As the glyphs are laid out first in a straight line they may exceed the
+  // boundaries of the surface in that case cairo ignores them.
+  std::unique_ptr<cairo_surface_t, void(*)(cairo_surface_t*)> circularSurfacePtr( nullptr, cairo_surface_destroy );
+  cairo_surface_t* circularSurface = nullptr;
+  if( isCircularText )
+  {
+    circularSurfacePtr.reset( cairo_surface_create_similar( surface,
+                                                            CAIRO_CONTENT_ALPHA,
+                                                            parameters.circularWidth,
+                                                            parameters.circularHeight ) );
+    circularSurface = circularSurfacePtr.get();
+
+    if( ( nullptr == circularSurface ) || ( CAIRO_STATUS_SUCCESS != cairo_surface_status( circularSurface ) ) )
+    {
+      DALI_LOG_ERROR( "Failed to create a cairo's circular surface\n" );
+
+      return CreateVoidPixelBuffer( parameters );
+    }
+  }
+
+  std::unique_ptr<cairo_t, void(*)(cairo_t*)> crPtr( cairo_create( surface ), cairo_destroy );
+  cairo_t* cr = crPtr.get();
+
+  if( CAIRO_STATUS_SUCCESS != cairo_status( cr ) )
+  {
+    DALI_LOG_ERROR( "Failed to create a cairo context\n" );
+
+    return CreateVoidPixelBuffer( parameters );
+  }
+
+  std::unique_ptr<cairo_t, void(*)(cairo_t*)> circularCrPtr( nullptr, cairo_destroy );
+  cairo_t* circularCr = nullptr;
+
+  if( isCircularText )
+  {
+    circularCrPtr.reset( cairo_create( circularSurface ) );
+    circularCr = circularCrPtr.get();
+
+    if( CAIRO_STATUS_SUCCESS != cairo_status( circularCr ) )
+    {
+      DALI_LOG_ERROR( "Failed to create a cairo context\n" );
+
+      return CreateVoidPixelBuffer( parameters );
+    }
+  }
+
+  CircularTextParameters circularTextParameters;
+
+  // Render the glyphs.
+  if( isCircularText )
+  {
+    // Set the parameters.
+    circularTextParameters.isClockwise = ( TextAbstraction::TextRenderer::Parameters::CLOCKWISE == parameters.circularLayout );
+
+    circularTextParameters.centerX = static_cast<double>( parameters.centerX );
+    circularTextParameters.centerY = static_cast<double>( parameters.centerY );
+    circularTextParameters.radius = static_cast<double>( parameters.radius );
+    circularTextParameters.invRadius = 1.0 / circularTextParameters.radius;
+    circularTextParameters.beginAngle = -parameters.beginAngle + Dali::Math::PI_2;
+  }
+
+  cairo_move_to( cr, 0.0, 0.0 );
+
+  for( const auto& run: glyphRuns )
+  {
+    const bool isEmoji = parameters.isEmoji[run.glyphIndex];
+    if( isEmoji || ( nullptr == run.fontFace ) )
+    {
+      // Retrieve the color for the glyph.
+      const Vector4& color = parameters.colors[run.colorIndex];
+
+      const unsigned int lastGlyphIndex = run.glyphIndex + run.numberOfGlyphs;
+      for( unsigned int index = run.glyphIndex; index < lastGlyphIndex; ++index )
+      {
+        // Whether it's a bitmap font.
+        const bool doBlendWithTextColor = !isEmoji && ( ColorBlendingMode::MULTIPLY == parameters.blendingMode[index] );
+
+        // Check if there is an embedded image or a bitmap font image.
+        const GlyphIndex glyphFontIndex = daliGlyphsBuffer[index].index;
+        if( 0u != glyphFontIndex )
+        {
+          // The embedded image could be A8, RGBA8888 or BGRA8888.
+          //
+          // If the embedded image is RGBA8888 or BGRA8888 then the cairo's buffer is ARGB32. It's needed to convert from RGBA or BGRA to ARGB.
+          // If the embedded image is A8 it's needed to check if the cairo's buffer is A8 or ARGB32 and do the conversion if needed.
+
+          const cairo_glyph_t& glyph = *( cairoGlyphsBuffer + index );
+
+          // Retrieve the image
+          TextAbstraction::FontClient::GlyphBufferData data;
+          std::unique_ptr<GlyphBuffer> glyphBufferPtr( new GlyphBuffer( data, GlyphBuffer::DELETE ) );
+          if( isEmoji )
+          {
+            data.width = parameters.glyphs[run.glyphIndex].width;
+            data.height = parameters.glyphs[run.glyphIndex].height;
+          }
+
+          fontClient.CreateBitmap( run.fontId, glyphFontIndex, false, false, data, 0u );
+
+          if( nullptr == data.buffer )
+          {
+            // nothing else to do if there is no image.
+            continue;
+          }
+
+          // Calculate the position for the circular text.
+          double glyphX = glyph.x;
+          double glyphY = glyph.y;
+
+          if( isCircularText )
+          {
+            // Center of the bitmap.
+            const double halfWidth = 0.5 * static_cast<double>( data.width );
+            const double halfHeight = 0.5 * static_cast<double>( data.height );
+
+            double centerX = glyph.x + halfWidth;
+            double centerY = glyph.y - halfHeight;
+
+            float radians = circularTextParameters.beginAngle + ( circularTextParameters.isClockwise ? -1.f : 1.f ) * ( Dali::Math::PI_2 + circularTextParameters.invRadius * centerX );
+            radians = fmod( radians, TWO_PI );
+            radians += ( radians < 0.f ) ? TWO_PI : 0.f;
+
+            TransformToArc( circularTextParameters, centerX, centerY );
+
+            uint8_t* pixelsOut = nullptr;
+            unsigned int widthOut = data.width;
+            unsigned int heightOut = data.height;
+            const unsigned int pixelSize = Pixel::GetBytesPerPixel( data.format );
+
+            Dali::Internal::Platform::RotateByShear( data.buffer,
+                                                     data.width,
+                                                     data.height,
+                                                     pixelSize,
+                                                     radians,
+                                                     pixelsOut,
+                                                     widthOut,
+                                                     heightOut );
+            if( nullptr != pixelsOut )
+            {
+              delete[] data.buffer;
+              data.buffer = pixelsOut;
+              glyphBufferPtr.get()->type = GlyphBuffer::FREE;
+              data.width = widthOut;
+              data.height = heightOut;
+            }
+
+            glyphX = centerX - 0.5 * static_cast<double>( data.width );
+            glyphY = centerY + 0.5 * static_cast<double>( data.height );
+          }
+
+
+          if( ( Pixel::A8 != data.format ) &&
+              ( Pixel::L8 != data.format ) &&
+              ( Pixel::RGBA8888 != data.format ) &&
+              ( Pixel::BGRA8888 != data.format ) )
+          {
+            DALI_LOG_ERROR( " Cairo Renderer: The valid pixel format for embedded items are A8 or RGBA8888\n" );
+            continue;
+          }
+
+          // Check if the item is out of the buffer.
+          if( ( glyphX + static_cast<float>( data.width ) < 0.f ) ||
+              ( glyphX > static_cast<float>( strideWidth ) ) ||
+              ( glyphY < 0.f ) ||
+              ( glyphY - static_cast<float>( data.height ) > static_cast<float>( parameters.height ) ) )
+          {
+            // The embedded item is completely out of the buffer.
+            continue;
+          }
+
+          const bool isSrcA = ( Pixel::A8 == data.format ) || ( Pixel::L8 == data.format );
+          const bool isSrcRgba = Pixel::RGBA8888 == data.format;
+          const bool isSrcBgra = Pixel::BGRA8888 == data.format;
+
+          // 0 -> image and cairo buffer are A8
+          // 1 -> image is A8, cairo buffer is ARGB
+          // 2 -> image is RGBA and cairo buffer is ARGB
+          // 3 -> image is BGRA and cairo buffer is ARGB
+          int rgbaCase = 0;
+          if( isSrcA && isDstRgba )
+          {
+            rgbaCase = 1;
+          }
+          else if( isSrcRgba && isDstRgba )
+          {
+            rgbaCase = 2;
+          }
+          else if( isSrcBgra && isDstRgba )
+          {
+            rgbaCase = 3;
+          }
+          else if( ( isSrcRgba || isSrcBgra ) && !isDstRgba )
+          {
+            DALI_LOG_ERROR( "Cairo Renderer: The embedded image is RGBA or BGRA and the Cairo's buffer has been creates with A8 format!\n" );
+            continue;
+          }
+
+          // Select the cropped source image area to copy into the surface buffer
+          unsigned int glyphUintX = 0u;
+          unsigned int glyphUintY = 0u;
+          unsigned int srcWidth = data.width;
+          unsigned int srcHeight = data.height;
+          unsigned int xSrcIndex = 0u;
+          unsigned int ySrcIndex = 0u;
+          if( glyphX < 0.f )
+          {
+            xSrcIndex = static_cast<unsigned int>( abs( glyphX ) );
+            srcWidth -= xSrcIndex;
+          }
+          else
+          {
+            glyphUintX = static_cast<unsigned int>( glyphX );
+          }
+
+          if( glyphUintX + srcWidth > static_cast<unsigned int>( strideWidth ) )
+          {
+            srcWidth -= ( ( glyphUintX + srcWidth ) - strideWidth );
+          }
+
+          if( glyphY - static_cast<float>( srcHeight ) < 0.f )
+          {
+            ySrcIndex = static_cast<unsigned int>( abs( glyphY - static_cast<float>( srcHeight ) ) );
+            srcHeight -= ySrcIndex;
+          }
+          else
+          {
+            glyphUintY = static_cast<unsigned int>( glyphY - static_cast<float>( srcHeight ) );
+          }
+
+          if( glyphUintY + srcHeight > parameters.height )
+          {
+            srcHeight -= ( ( glyphUintY + srcHeight ) - parameters.height );
+          }
+
+          // Calculate the source and destination indices.
+          const unsigned int srcPixelSize = Pixel::GetBytesPerPixel( data.format );
+          const unsigned int dstPixelSize = Pixel::GetBytesPerPixel( pixelFormat );
+
+          unsigned int srcIndex = srcPixelSize * ( ySrcIndex * srcWidth + xSrcIndex );
+          unsigned int dstIndex = dstPixelSize * ( glyphUintY * strideWidth + glyphUintX );
+
+          const unsigned int srcWidthOffset = srcPixelSize * ( data.width - srcWidth );
+          const unsigned int dstWidthOffset = dstPixelSize * ( strideWidth - srcWidth );
+
+          // Copy the image to the surface
+          for( unsigned int j = 0; j < srcHeight; ++j )
+          {
+            for( unsigned int i = 0; i < srcWidth; ++i )
+            {
+              switch( rgbaCase )
+              {
+                case 0: // Both the image's buffer and cairo's buffer are A8
+                {
+                  const unsigned char alpha = *( data.buffer + srcIndex );
+                  if( alpha != 0u )
+                  {
+                    // @todo needs a proper blending!
+                    *( buffer + dstIndex ) = alpha;
+                  }
+                  break;
+                }
+                case 1: // The image's buffer is A8 and the cairo's buffer is ARGB
+                {
+                  const unsigned char alpha = *( data.buffer + srcIndex );
+                  if( alpha != 0u )
+                  {
+                    // @todo needs a proper blending!
+                    const float srcAlpha = TO_FLOAT * static_cast<float>( alpha );
+
+                    // Write the RGBA modulated with the given default color.
+                    const float* const colorPtr = color.AsFloat();
+                    *( buffer + dstIndex + 0u ) = static_cast<unsigned char>( TO_UCHAR * colorPtr[0u] * srcAlpha );
+                    *( buffer + dstIndex + 1u ) = static_cast<unsigned char>( TO_UCHAR * colorPtr[1u] * srcAlpha );
+                    *( buffer + dstIndex + 2u ) = static_cast<unsigned char>( TO_UCHAR * colorPtr[2u] * srcAlpha );
+                    *( buffer + dstIndex + 3u ) = static_cast<unsigned char>( TO_UCHAR * colorPtr[3u] * srcAlpha );
+                  }
+                  break;
+                }
+                case 2: // The image's buffer is RGBA and the cairo's buffer is ARGB
+                {
+                  const unsigned char alpha = *(data.buffer + srcIndex + 3u);
+                  if( alpha != 0u )
+                  {
+                    if( doBlendWithTextColor )
+                    {
+                      const float* const colorPtr = color.AsFloat();
+
+                      const float srcAlpha = TO_FLOAT * static_cast<float>(alpha) * colorPtr[3u];
+
+                      *(buffer + dstIndex + 0u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 0u) ) * colorPtr[0u] );
+                      *(buffer + dstIndex + 1u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 1u) ) * colorPtr[1u] );
+                      *(buffer + dstIndex + 2u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 2u) ) * colorPtr[2u] );
+
+                      // Write the alpha.
+                      *(buffer + dstIndex + 3u) = static_cast<unsigned char>( TO_UCHAR * srcAlpha );
+                    }
+                    else
+                    {
+                      // @todo needs a proper blending!
+                      // Write the RGB
+                      *(buffer + dstIndex + 0u) = *(data.buffer + srcIndex + 0u);
+                      *(buffer + dstIndex + 1u) = *(data.buffer + srcIndex + 1u);
+                      *(buffer + dstIndex + 2u) = *(data.buffer + srcIndex + 2u);
+
+                      // Write the alpha.
+                      *(buffer + dstIndex + 3u) = *(data.buffer + srcIndex + 3u);
+                    }
+                  }
+                  break;
+                }
+                case 3: // The image's buffer is BGRA and the cairo's buffer is ARGB
+                {
+                  const unsigned char alpha = *(data.buffer + srcIndex + 3u);
+                  if( alpha != 0u )
+                  {
+                    if( doBlendWithTextColor )
+                    {
+                      const float* const colorPtr = color.AsFloat();
+
+                      const float srcAlpha = TO_FLOAT * static_cast<float>(alpha) * colorPtr[3u];
+
+                      *(buffer + dstIndex + 0u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 2u) ) * colorPtr[0u] );
+                      *(buffer + dstIndex + 1u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 1u) ) * colorPtr[1u] );
+                      *(buffer + dstIndex + 2u) = static_cast<unsigned char>( static_cast<float>( *(data.buffer + srcIndex + 0u) ) * colorPtr[2u] );
+
+                      // Write the alpha.
+                      *(buffer + dstIndex + 3u) = static_cast<unsigned char>( TO_UCHAR * srcAlpha );
+                    }
+                    else
+                    {
+                      // @todo needs a proper blending!
+                      // Write the RGBA
+                      *(buffer + dstIndex + 0u) = *(data.buffer + srcIndex + 2u);
+                      *(buffer + dstIndex + 1u) = *(data.buffer + srcIndex + 1u);
+                      *(buffer + dstIndex + 2u) = *(data.buffer + srcIndex + 0u);
+                      *(buffer + dstIndex + 3u) = *(data.buffer + srcIndex + 3u);
+                    }
+                  }
+                  break;
+                }
+                default:
+                {
+                  DALI_ASSERT_ALWAYS( !"Cairo Renderer: The accepted values for this switch case are: 0, 1, 2!" );
+                }
+              } // switch
+              srcIndex += srcPixelSize;
+              dstIndex += dstPixelSize;
+            } // for width
+            srcIndex += srcWidthOffset;
+            dstIndex += dstWidthOffset;
+          } // for height
+        }
+      }
+    }
+    else
+    {
+      // Sets the color. The color is actually BGRA
+      const Vector4& color = parameters.colors[run.colorIndex];
+
+      cairo_set_source_rgba( cr,
+                             static_cast<double>( color.b ),
+                             static_cast<double>( color.g ),
+                             static_cast<double>( color.r ),
+                             static_cast<double>( color.a ) );
+
+      // Create the Cairo's font from the FreeType font.
+      int options = 0;
+      options = CAIRO_HINT_STYLE_SLIGHT;
+      std::unique_ptr<cairo_font_face_t, void(*)(cairo_font_face_t*)> fontFacePtr( cairo_ft_font_face_create_for_ft_face( run.fontFace, options ), cairo_font_face_destroy );
+      cairo_font_face_t* fontFace = fontFacePtr.get();
+
+      static const cairo_user_data_key_t key = { 0 };
+      cairo_status_t status = cairo_font_face_set_user_data( fontFace, &key, run.fontFace, reinterpret_cast<cairo_destroy_func_t>( FT_Done_Face ) );
+      if( status )
+      {
+        cairo_font_face_destroy( fontFace );
+      }
+
+      unsigned int ftSynthesizeFlag = 0u;
+      if( run.isBoldRequired && !( run.fontFace->style_flags & FT_STYLE_FLAG_BOLD ) )
+      {
+        ftSynthesizeFlag |= CAIRO_FT_SYNTHESIZE_BOLD;
+      }
+
+      cairo_ft_font_face_set_synthesize( fontFace, ftSynthesizeFlag );
+
+      cairo_font_face_reference( fontFace );
+
+      const bool synthesizeItalic = ( run.isItalicRequired && !( run.fontFace->style_flags & FT_STYLE_FLAG_ITALIC ) );
+
+      if( CAIRO_STATUS_SUCCESS != cairo_font_face_status( fontFace ) )
+      {
+        DALI_LOG_ERROR( "Failed to load the Freetype Font\n" );
+      }
+
+      // Sets the font.
+      cairo_set_font_face( isCircularText ? circularCr : cr, fontFace );
+
+      // Sets the size
+      cairo_set_font_size( isCircularText ? circularCr : cr, run.fontSize );
+
+      // Render the glyphs.
+      if( isCircularText )
+      {
+        circularTextParameters.synthesizeItalic = synthesizeItalic;
+
+        const unsigned int glyphJump = circularTextParameters.synthesizeItalic ? 1u : run.numberOfGlyphs;
+
+        for( unsigned int index = 0u; index < run.numberOfGlyphs; index += glyphJump )
+        {
+          // Clears the current path where the text is laid out on a horizontal straight line.
+          cairo_new_path( circularCr );
+          cairo_move_to( circularCr, 0.0, 0.0 );
+
+          cairo_glyph_path( circularCr, ( cairoGlyphsBuffer + run.glyphIndex + index ), glyphJump );
+
+          WrapToCircularPath( cr, circularCr, circularTextParameters );
+          cairo_fill( cr );
+        }
+      }
+      else
+      {
+        if( synthesizeItalic )
+        {
+          // Apply a shear transform to synthesize the italics.
+          // For a reason Cairo may trim some glyphs if the CAIRO_FT_SYNTHESIZE_OBLIQUE flag is used.
+
+          // This is to calculate an offset used to compensate the 'translation' done by the shear transform
+          // as it's done for the whole render buffer.
+          double maxY = 0.0;
+          for( unsigned int index = run.glyphIndex, endIndex = run.glyphIndex + run.numberOfGlyphs; index < endIndex; ++index )
+          {
+            maxY = std::max( maxY, (*( cairoGlyphsBuffer + index )).y );
+          }
+
+          cairo_matrix_t matrix;
+          cairo_matrix_init( &matrix,
+                                                                                  1.0, 0.0,
+                                   -TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE, 1.0,
+                             maxY * TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE, 0.0 );
+
+          cairo_transform( cr, &matrix );
+        }
+
+        cairo_show_glyphs( cr, ( cairoGlyphsBuffer + run.glyphIndex ), run.numberOfGlyphs );
+
+        if( synthesizeItalic )
+        {
+          // Restore the transform matrix to the identity.
+          cairo_matrix_t matrix;
+          cairo_matrix_init_identity( &matrix );
+          cairo_set_matrix( cr, &matrix );
+        }
+
+        cairo_fill( cr );
+      }
+    }
+  }
+
+  return pixelBuffer;
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/internal/text/text-abstraction/cairo-renderer.h b/dali/internal/text/text-abstraction/cairo-renderer.h
new file mode 100755 (executable)
index 0000000..4b6595f
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef DALI_INTERNAL_TEXT_ABSTRACTION_CAIRO_RENDERER_H
+#define DALI_INTERNAL_TEXT_ABSTRACTION_CAIRO_RENDERER_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/text-abstraction/text-renderer.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+/**
+ * @brief Cairo implementation of the Dali::TextAbstraction::TextRenderer interface.
+ *
+ * @see Dali::TextAbstraction::TextRenderer.
+ */
+Devel::PixelBuffer RenderTextCairo( const TextAbstraction::TextRenderer::Parameters& parameters );
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TEXT_ABSTRACTION_CAIRO_RENDERER_H
+
diff --git a/dali/internal/text/text-abstraction/font-client-helper.cpp b/dali/internal/text/text-abstraction/font-client-helper.cpp
new file mode 100644 (file)
index 0000000..c6dec8d
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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 <dali/internal/text/text-abstraction/font-client-helper.h>
+
+// INTERNAL INCLUDES
+
+#include <dali/integration-api/debug.h>
+
+namespace
+{
+#if defined(DEBUG_ENABLED)
+Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT_VALUE_TO_INDEX");
+#endif
+}
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+int ValueToIndex( int value, const int* const table, unsigned int maxIndex )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "-->FontClient::Plugin::ValueToIndex value(%d)\n", value);
+
+  if( NULL == table )
+  {
+    // Return an invalid index if there is no table.
+    return -1;
+  }
+
+  if( value <= table[0] )
+  {
+    return 0;
+  }
+
+  if( value >= table[maxIndex] )
+  {
+    return maxIndex;
+  }
+
+  for( unsigned int index = 0u; index < maxIndex; ++index )
+  {
+    const int v1 = table[index];
+    const unsigned int indexPlus = index + 1u;
+    const int v2 = table[indexPlus];
+    if( ( v1 < value ) && ( value <= v2 ) )
+    {
+      const int result = ( ( v1 > 0 ) && ( ( value - v1 ) < ( v2 - value ) ) ) ? index : indexPlus;
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValueToIndex result(%d)\n",  result );
+      return result;
+    }
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FontClient::Plugin::ValueToIndex exit 0 <-- \n");
+
+  return 0;
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/internal/text/text-abstraction/font-client-helper.h b/dali/internal/text/text-abstraction/font-client-helper.h
new file mode 100644 (file)
index 0000000..91071f7
--- /dev/null
@@ -0,0 +1,47 @@
+#ifndef DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_HELPER_H
+#define DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_HELPER_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.
+ *
+ */
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * @brief Retrieves a table index for a given value.
+ *
+ * @param[in] value The value.
+ * @param[in] table The table.
+ * @param[in] maxIndex The maximum valid index of the table.
+ *
+ * @return The index to the closest available value
+ */
+int ValueToIndex( int value, const int* const table, unsigned int maxIndex );
+
+} // Internal
+
+} // TextAbstraction
+
+} // Dali
+
+#endif // DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_HELPER_H
diff --git a/dali/internal/text/text-abstraction/font-client-impl.cpp b/dali/internal/text/text-abstraction/font-client-impl.cpp
new file mode 100755 (executable)
index 0000000..4e82a54
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/text/text-abstraction/font-client-impl.h>
+
+// EXTERNAL INCLUDES
+#if !(defined(DALI_PROFILE_UBUNTU) || defined(ANDROID) || defined(WIN32))
+#include <vconf.h>
+#endif
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/common/singleton-service.h>
+#include <dali/internal/text/text-abstraction/font-client-plugin-impl.h>
+
+#include <dali/devel-api/text-abstraction/glyph-info.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+Dali::TextAbstraction::FontClient FontClient::gPreInitializedFontClient( NULL );
+
+FontClient::FontClient()
+: mPlugin( nullptr ),
+  mDpiHorizontal( 0 ),
+  mDpiVertical( 0 )
+{
+}
+
+FontClient::~FontClient()
+{
+  delete mPlugin;
+}
+
+Dali::TextAbstraction::FontClient FontClient::Get()
+{
+  Dali::TextAbstraction::FontClient fontClientHandle;
+
+  Dali::SingletonService service( SingletonService::Get() );
+  if ( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( Dali::TextAbstraction::FontClient ) );
+    if(handle)
+    {
+      // If so, downcast the handle
+      FontClient* impl = dynamic_cast< Dali::TextAbstraction::Internal::FontClient* >( handle.GetObjectPtr() );
+      fontClientHandle = Dali::TextAbstraction::FontClient( impl );
+    }
+    else // create and register the object
+    {
+      if( gPreInitializedFontClient )
+      {
+        fontClientHandle = gPreInitializedFontClient;
+        gPreInitializedFontClient.Reset(); // No longer needed
+      }
+      else
+      {
+        fontClientHandle = Dali::TextAbstraction::FontClient( new FontClient );
+      }
+
+      service.Register( typeid( fontClientHandle ), fontClientHandle );
+    }
+  }
+
+  return fontClientHandle;
+}
+
+Dali::TextAbstraction::FontClient FontClient::PreInitialize()
+{
+  gPreInitializedFontClient = Dali::TextAbstraction::FontClient( new FontClient );
+
+  // Make DefaultFontDescription cached
+  Dali::TextAbstraction::FontDescription defaultFontDescription;
+  gPreInitializedFontClient.GetDefaultPlatformFontDescription( defaultFontDescription );
+
+  return gPreInitializedFontClient;
+}
+
+void FontClient::ClearCache()
+{
+  if( mPlugin )
+  {
+    mPlugin->ClearCache();
+  }
+}
+
+
+void FontClient::SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi  )
+{
+  mDpiHorizontal = horizontalDpi;
+  mDpiVertical = verticalDpi;
+
+  // Allow DPI to be set without loading plugin
+  if( mPlugin )
+  {
+    mPlugin->SetDpi( horizontalDpi, verticalDpi  );
+  }
+}
+
+void FontClient::GetDpi( unsigned int& horizontalDpi, unsigned int& verticalDpi )
+{
+  horizontalDpi = mDpiHorizontal;
+  verticalDpi = mDpiVertical;
+}
+
+int FontClient::GetDefaultFontSize()
+{
+  int fontSize( -1 );
+
+#if !(defined(DALI_PROFILE_UBUNTU) || defined(ANDROID) || defined(WIN32))
+  vconf_get_int( VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, &fontSize );
+#endif
+
+  return fontSize;
+}
+
+void FontClient::ResetSystemDefaults()
+{
+  CreatePlugin();
+
+  mPlugin->ResetSystemDefaults();
+}
+
+void FontClient::GetDefaultFonts( FontList& defaultFonts )
+{
+  CreatePlugin();
+
+  mPlugin->GetDefaultFonts( defaultFonts );
+}
+
+void FontClient::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
+{
+  CreatePlugin();
+
+  mPlugin->GetDefaultPlatformFontDescription( fontDescription );
+}
+
+void FontClient::GetDescription( FontId id, FontDescription& fontDescription )
+{
+  CreatePlugin();
+
+  mPlugin->GetDescription( id, fontDescription );
+}
+
+PointSize26Dot6 FontClient::GetPointSize( FontId id )
+{
+  CreatePlugin();
+
+  return mPlugin->GetPointSize( id );
+}
+
+bool FontClient::IsCharacterSupportedByFont( FontId fontId, Character character )
+{
+  CreatePlugin();
+
+  return mPlugin->IsCharacterSupportedByFont( fontId, character );
+}
+
+void FontClient::GetSystemFonts( FontList& systemFonts )
+{
+  CreatePlugin();
+
+  mPlugin->GetSystemFonts( systemFonts );
+}
+
+FontId FontClient::FindDefaultFont( Character charcode,
+                                    PointSize26Dot6 requestedPointSize,
+                                    bool preferColor )
+{
+  CreatePlugin();
+
+  return mPlugin->FindDefaultFont( charcode,
+                                   requestedPointSize,
+                                   preferColor );
+}
+
+FontId FontClient::FindFallbackFont( Character charcode,
+                                     const FontDescription& preferredFontDescription,
+                                     PointSize26Dot6 requestedPointSize,
+                                     bool preferColor )
+{
+  CreatePlugin();
+
+  return mPlugin->FindFallbackFont( charcode,
+                                    preferredFontDescription,
+                                    requestedPointSize,
+                                    preferColor );
+}
+
+bool FontClient::IsScalable( const FontPath& path )
+{
+  CreatePlugin();
+
+  return mPlugin->IsScalable( path );
+}
+
+bool FontClient::IsScalable( const FontDescription& fontDescription )
+{
+  CreatePlugin();
+
+  return mPlugin->IsScalable( fontDescription );
+}
+
+void FontClient::GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes )
+{
+  CreatePlugin();
+
+  mPlugin->GetFixedSizes( path, sizes );
+}
+
+void FontClient::GetFixedSizes( const FontDescription& fontDescription,
+                                Dali::Vector< PointSize26Dot6 >& sizes )
+{
+  CreatePlugin();
+
+  mPlugin->GetFixedSizes( fontDescription, sizes );
+}
+
+bool FontClient::HasItalicStyle( FontId fontId ) const
+{
+  if( !mPlugin )
+  {
+    return false;
+  }
+  return mPlugin->HasItalicStyle( fontId );
+}
+
+FontId FontClient::GetFontId( const FontPath& path, PointSize26Dot6 requestedPointSize, FaceIndex faceIndex )
+{
+  CreatePlugin();
+
+  return mPlugin->GetFontId( path,
+                             requestedPointSize,
+                             faceIndex,
+                             true );
+}
+
+FontId FontClient::GetFontId( const FontDescription& fontDescription,
+                              PointSize26Dot6 requestedPointSize,
+                              FaceIndex faceIndex )
+{
+  CreatePlugin();
+
+  return mPlugin->GetFontId( fontDescription,
+                             requestedPointSize,
+                             faceIndex );
+}
+
+FontId FontClient::GetFontId( const BitmapFont& bitmapFont )
+{
+  CreatePlugin();
+
+  return mPlugin->GetFontId( bitmapFont );
+}
+
+void FontClient::GetFontMetrics( FontId fontId, FontMetrics& metrics )
+{
+  CreatePlugin();
+
+  mPlugin->GetFontMetrics( fontId, metrics );
+}
+
+GlyphIndex FontClient::GetGlyphIndex( FontId fontId, Character charcode )
+{
+  CreatePlugin();
+
+  return mPlugin->GetGlyphIndex( fontId, charcode );
+}
+
+bool FontClient::GetGlyphMetrics( GlyphInfo* array, uint32_t size, GlyphType type, bool horizontal )
+{
+  CreatePlugin();
+
+  return mPlugin->GetGlyphMetrics( array, size, type, horizontal );
+}
+
+void FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
+{
+  CreatePlugin();
+
+  mPlugin->CreateBitmap( fontId, glyphIndex, isItalicRequired, isBoldRequired, data, outlineWidth );
+}
+
+PixelData FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
+{
+  CreatePlugin();
+
+  return mPlugin->CreateBitmap( fontId, glyphIndex, outlineWidth );
+}
+
+void FontClient::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
+{
+  CreatePlugin();
+
+  mPlugin->CreateVectorBlob( fontId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
+}
+
+const GlyphInfo& FontClient::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
+{
+  CreatePlugin();
+
+  return mPlugin->GetEllipsisGlyph( requestedPointSize );
+}
+
+bool FontClient::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
+{
+  CreatePlugin();
+
+  return mPlugin->IsColorGlyph( fontId, glyphIndex );
+}
+
+GlyphIndex FontClient::CreateEmbeddedItem(const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat)
+{
+  CreatePlugin();
+
+  return mPlugin->CreateEmbeddedItem( description, pixelFormat );
+}
+
+FT_FaceRec_* FontClient::GetFreetypeFace( FontId fontId )
+{
+  CreatePlugin();
+
+  return mPlugin->GetFreetypeFace( fontId );
+}
+
+FontDescription::Type FontClient::GetFontType( FontId fontId )
+{
+  CreatePlugin();
+
+  return mPlugin->GetFontType( fontId );
+}
+
+bool FontClient::AddCustomFontDirectory( const FontPath& path )
+{
+  CreatePlugin();
+
+  return mPlugin->AddCustomFontDirectory( path );
+}
+
+void FontClient::CreatePlugin()
+{
+  if( !mPlugin )
+  {
+    mPlugin = new Plugin( mDpiHorizontal, mDpiVertical );
+  }
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/internal/text/text-abstraction/font-client-impl.h b/dali/internal/text/text-abstraction/font-client-impl.h
new file mode 100755 (executable)
index 0000000..def0799
--- /dev/null
@@ -0,0 +1,295 @@
+#ifndef DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_IMPL_H
+#define DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_IMPL_H
+
+/*
+ * Copyright (c) 2019 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/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-client.h>
+
+
+struct FT_FaceRec_;
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * Implementation of the FontClient
+ */
+class FontClient : public BaseObject
+{
+public:
+
+  /**
+   * Constructor
+   */
+  FontClient();
+
+  /**
+   * Destructor
+   */
+  ~FontClient();
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::Get()
+   */
+  static Dali::TextAbstraction::FontClient Get();
+
+  /**
+   * @brief This is used to improve application launch performance
+   *
+   * @return A pre-initialized FontClient
+   */
+  static Dali::TextAbstraction::FontClient PreInitialize();
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::ClearCache()
+   */
+  void ClearCache();
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::SetDpi()
+   */
+  void SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetDpi()
+   */
+  void GetDpi( unsigned int& horizontalDpi, unsigned int& verticalDpi );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetDefaultFontSize()
+   */
+  int GetDefaultFontSize();
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::ResetSystemDefaults()
+   */
+  void ResetSystemDefaults();
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetDefaultFonts()
+   */
+  void GetDefaultFonts( FontList& defaultFonts );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetDefaultPlatformFontDescription()
+   */
+  void GetDefaultPlatformFontDescription( FontDescription& fontDescription );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetSystemFonts()
+   */
+  void GetSystemFonts( FontList& systemFonts );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetDescription()
+   */
+  void GetDescription( FontId id, FontDescription& fontDescription );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetPointSize()
+   */
+  PointSize26Dot6 GetPointSize( FontId id );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::IsCharacterSupportedByFont()
+   */
+  bool IsCharacterSupportedByFont( FontId fontId, Character character );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::FindDefaultFont()
+   */
+  FontId FindDefaultFont( Character charcode,
+                          PointSize26Dot6 requestedPointSize,
+                          bool preferColor );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::FindFallbackFont()
+   */
+  FontId FindFallbackFont( Character charcode,
+                           const FontDescription& preferredFontDescription,
+                           PointSize26Dot6 requestedPointSize,
+                           bool preferColor );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetFontId( const FontPath& path, PointSize26Dot6 requestedPointSize, FaceIndex faceIndex )
+   */
+  FontId GetFontId( const FontPath& path, PointSize26Dot6 requestedPointSize, FaceIndex faceIndex );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetFontId( const FontDescription& fontDescription, PointSize26Dot6 requestedPointSize, FaceIndex faceIndex )
+   */
+  FontId GetFontId( const FontDescription& fontDescription,
+                    PointSize26Dot6 requestedPointSize,
+                    FaceIndex faceIndex );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetFontId( const BitmapFont& bitmapFont )
+   */
+  FontId GetFontId( const BitmapFont& bitmapFont );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::IsScalable( const FontPath& path )
+   */
+  bool IsScalable( const FontPath& path );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::IsScalable( const FontDescription& fontDescription )
+   */
+  bool IsScalable( const FontDescription& fontDescription );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes )
+   */
+  void GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetFixedSizes()
+   */
+  void GetFixedSizes( const FontDescription& fontDescription,
+                      Dali::Vector< PointSize26Dot6 >& sizes );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::HasItalicStyle()
+   */
+  bool HasItalicStyle( FontId fontId ) const;
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetFontMetrics()
+   */
+  void GetFontMetrics( FontId fontId, FontMetrics& metrics );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetGlyphIndex()
+   */
+  GlyphIndex GetGlyphIndex( FontId fontId, Character charcode );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetGlyphMetrics()
+   */
+  bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, GlyphType type, bool horizontal );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
+   */
+  void CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
+   */
+  PixelData CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::CreateVectorBlob()
+   */
+  void CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetEllipsisGlyph()
+   */
+  const GlyphInfo& GetEllipsisGlyph( PointSize26Dot6 requestedPointSize );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::IsColorGlyph()
+   */
+  bool IsColorGlyph( FontId fontId, GlyphIndex glyphIndex );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::CreateEmbeddedItem()
+   */
+  GlyphIndex CreateEmbeddedItem( const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat );
+
+  /**
+   * @brief Retrieves the pointer to the FreeType Font Face for the given @p fontId.
+   *
+   * @param[in] fontId The font id.
+   *
+   * @return The pointer to the FreeType Font Face.
+   */
+  FT_FaceRec_* GetFreetypeFace( FontId fontId );
+
+  /**
+   * @brief Retrieves the type of font.
+   *
+   * @param[in] fontId The font id.
+   *
+   * @return FACE_FONT if the font has been loaded by FreeType, BITMAP_FONT if it's a font that has been loaded from images or INVALID if it's a non valid font.
+   */
+  FontDescription::Type GetFontType( FontId fontId );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::AddCustomFontDirectory()
+   */
+  bool AddCustomFontDirectory( const FontPath& path );
+
+private:
+
+  /**
+   * Helper for lazy initialization.
+   */
+  void CreatePlugin();
+
+  // Undefined copy constructor.
+  FontClient( const FontClient& );
+
+  // Undefined assignment constructor.
+  FontClient& operator=( const FontClient& );
+
+private:
+
+  struct Plugin;
+  Plugin* mPlugin;
+
+  // Allows DPI to be set without loading plugin
+  unsigned int mDpiHorizontal;
+  unsigned int mDpiVertical;
+
+  static Dali::TextAbstraction::FontClient gPreInitializedFontClient;
+
+}; // class FontClient
+
+} // namespace Internal
+
+inline static Internal::FontClient& GetImplementation(FontClient& fontClient)
+{
+  DALI_ASSERT_ALWAYS( fontClient && "fontClient handle is empty" );
+  BaseObject& handle = fontClient.GetBaseObject();
+  return static_cast<Internal::FontClient&>(handle);
+}
+
+inline static const Internal::FontClient& GetImplementation(const FontClient& fontClient)
+{
+  DALI_ASSERT_ALWAYS( fontClient && "fontClient handle is empty" );
+  const BaseObject& handle = fontClient.GetBaseObject();
+  return static_cast<const Internal::FontClient&>(handle);
+}
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_IMPL_H
diff --git a/dali/internal/text/text-abstraction/font-client-plugin-impl.cpp b/dali/internal/text/text-abstraction/font-client-plugin-impl.cpp
new file mode 100755 (executable)
index 0000000..113931a
--- /dev/null
@@ -0,0 +1,2771 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/text/text-abstraction/font-client-plugin-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-list.h>
+
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/platform-abstraction.h>
+#include <dali/internal/text/text-abstraction/font-client-helper.h>
+#include <dali/internal/imaging/common/image-operations.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/devel-api/adaptor-framework/image-loading.h>
+
+// EXTERNAL INCLUDES
+#include <fontconfig/fontconfig.h>
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
+#endif
+
+/**
+ * Conversion from Fractional26.6 to float
+ */
+const float FROM_266 = 1.0f / 64.0f;
+const float POINTS_PER_INCH = 72.f;
+
+const std::string DEFAULT_FONT_FAMILY_NAME( "Tizen" );
+const int DEFAULT_FONT_WIDTH  = 100; // normal
+const int DEFAULT_FONT_WEIGHT =  80; // normal
+const int DEFAULT_FONT_SLANT  =   0; // normal
+
+const uint32_t ELLIPSIS_CHARACTER = 0x2026;
+
+// http://www.freedesktop.org/software/fontconfig/fontconfig-user.html
+
+// NONE            -1  --> DEFAULT_FONT_WIDTH (NORMAL) will be used.
+// ULTRA_CONDENSED 50
+// EXTRA_CONDENSED 63
+// CONDENSED       75
+// SEMI_CONDENSED  87
+// NORMAL         100
+// SEMI_EXPANDED  113
+// EXPANDED       125
+// EXTRA_EXPANDED 150
+// ULTRA_EXPANDED 200
+const int FONT_WIDTH_TYPE_TO_INT[] = { -1, 50, 63, 75, 87, 100, 113, 125, 150, 200 };
+const unsigned int NUM_FONT_WIDTH_TYPE = sizeof( FONT_WIDTH_TYPE_TO_INT ) / sizeof( int );
+
+// NONE                       -1  --> DEFAULT_FONT_WEIGHT (NORMAL) will be used.
+// THIN                        0
+// ULTRA_LIGHT, EXTRA_LIGHT   40
+// LIGHT                      50
+// DEMI_LIGHT, SEMI_LIGHT     55
+// BOOK                       75
+// NORMAL, REGULAR            80
+// MEDIUM                    100
+// DEMI_BOLD, SEMI_BOLD      180
+// BOLD                      200
+// ULTRA_BOLD, EXTRA_BOLD    205
+// BLACK, HEAVY, EXTRA_BLACK 210
+const int FONT_WEIGHT_TYPE_TO_INT[] = { -1, 0, 40, 50, 55, 75, 80, 100, 180, 200, 205, 210 };
+const unsigned int NUM_FONT_WEIGHT_TYPE = sizeof( FONT_WEIGHT_TYPE_TO_INT ) / sizeof( int );
+
+// NONE             -1 --> DEFAULT_FONT_SLANT (NORMAL) will be used.
+// NORMAL, ROMAN     0
+// ITALIC          100
+// OBLIQUE         110
+const int FONT_SLANT_TYPE_TO_INT[] = { -1, 0, 100, 110 };
+const unsigned int NUM_FONT_SLANT_TYPE = sizeof( FONT_SLANT_TYPE_TO_INT ) / sizeof( int );
+
+} // namespace
+
+using Dali::Vector;
+using namespace std;
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * @brief Returns the FontWidth's enum index for the given width value.
+ *
+ * @param[in] width The width value.
+ *
+ * @return The FontWidth's enum index.
+ */
+FontWidth::Type IntToWidthType( int width )
+{
+  return static_cast<FontWidth::Type>( ValueToIndex( width, FONT_WIDTH_TYPE_TO_INT, NUM_FONT_WIDTH_TYPE - 1u ) );
+}
+
+/**
+ * @brief Returns the FontWeight's enum index for the given weight value.
+ *
+ * @param[in] weight The weight value.
+ *
+ * @return The FontWeight's enum index.
+ */
+FontWeight::Type IntToWeightType( int weight )
+{
+  return static_cast<FontWeight::Type>( ValueToIndex( weight, FONT_WEIGHT_TYPE_TO_INT, NUM_FONT_WEIGHT_TYPE - 1u ) );
+}
+
+/**
+ * @brief Returns the FontSlant's enum index for the given slant value.
+ *
+ * @param[in] slant The slant value.
+ *
+ * @return The FontSlant's enum index.
+ */
+FontSlant::Type IntToSlantType( int slant )
+{
+  return static_cast<FontSlant::Type>( ValueToIndex( slant, FONT_SLANT_TYPE_TO_INT, NUM_FONT_SLANT_TYPE - 1u ) );
+}
+
+/**
+ * @brief Free the resources allocated by the FcCharSet objects.
+ *
+ * @param[in] characterSets The vector of character sets.
+ */
+void DestroyCharacterSets( CharacterSetList& characterSets )
+{
+  for( auto& item : characterSets )
+  {
+    if( item )
+    {
+      FcCharSetDestroy( item );
+    }
+  }
+}
+
+FontClient::Plugin::FallbackCacheItem::FallbackCacheItem( FontDescription&& font, FontList* fallbackFonts, CharacterSetList* characterSets )
+: fontDescription{ std::move( font ) },
+  fallbackFonts{ fallbackFonts },
+  characterSets{ characterSets }
+{
+}
+
+FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( const FontDescription& fontDescription,
+                                                                        FontDescriptionId index )
+: fontDescription{ fontDescription },
+  index{ index }
+{
+}
+
+FontClient::Plugin::FontDescriptionCacheItem::FontDescriptionCacheItem( FontDescription&& fontDescription,
+                                                                        FontDescriptionId index )
+: fontDescription{ std::move( fontDescription ) },
+  index{ index }
+{
+}
+
+FontClient::Plugin::FontDescriptionSizeCacheItem::FontDescriptionSizeCacheItem( FontDescriptionId validatedFontId,
+                                                                                PointSize26Dot6 requestedPointSize,
+                                                                                FontId fontId )
+: validatedFontId( validatedFontId ),
+  requestedPointSize( requestedPointSize ),
+  fontId( fontId )
+{
+}
+
+FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
+                                                          const FontPath& path,
+                                                          PointSize26Dot6 requestedPointSize,
+                                                          FaceIndex face,
+                                                          const FontMetrics& metrics )
+: mFreeTypeFace( ftFace ),
+  mPath( path ),
+  mRequestedPointSize( requestedPointSize ),
+  mFaceIndex( face ),
+  mMetrics( metrics ),
+  mCharacterSet( nullptr ),
+  mFixedSizeIndex( 0 ),
+  mFixedWidthPixels( 0.f ),
+  mFixedHeightPixels( 0.f ),
+  mVectorFontId( 0u ),
+  mFontId( 0u ),
+  mIsFixedSizeBitmap( false ),
+  mHasColorTables( false )
+{
+}
+
+FontClient::Plugin::FontFaceCacheItem::FontFaceCacheItem( FT_Face ftFace,
+                                                          const FontPath& path,
+                                                          PointSize26Dot6 requestedPointSize,
+                                                          FaceIndex face,
+                                                          const FontMetrics& metrics,
+                                                          int fixedSizeIndex,
+                                                          float fixedWidth,
+                                                          float fixedHeight,
+                                                          bool hasColorTables )
+: mFreeTypeFace( ftFace ),
+  mPath( path ),
+  mRequestedPointSize( requestedPointSize ),
+  mFaceIndex( face ),
+  mMetrics( metrics ),
+  mCharacterSet( nullptr ),
+  mFixedSizeIndex( fixedSizeIndex ),
+  mFixedWidthPixels( fixedWidth ),
+  mFixedHeightPixels( fixedHeight ),
+  mVectorFontId( 0u ),
+  mFontId( 0u ),
+  mIsFixedSizeBitmap( true ),
+  mHasColorTables( hasColorTables )
+{
+}
+
+FontClient::Plugin::Plugin( unsigned int horizontalDpi,
+                            unsigned int verticalDpi )
+: mFreeTypeLibrary( nullptr ),
+  mDpiHorizontal( horizontalDpi ),
+  mDpiVertical( verticalDpi ),
+  mDefaultFontDescription(),
+  mSystemFonts(),
+  mDefaultFonts(),
+  mFontIdCache(),
+  mFontFaceCache(),
+  mValidatedFontCache(),
+  mFontDescriptionCache(),
+  mCharacterSetCache(),
+  mFontDescriptionSizeCache(),
+  mVectorFontCache( nullptr ),
+  mEllipsisCache(),
+  mEmbeddedItemCache(),
+  mDefaultFontDescriptionCached( false )
+{
+  int error = FT_Init_FreeType( &mFreeTypeLibrary );
+  if( FT_Err_Ok != error )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Init error: %d\n", error );
+  }
+
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+  mVectorFontCache = new VectorFontCache( mFreeTypeLibrary );
+#endif
+}
+
+FontClient::Plugin::~Plugin()
+{
+  ClearFallbackCache( mFallbackCache );
+
+  // Free the resources allocated by the FcCharSet objects.
+  DestroyCharacterSets( mDefaultFontCharacterSets );
+  DestroyCharacterSets( mCharacterSetCache );
+  ClearCharacterSetFromFontFaceCache();
+
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+  delete mVectorFontCache;
+#endif
+  FT_Done_FreeType( mFreeTypeLibrary );
+}
+
+void FontClient::Plugin::ClearCache()
+{
+  mDefaultFontDescription = FontDescription();
+
+  mSystemFonts.clear();
+  mDefaultFonts.clear();
+
+  DestroyCharacterSets( mDefaultFontCharacterSets );
+  mDefaultFontCharacterSets.Clear();
+
+  ClearFallbackCache( mFallbackCache );
+  mFallbackCache.clear();
+
+  mFontIdCache.Clear();
+
+  ClearCharacterSetFromFontFaceCache();
+  mFontFaceCache.clear();
+
+  mValidatedFontCache.clear();
+  mFontDescriptionCache.clear();
+
+  DestroyCharacterSets( mCharacterSetCache );
+  mCharacterSetCache.Clear();
+
+  mFontDescriptionSizeCache.clear();
+
+  mEllipsisCache.Clear();
+  mPixelBufferCache.clear();
+  mEmbeddedItemCache.Clear();
+  mBitmapFontCache.clear();
+
+  mDefaultFontDescriptionCached = false;
+}
+
+void FontClient::Plugin::SetDpi( unsigned int horizontalDpi,
+                                 unsigned int verticalDpi )
+{
+  mDpiHorizontal = horizontalDpi;
+  mDpiVertical = verticalDpi;
+}
+
+void FontClient::Plugin::ResetSystemDefaults()
+{
+  mDefaultFontDescriptionCached = false;
+}
+
+void FontClient::Plugin::SetFontList( const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::SetFontList\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
+
+  fontList.clear();
+
+  FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription ); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
+
+  FcResult result = FcResultMatch;
+
+  // Match the pattern.
+  FcFontSet* fontSet = FcFontSort( nullptr /* use default configure */,
+                                   fontFamilyPattern,
+                                   false /* don't trim */,
+                                   nullptr,
+                                   &result ); // FcFontSort creates a font set that needs to be destroyed by calling FcFontSetDestroy.
+
+  if( nullptr != fontSet )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "  number of fonts found : [%d]\n", fontSet->nfont );
+    // Reserve some space to avoid reallocations.
+    fontList.reserve( fontSet->nfont );
+
+    for( int i = 0u; i < fontSet->nfont; ++i )
+    {
+      FcPattern* fontPattern = fontSet->fonts[i];
+
+      FontPath path;
+
+      // Skip fonts with no path
+      if( GetFcString( fontPattern, FC_FILE, path ) )
+      {
+        // Retrieve the character set. Need to call FcCharSetDestroy to free the resources.
+        FcCharSet* characterSet = nullptr;
+        FcPatternGetCharSet( fontPattern, FC_CHARSET, 0u, &characterSet );
+
+        // Increase the reference counter of the character set.
+        characterSetList.PushBack( FcCharSetCopy( characterSet ) );
+
+        fontList.push_back( FontDescription() );
+        FontDescription& newFontDescription = fontList.back();
+
+        newFontDescription.path = std::move( path );
+
+        int width = 0;
+        int weight = 0;
+        int slant = 0;
+        GetFcString( fontPattern, FC_FAMILY, newFontDescription.family );
+        GetFcInt( fontPattern, FC_WIDTH, width );
+        GetFcInt( fontPattern, FC_WEIGHT, weight );
+        GetFcInt( fontPattern, FC_SLANT, slant );
+        newFontDescription.width = IntToWidthType( width );
+        newFontDescription.weight = IntToWeightType( weight );
+        newFontDescription.slant = IntToSlantType( slant );
+
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  description; family : [%s]\n", newFontDescription.family.c_str() );
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", newFontDescription.path.c_str() );
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[newFontDescription.width] );
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[newFontDescription.weight] );
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[newFontDescription.slant] );
+      }
+    }
+
+    // Destroys the font set created by FcFontSort.
+    FcFontSetDestroy( fontSet );
+  }
+  else
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  No fonts found.\n" );
+  }
+
+  // Destroys the pattern created by FcPatternCreate in CreateFontFamilyPattern.
+  FcPatternDestroy( fontFamilyPattern );
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::SetFontList\n" );
+}
+
+void FontClient::Plugin::GetDefaultFonts( FontList& defaultFonts )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultFonts\n" );
+
+  if( mDefaultFonts.empty() )
+  {
+    FontDescription fontDescription;
+    fontDescription.family = DEFAULT_FONT_FAMILY_NAME;  // todo This could be set to the Platform font
+    fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
+    fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
+    fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
+    SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
+  }
+
+  defaultFonts = mDefaultFonts;
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  number of default fonts : [%d]\n", mDefaultFonts.size() );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultFonts\n" );
+}
+
+void FontClient::Plugin::GetDefaultPlatformFontDescription( FontDescription& fontDescription )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDefaultPlatformFontDescription\n");
+
+  if( !mDefaultFontDescriptionCached )
+  {
+    // Clear any font config stored info in the caches.
+
+    // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
+    DestroyCharacterSets( mDefaultFontCharacterSets );
+    DestroyCharacterSets( mCharacterSetCache );
+    mDefaultFontCharacterSets.Clear();
+    mCharacterSetCache.Clear();
+
+    for( auto& item : mFallbackCache )
+    {
+      // Decrease the reference counter and eventually free the resources allocated by FcCharSet objects.
+      DestroyCharacterSets( *item.characterSets );
+
+      delete item.characterSets;
+      item.characterSets = nullptr;
+    }
+
+    // Set the character set pointer as null. Will be created again the next time IsCharacterSupportedByFont()
+    ClearCharacterSetFromFontFaceCache();
+
+    // FcInitBringUptoDate did not seem to reload config file as was still getting old default font.
+    FcInitReinitialize();
+
+    FcPattern* matchPattern = FcPatternCreate(); // Creates a pattern that needs to be destroyed by calling FcPatternDestroy.
+
+    if( nullptr != matchPattern )
+    {
+      FcConfigSubstitute( nullptr, matchPattern, FcMatchPattern );
+      FcDefaultSubstitute( matchPattern );
+
+      FcCharSet* characterSet = nullptr;
+      MatchFontDescriptionToPattern( matchPattern, mDefaultFontDescription, &characterSet );
+      // Decrease the reference counter of the character set as it's not stored.
+      FcCharSetDestroy( characterSet );
+
+      // Destroys the pattern created.
+      FcPatternDestroy( matchPattern );
+    }
+
+    // Create again the character sets as they are not valid after FcInitReinitialize()
+
+    for( const auto& description : mDefaultFonts )
+    {
+      mDefaultFontCharacterSets.PushBack( FcCharSetCopy( CreateCharacterSetFromDescription( description ) ) );
+    }
+
+    for( const auto& description : mFontDescriptionCache )
+    {
+      mCharacterSetCache.PushBack( FcCharSetCopy( CreateCharacterSetFromDescription( description ) ) );
+    }
+
+    for( auto& item : mFallbackCache )
+    {
+      if( nullptr != item.fallbackFonts )
+      {
+        if( nullptr == item.characterSets )
+        {
+          item.characterSets = new CharacterSetList;
+        }
+
+        for( const auto& description : *( item.fallbackFonts ) )
+        {
+          item.characterSets->PushBack( FcCharSetCopy( CreateCharacterSetFromDescription( description ) ) );
+        }
+      }
+    }
+
+    mDefaultFontDescriptionCached = true;
+  }
+
+  fontDescription.path   = mDefaultFontDescription.path;
+  fontDescription.family = mDefaultFontDescription.family;
+  fontDescription.width  = mDefaultFontDescription.width;
+  fontDescription.weight = mDefaultFontDescription.weight;
+  fontDescription.slant  = mDefaultFontDescription.slant;
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDefaultPlatformFontDescription\n");
+}
+
+void FontClient::Plugin::GetSystemFonts( FontList& systemFonts )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetSystemFonts\n");
+
+  if( mSystemFonts.empty() )
+  {
+    InitSystemFonts();
+  }
+
+  systemFonts = mSystemFonts;
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  number of system fonts : [%d]\n", mSystemFonts.size() );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetSystemFonts\n");
+}
+
+void FontClient::Plugin::GetDescription( FontId id,
+                                         FontDescription& fontDescription ) const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetDescription\n");
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
+  const FontId index = id - 1u;
+
+  if( ( id > 0u ) && ( index < mFontIdCache.Count() ) )
+  {
+    const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
+    switch( fontIdCacheItem.type )
+    {
+      case FontDescription::FACE_FONT:
+      {
+        for( const auto& item : mFontDescriptionSizeCache )
+        {
+          if( item.fontId == fontIdCacheItem.id )
+          {
+            fontDescription = *( mFontDescriptionCache.begin() + item.validatedFontId - 1u );
+
+            DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
+            DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
+            DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
+            DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
+            DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
+            DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
+            return;
+          }
+        }
+        break;
+      }
+      case FontDescription::BITMAP_FONT:
+      {
+        fontDescription.type = FontDescription::BITMAP_FONT;
+        fontDescription.family = mBitmapFontCache[fontIdCacheItem.id].font.name;
+        break;
+      }
+      default:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
+        fontDescription.type = FontDescription::INVALID;
+        fontDescription.family.clear();
+      }
+    }
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  No description found for the font ID %d\n", id );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetDescription\n");
+}
+
+PointSize26Dot6 FontClient::Plugin::GetPointSize( FontId id )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetPointSize\n");
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
+  const FontId index = id - 1u;
+
+  if( ( id > 0u ) &&
+      ( index < mFontIdCache.Count() ) )
+  {
+    const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
+
+    switch( fontIdCacheItem.type )
+    {
+      case FontDescription::FACE_FONT:
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::General, "  point size : %d\n", ( *( mFontFaceCache.begin() + fontIdCacheItem.id ) ).mRequestedPointSize );
+        DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
+        return ( *( mFontFaceCache.begin() + fontIdCacheItem.id ) ).mRequestedPointSize;
+      }
+      case FontDescription::BITMAP_FONT:
+      {
+        return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
+      }
+      default:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
+      }
+    }
+  }
+  else
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "  Invalid font ID %d\n", id );
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  default point size : %d\n", TextAbstraction::FontClient::DEFAULT_POINT_SIZE );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetPointSize\n");
+  return TextAbstraction::FontClient::DEFAULT_POINT_SIZE;
+}
+
+bool FontClient::Plugin::IsCharacterSupportedByFont( FontId fontId, Character character )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::IsCharacterSupportedByFont\n");
+  DALI_LOG_INFO( gLogFilter, Debug::General, "    font id : %d\n", fontId );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  character : %p\n", character );
+
+  if( ( fontId < 1u ) || ( fontId > mFontIdCache.Count() ) )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "  Invalid font id. Number of items in the cache: %d\n",mFontIdCache.Count());
+    DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
+    return false;
+  }
+
+  --fontId;
+
+  bool isSupported = false;
+
+  const FontIdCacheItem& fontIdCacheItem = mFontIdCache[fontId];
+
+  switch( fontIdCacheItem.type )
+  {
+    case FontDescription::FACE_FONT:
+    {
+      if( fontIdCacheItem.id < mFontFaceCache.size() )
+      {
+        FontFaceCacheItem& cacheItem = mFontFaceCache[fontIdCacheItem.id];
+
+        if( nullptr == cacheItem.mCharacterSet )
+        {
+          // Create again the character set.
+          // It can be null if the ResetSystemDefaults() method has been called.
+
+          FontDescription description;
+          description.path = cacheItem.mPath;
+          description.family = std::move( FontFamily( cacheItem.mFreeTypeFace->family_name ) );
+          description.weight = FontWeight::NONE;
+          description.width = FontWidth::NONE;
+          description.slant = FontSlant::NONE;
+
+          // Note FreeType doesn't give too much info to build a proper font style.
+          if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC )
+          {
+            description.slant = FontSlant::ITALIC;
+          }
+          if( cacheItem.mFreeTypeFace->style_flags & FT_STYLE_FLAG_BOLD )
+          {
+            description.weight = FontWeight::BOLD;
+          }
+
+          cacheItem.mCharacterSet = FcCharSetCopy( CreateCharacterSetFromDescription( description ) );
+        }
+
+        isSupported = FcCharSetHasChar( cacheItem.mCharacterSet, character );
+      }
+      break;
+    }
+    case FontDescription::BITMAP_FONT:
+    {
+      const BitmapFont& bitmapFont = mBitmapFontCache[fontIdCacheItem.id].font;
+
+      for( const auto& glyph : bitmapFont.glyphs )
+      {
+        if( glyph.utf32 == character )
+        {
+          isSupported = true;
+          break;
+        }
+      }
+      break;
+    }
+    default:
+    {
+      DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
+    }
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  is supported : %s\n", (isSupported ? "true" : "false") );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::IsCharacterSupportedByFont\n");
+  return isSupported;
+}
+
+FontId FontClient::Plugin::FindFontForCharacter( const FontList& fontList,
+                                                 const CharacterSetList& characterSetList,
+                                                 Character character,
+                                                 PointSize26Dot6 requestedPointSize,
+                                                 bool preferColor )
+{
+  DALI_ASSERT_DEBUG( ( fontList.size() == characterSetList.Count() ) && "FontClient::Plugin::FindFontForCharacter. Different number of fonts and character sets." );
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFontForCharacter\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "           character : %p\n", character );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "         preferColor : %s\n", ( preferColor ? "true" : "false" ) );
+
+  FontId fontId = 0u;
+  bool foundColor = false;
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  number of fonts : %d\n", fontList.size() );
+
+  // Traverse the list of fonts.
+  // Check for each font if supports the character.
+  for( unsigned int index = 0u, numberOfFonts = fontList.size(); index < numberOfFonts; ++index )
+  {
+    const FontDescription& description = fontList[index];
+    const FcCharSet* const characterSet = characterSetList[index];
+
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  description; family : [%s]\n", description.family.c_str() );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", description.path.c_str() );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[description.width] );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[description.weight] );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[description.slant] );
+
+    bool foundInRanges = false;
+    if( nullptr != characterSet )
+    {
+      foundInRanges = FcCharSetHasChar( characterSet, character );
+    }
+
+    if( foundInRanges )
+    {
+      fontId = GetFontId( description,
+                          requestedPointSize,
+                          0u );
+
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "     font id : %d\n", fontId );
+
+      if( preferColor )
+      {
+        if( ( fontId > 0 ) &&
+            ( fontId - 1u < mFontIdCache.Count() ) )
+        {
+          const FontFaceCacheItem& item = mFontFaceCache[mFontIdCache[fontId - 1u].id];
+
+          foundColor = item.mHasColorTables;
+        }
+
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  foundColor : %s\n", ( foundColor ? "true" : "false" ) );
+      }
+
+      // Keep going unless we prefer a different (color) font.
+      if( !preferColor || foundColor )
+      {
+        break;
+      }
+    }
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", fontId );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFontForCharacter\n" );
+  return fontId;
+}
+
+FontId FontClient::Plugin::FindDefaultFont( Character charcode,
+                                            PointSize26Dot6 requestedPointSize,
+                                            bool preferColor )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindDefaultFont\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "           character : %p\n", charcode );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "         preferColor : %s\n", ( preferColor ? "true" : "false" ) );
+
+  FontId fontId(0);
+
+  // Create the list of default fonts if it has not been created.
+  if( mDefaultFonts.empty() )
+  {
+    FontDescription fontDescription;
+    fontDescription.family = DEFAULT_FONT_FAMILY_NAME;
+    fontDescription.width = IntToWidthType( DEFAULT_FONT_WIDTH );
+    fontDescription.weight = IntToWeightType( DEFAULT_FONT_WEIGHT );
+    fontDescription.slant = IntToSlantType( DEFAULT_FONT_SLANT );
+
+    SetFontList( fontDescription, mDefaultFonts, mDefaultFontCharacterSets );
+  }
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of default fonts : %d\n", mDefaultFonts.size() );
+
+
+  // Traverse the list of default fonts.
+  // Check for each default font if supports the character.
+  fontId = FindFontForCharacter( mDefaultFonts, mDefaultFontCharacterSets, charcode, requestedPointSize, preferColor );
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", fontId );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindDefaultFont\n" );
+
+  return fontId;
+}
+
+FontId FontClient::Plugin::FindFallbackFont( Character charcode,
+                                             const FontDescription& preferredFontDescription,
+                                             PointSize26Dot6 requestedPointSize,
+                                             bool preferColor )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFont\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "           character : %p\n", charcode );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "         preferColor : %s\n", ( preferColor ? "true" : "false" ) );
+
+  // The font id to be returned.
+  FontId fontId = 0u;
+
+  FontDescription fontDescription;
+
+  // Fill the font description with the preferred font description and complete with the defaults.
+  fontDescription.family = preferredFontDescription.family.empty() ? DEFAULT_FONT_FAMILY_NAME : preferredFontDescription.family;
+  fontDescription.weight = ( ( FontWeight::NONE == preferredFontDescription.weight ) ? IntToWeightType( DEFAULT_FONT_WEIGHT ) : preferredFontDescription.weight );
+  fontDescription.width = ( ( FontWidth::NONE == preferredFontDescription.width ) ? IntToWidthType( DEFAULT_FONT_WIDTH ) : preferredFontDescription.width );
+  fontDescription.slant = ( ( FontSlant::NONE == preferredFontDescription.slant ) ? IntToSlantType( DEFAULT_FONT_SLANT ) : preferredFontDescription.slant );
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  preferredFontDescription --> fontDescription\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  [%s] --> [%s]\n", preferredFontDescription.family.c_str(), fontDescription.family.c_str() );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  [%s] --> [%s]\n", FontWeight::Name[preferredFontDescription.weight], FontWeight::Name[fontDescription.weight] );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  [%s] --> [%s]\n", FontWidth::Name[preferredFontDescription.width], FontWidth::Name[fontDescription.width] );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  [%s] --> [%s]\n", FontSlant::Name[preferredFontDescription.slant], FontSlant::Name[fontDescription.slant] );
+
+  // Check first if the font's description has been queried before.
+  FontList* fontList = nullptr;
+  CharacterSetList* characterSetList = nullptr;
+
+  if( !FindFallbackFontList( fontDescription, fontList, characterSetList ) )
+  {
+    fontList = new FontList;
+    characterSetList = new CharacterSetList;
+
+    SetFontList( fontDescription, *fontList, *characterSetList );
+
+    // Add the font-list to the cache.
+    mFallbackCache.push_back( std::move( FallbackCacheItem( std::move( fontDescription ), fontList, characterSetList ) ) );
+  }
+
+  if( fontList && characterSetList )
+  {
+    fontId = FindFontForCharacter( *fontList, *characterSetList, charcode, requestedPointSize, preferColor );
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", fontId );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFont\n");
+  return fontId;
+}
+
+FontId FontClient::Plugin::GetFontId( const FontPath& path,
+                                      PointSize26Dot6 requestedPointSize,
+                                      FaceIndex faceIndex,
+                                      bool cacheDescription )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
+
+  FontId id = 0u;
+
+  if( nullptr != mFreeTypeLibrary )
+  {
+    FontId foundId = 0u;
+    if( FindFont( path, requestedPointSize, faceIndex, foundId ) )
+    {
+      id = foundId;
+    }
+    else
+    {
+      id = CreateFont( path, requestedPointSize, faceIndex, cacheDescription );
+    }
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
+
+  return id;
+}
+
+FontId FontClient::Plugin::GetFontId( const FontDescription& fontDescription,
+                                      PointSize26Dot6 requestedPointSize,
+                                      FaceIndex faceIndex )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetFontId\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "   requestedPointSize : %d\n", requestedPointSize );
+
+  // This method uses three vectors which caches:
+  // * The bitmap font cache
+  // * Pairs of non validated font descriptions and an index to a vector with paths to font file names.
+  // * The path to font file names.
+  // * The font ids of pairs 'font point size, index to the vector with paths to font file names'.
+
+  // 1) Checks if the font description matches with a previously loaded bitmap font.
+  //    Returns if a font is found.
+  // 2) Checks in the cache if the font's description has been validated before.
+  //    If it was it gets an index to the vector with paths to font file names. Otherwise,
+  //    retrieves using font config a path to a font file name which matches with the
+  //    font's description. The path is stored in the cache.
+  //
+  // 3) Checks in the cache if the pair 'font point size, index to the vector with paths to
+  //    font file names' exists. If exists, it gets the font id. If it doesn't it calls
+  //    the GetFontId() method with the path to the font file name and the point size to
+  //    get the font id.
+
+  // The font id to be returned.
+  FontId fontId = 0u;
+
+  // Check first if the font description matches with a previously loaded bitmap font.
+  if( FindBitmapFont( fontDescription.family, fontId ) )
+  {
+    return fontId;
+  }
+
+  // Check if the font's description have been validated before.
+  FontDescriptionId validatedFontId = 0u;
+
+  if( !FindValidatedFont( fontDescription,
+                          validatedFontId ) )
+  {
+    // Use font config to validate the font's description.
+    ValidateFont( fontDescription,
+                  validatedFontId );
+  }
+
+  FontId fontFaceId = 0u;
+  // Check if exists a pair 'validatedFontId, requestedPointSize' in the cache.
+  if( !FindFont( validatedFontId, requestedPointSize, fontFaceId ) )
+  {
+    // Retrieve the font file name path.
+    const FontDescription& description = *( mFontDescriptionCache.begin() + validatedFontId - 1u );
+
+    // Retrieve the font id. Do not cache the description as it has been already cached.
+    fontId = GetFontId( description.path,
+                        requestedPointSize,
+                        faceIndex,
+                        false );
+
+    fontFaceId = mFontIdCache[fontId-1u].id;
+    mFontFaceCache[fontFaceId].mCharacterSet = FcCharSetCopy( mCharacterSetCache[validatedFontId - 1u] );
+
+    // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
+    mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
+                                                                       requestedPointSize,
+                                                                       fontFaceId ) );
+  }
+  else
+  {
+    fontId = mFontFaceCache[fontFaceId].mFontId + 1u;
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", fontId );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetFontId\n" );
+
+  return fontId;
+}
+
+FontId FontClient::Plugin::GetFontId( const BitmapFont& bitmapFont )
+{
+  for( const auto& item : mBitmapFontCache )
+  {
+    if( bitmapFont.name == item.font.name )
+    {
+      return item.id + 1u;
+    }
+  }
+
+  BitmapFontCacheItem bitmapFontCacheItem;
+  bitmapFontCacheItem.font = bitmapFont;
+  bitmapFontCacheItem.id = mFontIdCache.Count();
+
+  // Resize the vector with the pixel buffers.
+  bitmapFontCacheItem.pixelBuffers.resize( bitmapFont.glyphs.size() );
+
+  // Traverse all the glyphs and load the pixel buffer of those with ascender and descender equal to zero.
+  unsigned int index = 0u;
+  for( auto& glyph : bitmapFontCacheItem.font.glyphs )
+  {
+    Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
+
+    if( EqualsZero( glyph.ascender ) && EqualsZero( glyph.descender ) )
+    {
+      // Load the glyph.
+      pixelBuffer = LoadImageFromFile( glyph.url );
+
+      if( pixelBuffer )
+      {
+        glyph.ascender = static_cast<float>(pixelBuffer.GetHeight());
+      }
+    }
+
+    bitmapFontCacheItem.font.ascender = std::max( glyph.ascender, bitmapFontCacheItem.font.ascender );
+    bitmapFontCacheItem.font.descender = std::min( glyph.descender, bitmapFontCacheItem.font.descender );
+
+    ++index;
+  }
+
+  FontIdCacheItem fontIdCacheItem;
+  fontIdCacheItem.type = FontDescription::BITMAP_FONT;
+  fontIdCacheItem.id = mBitmapFontCache.size();
+
+  mBitmapFontCache.push_back( std::move( bitmapFontCacheItem ) );
+  mFontIdCache.PushBack( fontIdCacheItem );
+
+  return bitmapFontCacheItem.id + 1u;
+}
+
+void FontClient::Plugin::ValidateFont( const FontDescription& fontDescription,
+                                       FontDescriptionId& validatedFontId )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::ValidateFont\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
+
+  // Create a font pattern.
+  FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription );
+
+  FontDescription description;
+
+  FcCharSet* characterSet = nullptr;
+  bool matched = MatchFontDescriptionToPattern( fontFamilyPattern, description, &characterSet );
+  FcPatternDestroy( fontFamilyPattern );
+
+  if( matched && ( nullptr != characterSet ) )
+  {
+    // Add the path to the cache.
+    description.type = FontDescription::FACE_FONT;
+    mFontDescriptionCache.push_back( description );
+
+    // Set the index to the vector of paths to font file names.
+    validatedFontId = mFontDescriptionCache.size();
+
+    DALI_LOG_INFO( gLogFilter, Debug::General, "  matched description; family : [%s]\n", description.family.c_str() );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                         path : [%s]\n", description.path.c_str() );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                        width : [%s]\n", FontWidth::Name[description.width] );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                       weight : [%s]\n", FontWeight::Name[description.weight] );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                        slant : [%s]\n\n", FontSlant::Name[description.slant] );
+    DALI_LOG_INFO( gLogFilter, Debug::General, "  validatedFontId : %d\n", validatedFontId );
+
+    // The reference counter of the character set has already been increased in MatchFontDescriptionToPattern.
+    mCharacterSetCache.PushBack( characterSet );
+
+    // Cache the index and the matched font's description.
+    FontDescriptionCacheItem item( description,
+                                   validatedFontId );
+
+    mValidatedFontCache.push_back( std::move( item ) );
+
+    if( ( fontDescription.family != description.family ) ||
+        ( fontDescription.width != description.width )   ||
+        ( fontDescription.weight != description.weight ) ||
+        ( fontDescription.slant != description.slant ) )
+    {
+      // Cache the given font's description if it's different than the matched.
+      FontDescriptionCacheItem item( fontDescription,
+                                     validatedFontId );
+
+      mValidatedFontCache.push_back( std::move( item ) );
+    }
+  }
+  else
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "  font validation failed for font [%s]\n", fontDescription.family.c_str() );
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::ValidateFont\n" );
+}
+
+void FontClient::Plugin::GetFontMetrics( FontId fontId,
+                                         FontMetrics& metrics )
+{
+  const FontId index = fontId - 1u;
+
+  if( ( fontId > 0 ) &&
+      ( index < mFontIdCache.Count() ) )
+  {
+    const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
+
+    switch( fontIdCacheItem.type )
+    {
+      case FontDescription::FACE_FONT:
+      {
+        const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
+
+        metrics = font.mMetrics;
+
+        // Adjust the metrics if the fixed-size font should be down-scaled
+        if( font.mIsFixedSizeBitmap )
+        {
+          const float desiredFixedSize =  static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
+
+          if( desiredFixedSize > 0.f )
+          {
+            const float scaleFactor = desiredFixedSize / font.mFixedHeightPixels;
+
+            metrics.ascender = metrics.ascender * scaleFactor;
+            metrics.descender = metrics.descender * scaleFactor;
+            metrics.height = metrics.height * scaleFactor;
+            metrics.underlinePosition = metrics.underlinePosition * scaleFactor;
+            metrics.underlineThickness = metrics.underlineThickness * scaleFactor;
+          }
+        }
+        break;
+      }
+      case FontDescription::BITMAP_FONT:
+      {
+        const BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
+
+        metrics.ascender = bitmapFontCacheItem.font.ascender;
+        metrics.descender = bitmapFontCacheItem.font.descender;
+        metrics.height = metrics.ascender - metrics.descender;
+        metrics.underlinePosition = bitmapFontCacheItem.font.underlinePosition;
+        metrics.underlineThickness = bitmapFontCacheItem.font.underlineThickness;
+        break;
+      }
+      default:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
+      }
+    }
+  }
+  else
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId );
+  }
+}
+
+GlyphIndex FontClient::Plugin::GetGlyphIndex( FontId fontId,
+                                              Character charcode )
+{
+  GlyphIndex glyphIndex = 0u;
+  const FontId index = fontId - 1u;
+
+  if( ( fontId > 0u ) &&
+      ( index < mFontIdCache.Count() ) )
+  {
+    const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
+
+    if( FontDescription::FACE_FONT == fontIdCacheItem.type )
+    {
+      FT_Face ftFace = mFontFaceCache[fontIdCacheItem.id].mFreeTypeFace;
+
+      glyphIndex = FT_Get_Char_Index( ftFace, charcode );
+    }
+  }
+
+  return glyphIndex;
+}
+
+bool FontClient::Plugin::GetGlyphMetrics( GlyphInfo* array,
+                                          uint32_t size,
+                                          GlyphType type,
+                                          bool horizontal )
+{
+  if( VECTOR_GLYPH == type )
+  {
+    return GetVectorMetrics( array, size, horizontal );
+  }
+
+  return GetBitmapMetrics( array, size, horizontal );
+}
+
+bool FontClient::Plugin::GetBitmapMetrics( GlyphInfo* array,
+                                           uint32_t size,
+                                           bool horizontal )
+{
+  bool success( true );
+
+  for( unsigned int i=0; i<size; ++i )
+  {
+    GlyphInfo& glyph = array[i];
+
+    FontId index = glyph.fontId - 1u;
+
+    if( ( glyph.fontId > 0u ) &&
+        ( index < mFontIdCache.Count() ) )
+    {
+      const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
+
+      switch( fontIdCacheItem.type )
+      {
+        case FontDescription::FACE_FONT:
+        {
+          const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
+
+          FT_Face ftFace = font.mFreeTypeFace;
+
+#ifdef FREETYPE_BITMAP_SUPPORT
+          // Check to see if we should be loading a Fixed Size bitmap?
+          if( font.mIsFixedSizeBitmap )
+          {
+            FT_Select_Size( ftFace, font.mFixedSizeIndex ); ///< @todo: needs to be investigated why it's needed to select the size again.
+            int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_COLOR );
+            if ( FT_Err_Ok == error )
+            {
+              glyph.width = font.mFixedWidthPixels;
+              glyph.height = font.mFixedHeightPixels;
+              glyph.advance = font.mFixedWidthPixels;
+              glyph.xBearing = 0.0f;
+              glyph.yBearing = font.mFixedHeightPixels;
+
+              // Adjust the metrics if the fixed-size font should be down-scaled
+              const float desiredFixedSize =  static_cast<float>( font.mRequestedPointSize ) * FROM_266 / POINTS_PER_INCH * mDpiVertical;
+
+              if( desiredFixedSize > 0.f )
+              {
+                const float scaleFactor = desiredFixedSize / font.mFixedHeightPixels;
+
+                glyph.width = glyph.width * scaleFactor ;
+                glyph.height = glyph.height * scaleFactor;
+                glyph.advance = glyph.advance * scaleFactor;
+                glyph.xBearing = glyph.xBearing * scaleFactor;
+                glyph.yBearing = glyph.yBearing * scaleFactor;
+
+                glyph.scaleFactor = scaleFactor;
+              }
+            }
+            else
+            {
+              DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetBitmapMetrics. FreeType Bitmap Load_Glyph error %d\n", error );
+              success = false;
+            }
+          }
+          else
+#endif
+          {
+            // FT_LOAD_DEFAULT causes some issues in the alignment of the glyph inside the bitmap.
+            // i.e. with the SNum-3R font.
+            // @todo: add an option to use the FT_LOAD_DEFAULT if required?
+            int error = FT_Load_Glyph( ftFace, glyph.index, FT_LOAD_NO_AUTOHINT );
+
+            // Keep the width of the glyph before doing the software emboldening.
+            // It will be used to calculate a scale factor to be applied to the
+            // advance as Harfbuzz doesn't apply any SW emboldening to calculate
+            // the advance of the glyph.
+            const float width = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
+
+            if( FT_Err_Ok == error )
+            {
+              const bool isEmboldeningRequired = glyph.isBoldRequired && !( ftFace->style_flags & FT_STYLE_FLAG_BOLD );
+              if( isEmboldeningRequired )
+              {
+                // Does the software bold.
+                FT_GlyphSlot_Embolden( ftFace->glyph );
+              }
+
+              glyph.width  = static_cast< float >( ftFace->glyph->metrics.width ) * FROM_266;
+              glyph.height = static_cast< float >( ftFace->glyph->metrics.height ) * FROM_266;
+              if( horizontal )
+              {
+                glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingX ) * FROM_266;
+                glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.horiBearingY ) * FROM_266;
+              }
+              else
+              {
+                glyph.xBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingX ) * FROM_266;
+                glyph.yBearing += static_cast< float >( ftFace->glyph->metrics.vertBearingY ) * FROM_266;
+              }
+
+              if( isEmboldeningRequired && !Dali::EqualsZero( width ) )
+              {
+                // If the glyph is emboldened by software, the advance is multiplied by a
+                // scale factor to make it slightly bigger.
+                glyph.advance *= ( glyph.width / width );
+              }
+
+              // Use the bounding box of the bitmap to correct the metrics.
+              // For some fonts i.e the SNum-3R the metrics need to be corrected,
+              // otherwise the glyphs 'dance' up and down depending on the
+              // font's point size.
+
+              FT_Glyph ftGlyph;
+              error = FT_Get_Glyph( ftFace->glyph, &ftGlyph );
+
+              FT_BBox bbox;
+              FT_Glyph_Get_CBox( ftGlyph, FT_GLYPH_BBOX_GRIDFIT, &bbox );
+
+              const float descender = glyph.height - glyph.yBearing;
+              glyph.height = ( bbox.yMax -  bbox.yMin) * FROM_266;
+              glyph.yBearing = glyph.height - round( descender );
+
+              // Created FT_Glyph object must be released with FT_Done_Glyph
+              FT_Done_Glyph( ftGlyph );
+            }
+            else
+            {
+              success = false;
+            }
+          }
+          break;
+        }
+        case FontDescription::BITMAP_FONT:
+        {
+          BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
+
+          unsigned int index = 0u;
+          for( auto& item : bitmapFontCacheItem.font.glyphs )
+          {
+            if( item.utf32 == glyph.index )
+            {
+              Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
+              if( !pixelBuffer )
+              {
+                pixelBuffer = LoadImageFromFile( item.url );
+              }
+
+              glyph.width  = static_cast< float >( pixelBuffer.GetWidth() );
+              glyph.height = static_cast< float >( pixelBuffer.GetHeight() );
+              glyph.xBearing = 0.f;
+              glyph.yBearing = glyph.height + item.descender;
+              glyph.advance = glyph.width;
+              glyph.scaleFactor = 1.f;
+              break;
+            }
+            ++index;
+          }
+
+          success = true;
+          break;
+        }
+        default:
+        {
+          DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
+        }
+      }
+    }
+    else
+    {
+      // Check if it's an embedded image.
+      if( ( 0u == glyph.fontId ) && ( 0u != glyph.index ) && ( glyph.index <= mEmbeddedItemCache.Count() ) )
+      {
+        const EmbeddedItem& item = mEmbeddedItemCache[glyph.index - 1u];
+
+        glyph.width = static_cast<float>( item.width );
+        glyph.height = static_cast<float>( item.height );
+        glyph.xBearing = 0.f;
+        glyph.yBearing = glyph.height;
+        glyph.advance = glyph.width;
+        glyph.scaleFactor = 1.f;
+      }
+      else
+      {
+        success = false;
+      }
+    }
+  }
+
+  return success;
+}
+
+bool FontClient::Plugin::GetVectorMetrics( GlyphInfo* array,
+                                           uint32_t size,
+                                           bool horizontal )
+{
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+  bool success( true );
+
+  for( unsigned int i = 0u; i < size; ++i )
+  {
+    FontId fontId = array[i].fontId;
+
+    if( ( fontId > 0u ) &&
+        ( fontId - 1u ) < mFontIdCache.Count() )
+    {
+      FontFaceCacheItem& font = mFontFaceCache[mFontIdCache[fontId - 1u].id];
+
+      if( ! font.mVectorFontId )
+      {
+        font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
+      }
+
+      mVectorFontCache->GetGlyphMetrics( font.mVectorFontId, array[i] );
+
+      // Vector metrics are in EMs, convert to pixels
+      const float scale = ( static_cast<float>( font.mRequestedPointSize ) * FROM_266 ) * static_cast<float>( mDpiVertical ) / POINTS_PER_INCH;
+      array[i].width    *= scale;
+      array[i].height   *= scale;
+      array[i].xBearing *= scale;
+      array[i].yBearing *= scale;
+      array[i].advance  *= scale;
+    }
+    else
+    {
+      success = false;
+    }
+  }
+
+  return success;
+#else
+  return false;
+#endif
+}
+
+void FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
+{
+  const FontId index = fontId - 1u;
+
+  if( ( fontId > 0u ) &&
+      ( index < mFontIdCache.Count() ) )
+  {
+    data.isColorBitmap = false;
+    data.isColorEmoji = false;
+
+    const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
+
+    switch( fontIdCacheItem.type )
+    {
+      case FontDescription::FACE_FONT:
+      {
+        // For the software italics.
+        bool isShearRequired = false;
+
+        const FontFaceCacheItem& fontFaceCacheItem = mFontFaceCache[fontIdCacheItem.id];
+        FT_Face ftFace = fontFaceCacheItem.mFreeTypeFace;
+
+        FT_Error error;
+
+#ifdef FREETYPE_BITMAP_SUPPORT
+        // Check to see if this is fixed size bitmap
+        if( fontFaceCacheItem.mIsFixedSizeBitmap )
+        {
+          error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
+        }
+        else
+#endif
+        {
+          // FT_LOAD_DEFAULT causes some issues in the alignment of the glyph inside the bitmap.
+          // i.e. with the SNum-3R font.
+          // @todo: add an option to use the FT_LOAD_DEFAULT if required?
+          error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_NO_AUTOHINT );
+        }
+        if( FT_Err_Ok == error )
+        {
+          if( isBoldRequired && !( ftFace->style_flags & FT_STYLE_FLAG_BOLD ) )
+          {
+            // Does the software bold.
+            FT_GlyphSlot_Embolden( ftFace->glyph );
+          }
+
+          if( isItalicRequired && !( ftFace->style_flags & FT_STYLE_FLAG_ITALIC ) )
+          {
+            // Will do the software italic.
+            isShearRequired = true;
+          }
+
+          FT_Glyph glyph;
+          error = FT_Get_Glyph( ftFace->glyph, &glyph );
+
+          // Convert to bitmap if necessary
+          if( FT_Err_Ok == error )
+          {
+            if( glyph->format != FT_GLYPH_FORMAT_BITMAP )
+            {
+              int offsetX = 0, offsetY = 0;
+              bool isOutlineGlyph = ( glyph->format == FT_GLYPH_FORMAT_OUTLINE && outlineWidth > 0 );
+
+              // Create a bitmap for the outline
+              if( isOutlineGlyph )
+              {
+                // Retrieve the horizontal and vertical distance from the current pen position to the
+                // left and top border of the glyph bitmap for a normal glyph before applying the outline.
+                if( FT_Err_Ok == error )
+                {
+                  FT_Glyph normalGlyph;
+                  error = FT_Get_Glyph( ftFace->glyph, &normalGlyph );
+
+                  error = FT_Glyph_To_Bitmap( &normalGlyph, FT_RENDER_MODE_NORMAL, 0, 1 );
+                  if( FT_Err_Ok == error )
+                  {
+                    FT_BitmapGlyph bitmapGlyph = reinterpret_cast< FT_BitmapGlyph >( normalGlyph );
+
+                    offsetX = bitmapGlyph->left;
+                    offsetY = bitmapGlyph->top;
+                  }
+
+                  // Created FT_Glyph object must be released with FT_Done_Glyph
+                  FT_Done_Glyph( normalGlyph );
+                }
+
+                // Now apply the outline
+
+                // Set up a stroker
+                FT_Stroker stroker;
+                error = FT_Stroker_New( mFreeTypeLibrary, &stroker );
+
+                if( FT_Err_Ok == error )
+                {
+                  FT_Stroker_Set( stroker, outlineWidth * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0 );
+                  error = FT_Glyph_StrokeBorder( &glyph, stroker, 0, 1 );
+
+                  if( FT_Err_Ok == error )
+                  {
+                    FT_Stroker_Done( stroker );
+                  }
+                  else
+                  {
+                    DALI_LOG_ERROR( "FT_Glyph_StrokeBorder Failed with error: %d\n", error );
+                  }
+                }
+                else
+                {
+                  DALI_LOG_ERROR( "FT_Stroker_New Failed with error: %d\n", error );
+                }
+              }
+
+              error = FT_Glyph_To_Bitmap( &glyph, FT_RENDER_MODE_NORMAL, 0, 1 );
+              if( FT_Err_Ok == error )
+              {
+                FT_BitmapGlyph bitmapGlyph = reinterpret_cast< FT_BitmapGlyph >( glyph );
+
+                if( isOutlineGlyph )
+                {
+                  // Calculate the additional horizontal and vertical offsets needed for the position of the outline glyph
+                  data.outlineOffsetX = offsetX - bitmapGlyph->left - outlineWidth;
+                  data.outlineOffsetY = bitmapGlyph->top - offsetY - outlineWidth;
+                }
+
+                ConvertBitmap( data, bitmapGlyph->bitmap, isShearRequired );
+              }
+              else
+              {
+                DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Get_Glyph Failed with error: %d\n", error );
+              }
+            }
+            else
+            {
+              ConvertBitmap( data, ftFace->glyph->bitmap, isShearRequired );
+            }
+
+            data.isColorEmoji = fontFaceCacheItem.mIsFixedSizeBitmap;
+
+            // Created FT_Glyph object must be released with FT_Done_Glyph
+            FT_Done_Glyph( glyph );
+          }
+        }
+        else
+        {
+          DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::CreateBitmap. FT_Load_Glyph Failed with error: %d\n", error );
+        }
+        break;
+      }
+      case FontDescription::BITMAP_FONT:
+      {
+        BitmapFontCacheItem& bitmapFontCacheItem = mBitmapFontCache[fontIdCacheItem.id];
+
+        unsigned int index = 0u;
+        for( auto& item : bitmapFontCacheItem.font.glyphs )
+        {
+          if( item.utf32 == glyphIndex )
+          {
+            Devel::PixelBuffer& pixelBuffer = bitmapFontCacheItem.pixelBuffers[index];
+            if( !pixelBuffer )
+            {
+              pixelBuffer = LoadImageFromFile( item.url );
+            }
+
+            data.width = pixelBuffer.GetWidth();
+            data.height = pixelBuffer.GetHeight();
+
+            data.isColorBitmap = bitmapFontCacheItem.font.isColorFont;
+
+            ConvertBitmap( data, data.width, data.height, pixelBuffer.GetBuffer() );
+
+            // Sets the pixel format.
+            data.format = pixelBuffer.GetPixelFormat();
+            break;
+          }
+          ++index;
+        }
+        break;
+      }
+      default:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
+      }
+    }
+  }
+  else
+  {
+    if( ( 0u != glyphIndex ) && ( glyphIndex <= mEmbeddedItemCache.Count() ) )
+    {
+      // It's an embedded item.
+      const EmbeddedItem& item = mEmbeddedItemCache[glyphIndex - 1u];
+
+      data.width = item.width;
+      data.height = item.height;
+      if( 0u != item.pixelBufferId )
+      {
+        Devel::PixelBuffer pixelBuffer = mPixelBufferCache[item.pixelBufferId-1u].pixelBuffer;
+        if( pixelBuffer )
+        {
+          ConvertBitmap( data, pixelBuffer.GetWidth(), pixelBuffer.GetHeight(), pixelBuffer.GetBuffer() );
+
+          // Sets the pixel format.
+          data.format = pixelBuffer.GetPixelFormat();
+        }
+      }
+      else
+      {
+        // Creates the output buffer
+        const unsigned int bufferSize = data.width * data.height * 4u;
+        data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
+
+        memset( data.buffer, 0u, bufferSize );
+
+        // Just creates a void buffer. Doesn't matter what pixel format is set as is the application code the responsible of filling it.
+      }
+    }
+  }
+}
+
+PixelData FontClient::Plugin::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
+{
+  TextAbstraction::FontClient::GlyphBufferData data;
+
+  CreateBitmap( fontId, glyphIndex, false, false, data, outlineWidth );
+
+  return PixelData::New( data.buffer,
+                         data.width * data.height * Pixel::GetBytesPerPixel( data.format ),
+                         data.width,
+                         data.height,
+                         data.format,
+                         PixelData::DELETE_ARRAY );
+}
+
+void FontClient::Plugin::CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight )
+{
+  blob = nullptr;
+  blobLength = 0;
+
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+  if( ( fontId > 0u ) &&
+      ( fontId - 1u < mFontIdCache.Count() ) )
+  {
+    const FontId fontFaceId = mFontIdCache[fontId - 1u].id;
+    FontFaceCacheItem& font = mFontFaceCache[fontFaceId];
+
+    if( ! font.mVectorFontId )
+    {
+      font.mVectorFontId = mVectorFontCache->GetFontId( font.mPath );
+    }
+
+    mVectorFontCache->GetVectorBlob( font.mVectorFontId, fontFaceId, glyphIndex, blob, blobLength, nominalWidth, nominalHeight );
+  }
+#endif
+}
+
+const GlyphInfo& FontClient::Plugin::GetEllipsisGlyph( PointSize26Dot6 requestedPointSize )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::GetEllipsisGlyph\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize %d.\n", requestedPointSize );
+
+  // First look into the cache if there is an ellipsis glyph for the requested point size.
+  for( const auto& item : mEllipsisCache )
+  {
+    if( item.requestedPointSize == requestedPointSize )
+    {
+      // Use the glyph in the cache.
+
+      DALI_LOG_INFO( gLogFilter, Debug::General, "  glyph id %d found in the cache.\n", item.glyph.index );
+      DALI_LOG_INFO( gLogFilter, Debug::General, "      font %d.\n", item.glyph.fontId );
+      DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
+
+      return item.glyph;
+    }
+  }
+
+  // No glyph has been found. Create one.
+  mEllipsisCache.PushBack( EllipsisItem() );
+  EllipsisItem& item = *( mEllipsisCache.End() - 1u );
+
+  item.requestedPointSize = requestedPointSize;
+
+  // Find a font for the ellipsis glyph.
+  item.glyph.fontId = FindDefaultFont( ELLIPSIS_CHARACTER,
+                                       requestedPointSize,
+                                       false );
+
+  // Set the character index to access the glyph inside the font.
+  item.glyph.index = FT_Get_Char_Index( mFontFaceCache[mFontIdCache[item.glyph.fontId-1u].id].mFreeTypeFace,
+                                        ELLIPSIS_CHARACTER );
+
+  GetBitmapMetrics( &item.glyph, 1u, true );
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  glyph id %d found in the cache.\n", item.glyph.index );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "      font %d.\n", item.glyph.fontId );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::GetEllipsisGlyph\n" );
+
+  return item.glyph;
+}
+
+bool FontClient::Plugin::IsColorGlyph( FontId fontId, GlyphIndex glyphIndex )
+{
+  FT_Error error = -1;
+
+  const FontId index = fontId - 1u;
+
+  if( ( fontId > 0u ) &&
+      ( index < mFontIdCache.Count() ) )
+  {
+    const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
+
+    switch( fontIdCacheItem.type )
+    {
+      case FontDescription::FACE_FONT:
+      {
+#ifdef FREETYPE_BITMAP_SUPPORT
+        const FontFaceCacheItem& item = mFontFaceCache[fontIdCacheItem.id];
+        FT_Face ftFace = item.mFreeTypeFace;
+
+        // Check to see if this is fixed size bitmap
+        if( item.mHasColorTables )
+        {
+          error = FT_Load_Glyph( ftFace, glyphIndex, FT_LOAD_COLOR );
+        }
+#endif
+        break;
+      }
+      case FontDescription::BITMAP_FONT:
+      {
+        error = FT_Err_Ok; // Will return true;
+        break;
+      }
+      default:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
+      }
+    }
+  }
+
+  return FT_Err_Ok == error;
+}
+
+FT_FaceRec_* FontClient::Plugin::GetFreetypeFace( FontId fontId )
+{
+  FT_Face fontFace = nullptr;
+
+  const FontId index = fontId - 1u;
+  if( ( fontId > 0u ) &&
+      ( index < mFontIdCache.Count() ) )
+  {
+    const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
+
+    if( FontDescription::FACE_FONT == fontIdCacheItem.type )
+    {
+      fontFace = mFontFaceCache[fontIdCacheItem.id].mFreeTypeFace;
+    }
+  }
+  return fontFace;
+}
+
+FontDescription::Type FontClient::Plugin::GetFontType( FontId fontId )
+{
+  const FontId index = fontId - 1u;
+  if( ( fontId > 0u ) &&
+      ( index < mFontIdCache.Count() ) )
+  {
+    return mFontIdCache[index].type;
+  }
+  return FontDescription::INVALID;
+}
+
+bool FontClient::Plugin::AddCustomFontDirectory( const FontPath& path )
+{
+  // nullptr as first parameter means the current configuration is used.
+  return FcConfigAppFontAddDir( nullptr, reinterpret_cast<const FcChar8 *>( path.c_str() ) );
+}
+
+GlyphIndex FontClient::Plugin::CreateEmbeddedItem( const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat )
+{
+  EmbeddedItem embeddedItem;
+
+  embeddedItem.pixelBufferId = 0u;
+  embeddedItem.width = description.width;
+  embeddedItem.height = description.height;
+
+  pixelFormat = Pixel::A8;
+
+  if( !description.url.empty() )
+  {
+    // Check if the url is in the cache.
+    PixelBufferId index = 0u;
+
+    for( const auto& cacheItem : mPixelBufferCache )
+    {
+      ++index;
+      if( cacheItem.url == description.url )
+      {
+        // The url is in the pixel buffer cache.
+        // Set the index +1 to the vector.
+        embeddedItem.pixelBufferId = index;
+        break;
+      }
+    }
+
+    Devel::PixelBuffer pixelBuffer;
+    if( 0u == embeddedItem.pixelBufferId )
+    {
+      // The pixel buffer is not in the cache. Create one and cache it.
+
+      // Load the image from the url.
+      pixelBuffer = LoadImageFromFile( description.url );
+
+      // Create the cache item.
+      PixelBufferCacheItem pixelBufferCacheItem;
+      pixelBufferCacheItem.pixelBuffer = pixelBuffer;
+      pixelBufferCacheItem.url = description.url;
+
+      // Store the cache item in the cache.
+      mPixelBufferCache.push_back( std::move( pixelBufferCacheItem ) );
+
+      // Set the pixel buffer id to the embedded item.
+      embeddedItem.pixelBufferId = mPixelBufferCache.size();
+    }
+    else
+    {
+      // Retrieve the pixel buffer from the cache to set the pixel format.
+      pixelBuffer = mPixelBufferCache[embeddedItem.pixelBufferId-1u].pixelBuffer;
+    }
+
+    if( pixelBuffer )
+    {
+      // Set the size of the embedded item if it has not been set.
+      if( 0u == embeddedItem.width )
+      {
+        embeddedItem.width = static_cast<unsigned int>( pixelBuffer.GetWidth() );
+      }
+
+      if( 0u == embeddedItem.height )
+      {
+        embeddedItem.height = static_cast<unsigned int>( pixelBuffer.GetHeight() );
+      }
+
+      // Set the pixel format.
+      pixelFormat = pixelBuffer.GetPixelFormat();
+    }
+  }
+
+  // Find if the same embeddedItem has already been created.
+  unsigned int index = 0u;
+  for( const auto& item : mEmbeddedItemCache )
+  {
+    ++index;
+    if( ( item.pixelBufferId == embeddedItem.pixelBufferId ) &&
+        ( item.width == embeddedItem.width ) &&
+        ( item.height == embeddedItem.height ) )
+    {
+      return index;
+    }
+  }
+
+  // Cache the embedded item.
+  mEmbeddedItemCache.PushBack( embeddedItem );
+
+  return mEmbeddedItemCache.Count();
+}
+
+void FontClient::Plugin::InitSystemFonts()
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::InitSystemFonts\n" );
+
+  FcFontSet* fontSet = GetFcFontSet(); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
+
+  if( fontSet )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "  number of system fonts : %d\n", fontSet->nfont );
+
+    // Reserve some space to avoid reallocations.
+    mSystemFonts.reserve( fontSet->nfont );
+
+    for( int i = 0u; i < fontSet->nfont; ++i )
+    {
+      FcPattern* fontPattern = fontSet->fonts[i];
+
+      FontPath path;
+
+      // Skip fonts with no path
+      if( GetFcString( fontPattern, FC_FILE, path ) )
+      {
+        mSystemFonts.push_back( FontDescription() );
+        FontDescription& fontDescription = mSystemFonts.back();
+
+        fontDescription.path = std::move( path );
+
+        int width = 0;
+        int weight = 0;
+        int slant = 0;
+        GetFcString( fontPattern, FC_FAMILY, fontDescription.family );
+        GetFcInt( fontPattern, FC_WIDTH, width );
+        GetFcInt( fontPattern, FC_WEIGHT, weight );
+        GetFcInt( fontPattern, FC_SLANT, slant );
+        fontDescription.width = IntToWidthType( width );
+        fontDescription.weight = IntToWeightType( weight );
+        fontDescription.slant = IntToSlantType( slant );
+
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  description; family : [%s]\n", fontDescription.family.c_str() );
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
+      }
+    }
+
+    // Destroys the font set created.
+    FcFontSetDestroy( fontSet );
+  }
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::InitSystemFonts\n" );
+}
+
+bool FontClient::Plugin::MatchFontDescriptionToPattern( FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, FcCharSet** characterSet )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::MatchFontDescriptionToPattern\n" );
+
+  FcResult result = FcResultMatch;
+  FcPattern* match = FcFontMatch( nullptr /* use default configure */, pattern, &result ); // Creates a new font pattern that needs to be destroyed by calling FcPatternDestroy.
+
+  const bool matched = nullptr != match;
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  pattern matched : %s\n", ( matched ? "true" : "false" ) );
+
+  if( matched )
+  {
+    int width = 0;
+    int weight = 0;
+    int slant = 0;
+    GetFcString( match, FC_FILE, fontDescription.path );
+    GetFcString( match, FC_FAMILY, fontDescription.family );
+    GetFcInt( match, FC_WIDTH, width );
+    GetFcInt( match, FC_WEIGHT, weight );
+    GetFcInt( match, FC_SLANT, slant );
+    fontDescription.width = IntToWidthType( width );
+    fontDescription.weight = IntToWeightType( weight );
+    fontDescription.slant = IntToSlantType( slant );
+
+    // Retrieve the character set and increase the reference counter.
+    FcPatternGetCharSet( match, FC_CHARSET, 0u, characterSet );
+    *characterSet = FcCharSetCopy( *characterSet );
+
+    // destroyed the matched pattern
+    FcPatternDestroy( match );
+
+    DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
+    DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::MatchFontDescriptionToPattern\n" );
+  return matched;
+}
+
+FcPattern* FontClient::Plugin::CreateFontFamilyPattern( const FontDescription& fontDescription ) const
+{
+  // create the cached font family lookup pattern
+  // a pattern holds a set of names, each name refers to a property of the font
+  FcPattern* fontFamilyPattern = FcPatternCreate(); // FcPatternCreate creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
+
+  if( !fontFamilyPattern )
+  {
+    return nullptr;
+  }
+
+  // add a property to the pattern for the font family
+  FcPatternAddString( fontFamilyPattern, FC_FAMILY, reinterpret_cast<const FcChar8*>( fontDescription.family.c_str() ) );
+
+  // add a property to the pattern for local setting.
+  const char* locale = setlocale( LC_MESSAGES, nullptr );
+  if( locale != nullptr)
+  {
+    FcPatternAddString( fontFamilyPattern, FC_LANG, reinterpret_cast<const FcChar8*>( locale ) );
+  }
+
+  int width = FONT_WIDTH_TYPE_TO_INT[fontDescription.width];
+  if( width < 0 )
+  {
+    // Use default.
+    width = DEFAULT_FONT_WIDTH;
+  }
+
+  int weight = FONT_WEIGHT_TYPE_TO_INT[fontDescription.weight];
+  if( weight < 0 )
+  {
+    // Use default.
+    weight = DEFAULT_FONT_WEIGHT;
+  }
+
+  int slant = FONT_SLANT_TYPE_TO_INT[fontDescription.slant];
+  if( slant < 0 )
+  {
+    // Use default.
+    slant = DEFAULT_FONT_SLANT;
+  }
+
+  FcPatternAddInteger( fontFamilyPattern, FC_WIDTH, width );
+  FcPatternAddInteger( fontFamilyPattern, FC_WEIGHT, weight );
+  FcPatternAddInteger( fontFamilyPattern, FC_SLANT, slant );
+
+  // modify the config, with the mFontFamilyPatterm
+  FcConfigSubstitute( nullptr /* use default configure */, fontFamilyPattern, FcMatchPattern );
+
+  // provide default values for unspecified properties in the font pattern
+  // e.g. patterns without a specified style or weight are set to Medium
+  FcDefaultSubstitute( fontFamilyPattern );
+
+  return fontFamilyPattern;
+}
+
+_FcFontSet* FontClient::Plugin::GetFcFontSet() const
+{
+  FcFontSet* fontset = nullptr;
+
+  // create a new pattern.
+  // a pattern holds a set of names, each name refers to a property of the font
+  FcPattern* pattern = FcPatternCreate();
+
+  if( nullptr != pattern )
+  {
+    // create an object set used to define which properties are to be returned in the patterns from FcFontList.
+    FcObjectSet* objectSet = FcObjectSetCreate();
+
+    if( nullptr != objectSet )
+    {
+      // build an object set from a list of property names
+      FcObjectSetAdd( objectSet, FC_FILE );
+      FcObjectSetAdd( objectSet, FC_FAMILY );
+      FcObjectSetAdd( objectSet, FC_WIDTH );
+      FcObjectSetAdd( objectSet, FC_WEIGHT );
+      FcObjectSetAdd( objectSet, FC_SLANT );
+
+      // get a list of fonts
+      // creates patterns from those fonts containing only the objects in objectSet and returns the set of unique such patterns
+      fontset = FcFontList( nullptr /* the default configuration is checked to be up to date, and used */, pattern, objectSet ); // Creates a FcFontSet that needs to be destroyed by calling FcFontSetDestroy.
+
+      // clear up the object set
+      FcObjectSetDestroy( objectSet );
+    }
+
+    // clear up the pattern
+    FcPatternDestroy( pattern );
+  }
+
+  return fontset;
+}
+
+bool FontClient::Plugin::GetFcString( const FcPattern* const pattern,
+                                      const char* const n,
+                                      std::string& string )
+{
+  FcChar8* file = nullptr;
+  const FcResult retVal = FcPatternGetString( pattern, n, 0u, &file );
+
+  if( FcResultMatch == retVal )
+  {
+    // Have to use reinterpret_cast because FcChar8 is unsigned char*, not a const char*.
+    string.assign( reinterpret_cast<const char*>( file ) );
+
+    return true;
+  }
+
+  return false;
+}
+
+bool FontClient::Plugin::GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal )
+{
+  const FcResult retVal = FcPatternGetInteger( pattern, n, 0u, &intVal );
+
+  if( FcResultMatch == retVal )
+  {
+    return true;
+  }
+
+  return false;
+}
+
+FontId FontClient::Plugin::CreateFont( const FontPath& path,
+                                       PointSize26Dot6 requestedPointSize,
+                                       FaceIndex faceIndex,
+                                       bool cacheDescription )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::CreateFont\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
+
+  FontId id = 0u;
+
+  // Create & cache new font face
+  FT_Face ftFace;
+  int error = FT_New_Face( mFreeTypeLibrary,
+                           path.c_str(),
+                           0,
+                           &ftFace );
+
+  if( FT_Err_Ok == error )
+  {
+    // Check if a font is scalable.
+    const bool isScalable = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_SCALABLE ) );
+    const bool hasFixedSizedBitmaps = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_FIXED_SIZES ) ) && ( 0 != ftFace->num_fixed_sizes );
+    const bool hasColorTables = ( 0 != ( ftFace->face_flags & FT_FACE_FLAG_COLOR ) );
+    FontId fontFaceId = 0u;
+
+    DALI_LOG_INFO( gLogFilter, Debug::General, "            isScalable : [%s]\n", ( isScalable ? "true" : "false" ) );
+    DALI_LOG_INFO( gLogFilter, Debug::General, "  hasFixedSizedBitmaps : [%s]\n", ( hasFixedSizedBitmaps ? "true" : "false" ) );
+    DALI_LOG_INFO( gLogFilter, Debug::General, "        hasColorTables : [%s]\n", ( hasColorTables ? "true" : "false" ) );
+
+    // Check to see if the font contains fixed sizes?
+    if( !isScalable && hasFixedSizedBitmaps )
+    {
+      PointSize26Dot6 actualPointSize = 0u;
+      int fixedSizeIndex = 0;
+      for( ; fixedSizeIndex < ftFace->num_fixed_sizes; ++fixedSizeIndex )
+      {
+        const PointSize26Dot6 fixedSize = ftFace->available_sizes[fixedSizeIndex].size;
+        DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  size index : %d, size : %d\n", fixedSizeIndex, fixedSize );
+
+        if( fixedSize >= requestedPointSize )
+        {
+          actualPointSize = fixedSize;
+          break;
+        }
+      }
+
+      if( 0u == actualPointSize )
+      {
+        // The requested point size is bigger than the bigest fixed size.
+        fixedSizeIndex = ftFace->num_fixed_sizes - 1;
+        actualPointSize = ftFace->available_sizes[fixedSizeIndex].size;
+      }
+
+      DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  size index : %d, actual size : %d\n", fixedSizeIndex, actualPointSize );
+
+      // Tell Freetype to use this size
+      error = FT_Select_Size( ftFace, fixedSizeIndex );
+      if ( FT_Err_Ok != error )
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::General, "FreeType Select_Size error: %d\n", error );
+      }
+      else
+      {
+        const float fixedWidth  = static_cast<float>( ftFace->available_sizes[ fixedSizeIndex ].width );
+        const float fixedHeight = static_cast<float>( ftFace->available_sizes[ fixedSizeIndex ].height );
+
+        // Indicate that the font is a fixed sized bitmap
+        FontMetrics metrics( fixedHeight, // The ascender in pixels.
+                             0.0f,
+                             fixedHeight, // The height in pixels.
+                             0.0f,
+                             0.0f );
+
+        // Create the FreeType font face item to cache.
+        FontFaceCacheItem fontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics, fixedSizeIndex, fixedWidth, fixedHeight, hasColorTables );
+
+        // Set the index to the font's id cache.
+        fontFaceCacheItem.mFontId = mFontIdCache.Count();
+
+        // Create the font id item to cache.
+        FontIdCacheItem fontIdCacheItem;
+        fontIdCacheItem.type = FontDescription::FACE_FONT;
+
+        // Set the index to the FreeType font face cache.
+        fontIdCacheItem.id = mFontFaceCache.size();
+        fontFaceId = fontIdCacheItem.id + 1u;
+
+        // Cache the items.
+        mFontFaceCache.push_back( fontFaceCacheItem );
+        mFontIdCache.PushBack( fontIdCacheItem );
+
+        // Set the font id to be returned.
+        id = mFontIdCache.Count();
+      }
+    }
+    else
+    {
+      error = FT_Set_Char_Size( ftFace,
+                                0,
+                                requestedPointSize,
+                                mDpiHorizontal,
+                                mDpiVertical );
+
+      if( FT_Err_Ok == error )
+      {
+
+        FT_Size_Metrics& ftMetrics = ftFace->size->metrics;
+
+        FontMetrics metrics( static_cast< float >( ftMetrics.ascender  ) * FROM_266,
+                             static_cast< float >( ftMetrics.descender ) * FROM_266,
+                             static_cast< float >( ftMetrics.height    ) * FROM_266,
+                             static_cast< float >( ftFace->underline_position ) * FROM_266,
+                             static_cast< float >( ftFace->underline_thickness ) * FROM_266 );
+
+        // Create the FreeType font face item to cache.
+        FontFaceCacheItem fontFaceCacheItem( ftFace, path, requestedPointSize, faceIndex, metrics );
+
+        // Set the index to the font's id cache.
+        fontFaceCacheItem.mFontId = mFontIdCache.Count();
+
+        // Create the font id item to cache.
+        FontIdCacheItem fontIdCacheItem;
+        fontIdCacheItem.type = FontDescription::FACE_FONT;
+
+        // Set the index to the FreeType font face cache.
+        fontIdCacheItem.id = mFontFaceCache.size();
+        fontFaceId = fontIdCacheItem.id + 1u;
+
+        // Cache the items.
+        mFontFaceCache.push_back( fontFaceCacheItem );
+        mFontIdCache.PushBack( fontIdCacheItem );
+
+        // Set the font id to be returned.
+        id = mFontIdCache.Count();
+      }
+      else
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::General, "  FreeType Set_Char_Size error: %d for pointSize %d\n", error, requestedPointSize );
+      }
+    }
+
+    if( 0u != fontFaceId )
+    {
+      if( cacheDescription )
+      {
+        CacheFontPath( ftFace, fontFaceId, requestedPointSize, path );
+      }
+    }
+  }
+  else
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "  FreeType New_Face error: %d for [%s]\n", error, path.c_str() );
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  font id : %d\n", id );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::CreateFont\n" );
+
+  return id;
+}
+
+void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, unsigned int srcWidth, unsigned int srcHeight, const unsigned char* const srcBuffer )
+{
+  // Set the input dimensions.
+  const ImageDimensions inputDimensions( srcWidth, srcHeight );
+
+  // Set the output dimensions.
+  // If the output dimension is not given, the input dimension is set
+  // and won't be downscaling.
+  data.width = ( data.width == 0 ) ? srcWidth : data.width;
+  data.height = ( data.height == 0 ) ? srcHeight : data.height;
+  const ImageDimensions desiredDimensions( data.width, data.height );
+
+  // Creates the output buffer
+  const unsigned int bufferSize = data.width * data.height * 4u;
+  data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
+
+  if( inputDimensions == desiredDimensions )
+  {
+    // There isn't downscaling.
+    memcpy( data.buffer, srcBuffer, bufferSize );
+  }
+  else
+  {
+    Dali::Internal::Platform::LanczosSample4BPP( srcBuffer,
+                                                 inputDimensions,
+                                                 data.buffer,
+                                                 desiredDimensions );
+  }
+}
+
+void FontClient::Plugin::ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap, bool isShearRequired )
+{
+  if( srcBitmap.width*srcBitmap.rows > 0 )
+  {
+    switch( srcBitmap.pixel_mode )
+    {
+      case FT_PIXEL_MODE_GRAY:
+      {
+        if( srcBitmap.pitch == static_cast<int>( srcBitmap.width ) )
+        {
+          uint8_t* pixelsIn = srcBitmap.buffer;
+          unsigned int width = srcBitmap.width;
+          unsigned height = srcBitmap.rows;
+
+          std::unique_ptr<uint8_t, void(*)(void*)> pixelsOutPtr( nullptr, free );
+
+          if( isShearRequired )
+          {
+            /**
+             * Glyphs' bitmaps with no slant retrieved from FreeType:
+             * __________     ____
+             * |XXXXXXXX|     |XX|
+             * |   XX   |     |XX|
+             * |   XX   |     |XX|
+             * |   XX   |     |XX|
+             * |   XX   |     |XX|
+             * |   XX   |     |XX|
+             * ----------     ----
+             *
+             * Expected glyphs' bitmaps with italic slant:
+             * ____________   ______
+             * |  XXXXXXXX|   |  XX|
+             * |     XX   |   |  XX|
+             * |    XX    |   | XX |
+             * |    XX    |   | XX |
+             * |   XX     |   |XX  |
+             * |   XX     |   |XX  |
+             * ------------   ------
+             *
+             * Glyphs' bitmaps with software italic slant retrieved from FreeType:
+             * __________     ______
+             * |XXXXXXXX|     |  XX|
+             * |   XX   |     |  XX|
+             * |  XX    |     | XX |
+             * |  XX    |     | XX |
+             * | XX     |     |XX  |
+             * | XX     |     |XX  |
+             * ----------     ------
+             *
+             * This difference in some bitmaps' width causes an overlap of some glyphs. This is the reason why a shear operation is done here instead of relying on the experimental FT_GlyphSlot_Oblique() implementation.
+             */
+            unsigned int widthOut = 0u;
+            unsigned int heightOut = 0u;
+            uint8_t* pixelsOut = nullptr;
+
+            Dali::Internal::Platform::HorizontalShear( pixelsIn,
+                                                       width,
+                                                       height,
+                                                       1u,
+                                                       -TextAbstraction::FontClient::DEFAULT_ITALIC_ANGLE,
+                                                       pixelsOut,
+                                                       widthOut,
+                                                       heightOut );
+
+            width = widthOut;
+            height = heightOut;
+            pixelsIn = pixelsOut;
+            pixelsOutPtr.reset( pixelsOut );
+          }
+
+          const unsigned int bufferSize = width * height;
+          data.buffer = new unsigned char[bufferSize]; // @note The caller is responsible for deallocating the bitmap data using delete[].
+          data.width = width;
+          data.height = height;
+          data.format = Pixel::L8; // Sets the pixel format.
+          memcpy( data.buffer, pixelsIn, bufferSize );
+        }
+        break;
+      }
+
+#ifdef FREETYPE_BITMAP_SUPPORT
+      case FT_PIXEL_MODE_BGRA:
+      {
+        if( srcBitmap.pitch == static_cast<int>( srcBitmap.width << 2u ) )
+        {
+          ConvertBitmap( data, srcBitmap.width, srcBitmap.rows, srcBitmap.buffer );
+
+          // Sets the pixel format.
+          data.format = Pixel::BGRA8888;
+        }
+        break;
+      }
+#endif
+      default:
+      {
+        DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::ConvertBitmap. FontClient Unable to create Bitmap of this PixelType\n" );
+        break;
+      }
+    }
+  }
+}
+
+bool FontClient::Plugin::FindFont( const FontPath& path,
+                                   PointSize26Dot6 requestedPointSize,
+                                   FaceIndex faceIndex,
+                                   FontId& fontId ) const
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "                path : [%s]\n", path.c_str() );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of fonts in the cache : %d\n", mFontFaceCache.size() );
+
+  fontId = 0u;
+  for( const auto& cacheItem : mFontFaceCache )
+  {
+    if( cacheItem.mRequestedPointSize == requestedPointSize &&
+        cacheItem.mFaceIndex == faceIndex &&
+        cacheItem.mPath == path )
+    {
+      fontId = cacheItem.mFontId + 1u;
+
+      DALI_LOG_INFO( gLogFilter, Debug::General, "  font found, id : %d\n", fontId );
+      DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
+
+      return true;
+    }
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  font not found\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
+
+  return false;
+}
+
+bool FontClient::Plugin::FindValidatedFont( const FontDescription& fontDescription,
+                                            FontDescriptionId& validatedFontId )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindValidatedFont\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of validated fonts in the cache : %d\n", mValidatedFontCache.size() );
+
+  validatedFontId = 0u;
+
+  for( const auto& item : mValidatedFontCache )
+  {
+    if( !fontDescription.family.empty() &&
+        ( fontDescription.family == item.fontDescription.family ) &&
+        ( fontDescription.width == item.fontDescription.width ) &&
+        ( fontDescription.weight == item.fontDescription.weight ) &&
+        ( fontDescription.slant == item.fontDescription.slant ) )
+    {
+      validatedFontId = item.index;
+
+      DALI_LOG_INFO( gLogFilter, Debug::General, "  validated font found, id : %d\n", validatedFontId );
+      DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
+      return true;
+    }
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  validated font not found\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindValidatedFont\n" );
+  return false;
+}
+
+bool FontClient::Plugin::FindFallbackFontList( const FontDescription& fontDescription,
+                                               FontList*& fontList,
+                                               CharacterSetList*& characterSetList )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFallbackFontList\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  description; family : [%s]\n", fontDescription.family.c_str() );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                 path : [%s]\n", fontDescription.path.c_str() );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                width : [%s]\n", FontWidth::Name[fontDescription.width] );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "               weight : [%s]\n", FontWeight::Name[fontDescription.weight] );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "                slant : [%s]\n\n", FontSlant::Name[fontDescription.slant] );
+  DALI_LOG_INFO( gLogFilter, Debug::Verbose, "  number of fallback font lists in the cache : %d\n", mFallbackCache.size() );
+
+  fontList = nullptr;
+
+  for( const auto& item : mFallbackCache )
+  {
+    if( !fontDescription.family.empty() &&
+        ( fontDescription.family == item.fontDescription.family ) &&
+        ( fontDescription.width == item.fontDescription.width ) &&
+        ( fontDescription.weight == item.fontDescription.weight ) &&
+        ( fontDescription.slant == item.fontDescription.slant ) )
+    {
+      fontList = item.fallbackFonts;
+      characterSetList = item.characterSets;
+
+      DALI_LOG_INFO( gLogFilter, Debug::General, "  fallback font list found.\n" );
+      DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
+      return true;
+    }
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  fallback font list not found.\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFallbackFontList\n" );
+  return false;
+}
+
+bool FontClient::Plugin::FindFont( FontDescriptionId validatedFontId,
+                                   PointSize26Dot6 requestedPointSize,
+                                   FontId& fontId )
+{
+  DALI_LOG_INFO( gLogFilter, Debug::General, "-->FontClient::Plugin::FindFont\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "    validatedFontId  : %d\n", validatedFontId );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  requestedPointSize : %d\n", requestedPointSize );
+
+  fontId = 0u;
+
+  for( const auto& item : mFontDescriptionSizeCache )
+  {
+    if( ( validatedFontId == item.validatedFontId ) &&
+        ( requestedPointSize == item.requestedPointSize ) )
+    {
+      fontId = item.fontId;
+
+      DALI_LOG_INFO( gLogFilter, Debug::General, "  font found, id : %d\n", fontId );
+      DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
+      return true;
+    }
+  }
+
+  DALI_LOG_INFO( gLogFilter, Debug::General, "  font not found.\n" );
+  DALI_LOG_INFO( gLogFilter, Debug::General, "<--FontClient::Plugin::FindFont\n" );
+  return false;
+}
+
+bool FontClient::Plugin::FindBitmapFont( const FontFamily& bitmapFont, FontId& fontId ) const
+{
+  fontId = 0u;
+
+  for( const auto& item : mBitmapFontCache )
+  {
+    if( bitmapFont == item.font.name )
+    {
+      fontId = item.id + 1u;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+bool FontClient::Plugin::IsScalable( const FontPath& path )
+{
+  bool isScalable = false;
+
+  FT_Face ftFace;
+  int error = FT_New_Face( mFreeTypeLibrary,
+                           path.c_str(),
+                           0,
+                           &ftFace );
+  if( FT_Err_Ok != error )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: %s\n", path.c_str() );
+  }
+  else
+  {
+    isScalable = ftFace->face_flags & FT_FACE_FLAG_SCALABLE;
+  }
+
+  return isScalable;
+}
+
+bool FontClient::Plugin::IsScalable( const FontDescription& fontDescription )
+{
+  // Create a font pattern.
+  FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription ); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
+
+  FcResult result = FcResultMatch;
+
+  // match the pattern
+  FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result ); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
+  bool isScalable = false;
+
+  if( match )
+  {
+    // Get the path to the font file name.
+    FontPath path;
+    GetFcString( match, FC_FILE, path );
+    isScalable = IsScalable( path );
+  }
+  else
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::IsScalable. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
+  }
+
+  // Destroys the created patterns.
+  FcPatternDestroy( match );
+  FcPatternDestroy( fontFamilyPattern );
+
+  return isScalable;
+}
+
+void FontClient::Plugin::GetFixedSizes( const FontPath& path, Vector< PointSize26Dot6 >& sizes )
+{
+  // Empty the caller container
+  sizes.Clear();
+
+  FT_Face ftFace;
+  int error = FT_New_Face( mFreeTypeLibrary,
+                           path.c_str(),
+                           0,
+                           &ftFace );
+  if( FT_Err_Ok != error )
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font path : [%s]\n", path.c_str() );
+  }
+
+  // Fetch the number of fixed sizes available
+  if ( ftFace->num_fixed_sizes && ftFace->available_sizes )
+  {
+    for ( int i = 0; i < ftFace->num_fixed_sizes; ++i )
+    {
+      sizes.PushBack( ftFace->available_sizes[ i ].size );
+    }
+  }
+}
+
+void FontClient::Plugin::GetFixedSizes( const FontDescription& fontDescription,
+                                        Vector< PointSize26Dot6 >& sizes )
+{
+  // Create a font pattern.
+  FcPattern* fontFamilyPattern = CreateFontFamilyPattern( fontDescription ); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
+
+  FcResult result = FcResultMatch;
+
+  // match the pattern
+  FcPattern* match = FcFontMatch( nullptr /* use default configure */, fontFamilyPattern, &result ); // Creates a font pattern that needs to be destroyed by calling FcPatternDestroy.
+
+  if( match )
+  {
+    // Get the path to the font file name.
+    FontPath path;
+    GetFcString( match, FC_FILE, path );
+    GetFixedSizes( path, sizes );
+  }
+  else
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFixedSizes. FreeType Cannot check font: [%s]\n", fontDescription.family.c_str() );
+  }
+
+  // Destroys the created patterns.
+  FcPatternDestroy( match );
+  FcPatternDestroy( fontFamilyPattern );
+}
+
+bool FontClient::Plugin::HasItalicStyle( FontId fontId ) const
+{
+  bool hasItalicStyle = false;
+
+  const FontId index = fontId - 1u;
+
+  if( ( fontId > 0 ) &&
+      ( index < mFontIdCache.Count() ) )
+  {
+    const FontIdCacheItem& fontIdCacheItem = mFontIdCache[index];
+
+    if( FontDescription::FACE_FONT == fontIdCacheItem.type )
+    {
+      const FontFaceCacheItem& font = mFontFaceCache[fontIdCacheItem.id];
+
+      hasItalicStyle = 0u != ( font.mFreeTypeFace->style_flags & FT_STYLE_FLAG_ITALIC );
+    }
+  }
+  else
+  {
+    DALI_LOG_INFO( gLogFilter, Debug::General, "FontClient::Plugin::GetFontMetrics. Invalid font id : %d\n", fontId );
+  }
+
+  return hasItalicStyle;
+}
+
+void FontClient::Plugin::CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize,  const FontPath& path )
+{
+  FontDescription description;
+  description.path = path;
+  description.family = std::move( FontFamily( ftFace->family_name ) );
+  description.weight = FontWeight::NONE;
+  description.width = FontWidth::NONE;
+  description.slant = FontSlant::NONE;
+
+  // Note FreeType doesn't give too much info to build a proper font style.
+  if( ftFace->style_flags & FT_STYLE_FLAG_ITALIC )
+  {
+    description.slant = FontSlant::ITALIC;
+  }
+  if( ftFace->style_flags & FT_STYLE_FLAG_BOLD )
+  {
+    description.weight = FontWeight::BOLD;
+  }
+
+  FontDescriptionId validatedFontId = 0u;
+  if( !FindValidatedFont( description,
+                          validatedFontId ) )
+  {
+    FcPattern* pattern = CreateFontFamilyPattern( description ); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
+
+    FcResult result = FcResultMatch;
+    FcPattern* match = FcFontMatch( nullptr, pattern, &result ); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
+
+    FcCharSet* characterSet = nullptr;
+    FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
+
+    const FontId fontFaceId = id - 1u;
+    mFontFaceCache[fontFaceId].mCharacterSet = FcCharSetCopy( characterSet ); // Increases the reference counter.
+
+    // Destroys the created patterns.
+    FcPatternDestroy( match );
+    FcPatternDestroy( pattern );
+
+    // Add the path to the cache.
+    description.type = FontDescription::FACE_FONT;
+    mFontDescriptionCache.push_back( description );
+
+    // Set the index to the vector of paths to font file names.
+    validatedFontId = mFontDescriptionCache.size();
+
+    // Increase the reference counter and add the character set to the cache.
+    mCharacterSetCache.PushBack( FcCharSetCopy( characterSet ) );
+
+    // Cache the index and the font's description.
+    mValidatedFontCache.push_back( std::move( FontDescriptionCacheItem( std::move( description ),
+                                                                        validatedFontId) ) );
+
+    // Cache the pair 'validatedFontId, requestedPointSize' to improve the following queries.
+    mFontDescriptionSizeCache.push_back( FontDescriptionSizeCacheItem( validatedFontId,
+                                                                       requestedPointSize,
+                                                                       fontFaceId ) );
+  }
+}
+
+FcCharSet* FontClient::Plugin::CreateCharacterSetFromDescription( const FontDescription& description )
+{
+  FcCharSet* characterSet = nullptr;
+
+  FcPattern* pattern = CreateFontFamilyPattern( description ); // Creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
+
+  if( nullptr != pattern )
+  {
+    FcResult result = FcResultMatch;
+    FcPattern* match = FcFontMatch( nullptr, pattern, &result ); // FcFontMatch creates a new pattern that needs to be destroyed by calling FcPatternDestroy.
+
+    FcPatternGetCharSet( match, FC_CHARSET, 0u, &characterSet );
+
+    // Destroys the created patterns.
+    FcPatternDestroy( match );
+    FcPatternDestroy( pattern );
+  }
+
+  return characterSet;
+}
+
+void FontClient::Plugin::ClearFallbackCache( std::vector<FallbackCacheItem>& fallbackCache )
+{
+  for( auto& item : fallbackCache )
+  {
+    if( nullptr != item.fallbackFonts )
+    {
+      delete item.fallbackFonts;
+    }
+
+    if( nullptr != item.characterSets )
+    {
+      // Free the resources allocated by the FcCharSet objects in the 'characterSets' vector.
+      DestroyCharacterSets( *item.characterSets );
+      delete item.characterSets;
+    }
+  }
+}
+
+void FontClient::Plugin::ClearCharacterSetFromFontFaceCache()
+{
+  for( auto& item : mFontFaceCache )
+  {
+    FcCharSetDestroy( item.mCharacterSet );
+    item.mCharacterSet = nullptr;
+  }
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/internal/text/text-abstraction/font-client-plugin-impl.h b/dali/internal/text/text-abstraction/font-client-plugin-impl.h
new file mode 100755 (executable)
index 0000000..9775238
--- /dev/null
@@ -0,0 +1,666 @@
+#ifndef DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_PLUGIN_IMPL_H
+#define DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_PLUGIN_IMPL_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/text-abstraction/bitmap-font.h>
+#include <dali/devel-api/text-abstraction/font-metrics.h>
+#include <dali/devel-api/text-abstraction/glyph-info.h>
+#include <dali/internal/text/text-abstraction/font-client-impl.h>
+#include <dali/devel-api/adaptor-framework/pixel-buffer.h>
+
+#ifdef ENABLE_VECTOR_BASED_TEXT_RENDERING
+#include <dali/internal/text/glyphy/vector-font-cache.h>
+#else
+class VectorFontCache;
+#endif
+
+// EXTERNAL INCLUDES
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include FT_OUTLINE_H
+#include FT_STROKER_H
+#include FT_SYNTHESIS_H
+
+// forward declarations of font config types.
+struct _FcCharSet;
+struct _FcFontSet;
+struct _FcPattern;
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * @brief Type used for indices addressing the vector with front descriptions of validated fonts.
+ */
+typedef uint32_t FontDescriptionId;
+
+/**
+ * @brief Type used for indices addressing the vector with pixel buffers.
+ */
+typedef uint32_t PixelBufferId;
+
+/**
+ * @brief Vector of character sets.
+ */
+typedef Vector<_FcCharSet*> CharacterSetList;
+
+/**
+ * @brief FontClient implementation.
+ */
+struct FontClient::Plugin
+{
+  struct FontIdCacheItem
+  {
+    FontDescription::Type type; ///< The type of font.
+    FontId                id;   ///< Index to the cache of fonts for the specified type.
+  };
+
+  /**
+   * @brief Caches an list of fallback fonts for a given font-description
+   */
+  struct FallbackCacheItem
+  {
+    FallbackCacheItem( FontDescription&& fontDescription, FontList* fallbackFonts, CharacterSetList* characterSets );
+
+    FontDescription fontDescription; ///< The font description.
+    FontList* fallbackFonts;         ///< The list of fallback fonts for the given font-description.
+    CharacterSetList* characterSets; ///< The list of character sets for the given font-description.
+  };
+
+  /**
+   * @brief Caches an index to the vector of font descriptions for a given font.
+   */
+  struct FontDescriptionCacheItem
+  {
+    FontDescriptionCacheItem( const FontDescription& fontDescription,
+                              FontDescriptionId index );
+    FontDescriptionCacheItem( FontDescription&& fontDescription,
+                              FontDescriptionId index );
+
+    FontDescription fontDescription; ///< The font description.
+    FontDescriptionId index;         ///< Index to the vector of font descriptions.
+  };
+
+  /**
+   * @brief Caches the font id of the pair font point size and the index to the vector of font descriptions of validated fonts.
+   */
+  struct FontDescriptionSizeCacheItem
+  {
+    FontDescriptionSizeCacheItem( FontDescriptionId validatedFontId,
+                                  PointSize26Dot6 requestedPointSize,
+                                  FontId fontId );
+
+    FontDescriptionId validatedFontId;    ///< Index to the vector with font descriptions.
+    PointSize26Dot6   requestedPointSize; ///< The font point size.
+    FontId            fontId;             ///< The font identifier.
+  };
+
+  /**
+   * @brief Caches the FreeType face and font metrics of the triplet 'path to the font file name, font point size and face index'.
+   */
+  struct FontFaceCacheItem
+  {
+    FontFaceCacheItem( FT_Face ftFace,
+                       const FontPath& path,
+                       PointSize26Dot6 requestedPointSize,
+                       FaceIndex face,
+                       const FontMetrics& metrics );
+
+    FontFaceCacheItem( FT_Face ftFace,
+                       const FontPath& path,
+                       PointSize26Dot6 requestedPointSize,
+                       FaceIndex face,
+                       const FontMetrics& metrics,
+                       int fixedSizeIndex,
+                       float fixedWidth,
+                       float fixedHeight,
+                       bool hasColorTables );
+
+    FT_Face mFreeTypeFace;               ///< The FreeType face.
+    FontPath mPath;                      ///< The path to the font file name.
+    PointSize26Dot6 mRequestedPointSize; ///< The font point size.
+    FaceIndex mFaceIndex;                ///< The face index.
+    FontMetrics mMetrics;                ///< The font metrics.
+    _FcCharSet* mCharacterSet;           ///< Pointer with the range of characters.
+    int mFixedSizeIndex;                 ///< Index to the fixed size table for the requested size.
+    float mFixedWidthPixels;             ///< The height in pixels (fixed size bitmaps only)
+    float mFixedHeightPixels;            ///< The height in pixels (fixed size bitmaps only)
+    unsigned int mVectorFontId;          ///< The ID of the equivalent vector-based font
+    FontId mFontId;                      ///< Index to the vector with the cache of font's ids.
+    bool mIsFixedSizeBitmap : 1;         ///< Whether the font has fixed size bitmaps.
+    bool mHasColorTables    : 1;         ///< Whether the font has color tables.
+  };
+
+  struct EllipsisItem
+  {
+    PointSize26Dot6 requestedPointSize;
+    GlyphInfo glyph;
+  };
+
+  /**
+   * @brief Caches pixel buffers.
+   */
+  struct PixelBufferCacheItem
+  {
+    Devel::PixelBuffer pixelBuffer; ///< The pixel buffer loaded from the url.
+    std::string url;                ///< The url.
+  };
+
+  /**
+   * @brief Caches embedded items.
+   */
+  struct EmbeddedItem
+  {
+    PixelBufferId pixelBufferId; ///< Index to the vector of pixel buffers
+    unsigned int width;          ///< The desired width.
+    unsigned int height;         ///< The desired height.
+  };
+
+  /**
+   * @brief Stores a bitmap font and its pixel buffers per glyph.
+   */
+  struct BitmapFontCacheItem
+  {
+    BitmapFont font;                              ///< The bitmap font.
+    std::vector<Devel::PixelBuffer> pixelBuffers; ///< The pixel buffers of the glyphs.
+    FontId id;                                    ///< Index to the vector with the cache of font's ids.
+  };
+
+  /**
+   * Constructor.
+   *
+   * Initializes the FreeType library.
+   * Initializes the dpi values.
+   *
+   * @param[in] horizontalDpi The horizontal dpi.
+   * @param[in] verticalDpi The vertical dpi.
+   */
+  Plugin( unsigned int horizontalDpi, unsigned int verticalDpi );
+
+  /**
+   * Default destructor.
+   *
+   * Frees any allocated resource.
+   */
+  ~Plugin();
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::ClearCache()
+   */
+  void ClearCache();
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::SetDpi()
+   */
+  void SetDpi( unsigned int horizontalDpi, unsigned int verticalDpi );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::ResetSystemDefaults()
+   */
+  void ResetSystemDefaults();
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::SetDefaultFont()
+   */
+  void SetDefaultFont( const FontDescription& preferredFontDescription );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetDefaultPlatformFontDescription()
+   */
+  void GetDefaultPlatformFontDescription( FontDescription& fontDescription );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetDefaultFonts()
+   */
+  void GetDefaultFonts( FontList& defaultFonts );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetSystemFonts()
+   */
+  void GetSystemFonts( FontList& systemFonts );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetDescription()
+   */
+  void GetDescription( FontId id, FontDescription& fontDescription ) const;
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetPointSize()
+   */
+  PointSize26Dot6 GetPointSize( FontId id );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::IsCharacterSupportedByFont()
+   */
+  bool IsCharacterSupportedByFont( FontId fontId, Character character );
+
+  /**
+   * @brief Finds within the @p fontList a font which support the @p carcode.
+   *
+   * @param[in] fontList A list of font paths, family, width, weight and slant.
+   * @param[in] characterSetList A list that contains a character set for each description of the font list.
+   * @param[in] charcode The character for which a font is needed.
+   * @param[in] requestedPointSize The point size in 26.6 fractional points.
+   * @param[in] preferColor @e true if a color font is preferred.
+   *
+   * @return A valid font identifier, or zero if no font is found.
+   */
+  FontId FindFontForCharacter( const FontList& fontList,
+                               const CharacterSetList& characterSetList,
+                               Character charcode,
+                               PointSize26Dot6 requestedPointSize,
+                               bool preferColor );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::FindDefaultFont()
+   */
+  FontId FindDefaultFont( Character charcode,
+                          PointSize26Dot6 requestedPointSize,
+                          bool preferColor );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::FindFallbackFont()
+   */
+  FontId FindFallbackFont( Character charcode,
+                           const FontDescription& preferredFontDescription,
+                           PointSize26Dot6 requestedPointSize,
+                           bool preferColor );
+
+  /**
+   * @see Dali::TextAbstraction::FontClient::GetFontId( const FontPath& path, PointSize26Dot6 requestedPointSize, FaceIndex faceIndex )
+   *
+   * @param[in] cacheDescription Whether to cache the font description.
+   */
+  FontId GetFontId( const FontPath& path,
+                    PointSize26Dot6 requestedPointSize,
+                    FaceIndex faceIndex,
+                    bool cacheDescription );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetFontId( const FontDescription& preferredFontDescription, PointSize26Dot6 requestedPointSize, FaceIndex faceIndex )
+   */
+  FontId GetFontId( const FontDescription& fontDescription,
+                    PointSize26Dot6 requestedPointSize,
+                    FaceIndex faceIndex );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetFontId( const BitmapFont& bitmapFont )
+   */
+  FontId GetFontId( const BitmapFont& bitmapFont );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::IsScalable( const FontPath& path )
+   */
+  bool IsScalable( const FontPath& path );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::IsScalable( const FontDescription& fontDescription )
+   */
+  bool IsScalable( const FontDescription& fontDescription );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetFixedSizes()
+   */
+  void GetFixedSizes( const FontPath& path, Dali::Vector< PointSize26Dot6>& sizes );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetFixedSizes()
+   */
+  void GetFixedSizes( const FontDescription& fontDescription,
+                      Dali::Vector< PointSize26Dot6 >& sizes );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::HasItalicStyle()
+   */
+  bool HasItalicStyle( FontId fontId ) const;
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetFontMetrics()
+   */
+  void GetFontMetrics( FontId fontId, FontMetrics& metrics );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetGlyphIndex()
+   */
+  GlyphIndex GetGlyphIndex( FontId fontId, Character charcode );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetGlyphMetrics()
+   */
+  bool GetGlyphMetrics( GlyphInfo* array, uint32_t size, GlyphType type, bool horizontal );
+
+  /**
+   * Helper for GetGlyphMetrics when using bitmaps
+   */
+  bool GetBitmapMetrics( GlyphInfo* array, uint32_t size, bool horizontal );
+
+  /**
+   * Helper for GetGlyphMetrics when using vectors
+   */
+  bool GetVectorMetrics( GlyphInfo* array, uint32_t size, bool horizontal );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth )
+   */
+  void CreateBitmap( FontId fontId, GlyphIndex glyphIndex, bool isItalicRequired, bool isBoldRequired, Dali::TextAbstraction::FontClient::GlyphBufferData& data, int outlineWidth );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth )
+   */
+  PixelData CreateBitmap( FontId fontId, GlyphIndex glyphIndex, int outlineWidth );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::CreateVectorBlob()
+   */
+  void CreateVectorBlob( FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::GetEllipsisGlyph()
+   */
+  const GlyphInfo& GetEllipsisGlyph( PointSize26Dot6 requestedPointSize );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::IsColorGlyph()
+   */
+  bool IsColorGlyph( FontId fontId, GlyphIndex glyphIndex );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::CreateEmbeddedItem()
+   */
+  GlyphIndex CreateEmbeddedItem( const TextAbstraction::FontClient::EmbeddedItemDescription& description, Pixel::Format& pixelFormat );
+
+  /**
+   * @copydoc Dali::TextAbstraction::Internal::FontClient::GetFreetypeFace()
+   */
+  FT_FaceRec_* GetFreetypeFace( FontId fontId );
+
+  /**
+   * @copydoc Dali::TextAbstraction::Internal::FontClient::GetFontType()
+   */
+  FontDescription::Type GetFontType( FontId fontId );
+
+  /**
+   * @copydoc Dali::TextAbstraction::FontClient::AddCustomFontDirectory()
+   */
+  bool AddCustomFontDirectory( const FontPath& path );
+
+private:
+
+  /**
+   * @brief Caches the fonts present in the platform.
+   *
+   * Calls GetFcFontSet() to retrieve the fonts.
+   */
+  void InitSystemFonts();
+
+  /**
+   * @brief Gets the FontDescription which matches the given pattern.
+   *
+   * @note The reference counter of the @p characterSet has been increased. Call FcCharSetDestroy to decrease it.
+   *
+   * @param[in] pattern pattern to match against.
+   * @param[out] fontDescription the resultant fontDescription that matched.
+   * @param[out] characterSet The character set for that pattern.
+   * @return true if match found.
+   */
+  bool MatchFontDescriptionToPattern( _FcPattern* pattern, Dali::TextAbstraction::FontDescription& fontDescription, _FcCharSet** characterSet );
+
+  /**
+   * @brief Creates a font family pattern used to match fonts.
+   *
+   * @note Need to call FcPatternDestroy to free the resources.
+   *
+   * @param[in] fontDescription The font to cache.
+   *
+   * @return The pattern.
+   */
+  _FcPattern* CreateFontFamilyPattern( const FontDescription& fontDescription ) const;
+
+  /**
+   * @brief Retrieves the fonts present in the platform.
+   *
+   * @note Need to call FcFontSetDestroy to free the allocated resources.
+   *
+   * @return A font fonfig data structure with the platform's fonts.
+   */
+  _FcFontSet* GetFcFontSet() const;
+
+  /**
+   * @brief Retrieves a font config object's value from a pattern.
+   *
+   * @param[in] pattern The font config pattern.
+   * @param[in] n The object.
+   * @param[out] string The object's value.
+   *
+   * @return @e true if the operation is successful.
+   */
+  bool GetFcString( const _FcPattern* const pattern, const char* const n, std::string& string );
+
+  /**
+   * @brief Retrieves a font config object's value from a pattern.
+   *
+   * @param[in] pattern The font config pattern.
+   * @param[in] n The object.
+   * @param[out] intVal The object's value.
+   *
+   * @return @e true if the operation is successful.
+   */
+  bool GetFcInt( const _FcPattern* const pattern, const char* const n, int& intVal );
+
+  /**
+   * @brief Creates a font.
+   *
+   * @param[in] path The path to the font file name.
+   * @param[in] requestedPointSize The requested point size.
+   * @param[in] faceIndex A face index.
+   * @param[in] cacheDescription Whether to cache the font description.
+   *
+   * @return The font identifier.
+   */
+  FontId CreateFont( const FontPath& path,
+                     PointSize26Dot6 requestedPointSize,
+                     FaceIndex faceIndex,
+                     bool cacheDescription );
+
+  /**
+   * @brief Copy the color bitmap given in @p srcBuffer to @p data.
+   *
+   * @param[out] data The bitmap data.
+   * @param[in] srcWidth The width of the bitmap.
+   * @param[in] srcHeight The height of the bitmap.
+   * @param[in] srcBuffer The buffer of the bitmap.
+   */
+  void ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, unsigned int srcWidth, unsigned int srcHeight, const unsigned char* const srcBuffer );
+
+  /**
+   * @brief Copy the FreeType bitmap to the given buffer.
+   *
+   * @param[out] data The bitmap data.
+   * @param[in] srcBitmap The FreeType bitmap.
+   * @param[in] isShearRequired Whether the bitmap needs a shear transform (for software italics).
+   */
+  void ConvertBitmap( TextAbstraction::FontClient::GlyphBufferData& data, FT_Bitmap srcBitmap, bool isShearRequired );
+
+  /**
+   * @brief Finds in the cache if there is a triplet with the path to the font file name, the font point size and the face index.
+   * If there is one , if writes the font identifier in the param @p fontId.
+   *
+   * @param[in] path Path to the font file name.
+   * @param[in] requestedPointSize The font point size.
+   * @param[in] faceIndex The face index.
+   * @param[out] fontId The font identifier.
+   *
+   * @return @e true if there triplet is found.
+   */
+  bool FindFont( const FontPath& path, PointSize26Dot6 requestedPointSize, FaceIndex faceIndex, FontId& fontId ) const;
+
+  /**
+   * @brief Finds in the cache a cluster 'font family, font width, font weight, font slant'
+   * If there is one, it writes the index to the vector with font descriptions in the param @p validatedFontId.
+   *
+   * @param[in] fontDescription The font to validate.
+   * @param[out] validatedFontId The index to the vector with font descriptions.
+   *
+   * @return @e true if the pair is found.
+   */
+  bool FindValidatedFont( const FontDescription& fontDescription,
+                          FontDescriptionId& validatedFontId );
+
+  /**
+   * @brief Finds a fallback font list from the cache for a given font-description
+   *
+   * @param[in] fontDescription The font to validate.
+   * @param[out] A valid pointer to a font list, or @e nullptr if not found.
+   * @param[out] characterSetList A valid pointer to a character set list, or @e nullptr if not found.
+   */
+  bool FindFallbackFontList( const FontDescription& fontDescription,
+                             FontList*& fontList,
+                             CharacterSetList*& characterSetList );
+
+  /**
+   * @brief Finds in the cache a pair 'validated font identifier and font point size'.
+   * If there is one it writes the font identifier in the param @p fontId.
+   *
+   * @param[in] validatedFontId Index to the vector with font descriptions.
+   * @param[in] requestedPointSize The font point size.
+   * @param[out] fontId The font identifier.
+   *
+   * @return @e true if the pair is found.
+   */
+  bool FindFont( FontDescriptionId validatedFontId,
+                 PointSize26Dot6 requestedPointSize,
+                 FontId& fontId );
+
+  /**
+   * @brief Finds in the cache a bitmap font with the @p bitmapFont family name.
+   *
+   * @param[in] bitmapFont The font's family name.
+   * @param[out] fontId The id of the font.
+   *
+   * @return Whether the font has been found.
+   */
+  bool FindBitmapFont( const FontFamily& bitmapFont, FontId& fontId ) const;
+
+  /**
+   * @brief Validate a font description.
+   *
+   * @param[in] fontDescription The font to validate.
+   * @param[out] validatedFontId Result of validation
+   */
+  void ValidateFont( const FontDescription& fontDescription,
+                     FontDescriptionId& validatedFontId );
+
+  /**
+   * @brief Helper for GetDefaultFonts etc.
+   *
+   * @note CharacterSetList is a vector of FcCharSet that are reference counted. It's needed to call FcCharSetDestroy to decrease the reference counter.
+   *
+   * @param[in] fontDescription A font description.
+   * @param[out] fontList A list of the fonts which are a close match for fontDescription.
+   * @param[out] characterSetList A list of character sets which are a close match for fontDescription.
+   */
+  void SetFontList( const FontDescription& fontDescription, FontList& fontList, CharacterSetList& characterSetList );
+
+  /**
+   * Caches a font path.
+   *
+   * @param[in] ftFace The FreeType face.
+   * @param[in] id The font identifier.
+   * @param[in] requestedPointSize The font point size.
+   * @param[in] path Path to the font file name.
+   */
+  void CacheFontPath( FT_Face ftFace, FontId id, PointSize26Dot6 requestedPointSize,  const FontPath& path );
+
+  /**
+   * @brief Creates a character set from a given font's @p description.
+   *
+   * @note Need to call FcCharSetDestroy to free the resources.
+   *
+   * @param[in] description The font's description.
+   *
+   * @return A character set.
+   */
+  _FcCharSet* CreateCharacterSetFromDescription( const FontDescription& description );
+
+  /**
+   * @brief Free the resources allocated in the fallback cache.
+   *
+   * @param[in] fallbackCache The fallback cache.
+   */
+  void ClearFallbackCache( std::vector<FallbackCacheItem>& fallbackCache );
+
+  /**
+   * @brief Free the resources allocated by the FcCharSet objects.
+   */
+  void ClearCharacterSetFromFontFaceCache();
+
+private:
+
+  // Declared private and left undefined to avoid copies.
+  Plugin( const Plugin& );
+  // Declared private and left undefined to avoid copies.
+  Plugin& operator=( const Plugin& );
+
+private:
+
+  FT_Library mFreeTypeLibrary; ///< A handle to a FreeType library instance.
+
+  unsigned int mDpiHorizontal; ///< Horizontal dpi.
+  unsigned int mDpiVertical;   ///< Vertical dpi.
+
+  FontDescription mDefaultFontDescription; ///< The cached default font from the system
+
+  FontList mSystemFonts;       ///< Cached system fonts.
+  FontList mDefaultFonts;      ///< Cached default fonts.
+  CharacterSetList mDefaultFontCharacterSets;
+
+  std::vector<FallbackCacheItem> mFallbackCache; ///< Cached fallback font lists.
+
+  Vector<FontIdCacheItem>                   mFontIdCache;
+  std::vector<FontFaceCacheItem>            mFontFaceCache;            ///< Caches the FreeType face and font metrics of the triplet 'path to the font file name, font point size and face index'.
+  std::vector<FontDescriptionCacheItem>     mValidatedFontCache;       ///< Caches indices to the vector of font descriptions for a given font.
+  FontList                                  mFontDescriptionCache;     ///< Caches font descriptions for the validated font.
+  CharacterSetList                          mCharacterSetCache;        ///< Caches character set lists for the validated font.
+  std::vector<FontDescriptionSizeCacheItem> mFontDescriptionSizeCache; ///< Caches font identifiers for the pairs of font point size and the index to the vector with font descriptions of the validated fonts.
+
+  VectorFontCache* mVectorFontCache; ///< Separate cache for vector data blobs etc.
+
+  Vector<EllipsisItem> mEllipsisCache;      ///< Caches ellipsis glyphs for a particular point size.
+  std::vector<PixelBufferCacheItem> mPixelBufferCache; ///< Caches the pixel buffer of a url.
+  Vector<EmbeddedItem> mEmbeddedItemCache; ///< Cache embedded items.
+  std::vector<BitmapFontCacheItem> mBitmapFontCache; ///< Stores bitmap fonts.
+
+  bool mDefaultFontDescriptionCached : 1; ///< Whether the default font is cached or not
+};
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TEXT_ABSTRACTION_FONT_CLIENT_PLUGIN_IMPL_H
diff --git a/dali/internal/text/text-abstraction/segmentation-impl.cpp b/dali/internal/text/text-abstraction/segmentation-impl.cpp
new file mode 100644 (file)
index 0000000..fd97c20
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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 <dali/internal/text/text-abstraction/segmentation-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/common/singleton-service.h>
+#include <third-party/libunibreak/linebreak.h>
+#include <third-party/libunibreak/wordbreak.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+struct Segmentation::Plugin
+{
+  void GetLineBreakPositions( const Character* const text,
+                              Length numberOfCharacters,
+                              LineBreakInfo* breakInfo )
+  {
+    set_linebreaks_utf32( text, numberOfCharacters, NULL, breakInfo );
+  }
+
+  void GetWordBreakPositions( const Character* const text,
+                              Length numberOfCharacters,
+                              WordBreakInfo* breakInfo )
+  {
+    set_wordbreaks_utf32( text, numberOfCharacters, NULL, breakInfo );
+  }
+};
+
+Segmentation::Segmentation()
+: mPlugin( NULL )
+{}
+
+Segmentation::~Segmentation()
+{
+  delete mPlugin;
+}
+
+TextAbstraction::Segmentation Segmentation::Get()
+{
+  TextAbstraction::Segmentation segmentationHandle;
+
+  SingletonService service( SingletonService::Get() );
+  if( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( TextAbstraction::Segmentation ) );
+    if( handle )
+    {
+      // If so, downcast the handle
+      Segmentation* impl = dynamic_cast< Internal::Segmentation* >( handle.GetObjectPtr() );
+      segmentationHandle = TextAbstraction::Segmentation( impl );
+    }
+    else // create and register the object
+    {
+      segmentationHandle = TextAbstraction::Segmentation( new Segmentation );
+      service.Register( typeid( segmentationHandle ), segmentationHandle );
+    }
+  }
+
+  return segmentationHandle;
+}
+
+void Segmentation::GetLineBreakPositions( const Character* const text,
+                                          Length numberOfCharacters,
+                                          LineBreakInfo* breakInfo )
+{
+  CreatePlugin();
+
+  mPlugin->GetLineBreakPositions( text, numberOfCharacters, breakInfo );
+}
+
+void Segmentation::GetWordBreakPositions( const Character* const text,
+                                          Length numberOfCharacters,
+                                          WordBreakInfo* breakInfo )
+{
+  CreatePlugin();
+
+  mPlugin->GetWordBreakPositions( text, numberOfCharacters, breakInfo );
+}
+
+void Segmentation::CreatePlugin()
+{
+  if( !mPlugin )
+  {
+    mPlugin = new Plugin();
+  }
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/internal/text/text-abstraction/segmentation-impl.h b/dali/internal/text/text-abstraction/segmentation-impl.h
new file mode 100644 (file)
index 0000000..f8404c7
--- /dev/null
@@ -0,0 +1,116 @@
+#ifndef DALI_INTERNAL_TEXT_ABSTRACTION_SEGMENTATION_IMPL_H
+#define DALI_INTERNAL_TEXT_ABSTRACTION_SEGMENTATION_IMPL_H
+
+/*
+ * Copyright (c) 2019 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/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/segmentation.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * Implementation of the Segmentation
+ */
+
+class Segmentation : public BaseObject
+{
+public:
+
+  /**
+   * Constructor
+   */
+  Segmentation();
+
+  /**
+   * Destructor
+   */
+  ~Segmentation();
+
+  /**
+   * @copydoc Dali::Segmentation::Get()
+   */
+  static TextAbstraction::Segmentation Get();
+
+  /**
+   * @copydoc Dali::Segmentation::GetLineBreakPositions()
+   */
+  void GetLineBreakPositions( const Character* const text,
+                              Length numberOfCharacters,
+                              LineBreakInfo* breakInfo );
+
+
+  /**
+   * @copydoc Dali::Segmentation::GetWordBreakPositions()
+   */
+  void GetWordBreakPositions( const Character* const text,
+                              Length numberOfCharacters,
+                              WordBreakInfo* breakInfo );
+
+private:
+
+  /**
+   * Helper for lazy initialization.
+   */
+  void CreatePlugin();
+
+private:
+
+  // Undefined copy constructor.
+  Segmentation( const Segmentation& );
+
+  // Undefined assignment constructor.
+  Segmentation& operator=( Segmentation& );
+
+private:
+
+  struct Plugin;
+  Plugin* mPlugin;
+
+}; // class Segmentation
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+inline static TextAbstraction::Internal::Segmentation& GetImplementation( TextAbstraction::Segmentation& segmentation )
+{
+  DALI_ASSERT_ALWAYS( segmentation && "segmentation handle is empty" );
+  BaseObject& handle = segmentation.GetBaseObject();
+  return static_cast<TextAbstraction::Internal::Segmentation&>( handle );
+}
+
+inline static const TextAbstraction::Internal::Segmentation& GetImplementation( const TextAbstraction::Segmentation& segmentation )
+{
+  DALI_ASSERT_ALWAYS( segmentation && "segmentation handle is empty" );
+  const BaseObject& handle = segmentation.GetBaseObject();
+  return static_cast<const TextAbstraction::Internal::Segmentation&>( handle );
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TEXT_ABSTRACTION_SEGMENTATION_IMPL_H
diff --git a/dali/internal/text/text-abstraction/shaping-impl.cpp b/dali/internal/text/text-abstraction/shaping-impl.cpp
new file mode 100755 (executable)
index 0000000..b785c02
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS  HEADER
+#include <dali/internal/text/text-abstraction/shaping-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/font-client.h>
+#include <dali/devel-api/text-abstraction/glyph-info.h>
+#include <dali/integration-api/debug.h>
+#include "font-client-impl.h"
+
+// EXTERNAL INCLUDES
+#include <harfbuzz/hb.h>
+#include <harfbuzz/hb-ft.h>
+#include <dali/devel-api/common/singleton-service.h>
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Dali::Integration::Log::Filter* gLogFilter = Dali::Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_FONT_CLIENT");
+#endif
+
+}
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+const char* const  DEFAULT_LANGUAGE = "en";
+const unsigned int DEFAULT_LANGUAGE_LENGTH = 2u;
+const float        FROM_266 = 1.0f / 64.0f;
+
+const hb_script_t SCRIPT_TO_HARFBUZZ[] =
+{
+  HB_SCRIPT_COMMON,
+
+  HB_SCRIPT_COMMON, // ASCII_DIGITS
+  HB_SCRIPT_COMMON, // ASCII_PS
+
+  HB_SCRIPT_COMMON, // C1_CONTROLS
+  HB_SCRIPT_COMMON, // C1_PS
+  HB_SCRIPT_COMMON, // C1_MATH
+  HB_SCRIPT_COMMON, // SML_P
+  HB_SCRIPT_COMMON, // PHONETIC_U
+  HB_SCRIPT_COMMON, // PHONETIC_SS
+  HB_SCRIPT_COMMON, // NUMERIC_SS
+  HB_SCRIPT_COMMON, // LETTER_LIKE
+  HB_SCRIPT_COMMON, // NUMBER_FORMS
+  HB_SCRIPT_COMMON, // FRACTIONS_NF
+  HB_SCRIPT_COMMON, // NON_LATIN_LED
+  HB_SCRIPT_COMMON, // HWFW_S
+
+  HB_SCRIPT_CYRILLIC,
+  HB_SCRIPT_GREEK,
+  HB_SCRIPT_LATIN,
+
+  HB_SCRIPT_ARABIC,
+  HB_SCRIPT_HEBREW,
+
+  HB_SCRIPT_ARMENIAN,
+  HB_SCRIPT_GEORGIAN,
+
+  HB_SCRIPT_HAN,
+  HB_SCRIPT_HANGUL,
+  HB_SCRIPT_HIRAGANA,
+  HB_SCRIPT_KATAKANA,
+  HB_SCRIPT_BOPOMOFO,
+
+  HB_SCRIPT_BENGALI,
+  HB_SCRIPT_MYANMAR,
+  HB_SCRIPT_DEVANAGARI,
+  HB_SCRIPT_GUJARATI,
+  HB_SCRIPT_GURMUKHI,
+  HB_SCRIPT_KANNADA,
+  HB_SCRIPT_MALAYALAM,
+  HB_SCRIPT_ORIYA,
+  HB_SCRIPT_SINHALA,
+  HB_SCRIPT_TAMIL,
+  HB_SCRIPT_TELUGU,
+
+  HB_SCRIPT_LAO,
+  HB_SCRIPT_THAI,
+  HB_SCRIPT_KHMER,
+  HB_SCRIPT_JAVANESE,
+  HB_SCRIPT_SUNDANESE,
+
+  HB_SCRIPT_ETHIOPIC,
+  HB_SCRIPT_OL_CHIKI,
+  HB_SCRIPT_TAGALOG,
+  HB_SCRIPT_MEETEI_MAYEK,
+
+  HB_SCRIPT_UNKNOWN, // EMOJI
+  HB_SCRIPT_UNKNOWN, // SYMBOLS1
+  HB_SCRIPT_UNKNOWN, // SYMBOLS2
+  HB_SCRIPT_UNKNOWN, // SYMBOLS3
+  HB_SCRIPT_UNKNOWN, // SYMBOLS4
+  HB_SCRIPT_UNKNOWN, // SYMBOLS5
+  HB_SCRIPT_UNKNOWN
+};
+
+struct Shaping::Plugin
+{
+  Plugin()
+  : mIndices(),
+    mAdvance(),
+    mCharacterMap(),
+    mFontId( 0u )
+  {
+  }
+
+  ~Plugin()
+  {
+  }
+
+  Length Shape( const Character* const text,
+                Length numberOfCharacters,
+                FontId fontId,
+                Script script )
+  {
+    // Clear previoursly shaped texts.
+    mIndices.Clear();
+    mAdvance.Clear();
+    mCharacterMap.Clear();
+    mOffset.Clear();
+    mFontId = fontId;
+
+    TextAbstraction::FontClient fontClient = TextAbstraction::FontClient::Get();
+    TextAbstraction::Internal::FontClient& fontClientImpl = TextAbstraction::GetImplementation( fontClient );
+
+    const FontDescription::Type type = fontClientImpl.GetFontType( fontId );
+
+    switch( type )
+    {
+      case FontDescription::FACE_FONT:
+      {
+        // Reserve some space to avoid reallocations.
+        const Length numberOfGlyphs = static_cast<Length>( 1.3f * static_cast<float>( numberOfCharacters ) );
+        mIndices.Reserve( numberOfGlyphs );
+        mAdvance.Reserve( numberOfGlyphs );
+        mCharacterMap.Reserve( numberOfGlyphs );
+        mOffset.Reserve( 2u * numberOfGlyphs );
+
+        // Retrieve a FreeType font's face.
+        FT_Face face = fontClientImpl.GetFreetypeFace( fontId );
+        if( nullptr == face )
+        {
+          // Nothing to do if the face is null.
+          return 0u;
+        }
+
+        unsigned int horizontalDpi = 0u;
+        unsigned int verticalDpi = 0u;
+        fontClient.GetDpi( horizontalDpi, verticalDpi );
+
+        FT_Set_Char_Size( face,
+                          0u,
+                          fontClient.GetPointSize( fontId ),
+                          horizontalDpi,
+                          verticalDpi );
+
+        /* Get our harfbuzz font struct */
+        hb_font_t* harfBuzzFont;
+        harfBuzzFont = hb_ft_font_create( face, NULL );
+
+        /* Create a buffer for harfbuzz to use */
+        hb_buffer_t* harfBuzzBuffer = hb_buffer_create();
+
+        const bool rtlDirection = IsRightToLeftScript( script );
+        hb_buffer_set_direction( harfBuzzBuffer,
+                                 rtlDirection ? HB_DIRECTION_RTL : HB_DIRECTION_LTR ); /* or LTR */
+
+        hb_buffer_set_script( harfBuzzBuffer,
+                              SCRIPT_TO_HARFBUZZ[ script ] ); /* see hb-unicode.h */
+
+
+        char* currentLocale = setlocale(LC_MESSAGES,NULL);
+
+        std::istringstream stringStream( currentLocale );
+        std::string localeString;
+        std::getline(stringStream, localeString, '_');
+        hb_buffer_set_language( harfBuzzBuffer, hb_language_from_string( localeString.c_str(), localeString.size() ) );
+
+        /* Layout the text */
+        hb_buffer_add_utf32( harfBuzzBuffer, text, numberOfCharacters, 0u, numberOfCharacters );
+
+        hb_shape( harfBuzzFont, harfBuzzBuffer, NULL, 0u );
+
+        /* Get glyph data */
+        unsigned int glyphCount;
+        hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos( harfBuzzBuffer, &glyphCount );
+        hb_glyph_position_t *glyphPositions = hb_buffer_get_glyph_positions( harfBuzzBuffer, &glyphCount );
+        const GlyphIndex lastGlyphIndex = glyphCount - 1u;
+
+        for( GlyphIndex i = 0u; i < glyphCount; )
+        {
+          if( rtlDirection )
+          {
+            // If the direction is right to left, Harfbuzz retrieves the glyphs in the visual order.
+            // The glyphs are needed in the logical order to layout the text in lines.
+            // Do not change the order of the glyphs if they belong to the same cluster.
+            GlyphIndex rtlIndex = lastGlyphIndex - i;
+
+            unsigned int cluster = glyphInfo[rtlIndex].cluster;
+            unsigned int previousCluster = cluster;
+            Length numberOfGlyphsInCluster = 0u;
+
+            while( ( cluster == previousCluster ) )
+            {
+              ++numberOfGlyphsInCluster;
+              previousCluster = cluster;
+
+              if( rtlIndex > 0u )
+              {
+                --rtlIndex;
+
+                cluster = glyphInfo[rtlIndex].cluster;
+              }
+              else
+              {
+                break;
+              }
+            }
+
+            rtlIndex = lastGlyphIndex - ( i + ( numberOfGlyphsInCluster - 1u ) );
+
+            for( GlyphIndex j = 0u; j < numberOfGlyphsInCluster; ++j )
+            {
+              const GlyphIndex index = rtlIndex + j;
+
+              mIndices.PushBack( glyphInfo[index].codepoint );
+              mAdvance.PushBack( floor( glyphPositions[index].x_advance * FROM_266 ) );
+              mCharacterMap.PushBack( glyphInfo[index].cluster );
+              mOffset.PushBack( floor( glyphPositions[index].x_offset * FROM_266 ) );
+              mOffset.PushBack( floor( glyphPositions[index].y_offset * FROM_266 ) );
+            }
+
+            i += numberOfGlyphsInCluster;
+          }
+          else
+          {
+            mIndices.PushBack( glyphInfo[i].codepoint );
+            mAdvance.PushBack( floor( glyphPositions[i].x_advance * FROM_266 ) );
+            mCharacterMap.PushBack( glyphInfo[i].cluster );
+            mOffset.PushBack( floor( glyphPositions[i].x_offset * FROM_266 ) );
+            mOffset.PushBack( floor( glyphPositions[i].y_offset * FROM_266 ) );
+
+            ++i;
+          }
+        }
+
+        /* Cleanup */
+        hb_buffer_destroy( harfBuzzBuffer );
+        hb_font_destroy( harfBuzzFont );
+        break;
+      }
+      case FontDescription::BITMAP_FONT:
+      {
+        // Reserve some space to avoid reallocations.
+        // The advance and offset tables can be initialized with zeros as it's not needed to get metrics from the bitmaps here.
+        mIndices.Resize( numberOfCharacters );
+        mAdvance.Resize( numberOfCharacters, 0u );
+        mCharacterMap.Reserve( numberOfCharacters );
+        mOffset.Resize( 2u * numberOfCharacters, 0.f );
+
+        // The utf32 character can be used as the glyph's index.
+        std::copy( text, text + numberOfCharacters, mIndices.Begin() );
+
+        // The glyph to character map is 1 to 1.
+        for( unsigned int index = 0u; index < numberOfCharacters; ++index )
+        {
+          mCharacterMap.PushBack( index );
+        }
+        break;
+      }
+      default:
+      {
+        DALI_LOG_INFO(gLogFilter, Debug::General, "  Invalid type of font\n");
+      }
+    }
+
+    return mIndices.Count();
+  }
+
+  void GetGlyphs( GlyphInfo* glyphInfo,
+                  CharacterIndex* glyphToCharacterMap )
+  {
+    Vector<CharacterIndex>::ConstIterator indicesIt = mIndices.Begin();
+    Vector<float>::ConstIterator advanceIt = mAdvance.Begin();
+    Vector<float>::ConstIterator offsetIt = mOffset.Begin();
+    Vector<CharacterIndex>::ConstIterator characterMapIt = mCharacterMap.Begin();
+
+    for( GlyphIndex index = 0u, size = mIndices.Count(); index < size; ++index )
+    {
+      GlyphInfo& glyph = *( glyphInfo + index );
+      CharacterIndex& glyphToCharacter = *( glyphToCharacterMap + index );
+
+      glyph.fontId = mFontId;
+      glyph.index = *( indicesIt + index );
+      glyph.advance = *( advanceIt + index );
+
+      const GlyphIndex offsetIndex = 2u * index;
+      glyph.xBearing = *( offsetIt + offsetIndex );
+      glyph.yBearing = *( offsetIt + offsetIndex + 1u );
+
+      glyphToCharacter = *( characterMapIt + index );
+    }
+  }
+
+  Vector<CharacterIndex> mIndices;
+  Vector<float>          mAdvance;
+  Vector<float>          mOffset;
+  Vector<CharacterIndex> mCharacterMap;
+  FontId                 mFontId;
+};
+
+Shaping::Shaping()
+: mPlugin( NULL )
+{
+}
+
+Shaping::~Shaping()
+{
+  delete mPlugin;
+}
+
+TextAbstraction::Shaping Shaping::Get()
+{
+  TextAbstraction::Shaping shapingHandle;
+
+  SingletonService service( SingletonService::Get() );
+  if( service )
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton( typeid( TextAbstraction::Shaping ) );
+    if( handle )
+    {
+      // If so, downcast the handle
+      Shaping* impl = dynamic_cast< Internal::Shaping* >( handle.GetObjectPtr() );
+      shapingHandle = TextAbstraction::Shaping( impl );
+    }
+    else // create and register the object
+    {
+      shapingHandle = TextAbstraction::Shaping( new Shaping );
+      service.Register( typeid( shapingHandle ), shapingHandle );
+    }
+  }
+
+  return shapingHandle;
+}
+
+Length Shaping::Shape( const Character* const text,
+                       Length numberOfCharacters,
+                       FontId fontId,
+                       Script script )
+{
+  CreatePlugin();
+
+  return mPlugin->Shape( text,
+                         numberOfCharacters,
+                         fontId,
+                         script );
+}
+
+void Shaping::GetGlyphs( GlyphInfo* glyphInfo,
+                         CharacterIndex* glyphToCharacterMap )
+{
+  CreatePlugin();
+
+  mPlugin->GetGlyphs( glyphInfo,
+                      glyphToCharacterMap );
+}
+
+void Shaping::CreatePlugin()
+{
+  if( !mPlugin )
+  {
+    mPlugin = new Plugin();
+  }
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/internal/text/text-abstraction/shaping-impl.h b/dali/internal/text/text-abstraction/shaping-impl.h
new file mode 100644 (file)
index 0000000..2eb809e
--- /dev/null
@@ -0,0 +1,113 @@
+#ifndef DALI_INTERNAL_TEXT_ABSTRACTION_SHAPING_IMPL_H
+#define DALI_INTERNAL_TEXT_ABSTRACTION_SHAPING_IMPL_H
+
+/*
+ * Copyright (c) 2019 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/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+#include <dali/devel-api/text-abstraction/shaping.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * Implementation of the Shaping
+ */
+class Shaping : public BaseObject
+{
+public:
+
+  /**
+   * Constructor
+   */
+  Shaping();
+
+  /**
+   * Destructor
+   */
+  ~Shaping();
+
+  /**
+   * @copydoc Dali::Shaping::Get()
+   */
+  static TextAbstraction::Shaping Get();
+
+  /**
+   * @copydoc Dali::Shaping::Shape()
+   */
+  Length Shape( const Character* const text,
+                Length numberOfCharacters,
+                FontId fontId,
+                Script script );
+
+  /**
+   * @copydoc Dali::Shaping::GetGlyphs()
+   */
+  void GetGlyphs( GlyphInfo* glyphInfo,
+                  CharacterIndex* glyphToCharacterMap );
+
+private:
+
+  /**
+   * Helper for lazy initialization.
+   */
+  void CreatePlugin();
+
+private:
+
+  // Undefined copy constructor.
+  Shaping( const Shaping& );
+
+  // Undefined assignment constructor.
+  Shaping& operator=( const Shaping& );
+
+  struct Plugin;
+  Plugin* mPlugin;
+
+}; // class Shaping
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+inline static TextAbstraction::Internal::Shaping& GetImplementation( TextAbstraction::Shaping& shaping )
+{
+  DALI_ASSERT_ALWAYS( shaping && "shaping handle is empty" );
+  BaseObject& handle = shaping.GetBaseObject();
+  return static_cast<TextAbstraction::Internal::Shaping&>( handle );
+}
+
+inline static const TextAbstraction::Internal::Shaping& GetImplementation( const TextAbstraction::Shaping& shaping )
+{
+  DALI_ASSERT_ALWAYS( shaping && "shaping handle is empty" );
+  const BaseObject& handle = shaping.GetBaseObject();
+  return static_cast<const TextAbstraction::Internal::Shaping&>( handle );
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TEXT_ABSTRACTION_SHAPING_IMPL_H
diff --git a/dali/internal/text/text-abstraction/text-renderer-impl.cpp b/dali/internal/text/text-abstraction/text-renderer-impl.cpp
new file mode 100755 (executable)
index 0000000..a360361
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS  HEADER
+#include <dali/internal/text/text-abstraction/text-renderer-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/common/singleton-service.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/text/text-abstraction/cairo-renderer.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+TextRenderer::TextRenderer()
+{
+}
+
+TextRenderer::~TextRenderer()
+{
+}
+
+TextAbstraction::TextRenderer TextRenderer::Get()
+{
+  TextAbstraction::TextRenderer shapingHandle;
+
+  SingletonService service(SingletonService::Get());
+  if (service)
+  {
+    // Check whether the singleton is already created
+    Dali::BaseHandle handle = service.GetSingleton(typeid(TextAbstraction::TextRenderer));
+    if (handle)
+    {
+      // If so, downcast the handle
+      TextRenderer* impl = dynamic_cast< Internal::TextRenderer* >(handle.GetObjectPtr());
+      shapingHandle = TextAbstraction::TextRenderer(impl);
+    }
+    else // create and register the object
+    {
+      shapingHandle = TextAbstraction::TextRenderer(new TextRenderer);
+      service.Register(typeid(shapingHandle), shapingHandle);
+    }
+  }
+
+  return shapingHandle;
+}
+
+Devel::PixelBuffer TextRenderer::Render(const TextAbstraction::TextRenderer::Parameters& parameters)
+{
+  return RenderTextCairo(parameters);
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/internal/text/text-abstraction/text-renderer-impl.h b/dali/internal/text/text-abstraction/text-renderer-impl.h
new file mode 100755 (executable)
index 0000000..5133ff4
--- /dev/null
@@ -0,0 +1,93 @@
+#ifndef DALI_INTERNAL_TEXT_ABSTRACTION_TEXT_RENDERER_IMPL_H
+#define DALI_INTERNAL_TEXT_ABSTRACTION_TEXT_RENDERER_IMPL_H
+
+/*
+ * Copyright (c) 2019 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/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/text-renderer.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * Implementation of the TextRenderer
+ */
+class TextRenderer : public BaseObject
+{
+public:
+
+  /**
+   * Constructor
+   */
+  TextRenderer();
+
+  /**
+   * Destructor
+   */
+  ~TextRenderer();
+
+  /**
+   * @copydoc Dali::TextRenderer::Get()
+   */
+  static TextAbstraction::TextRenderer Get();
+
+  /**
+   * @copydoc Dali::TextRenderer::Render()
+   */
+  Devel::PixelBuffer Render(const TextAbstraction::TextRenderer::Parameters& parameters);
+
+private:
+
+  // Undefined copy constructor.
+  TextRenderer(const TextRenderer&);
+
+  // Undefined assignment constructor.
+  TextRenderer& operator=(const TextRenderer&);
+
+}; // class TextRenderer
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+inline static TextAbstraction::Internal::TextRenderer& GetImplementation(TextAbstraction::TextRenderer& textRenderer)
+{
+  DALI_ASSERT_ALWAYS(textRenderer && "textRenderer handle is empty");
+  BaseObject& handle = textRenderer.GetBaseObject();
+  return static_cast<TextAbstraction::Internal::TextRenderer&>(handle);
+}
+
+inline static const TextAbstraction::Internal::TextRenderer& GetImplementation(const TextAbstraction::TextRenderer& textRenderer)
+{
+  DALI_ASSERT_ALWAYS(textRenderer && "textRenderer handle is empty");
+  const BaseObject& handle = textRenderer.GetBaseObject();
+  return static_cast<const TextAbstraction::Internal::TextRenderer&>(handle);
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TEXT_ABSTRACTION_TEXT_RENDERER_IMPL_H
diff --git a/dali/internal/text/ubuntu/vector-font-cache.cpp b/dali/internal/text/ubuntu/vector-font-cache.cpp
new file mode 100644 (file)
index 0000000..9b704a5
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/text/glyphy/vector-font-cache.h>
+
+// EXTERNAL INCLUDES
+#include <vector>
+#include <math.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/text/glyphy/glyphy.h>
+#include <dali/internal/text/glyphy/glyphy-freetype.h>
+
+using namespace std;
+
+namespace
+{
+
+const unsigned int INITIAL_GLYPH_CAPACITY = 50;
+const double MIN_FONT_SIZE = 10;
+
+static glyphy_bool_t
+accumulate_endpoint( glyphy_arc_endpoint_t*         endpoint,
+                     vector<glyphy_arc_endpoint_t>* endpoints )
+{
+  endpoints->push_back( *endpoint );
+  return true;
+}
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+typedef vector<VectorBlob> BlobArray;
+
+struct VectorGlyph
+{
+  /**
+   * @brief Create a vector-based glyph.
+   */
+  static VectorGlyph* New( FT_Face face,
+                           FontId fontId,
+                           GlyphIndex index,
+                           glyphy_arc_accumulator_t* accumulator )
+  {
+    VectorGlyph* newGlyph = new VectorGlyph();
+    newGlyph->blobData.resize( 1024 * 16 );
+
+    if( FT_Err_Ok != FT_Load_Glyph( face,
+                                    index,
+                                    FT_LOAD_NO_BITMAP |
+                                    FT_LOAD_NO_HINTING |
+                                    FT_LOAD_NO_AUTOHINT |
+                                    FT_LOAD_NO_SCALE |
+                                    FT_LOAD_LINEAR_DESIGN |
+                                    FT_LOAD_IGNORE_TRANSFORM))
+    {
+      DALI_LOG_ERROR( "FT_Load_Glyph failed\n" );
+      delete newGlyph;
+      return NULL;
+    }
+
+    const double upem = static_cast<double>( face->units_per_EM );
+    const double tolerance = upem * 1.0f/2048.0f;
+
+    glyphy_arc_accumulator_reset( accumulator);
+    glyphy_arc_accumulator_set_tolerance( accumulator, tolerance );
+
+    vector<glyphy_arc_endpoint_t> endpoints;
+    glyphy_arc_accumulator_set_callback( accumulator,
+                                         reinterpret_cast<glyphy_arc_endpoint_accumulator_callback_t>( accumulate_endpoint ),
+                                         &endpoints );
+
+    if( FT_Err_Ok != glyphy_freetype_outline_decompose( &face->glyph->outline, accumulator ) )
+    {
+      DALI_LOG_ERROR( "glyphy_freetype_outline_decompose failed\n" );
+      delete newGlyph;
+      return NULL;
+    }
+
+    DALI_ASSERT_DEBUG( glyphy_arc_accumulator_get_error(accumulator) <= tolerance && "glyphy_arc_accumulator_get_error > tolerance" );
+
+    if( endpoints.size() )
+    {
+      glyphy_outline_winding_from_even_odd( &endpoints[0], endpoints.size (), false );
+    }
+
+    unsigned int blobLength( 0 );
+    double averageFetchAchieved( 0.0 );
+    if (!glyphy_arc_list_encode_blob( endpoints.size() ? &endpoints[0] : NULL,
+                                      endpoints.size(),
+                                      &newGlyph->blobData[0],
+                                      newGlyph->blobData.capacity(),
+                                      upem / ( MIN_FONT_SIZE * M_SQRT2 ),
+                                      4,
+                                      &averageFetchAchieved,
+                                      &blobLength,
+                                      &newGlyph->nominalWidth,
+                                      &newGlyph->nominalHeight,
+                                      &newGlyph->extents ) )
+    {
+      DALI_LOG_ERROR( "glyphy_arc_list_encode_blob failed\n" );
+      delete newGlyph;
+      return NULL;
+    }
+    newGlyph->blobData.resize( blobLength );
+
+    glyphy_extents_scale( &newGlyph->extents, 1.0/upem, 1.0/upem );
+
+    newGlyph->glyphInfo.fontId = fontId;
+    newGlyph->glyphInfo.index  = index;
+
+    if( glyphy_extents_is_empty( &newGlyph->extents ) )
+    {
+      newGlyph->glyphInfo.width  = 0.0f;
+      newGlyph->glyphInfo.height = 0.0f;
+
+      newGlyph->glyphInfo.xBearing = 0.0f;
+      newGlyph->glyphInfo.yBearing = 0.0f;
+    }
+    else
+    {
+      newGlyph->glyphInfo.width  = (newGlyph->extents.max_x - newGlyph->extents.min_x);
+      newGlyph->glyphInfo.height = (newGlyph->extents.max_y - newGlyph->extents.min_y);
+
+      newGlyph->glyphInfo.xBearing = newGlyph->extents.min_x;
+      newGlyph->glyphInfo.yBearing = newGlyph->glyphInfo.height + (newGlyph->extents.min_y);
+    }
+
+    newGlyph->glyphInfo.advance = face->glyph->metrics.horiAdvance / upem;
+    newGlyph->glyphInfo.scaleFactor = 0.0f;
+
+    return newGlyph;
+  }
+
+  VectorGlyph()
+  : advance( 0.0 ),
+    nominalWidth( 0 ),
+    nominalHeight( 0 ),
+    glyphInfo(),
+    blobData()
+  {
+    glyphy_extents_clear( &extents );
+  }
+
+  glyphy_extents_t extents;
+  double           advance;
+  unsigned int     nominalWidth;
+  unsigned int     nominalHeight;
+  GlyphInfo        glyphInfo;
+  BlobArray        blobData;
+};
+
+typedef vector<VectorGlyph*> GlyphCache;
+
+struct VectorFont
+{
+  VectorFont( FT_Face face )
+  : mFace( face ),
+    mGlyphCache()
+  {
+    mGlyphCache.reserve( INITIAL_GLYPH_CAPACITY );
+  }
+
+  FT_Face    mFace;
+  GlyphCache mGlyphCache;
+};
+
+struct VectorFontCache::Impl
+{
+  Impl( FT_Library freeTypeLibrary )
+  : mFreeTypeLibrary( freeTypeLibrary ),
+    mIdLookup(),
+    mVectorFonts(),
+    mAccumulator( NULL )
+  {
+    mAccumulator = glyphy_arc_accumulator_create();
+  }
+
+  ~Impl()
+  {
+    glyphy_arc_accumulator_destroy( mAccumulator );
+  }
+
+private:
+
+  // Declared private and left undefined to avoid copies.
+  Impl( const Impl& );
+  // Declared private and left undefined to avoid copies.
+  Impl& operator=( const Impl& );
+
+public:
+
+  FT_Library mFreeTypeLibrary; ///< A handle to a FreeType library instance.
+
+  vector<string> mIdLookup;
+
+  vector<VectorFont*> mVectorFonts;
+
+  glyphy_arc_accumulator_t* mAccumulator;
+};
+
+VectorFontCache::VectorFontCache( FT_Library freeTypeLibrary )
+: mImpl( NULL )
+{
+  mImpl = new Impl( freeTypeLibrary );
+}
+
+VectorFontCache::~VectorFontCache()
+{
+  delete mImpl;
+}
+
+FontId VectorFontCache::GetFontId( const std::string& url )
+{
+  FontId id( 0 );
+
+  if( mImpl )
+  {
+    if( ! FindFont( url, id ) )
+    {
+      id = CreateFont( url );
+    }
+  }
+
+  return id;
+}
+
+void VectorFontCache::GetGlyphMetrics( FontId vectorFontId, GlyphInfo& glyphInfo )
+{
+  if( mImpl )
+  {
+    if( vectorFontId > 0 &&
+        vectorFontId-1 < mImpl->mVectorFonts.size() )
+    {
+      VectorFont* font = mImpl->mVectorFonts[ vectorFontId-1 ];
+      GlyphCache& cache = font->mGlyphCache;
+
+      bool foundGlyph( false );
+      unsigned int foundIndex( 0 );
+      for( unsigned int i=0; i<cache.size(); ++i )
+      {
+        VectorGlyph* glyph = cache[i];
+
+        if( glyph->glyphInfo.index == glyphInfo.index )
+        {
+          foundIndex = i;
+          foundGlyph = true;
+          break;
+        }
+      }
+
+      if( foundGlyph )
+      {
+        VectorGlyph* glyph = cache[foundIndex];
+        // Note - this clobbers the original fontId, but helps avoid duplicating identical blobs
+        // e.g. if when the same font family is requested in different point-sizes
+        glyphInfo = glyph->glyphInfo;
+      }
+      else
+      {
+        VectorGlyph* newGlyph = VectorGlyph::New( font->mFace,
+                                                  glyphInfo.fontId,
+                                                  glyphInfo.index,
+                                                  mImpl->mAccumulator );
+
+        if( newGlyph )
+        {
+          glyphInfo = newGlyph->glyphInfo;
+
+          cache.push_back( newGlyph );
+        }
+      }
+    }
+  }
+}
+
+void VectorFontCache::GetVectorBlob( FontId vectorFontId,
+                                     FontId fontId,
+                                     GlyphIndex glyphIndex,
+                                     VectorBlob*& blob,
+                                     unsigned int& blobLength,
+                                     unsigned int& nominalWidth,
+                                     unsigned int& nominalHeight )
+{
+  if( mImpl )
+  {
+    if( vectorFontId > 0 &&
+        vectorFontId-1 < mImpl->mVectorFonts.size() )
+    {
+      VectorFont* font = mImpl->mVectorFonts[ vectorFontId-1 ];
+      GlyphCache& cache = font->mGlyphCache;
+
+      bool foundGlyph( false );
+      unsigned int foundIndex( 0 );
+      for( unsigned int i=0; i<cache.size(); ++i )
+      {
+        VectorGlyph* glyph = cache[i];
+
+        if( glyph->glyphInfo.index == glyphIndex )
+        {
+          foundIndex = i;
+          foundGlyph = true;
+          break;
+        }
+      }
+
+      if( foundGlyph )
+      {
+        VectorGlyph* glyph = cache[foundIndex];
+
+        blob          = &glyph->blobData[0];
+        blobLength    = glyph->blobData.size();
+        nominalWidth  = glyph->nominalWidth;
+        nominalHeight = glyph->nominalHeight;
+      }
+      else
+      {
+        VectorGlyph* newGlyph = VectorGlyph::New( font->mFace, fontId, glyphIndex, mImpl->mAccumulator );
+
+        if( newGlyph )
+        {
+          blob          = &newGlyph->blobData[0];
+          blobLength    = newGlyph->blobData.size();
+          nominalWidth  = newGlyph->nominalWidth;
+          nominalHeight = newGlyph->nominalHeight;
+
+          cache.push_back( newGlyph );
+        }
+      }
+    }
+  }
+}
+
+bool VectorFontCache::FindFont( const string& url, FontId& vectorFontId ) const
+{
+  vectorFontId = 0u;
+
+  const vector<string>& idLookup = mImpl->mIdLookup;
+
+  for( unsigned int i=0; i<idLookup.size(); ++i, ++vectorFontId )
+  {
+    if( url == idLookup[i] )
+    {
+      ++vectorFontId;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+FontId VectorFontCache::CreateFont( const string& url )
+{
+  FontId id( 0 );
+
+  // Create & cache new font face
+  FT_Face face;
+  int error = FT_New_Face( mImpl->mFreeTypeLibrary,
+                           url.c_str(),
+                           0,
+                           &face );
+
+  if( FT_Err_Ok == error )
+  {
+    mImpl->mIdLookup.push_back( url );
+    id = mImpl->mIdLookup.size();
+
+    VectorFont* newFont = new VectorFont( face );
+    mImpl->mVectorFonts.push_back( newFont );
+
+    DALI_ASSERT_DEBUG( mImpl->mIdLookup.size() == mImpl->mVectorFonts.size() );
+  }
+
+  return id;
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/dali/internal/thread/common/thread-settings-impl.cpp b/dali/internal/thread/common/thread-settings-impl.cpp
new file mode 100644 (file)
index 0000000..849cb4d
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/thread/common/thread-settings-impl.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace ThreadSettings
+{
+
+void SetThreadName(const std::string& threadName)
+{
+  int err = prctl(PR_SET_NAME, threadName.c_str());
+  if ( err )
+  {
+    DALI_LOG_ERROR( "prctl(PR_SET_NAME, %s) failed\n", threadName.c_str() );
+  }
+}
+
+} // namespace ThreadSettings
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/thread/common/thread-settings-impl.h b/dali/internal/thread/common/thread-settings-impl.h
new file mode 100644 (file)
index 0000000..43f1c09
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef DALI_INTERNAL_THREAD_SETTINGS_H
+#define DALI_INTERNAL_THREAD_SETTINGS_H
+
+/*
+ * Copyright (c) 2019 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 <sys/prctl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Implementation of the Thread Settings
+ */
+namespace ThreadSettings
+{
+
+/**
+ * @brief Set the thread name.
+ *
+ * @param [in] threadName The name of thread. The name can be up to 16 bytes long, and should be null-terminated if it contains fewer bytes.
+ */
+void SetThreadName(const std::string& threadName);
+
+} // namespace ThreadSettings
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_THREAD_SETTINGS_H
diff --git a/dali/internal/thread/file.list b/dali/internal/thread/file.list
new file mode 100644 (file)
index 0000000..4cc599c
--- /dev/null
@@ -0,0 +1,6 @@
+
+# module: trace, backend: common
+SET( adaptor_thread_common_src_files 
+    ${adaptor_thread_dir}/common/thread-settings-impl.cpp
+)
+
diff --git a/dali/internal/trace/android/trace-factory-android.cpp b/dali/internal/trace/android/trace-factory-android.cpp
new file mode 100644 (file)
index 0000000..3e78e8a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 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/internal/trace/common/trace-factory.h>
+#include <dali/internal/trace/android/trace-manager-impl-android.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace TraceManagerFactory
+{
+
+// TraceManager Factory to be implemented by the platform
+TraceManagerUPtr CreateTraceFactory( PerformanceInterface* performanceInterface )
+{
+  return TraceManagerUPtr( new Dali::Internal::Adaptor::TraceManagerAndroid( performanceInterface ) );
+}
+
+} // namespace TraceManagerFactory
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali // namespace Dali
diff --git a/dali/internal/trace/android/trace-manager-impl-android.cpp b/dali/internal/trace/android/trace-manager-impl-android.cpp
new file mode 100644 (file)
index 0000000..d0d235c
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2019 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/internal/trace/android/trace-manager-impl-android.h>
+#include <dali/internal/system/common/performance-interface.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+TraceManagerAndroid* TraceManagerAndroid::traceManagerAndroid = nullptr;
+
+TraceManagerAndroid::TraceManagerAndroid( PerformanceInterface* performanceInterface )
+: TraceManager( performanceInterface )
+{
+  TraceManagerAndroid::traceManagerAndroid = this;
+}
+
+Dali::Integration::Trace::LogContextFunction TraceManagerAndroid::GetLogContextFunction()
+{
+  return LogContext;
+}
+
+void TraceManagerAndroid::LogContext( bool start, const char* tag )
+{
+  if( start )
+  {
+    unsigned short contextId = traceManagerAndroid->mPerformanceInterface->AddContext( tag );
+    traceManagerAndroid->mPerformanceInterface->AddMarker( PerformanceInterface::START, contextId );
+  }
+  else
+  {
+    unsigned short contextId = traceManagerAndroid->mPerformanceInterface->AddContext( tag );
+    traceManagerAndroid->mPerformanceInterface->AddMarker( PerformanceInterface::END, contextId );
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/trace/android/trace-manager-impl-android.h b/dali/internal/trace/android/trace-manager-impl-android.h
new file mode 100644 (file)
index 0000000..419bf4a
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef DALI_INTERNAL_TRACE_MANAGER_IMPL_ANDROID_H
+#define DALI_INTERNAL_TRACE_MANAGER_IMPL_ANDROID_H
+
+/*
+ * Copyright (c) 2019 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
+
+// INTERNAL INCLUDES
+#include <dali/internal/trace/common/trace-manager-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class PerformanceInterface;
+
+class TraceManagerAndroid : public Dali::Internal::Adaptor::TraceManager
+{
+public:
+  /**
+   * Static member to hold TraceManagerAndroid instance. This allows
+   * to access PerformanceInterface for network logging.
+   */
+  static TraceManagerAndroid* traceManagerAndroid;
+
+  /**
+   * Explicit Constructor
+   */
+  explicit TraceManagerAndroid( PerformanceInterface* performanceInterface );
+
+protected:
+  /**
+   * Destructor
+   */
+  ~TraceManagerAndroid() override = default;
+
+  /**
+   * Obtain the LogContextFunction method (Android specific) used for tracing
+   */
+  virtual Dali::Integration::Trace::LogContextFunction GetLogContextFunction() final;
+
+private:
+
+  /**
+   * LogContext method (Android specific) used for tracing
+   */
+  static void LogContext( bool start, const char* tag );
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TRACE_MANAGER_IMPL_ANDROID_H
diff --git a/dali/internal/trace/common/trace-factory.cpp b/dali/internal/trace/common/trace-factory.cpp
new file mode 100644 (file)
index 0000000..c7d15f7
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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/internal/trace/common/trace-factory.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace TraceManagerFactory
+{
+
+// Factory function creating new TraceFactory
+// Symbol exists but may be overriden during linking
+
+__attribute__((weak))
+TraceManagerUPtr CreateTraceFactory( PerformanceInterface* performanceInterface )
+{
+  // return empty handle if TraceManager not implemented
+  return nullptr;
+}
+
+} // namespace TraceManagerFactory
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali/internal/trace/common/trace-factory.h b/dali/internal/trace/common/trace-factory.h
new file mode 100644 (file)
index 0000000..5f1cfb9
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef DALI_INTERNAL_TRACE_FACTORY_H
+#define DALI_INTERNAL_TRACE_FACTORY_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.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <memory>
+
+// INTERNAL INCLUDES
+#include <dali/internal/trace/common/trace-manager-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace TraceManagerFactory
+{
+
+using TraceManagerUPtr = std::unique_ptr<TraceManager>;
+
+// Factory function creating new TraceFactory
+// Symbol exists but may be overriden during linking
+TraceManagerUPtr CreateTraceFactory( PerformanceInterface* performanceInterface );
+
+} // namespace TraceManagerFactory
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif //DALI_INTERNAL_TRACE_FACTORY_H
diff --git a/dali/internal/trace/common/trace-manager-impl.cpp b/dali/internal/trace/common/trace-manager-impl.cpp
new file mode 100644 (file)
index 0000000..8a34c2f
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018 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/internal/trace/common/trace-manager-impl.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+TraceManager::TraceManager( PerformanceInterface* performanceInterface )
+: mPerformanceInterface( performanceInterface )
+{
+}
+
+bool TraceManager::Initialise()
+{
+  auto logFunction = GetLogContextFunction();
+  if( !logFunction )
+  {
+      return false;
+  }
+  Dali::Integration::Trace::InstallLogContextFunction( logFunction );
+  return true;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/trace/common/trace-manager-impl.h b/dali/internal/trace/common/trace-manager-impl.h
new file mode 100644 (file)
index 0000000..7bbb6cc
--- /dev/null
@@ -0,0 +1,91 @@
+#ifndef DALI_INTERNAL_TRACE_MANAGER_IMPL_H
+#define DALI_INTERNAL_TRACE_MANAGER_IMPL_H
+
+/*
+ * Copyright (c) 2018 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/trace.h>
+
+// INTERNAL INCLUDES
+
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class PerformanceInterface;
+
+class TraceManager
+{
+public:
+
+  /**
+   * Explicit Constructor
+   */
+  explicit TraceManager( PerformanceInterface* performanceInterface );
+
+  /**
+   * Constructor
+   */
+  TraceManager() = default;
+
+  /**
+   * Virtual Destructor
+   */
+  virtual ~TraceManager() = default;
+
+  /**
+   * Second phase initialisation of TraceManager
+   */
+  bool Initialise();
+
+  /**
+   * Used for network server logging on Ubuntu
+   */
+  PerformanceInterface* mPerformanceInterface;
+
+protected:
+
+  /**
+   * Obtain the platform dependent LogContextFunction method used for tracing
+   */
+  virtual Dali::Integration::Trace::LogContextFunction GetLogContextFunction() { return nullptr; };
+
+private:
+
+  /**
+   * Set / Install the platform dependent trace function
+   * @param logContextFunction - Platform dependent trace function
+   */
+  void SetTraceLogContextFunction( const Dali::Integration::Trace::LogContextFunction& logContextFunction );
+
+  TraceManager( const TraceManager& ) = delete;
+  TraceManager& operator=( TraceManager& )  = delete;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TRACE_MANAGER_IMPL_H
diff --git a/dali/internal/trace/file.list b/dali/internal/trace/file.list
new file mode 100644 (file)
index 0000000..cccd8d8
--- /dev/null
@@ -0,0 +1,19 @@
+
+# module: trace, backend: common
+SET( adaptor_trace_common_src_files 
+    ${adaptor_trace_dir}/common/trace-manager-impl.cpp 
+    ${adaptor_trace_dir}/common/trace-factory.cpp
+)
+
+# module: trace, backend: generic
+SET( adaptor_trace_generic_src_files 
+    ${adaptor_trace_dir}/generic/trace-manager-impl-generic.cpp 
+    ${adaptor_trace_dir}/generic/trace-factory-generic.cpp
+)
+
+# module: trace, backend: tizen
+SET( adaptor_trace_tizen_src_files 
+    ${adaptor_trace_dir}/tizen/trace-manager-impl-tizen.cpp 
+    ${adaptor_trace_dir}/tizen/trace-factory-tizen.cpp
+)
+
diff --git a/dali/internal/trace/generic/trace-factory-generic.cpp b/dali/internal/trace/generic/trace-factory-generic.cpp
new file mode 100644 (file)
index 0000000..9c30534
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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/internal/trace/common/trace-factory.h>
+#include <dali/internal/trace/generic/trace-manager-impl-generic.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace TraceManagerFactory
+{
+
+// TraceManager Factory to be implemented by the platform
+TraceManagerUPtr CreateTraceFactory( PerformanceInterface* performanceInterface )
+{
+  return TraceManagerUPtr( new Dali::Internal::Adaptor::TraceManagerGeneric( performanceInterface ) );
+}
+
+} // namespace TraceManagerFactory
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/trace/generic/trace-manager-impl-generic.cpp b/dali/internal/trace/generic/trace-manager-impl-generic.cpp
new file mode 100644 (file)
index 0000000..e741a64
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2019 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/internal/system/common/performance-interface.h>
+#include "trace-manager-impl-generic.h"
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+TraceManagerGeneric* TraceManagerGeneric::traceManagerGeneric = nullptr;
+
+TraceManagerGeneric::TraceManagerGeneric( PerformanceInterface* performanceInterface )
+: TraceManager( performanceInterface )
+{
+  TraceManagerGeneric::traceManagerGeneric = this;
+}
+
+Dali::Integration::Trace::LogContextFunction TraceManagerGeneric::GetLogContextFunction()
+{
+  return LogContext;
+}
+
+void TraceManagerGeneric::LogContext( bool start, const char* tag )
+{
+  if( start )
+  {
+    unsigned short contextId = traceManagerGeneric->mPerformanceInterface->AddContext( tag );
+    traceManagerGeneric->mPerformanceInterface->AddMarker( PerformanceInterface::START, contextId );
+  }
+  else
+  {
+    unsigned short contextId = traceManagerGeneric->mPerformanceInterface->AddContext( tag );
+    traceManagerGeneric->mPerformanceInterface->AddMarker( PerformanceInterface::END, contextId );
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/trace/generic/trace-manager-impl-generic.h b/dali/internal/trace/generic/trace-manager-impl-generic.h
new file mode 100644 (file)
index 0000000..be99e8e
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef DALI_INTERNAL_TRACE_MANAGER_IMPL_GENERIC_H
+#define DALI_INTERNAL_TRACE_MANAGER_IMPL_GENERIC_H
+
+/*
+ * Copyright (c) 2019 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
+
+// INTERNAL INCLUDES
+#include <dali/internal/trace/common/trace-manager-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class PerformanceInterface;
+
+class TraceManagerGeneric : public Dali::Internal::Adaptor::TraceManager
+{
+public:
+  /**
+   * Static member to hold TraceManagerGeneric instance. This allows
+   * to access PerformanceInterface for network logging.
+   */
+  static TraceManagerGeneric* traceManagerGeneric;
+
+  /**
+   * Explicit Constructor
+   */
+  explicit TraceManagerGeneric( PerformanceInterface* performanceInterface );
+
+protected:
+  /**
+   * Destructor
+   */
+  ~TraceManagerGeneric() override = default;
+
+  /**
+   * Obtain the LogContextFunction method (Generic specific) used for tracing
+   */
+  virtual Dali::Integration::Trace::LogContextFunction GetLogContextFunction() final;
+
+private:
+
+  /**
+   * LogContext method (Generic specific) used for tracing
+   */
+  static void LogContext( bool start, const char* tag );
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TRACE_MANAGER_IMPL_GENERIC_H
diff --git a/dali/internal/trace/tizen/trace-factory-tizen.cpp b/dali/internal/trace/tizen/trace-factory-tizen.cpp
new file mode 100644 (file)
index 0000000..51715ba
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * 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/internal/trace/common/trace-factory.h>
+#include <dali/internal/trace/tizen/trace-manager-impl-tizen.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace TraceManagerFactory
+{
+
+// TraceManager Factory to be implemented by the platform
+TraceManagerUPtr CreateTraceFactory( PerformanceInterface* performanceInterface )
+{
+  return TraceManagerUPtr( new Dali::Internal::Adaptor::TraceManagerTizen( performanceInterface ) );
+}
+
+} // namespace TraceManagerFactory
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
\ No newline at end of file
diff --git a/dali/internal/trace/tizen/trace-manager-impl-tizen.cpp b/dali/internal/trace/tizen/trace-manager-impl-tizen.cpp
new file mode 100644 (file)
index 0000000..9095bcf
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018 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 <ttrace.h>
+#include <dali/internal/trace/tizen/trace-manager-impl-tizen.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+TraceManagerTizen::TraceManagerTizen( PerformanceInterface* performanceInterface )
+: TraceManager( performanceInterface )
+{
+}
+
+Dali::Integration::Trace::LogContextFunction TraceManagerTizen::GetLogContextFunction()
+{
+  return LogContext;
+}
+
+void TraceManagerTizen::LogContext( bool start, const char* tag )
+{
+  if( start )
+  {
+    traceBegin( TTRACE_TAG_GRAPHICS, tag );
+  }
+  else
+  {
+    traceEnd( TTRACE_TAG_GRAPHICS );
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/trace/tizen/trace-manager-impl-tizen.h b/dali/internal/trace/tizen/trace-manager-impl-tizen.h
new file mode 100644 (file)
index 0000000..58432cc
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef DALI_INTERNAL_TRACE_MANAGER_IMPL_TIZEN_H
+#define DALI_INTERNAL_TRACE_MANAGER_IMPL_TIZEN_H
+
+/*
+ * Copyright (c) 2018 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
+
+// INTERNAL INCLUDES
+#include <dali/internal/trace/common/trace-manager-impl.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class PerformanceInterface;
+
+class TraceManagerTizen : public Dali::Internal::Adaptor::TraceManager
+{
+public:
+  /**
+   * Explicit Constructor
+   */
+  explicit TraceManagerTizen( PerformanceInterface* performanceInterface );
+
+protected:
+
+  /**
+   * Destructor
+   */
+  ~TraceManagerTizen() override = default;
+
+  /**
+   * Obtain the LogContextFunction method (Tizen specific) used for tracing
+   */
+  virtual Dali::Integration::Trace::LogContextFunction GetLogContextFunction() final;
+
+private:
+
+  /**
+   * LogContext method (Tizen specific) used for tracing
+   */
+  static void LogContext( bool start, const char* tag );
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TRACE_MANAGER_IMPL_TIZEN_H
diff --git a/dali/internal/vector-animation/common/vector-animation-renderer-impl.cpp b/dali/internal/vector-animation/common/vector-animation-renderer-impl.cpp
new file mode 100644 (file)
index 0000000..1b76ff3
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/vector-animation/common/vector-animation-renderer-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/type-registry.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // unnamed namespace
+{
+
+// Type Registration
+Dali::BaseHandle Create()
+{
+  return Dali::BaseHandle();
+}
+
+Dali::TypeRegistration type( typeid( Dali::VectorAnimationRenderer ), typeid( Dali::BaseHandle ), Create );
+
+} // unnamed namespace
+
+VectorAnimationRendererPtr VectorAnimationRenderer::New()
+{
+  VectorAnimationRendererPtr renderer = new VectorAnimationRenderer();
+  return renderer;
+}
+
+VectorAnimationRenderer::VectorAnimationRenderer()
+: mPlugin( std::string() )
+{
+}
+
+VectorAnimationRenderer::~VectorAnimationRenderer()
+{
+}
+
+void VectorAnimationRenderer::Initialize( const std::string& url )
+{
+  mPlugin.Initialize( url );
+}
+
+void VectorAnimationRenderer::Finalize()
+{
+  mPlugin.Finalize();
+}
+
+void VectorAnimationRenderer::SetRenderer( Dali::Renderer renderer )
+{
+  mPlugin.SetRenderer( renderer );
+}
+
+void VectorAnimationRenderer::SetSize( uint32_t width, uint32_t height )
+{
+  mPlugin.SetSize( width, height );
+}
+
+bool VectorAnimationRenderer::Render( uint32_t frameNumber )
+{
+  return mPlugin.Render( frameNumber );
+}
+
+uint32_t VectorAnimationRenderer::GetTotalFrameNumber() const
+{
+  return mPlugin.GetTotalFrameNumber();
+}
+
+float VectorAnimationRenderer::GetFrameRate() const
+{
+  return mPlugin.GetFrameRate();
+}
+
+void VectorAnimationRenderer::GetDefaultSize( uint32_t& width, uint32_t& height ) const
+{
+  mPlugin.GetDefaultSize( width, height );
+}
+
+void VectorAnimationRenderer::GetLayerInfo( Property::Map& map ) const
+{
+  mPlugin.GetLayerInfo( map );
+}
+
+bool VectorAnimationRenderer::GetMarkerInfo( const std::string& marker, uint32_t& startFrame, uint32_t& endFrame ) const
+{
+  return mPlugin.GetMarkerInfo( marker, startFrame, endFrame );
+}
+
+Dali::VectorAnimationRenderer::UploadCompletedSignalType& VectorAnimationRenderer::UploadCompletedSignal()
+{
+  return mPlugin.UploadCompletedSignal();
+}
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
diff --git a/dali/internal/vector-animation/common/vector-animation-renderer-impl.h b/dali/internal/vector-animation/common/vector-animation-renderer-impl.h
new file mode 100755 (executable)
index 0000000..b635683
--- /dev/null
@@ -0,0 +1,155 @@
+#ifndef DALI_INTERNAL_VECTOR_ANIMATION_RENDERER_IMPL_H
+#define DALI_INTERNAL_VECTOR_ANIMATION_RENDERER_IMPL_H
+
+/*
+ * Copyright (c) 2019 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/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/vector-animation-renderer.h>
+#include <dali/internal/vector-animation/common/vector-animation-renderer-plugin-proxy.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class VectorAnimationRenderer;
+using VectorAnimationRendererPtr = IntrusivePtr< VectorAnimationRenderer >;
+
+/**
+ * Dali internal VectorAnimationRenderer.
+ */
+class VectorAnimationRenderer : public BaseObject, public ConnectionTracker
+{
+public:
+
+  /**
+   * @brief Creates a VectorAnimationRenderer object.
+   *
+   * @param[in] url The url of the vector animation file
+   */
+  static VectorAnimationRendererPtr New();
+
+  /**
+   * @brief Initializes member data.
+   */
+  void Initialize( const std::string& url );
+
+  /**
+   * @copydoc Dali::VectorAnimationRenderer::Finalize()
+   */
+  void Finalize();
+
+  /**
+   * @copydoc Dali::VectorAnimationRenderer::SetRenderer()
+   */
+  void SetRenderer( Dali::Renderer renderer );
+
+  /**
+   * @copydoc Dali::VectorAnimationRenderer::SetSize()
+   */
+  void SetSize( uint32_t width, uint32_t height );
+
+  /**
+   * @copydoc Dali::VectorAnimationRenderer::Render()
+   */
+  bool Render( uint32_t frameNumber );
+
+  /**
+   * @copydoc Dali::VectorAnimationRenderer::GetTotalFrameNumber()
+   */
+  uint32_t GetTotalFrameNumber() const;
+
+  /**
+   * @copydoc Dali::VectorAnimationRenderer::GetFrameRate()
+   */
+  float GetFrameRate() const;
+
+  /**
+   * @copydoc Dali::VectorAnimationRenderer::GetDefaultSize()
+   */
+  void GetDefaultSize( uint32_t& width, uint32_t& height ) const;
+
+  /**
+   * @copydoc Dali::VectorAnimationRenderer::GetLayerInfo()
+   */
+  void GetLayerInfo( Property::Map& map ) const;
+
+  /**
+   * @copydoc Dali::VectorAnimationRenderer::GetMarkerInfo()
+   */
+  bool GetMarkerInfo( const std::string& marker, uint32_t& startFrame, uint32_t& endFrame ) const;
+
+  /**
+   * @copydoc Dali::VectorAnimationRenderer::UploadCompletedSignal()
+   */
+  Dali::VectorAnimationRenderer::UploadCompletedSignalType& UploadCompletedSignal();
+
+private:
+
+  /**
+   * @brief Constructor
+   */
+  VectorAnimationRenderer();
+
+  /**
+   * @brief Destructor.
+   */
+  ~VectorAnimationRenderer();
+
+private:
+
+  VectorAnimationRenderer( const VectorAnimationRenderer& ) = delete;
+  VectorAnimationRenderer& operator=( VectorAnimationRenderer& )  = delete;
+
+private:
+
+  VectorAnimationRendererPluginProxy mPlugin;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+inline static Internal::Adaptor::VectorAnimationRenderer& GetImplementation( Dali::VectorAnimationRenderer& renderer )
+{
+  DALI_ASSERT_ALWAYS( renderer && "VectorAnimationRenderer handle is empty." );
+
+  BaseObject& handle = renderer.GetBaseObject();
+
+  return static_cast< Internal::Adaptor::VectorAnimationRenderer& >( handle );
+}
+
+inline static const Internal::Adaptor::VectorAnimationRenderer& GetImplementation( const Dali::VectorAnimationRenderer& renderer )
+{
+  DALI_ASSERT_ALWAYS( renderer && "VectorAnimationRenderer handle is empty." );
+
+  const BaseObject& handle = renderer.GetBaseObject();
+
+  return static_cast< const Internal::Adaptor::VectorAnimationRenderer& >( handle );
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_VECTOR_ANIMATION_RENDERER_IMPL_H
diff --git a/dali/internal/vector-animation/common/vector-animation-renderer-plugin-proxy.cpp b/dali/internal/vector-animation/common/vector-animation-renderer-plugin-proxy.cpp
new file mode 100644 (file)
index 0000000..6eae9bf
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/vector-animation/common/vector-animation-renderer-plugin-proxy.h>
+
+// EXTERNAL INCLUDES
+#include <dlfcn.h>
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+// The default plugin name
+const char* DEFAULT_OBJECT_NAME( "libdali-vector-animation-renderer-plugin.so" );
+
+}
+
+VectorAnimationRendererPluginProxy::VectorAnimationRendererPluginProxy( const std::string& sharedObjectName )
+: mSharedObjectName(),
+  mLibHandle( NULL ),
+  mPlugin( NULL ),
+  mCreateVectorAnimationRendererPtr( NULL ),
+  mDefaultSignal()
+{
+  if( !sharedObjectName.empty() )
+  {
+    mSharedObjectName = sharedObjectName;
+  }
+  else
+  {
+    mSharedObjectName = DEFAULT_OBJECT_NAME;
+  }
+
+  Initialize();
+}
+
+VectorAnimationRendererPluginProxy::~VectorAnimationRendererPluginProxy()
+{
+  if( mPlugin )
+  {
+    delete mPlugin;
+    mPlugin = NULL;
+
+    if( mLibHandle && dlclose( mLibHandle ) )
+    {
+      DALI_LOG_ERROR( "Error closing vector animation renderer plugin library: %s\n", dlerror() );
+    }
+  }
+}
+
+void VectorAnimationRendererPluginProxy::Initialize()
+{
+  mLibHandle = dlopen( mSharedObjectName.c_str(), RTLD_LAZY );
+
+  char* error = dlerror();
+  if( mLibHandle == NULL || error != NULL )
+  {
+    DALI_LOG_ERROR( "VectorAnimationRendererPluginProxy::Initialize: dlopen error [%s]\n", error );
+    return;
+  }
+
+  // load plugin
+  mCreateVectorAnimationRendererPtr = reinterpret_cast< CreateVectorAnimationRendererFunction >( dlsym( mLibHandle, "CreateVectorAnimationRendererPlugin" ) );
+
+  error = dlerror();
+  if( mCreateVectorAnimationRendererPtr == NULL || error != NULL )
+  {
+    DALI_LOG_ERROR( "VectorAnimationRendererPluginProxy::Initialize: Cannot load symbol: %s\n", error );
+    return;
+  }
+
+  mPlugin = mCreateVectorAnimationRendererPtr();
+  if( !mPlugin )
+  {
+    DALI_LOG_ERROR("VectorAnimationRendererPluginProxy::Initialize: Plugin creation failed\n");
+    return;
+  }
+}
+
+bool VectorAnimationRendererPluginProxy::Initialize( const std::string& url )
+{
+  if( mPlugin )
+  {
+    return mPlugin->Initialize( url );
+  }
+  return false;
+}
+
+void VectorAnimationRendererPluginProxy::Finalize()
+{
+  if( mPlugin )
+  {
+    mPlugin->Finalize();
+  }
+}
+
+void VectorAnimationRendererPluginProxy::SetRenderer( Dali::Renderer renderer )
+{
+  if( mPlugin )
+  {
+    mPlugin->SetRenderer( renderer );
+  }
+}
+
+void VectorAnimationRendererPluginProxy::SetSize( uint32_t width, uint32_t height )
+{
+  if( mPlugin )
+  {
+    mPlugin->SetSize( width, height );
+  }
+}
+
+bool VectorAnimationRendererPluginProxy::Render( uint32_t frameNumber )
+{
+  if( mPlugin )
+  {
+    return mPlugin->Render( frameNumber );
+  }
+  return false;
+}
+
+uint32_t VectorAnimationRendererPluginProxy::GetTotalFrameNumber() const
+{
+  if( mPlugin )
+  {
+    return mPlugin->GetTotalFrameNumber();
+  }
+  return 0;
+}
+
+float VectorAnimationRendererPluginProxy::GetFrameRate() const
+{
+  if( mPlugin )
+  {
+    return mPlugin->GetFrameRate();
+  }
+  return 0.0f;
+}
+
+void VectorAnimationRendererPluginProxy::GetDefaultSize( uint32_t& width, uint32_t& height ) const
+{
+  if( mPlugin )
+  {
+    mPlugin->GetDefaultSize( width, height );
+  }
+}
+
+void VectorAnimationRendererPluginProxy::GetLayerInfo( Property::Map& map ) const
+{
+  if( mPlugin )
+  {
+    mPlugin->GetLayerInfo( map );
+  }
+}
+
+bool VectorAnimationRendererPluginProxy::GetMarkerInfo( const std::string& marker, uint32_t& startFrame, uint32_t& endFrame ) const
+{
+  if( mPlugin )
+  {
+    return mPlugin->GetMarkerInfo( marker, startFrame, endFrame );
+  }
+  return false;
+}
+
+VectorAnimationRendererPlugin::UploadCompletedSignalType& VectorAnimationRendererPluginProxy::UploadCompletedSignal()
+{
+  if( mPlugin )
+  {
+    return mPlugin->UploadCompletedSignal();
+  }
+  return mDefaultSignal;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/vector-animation/common/vector-animation-renderer-plugin-proxy.h b/dali/internal/vector-animation/common/vector-animation-renderer-plugin-proxy.h
new file mode 100644 (file)
index 0000000..1480aca
--- /dev/null
@@ -0,0 +1,137 @@
+#ifndef DALI_INTERNAL_VECTOR_ANIMATION_RENDERER_PLUGIN_PROXY_H
+#define DALI_INTERNAL_VECTOR_ANIMATION_RENDERER_PLUGIN_PROXY_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/adaptor-framework/vector-animation-renderer-plugin.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * Proxy class to dynamically load, use and unload vector animation renderer plugin.
+ */
+class VectorAnimationRendererPluginProxy
+{
+public:
+
+  /**
+   * @brief Constructor
+   */
+  VectorAnimationRendererPluginProxy( const std::string& sharedObjectName );
+
+  /**
+   * @brief Destructor
+   */
+  ~VectorAnimationRendererPluginProxy();
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::Initialize()
+   */
+  bool Initialize( const std::string& url );
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::Finalize()
+   */
+  void Finalize();
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::SetRenderer()
+   */
+  void SetRenderer( Dali::Renderer renderer );
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::SetSize()
+   */
+  void SetSize( uint32_t width, uint32_t height );
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::Render()
+   */
+  bool Render( uint32_t frameNumber );
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::GetTotalFrameNumber()
+   */
+  uint32_t GetTotalFrameNumber() const;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::GetFrameRate()
+   */
+  float GetFrameRate() const;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::GetDefaultSize()
+   */
+  void GetDefaultSize( uint32_t& width, uint32_t& height ) const;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::GetLayerInfo()
+   */
+  void GetLayerInfo( Property::Map& map ) const;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::GetMarkerInfo()
+   */
+  bool GetMarkerInfo( const std::string& marker, uint32_t& startFrame, uint32_t& endFrame ) const;
+
+  /**
+   * @copydoc Dali::VectorAnimationRendererPlugin::UploadCompletedSignal()
+   */
+  VectorAnimationRendererPlugin::UploadCompletedSignalType& UploadCompletedSignal();
+
+  // Not copyable or movable
+  VectorAnimationRendererPluginProxy( const VectorAnimationRendererPluginProxy& ) = delete; ///< Deleted copy constructor
+  VectorAnimationRendererPluginProxy( VectorAnimationRendererPluginProxy&& ) = delete; ///< Deleted move constructor
+  VectorAnimationRendererPluginProxy& operator=( const VectorAnimationRendererPluginProxy& ) = delete; ///< Deleted copy assignment operator
+  VectorAnimationRendererPluginProxy& operator=( VectorAnimationRendererPluginProxy&& ) = delete; ///< Deleted move assignment operator
+
+private:
+
+  /**
+   * Dynamically loads the plugin.
+   */
+  void Initialize();
+
+private:
+
+  using CreateVectorAnimationRendererFunction = Dali::VectorAnimationRendererPlugin* (*)();
+
+  std::string                            mSharedObjectName;   ///< Shared object name
+  void*                                  mLibHandle;          ///< Handle for the loaded library
+  Dali::VectorAnimationRendererPlugin*   mPlugin;             ///< Plugin handle
+
+  CreateVectorAnimationRendererFunction  mCreateVectorAnimationRendererPtr;   ///< Function pointer called in adaptor to create a plugin instance
+  VectorAnimationRendererPlugin::UploadCompletedSignalType mDefaultSignal;
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_VECTOR_ANIMATION_RENDERER_PLUGIN_PROXY_H
diff --git a/dali/internal/vector-animation/file.list b/dali/internal/vector-animation/file.list
new file mode 100644 (file)
index 0000000..197d590
--- /dev/null
@@ -0,0 +1,7 @@
+
+# module: vector-animation, backend: common
+SET( adaptor_vector_animation_common_src_files 
+    ${adaptor_vector_animation_dir}/common/vector-animation-renderer-impl.cpp 
+    ${adaptor_vector_animation_dir}/common/vector-animation-renderer-plugin-proxy.cpp
+)
+
diff --git a/dali/internal/video/common/video-player-impl.cpp b/dali/internal/video/common/video-player-impl.cpp
new file mode 100755 (executable)
index 0000000..a431ecb
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * 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.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/video/common/video-player-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dlfcn.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/type-registry.h>
+#include <dali/public-api/object/any.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/native-image-source.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // unnamed namespace
+{
+
+#if _GLIBCXX_USE_CXX11_ABI
+const char* VIDEO_PLUGIN_SO( "libdali-video-player-plugin.so" );
+#else
+const char* VIDEO_PLUGIN_SO( "libdali-video-player-plugin-cxx03.so" );
+#endif
+
+Dali::BaseHandle Create()
+{
+  return Dali::VideoPlayer::New();
+}
+
+Dali::TypeRegistration type( typeid( Dali::VideoPlayer ), typeid( Dali::BaseHandle ), Create );
+
+} // unnamed namespace
+
+VideoPlayerPtr VideoPlayer::New()
+{
+  VideoPlayerPtr player = new VideoPlayer();
+  return player;
+}
+
+VideoPlayer::VideoPlayer()
+: mPlugin( NULL ),
+  mHandle( NULL ),
+  mCreateVideoPlayerPtr( NULL ),
+  mDestroyVideoPlayerPtr( NULL )
+{
+}
+
+VideoPlayer::~VideoPlayer()
+{
+  if( mHandle != NULL )
+  {
+    if( mDestroyVideoPlayerPtr != NULL )
+    {
+      mDestroyVideoPlayerPtr( mPlugin );
+    }
+
+    dlclose( mHandle );
+  }
+}
+
+void VideoPlayer::Initialize()
+{
+  char* error = NULL;
+
+  mHandle = dlopen( VIDEO_PLUGIN_SO, RTLD_LAZY );
+
+  error = dlerror();
+  if( mHandle == NULL || error != NULL )
+  {
+    DALI_LOG_ERROR( "VideoPlayer::Initialize(), dlopen error: %s\n", error );
+    return;
+  }
+
+  mCreateVideoPlayerPtr = reinterpret_cast< CreateVideoPlayerFunction >( dlsym( mHandle, "CreateVideoPlayerPlugin" ) );
+
+  error = dlerror();
+  if( mCreateVideoPlayerPtr == NULL || error != NULL )
+  {
+    DALI_LOG_ERROR( "Can't load symbol CreateVideoPlayerPlugin(), error: %s\n", error );
+    return;
+  }
+
+  mPlugin = mCreateVideoPlayerPtr();
+
+  if( mPlugin == NULL )
+  {
+    DALI_LOG_ERROR( "Can't create the VideoPlayerPlugin object\n" );
+    return;
+  }
+
+  mDestroyVideoPlayerPtr = reinterpret_cast< DestroyVideoPlayerFunction >( dlsym( mHandle, "DestroyVideoPlayerPlugin" ) );
+
+  error = dlerror();
+  if( mDestroyVideoPlayerPtr == NULL || error != NULL )
+  {
+    DALI_LOG_ERROR( "Can't load symbol DestroyVideoPlayerPlugin(), error: %s\n", error );
+    return;
+  }
+}
+
+void VideoPlayer::SetUrl( const std::string& url )
+{
+  if( mPlugin != NULL )
+  {
+    mPlugin->SetUrl( url );
+  }
+}
+
+std::string VideoPlayer::GetUrl()
+{
+  if( mPlugin != NULL )
+  {
+    return mPlugin->GetUrl();
+  }
+
+  return std::string();
+}
+
+void VideoPlayer::SetLooping(bool looping)
+{
+  if( mPlugin != NULL )
+  {
+    mPlugin->SetLooping( looping );
+  }
+}
+
+bool VideoPlayer::IsLooping()
+{
+  if( mPlugin != NULL )
+  {
+    return mPlugin->IsLooping();
+  }
+
+  return false;
+}
+
+void VideoPlayer::Play()
+{
+  if( mPlugin != NULL )
+  {
+    mPlugin->Play();
+  }
+}
+
+void VideoPlayer::Pause()
+{
+  if( mPlugin != NULL )
+  {
+    mPlugin->Pause();
+  }
+}
+
+void VideoPlayer::Stop()
+{
+  if( mPlugin != NULL )
+  {
+    mPlugin->Stop();
+  }
+}
+
+void VideoPlayer::SetMute( bool mute )
+{
+  if( mPlugin != NULL )
+  {
+    mPlugin->SetMute( mute );
+  }
+}
+
+bool VideoPlayer::IsMuted()
+{
+  if( mPlugin != NULL )
+  {
+    return mPlugin->IsMuted();
+  }
+
+  return false;
+}
+
+void VideoPlayer::SetVolume( float left, float right )
+{
+  if( mPlugin != NULL )
+  {
+    mPlugin->SetVolume( left, right );
+  }
+}
+
+void VideoPlayer::GetVolume( float& left, float& right )
+{
+  if( mPlugin != NULL )
+  {
+    mPlugin->GetVolume( left, right );
+  }
+}
+
+void VideoPlayer::SetRenderingTarget( Dali::Any target )
+{
+  if( mPlugin != NULL )
+  {
+    mPlugin->SetRenderingTarget( target );
+  }
+}
+
+void VideoPlayer::SetPlayPosition( int millisecond )
+{
+  if( mPlugin != NULL )
+  {
+    mPlugin->SetPlayPosition( millisecond );
+  }
+}
+
+int VideoPlayer::GetPlayPosition()
+{
+  if( mPlugin != NULL )
+  {
+    return mPlugin->GetPlayPosition();
+  }
+  return 0;
+}
+
+void VideoPlayer::SetDisplayArea( DisplayArea area )
+{
+  if( mPlugin != NULL )
+  {
+    mPlugin->SetDisplayArea( area );
+  }
+}
+
+void VideoPlayer::SetDisplayRotation( Dali::VideoPlayerPlugin::DisplayRotation rotation )
+{
+  if( mPlugin != NULL )
+  {
+    mPlugin->SetDisplayRotation( rotation );
+  }
+}
+
+Dali::VideoPlayerPlugin::DisplayRotation VideoPlayer::GetDisplayRotation()
+{
+  if( mPlugin != NULL )
+  {
+    return mPlugin->GetDisplayRotation();
+  }
+
+  return Dali::VideoPlayerPlugin::ROTATION_NONE;
+}
+
+Dali::VideoPlayerPlugin::VideoPlayerSignalType& VideoPlayer::FinishedSignal()
+{
+  if( mPlugin != NULL )
+  {
+    return mPlugin->FinishedSignal();
+  }
+
+  return mFinishedSignal;
+}
+
+void VideoPlayer::Forward( int millisecond )
+{
+  if( mPlugin != NULL )
+  {
+    mPlugin->Forward( millisecond );
+  }
+}
+
+void VideoPlayer::Backward( int millisecond )
+{
+  if( mPlugin != NULL )
+  {
+    mPlugin->Backward( millisecond );
+  }
+}
+
+bool VideoPlayer::IsVideoTextureSupported()
+{
+  if( mPlugin != NULL )
+  {
+    return mPlugin->IsVideoTextureSupported();
+  }
+
+  return false;
+}
+
+void VideoPlayer::SetCodecType( Dali::VideoPlayerPlugin::CodecType type )
+{
+  if( mPlugin != NULL )
+  {
+    mPlugin->SetCodecType( type );
+  }
+}
+
+Dali::VideoPlayerPlugin::CodecType VideoPlayer::GetCodecType() const
+{
+  if( mPlugin != NULL )
+  {
+    return mPlugin->GetCodecType();
+  }
+
+  return Dali::VideoPlayerPlugin::CodecType::DEFAULT;
+}
+
+void VideoPlayer::SetDisplayMode( Dali::VideoPlayerPlugin::DisplayMode::Type mode )
+{
+  if( mPlugin != NULL )
+  {
+    mPlugin->SetDisplayMode( mode );
+  }
+}
+
+Dali::VideoPlayerPlugin::DisplayMode::Type VideoPlayer::GetDisplayMode() const
+{
+  if( mPlugin != NULL )
+  {
+    return mPlugin->GetDisplayMode();
+  }
+
+  return Dali::VideoPlayerPlugin::DisplayMode::DST_ROI;
+}
+
+Any VideoPlayer::GetMediaPlayer()
+{
+  if( mPlugin != NULL )
+  {
+    return mPlugin->GetMediaPlayer();
+  }
+  return NULL;
+}
+
+} // namespace Adaptor;
+} // namespace Internal;
+} // namespace Dali;
+
diff --git a/dali/internal/video/common/video-player-impl.h b/dali/internal/video/common/video-player-impl.h
new file mode 100755 (executable)
index 0000000..71a493e
--- /dev/null
@@ -0,0 +1,250 @@
+#ifndef DALI_VIDEO_PLAYER_IMPL_H
+#define DALI_VIDEO_PLAYER_IMPL_H
+
+/*
+ * Copyright (c) 2019 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/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/video-player.h>
+#include <dali/devel-api/adaptor-framework/video-player-plugin.h>
+
+namespace Dali
+{
+class Any;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class VideoPlayer;
+
+typedef IntrusivePtr< VideoPlayer > VideoPlayerPtr;
+
+/**
+ * @brief VideoPlayer class is used for video playback.
+ * @SINCE_1_1.24
+ */
+class VideoPlayer: public Dali::BaseObject
+{
+public:
+
+  /**
+   * @brief Creates a new VideoPlayer handle
+   * @SINCE_1_1.24
+   * @return VideoPlayer pointer
+   */
+  static VideoPlayerPtr New();
+
+  /**
+   * @copydoc Dali::VideoPlayer::SetUrl()
+   */
+  void SetUrl( const std::string& url );
+
+  /**
+   * @copydoc Dali::VideoPlayer::GetUrl()
+   */
+  std::string GetUrl();
+
+  /**
+   * @copydoc Dali::VideoPlayer::SetLooping()
+   */
+  void SetLooping(bool looping);
+
+  /**
+   * @copydoc Dali::VideoPlayer::IsLooping()
+   */
+  bool IsLooping();
+
+  /**
+   * @copydoc Dali::VideoPlayer::Play()
+   */
+  void Play();
+
+  /**
+   * @copydoc Dali::VideoPlayer::Pause()
+   */
+  void Pause();
+
+  /**
+   * @copydoc Dali::VideoPlayer::Stop()
+   */
+  void Stop();
+
+  /**
+   * @copydoc Dali::VideoPlayer::SetMute()
+   */
+  void SetMute( bool mute );
+
+  /**
+   * @copydoc Dali::VideoPlayer::IsMuted()
+   */
+  bool IsMuted();
+
+  /**
+   * @copydoc Dali::VideoPlayer::SetVolume()
+   */
+  void SetVolume( float left, float right );
+
+  /**
+   * @copydoc Dali::VideoPlayer::GetVolume()
+   */
+  void GetVolume( float& left, float& right );
+
+  /**
+   * @copydoc Dali::VideoPlayer::SetRenderingTarget()
+   */
+  void SetRenderingTarget( Dali::Any target );
+
+  /**
+   * @copydoc Dali::VideoPlayer::SetPlayPosition()
+   */
+  void SetPlayPosition( int millisecond );
+
+  /**
+   * @copydoc Dali::VideoPlayer::GetPlayPosition()
+   */
+  int GetPlayPosition();
+
+  /**
+   * @copydoc Dali::VideoPlayer::SetDisplayArea()
+   */
+  void SetDisplayArea( DisplayArea area );
+
+  /**
+   * @copydoc Dali::VideoPlayer::SetSetDisplayRotation()
+   */
+  void SetDisplayRotation( Dali::VideoPlayerPlugin::DisplayRotation rotation );
+
+  /**
+   * @copydoc Dali::VideoPlayer::GetDisplayRotation()
+   */
+  Dali::VideoPlayerPlugin::DisplayRotation GetDisplayRotation();
+
+  /**
+   * @copydoc Dali::VideoPlayer::FinishedSignal()
+   */
+  Dali::VideoPlayerPlugin::VideoPlayerSignalType& FinishedSignal();
+
+  /**
+   * @brief Initializes member data.
+   */
+  void Initialize();
+
+  /**
+   * @brief Dali::VideoPlayer::Forward()
+   */
+  void Forward( int millisecond );
+
+  /**
+   * @brief Dali::VideoPlayer::Backward()
+   */
+  void Backward( int millisecond );
+
+  /**
+   * @brief Dali::VideoPlayer::IsVideoTextureSupported()
+   */
+  bool IsVideoTextureSupported();
+
+  /**
+   * @brief Dali::VideoPlayer::SetCodecType()
+   */
+  void SetCodecType( Dali::VideoPlayerPlugin::CodecType type );
+
+  /**
+   * @brief Dali::VideoPlayer::GetCodecType()
+   */
+  Dali::VideoPlayerPlugin::CodecType GetCodecType() const;
+
+  /**
+   * @copydoc Dali::VideoPlayer::SetDisplayMode()
+   */
+  void SetDisplayMode( Dali::VideoPlayerPlugin::DisplayMode::Type mode );
+
+  /**
+   * @brief Dali::VideoPlayer::GetDisplayMode()
+   */
+  Dali::VideoPlayerPlugin::DisplayMode::Type GetDisplayMode() const;
+
+  /**
+   * @brief Dali::VideoPlayer::GetMediaPlayer()
+   */
+  Any GetMediaPlayer();
+
+private:
+
+  /**
+   * @brief Constructor.
+   * @SINCE_1_1.24
+   */
+  VideoPlayer();
+
+  /**
+   * @brief Destructor.
+   * @SINCE_1_1.24
+   */
+  virtual ~VideoPlayer();
+
+  // Undefined copy constructor
+  VideoPlayer( const VideoPlayer& player );
+
+  // Undefined assignment operator
+  VideoPlayer& operator=( const VideoPlayer& player );
+
+private:
+
+  Dali::VideoPlayerPlugin* mPlugin; ///< Videoplayer plugin handle
+  void* mHandle; ///< Handle for the loaded library
+
+  typedef Dali::VideoPlayerPlugin* (*CreateVideoPlayerFunction)();
+  typedef void (*DestroyVideoPlayerFunction)( Dali::VideoPlayerPlugin* plugin );
+
+  CreateVideoPlayerFunction mCreateVideoPlayerPtr;
+  DestroyVideoPlayerFunction mDestroyVideoPlayerPtr;
+
+  Dali::VideoPlayerPlugin::VideoPlayerSignalType mFinishedSignal;
+};
+
+} // namespace Adaptor
+} // namespace Internal
+
+inline static Internal::Adaptor::VideoPlayer& GetImplementation( Dali::VideoPlayer& player )
+{
+  DALI_ASSERT_ALWAYS( player && "VideoPlayer handle is empty." );
+
+  BaseObject& handle = player.GetBaseObject();
+
+  return static_cast< Internal::Adaptor::VideoPlayer& >( handle );
+}
+
+inline static const Internal::Adaptor::VideoPlayer& GetImplementation( const Dali::VideoPlayer& player )
+{
+  DALI_ASSERT_ALWAYS( player && "VideoPlayer handle is empty." );
+
+  const BaseObject& handle = player.GetBaseObject();
+
+  return static_cast< const Internal::Adaptor::VideoPlayer& >( handle );
+}
+
+} // namespace Dali;
+
+#endif // DALI_VIDEO_PLAYER_IMPL_H
+
diff --git a/dali/internal/video/file.list b/dali/internal/video/file.list
new file mode 100644 (file)
index 0000000..ab8de67
--- /dev/null
@@ -0,0 +1,6 @@
+
+# module: video, backend: common
+SET( adaptor_video_common_src_files 
+    ${adaptor_video_dir}/common/video-player-impl.cpp
+)
+
diff --git a/dali/internal/web-engine/common/web-engine-impl.cpp b/dali/internal/web-engine/common/web-engine-impl.cpp
new file mode 100644 (file)
index 0000000..a8c40b5
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/web-engine/common/web-engine-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dlfcn.h>
+#include <dali/integration-api/debug.h>
+#include <dali/public-api/object/type-registry.h>
+#include <sstream>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/environment-variable.h>
+#include <dali/internal/system/common/environment-variables.h>
+#include <dali/public-api/adaptor-framework/native-image-source.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace // unnamed namespace
+{
+
+constexpr char const * const kPluginFullNamePrefix = "libdali-web-engine-";
+constexpr char const * const kPluginFullNamePostfix = "-plugin.so";
+constexpr char const * const kPluginFullNameDefault = "libdali-web-engine-plugin.so";
+
+// Note: Dali WebView policy does not allow to use multiple web engines in an application.
+// So once pluginName is set to non-empty string, it will not change.
+std::string pluginName;
+
+std::string MakePluginName( const char* environmentName )
+{
+  std::stringstream fullName;
+  fullName << kPluginFullNamePrefix << environmentName << kPluginFullNamePostfix;
+  return std::move( fullName.str() );
+}
+
+Dali::BaseHandle Create()
+{
+  return Dali::WebEngine::New();
+}
+
+Dali::TypeRegistration type( typeid( Dali::WebEngine ), typeid( Dali::BaseHandle ), Create );
+
+} // unnamed namespace
+
+WebEnginePtr WebEngine::New()
+{
+  WebEngine* instance = new WebEngine();
+
+  if( !instance->Initialize() )
+  {
+    delete instance;
+    return nullptr;
+  }
+
+  return instance;
+}
+
+WebEngine::WebEngine()
+: mPlugin( NULL ),
+  mHandle( NULL ),
+  mCreateWebEnginePtr( NULL ),
+  mDestroyWebEnginePtr( NULL )
+{
+}
+
+WebEngine::~WebEngine()
+{
+  if( mHandle != NULL )
+  {
+    if( mDestroyWebEnginePtr != NULL )
+    {
+      mPlugin->Destroy();
+      mDestroyWebEnginePtr( mPlugin );
+    }
+
+    dlclose( mHandle );
+  }
+}
+
+bool WebEngine::InitializePluginHandle()
+{
+  if( pluginName.length() == 0 )
+  {
+    // pluginName is not initialized yet.
+    const char* name = EnvironmentVariable::GetEnvironmentVariable( DALI_ENV_WEB_ENGINE_NAME );
+    if( name )
+    {
+      pluginName = MakePluginName( name );
+      mHandle = dlopen( pluginName.c_str(), RTLD_LAZY );
+      if( mHandle )
+      {
+        return true;
+      }
+    }
+    pluginName = std::string( kPluginFullNameDefault );
+  }
+
+  mHandle = dlopen( pluginName.c_str(), RTLD_LAZY );
+  if( !mHandle )
+  {
+    DALI_LOG_ERROR( "Can't load %s : %s\n", pluginName.c_str(), dlerror() );
+    return false;
+  }
+
+  return true;
+}
+
+bool WebEngine::Initialize()
+{
+  char* error = NULL;
+
+  if( !InitializePluginHandle() )
+  {
+    return false;
+  }
+
+  mCreateWebEnginePtr = reinterpret_cast< CreateWebEngineFunction >( dlsym( mHandle, "CreateWebEnginePlugin" ) );
+  if( mCreateWebEnginePtr == NULL )
+  {
+    DALI_LOG_ERROR( "Can't load symbol CreateWebEnginePlugin(), error: %s\n", error );
+    return false;
+  }
+
+  mDestroyWebEnginePtr = reinterpret_cast< DestroyWebEngineFunction >( dlsym( mHandle, "DestroyWebEnginePlugin" ) );
+
+  if( mDestroyWebEnginePtr == NULL )
+  {
+    DALI_LOG_ERROR( "Can't load symbol DestroyWebEnginePlugin(), error: %s\n", error );
+    return false;
+  }
+
+  mPlugin = mCreateWebEnginePtr();
+
+  if( mPlugin == NULL )
+  {
+    DALI_LOG_ERROR( "Can't create the WebEnginePlugin object\n" );
+    return false;
+  }
+
+  return true;
+}
+
+void WebEngine::Create( int width, int height, const std::string& locale, const std::string& timezoneId )
+{
+  mPlugin->Create( width, height, locale, timezoneId );
+}
+
+void WebEngine::Destroy()
+{
+  mPlugin->Destroy();
+}
+
+Dali::NativeImageInterfacePtr WebEngine::GetNativeImageSource()
+{
+  return mPlugin->GetNativeImageSource();
+}
+
+void WebEngine::LoadUrl( const std::string& url )
+{
+  mPlugin->LoadUrl( url );
+}
+
+const std::string& WebEngine::GetUrl()
+{
+  return mPlugin->GetUrl();
+}
+
+void WebEngine::LoadHTMLString( const std::string& htmlString )
+{
+  mPlugin->LoadHTMLString( htmlString );
+}
+
+void WebEngine::Reload()
+{
+  mPlugin->Reload();
+}
+
+void WebEngine::StopLoading()
+{
+  mPlugin->StopLoading();
+}
+
+void WebEngine::Suspend()
+{
+  mPlugin->Suspend();
+}
+
+void WebEngine::Resume()
+{
+  mPlugin->Resume();
+}
+
+bool WebEngine::CanGoForward()
+{
+  return mPlugin->CanGoForward();
+}
+
+void WebEngine::GoForward()
+{
+  mPlugin->GoForward();
+}
+
+bool WebEngine::CanGoBack()
+{
+  return mPlugin->CanGoBack();
+}
+
+void WebEngine::GoBack()
+{
+  mPlugin->GoBack();
+}
+
+void WebEngine::EvaluateJavaScript( const std::string& script, std::function< void( const std::string& ) > resultHandler )
+{
+  mPlugin->EvaluateJavaScript( script, resultHandler );
+}
+
+void WebEngine::AddJavaScriptMessageHandler( const std::string& exposedObjectName, std::function< void(const std::string&) > handler )
+{
+  mPlugin->AddJavaScriptMessageHandler( exposedObjectName, handler );
+}
+
+void WebEngine::ClearHistory()
+{
+  mPlugin->ClearHistory();
+}
+
+void WebEngine::ClearCache()
+{
+  mPlugin->ClearCache();
+}
+
+void WebEngine::ClearCookies()
+{
+  mPlugin->ClearCookies();
+}
+
+Dali::WebEnginePlugin::CacheModel WebEngine::GetCacheModel() const
+{
+  return mPlugin->GetCacheModel();
+}
+
+void WebEngine::SetCacheModel( Dali::WebEnginePlugin::CacheModel cacheModel )
+{
+  mPlugin->SetCacheModel( cacheModel );
+}
+
+Dali::WebEnginePlugin::CookieAcceptPolicy WebEngine::GetCookieAcceptPolicy() const
+{
+  return mPlugin->GetCookieAcceptPolicy();
+}
+
+void WebEngine::SetCookieAcceptPolicy( Dali::WebEnginePlugin::CookieAcceptPolicy policy )
+{
+  mPlugin->SetCookieAcceptPolicy( policy );
+}
+
+const std::string& WebEngine::GetUserAgent() const
+{
+  return mPlugin->GetUserAgent();
+}
+
+void WebEngine::SetUserAgent( const std::string& userAgent )
+{
+  mPlugin->SetUserAgent( userAgent );
+}
+
+bool WebEngine::IsJavaScriptEnabled() const
+{
+  return mPlugin->IsJavaScriptEnabled();
+}
+
+void WebEngine::EnableJavaScript( bool enabled )
+{
+  mPlugin->EnableJavaScript( enabled );
+}
+
+bool WebEngine::AreImagesAutomaticallyLoaded() const
+{
+  return mPlugin->AreImagesAutomaticallyLoaded();
+}
+
+void WebEngine::LoadImagesAutomatically( bool automatic )
+{
+  mPlugin->LoadImagesAutomatically( automatic );
+}
+
+const std::string& WebEngine::GetDefaultTextEncodingName() const
+{
+  return mPlugin->GetDefaultTextEncodingName();
+}
+
+void WebEngine::SetDefaultTextEncodingName( const std::string& defaultTextEncodingName )
+{
+  mPlugin->SetDefaultTextEncodingName( defaultTextEncodingName );
+}
+
+int WebEngine::GetDefaultFontSize() const
+{
+  return mPlugin->GetDefaultFontSize();
+}
+
+void WebEngine::SetDefaultFontSize( int defaultFontSize )
+{
+  mPlugin->SetDefaultFontSize( defaultFontSize );
+}
+
+void WebEngine::SetSize( int width, int height )
+{
+  mPlugin->SetSize( width, height );
+}
+
+bool WebEngine::SendTouchEvent( const Dali::TouchData& touch )
+{
+  return mPlugin->SendTouchEvent( touch );
+}
+
+bool WebEngine::SendKeyEvent( const Dali::KeyEvent& event )
+{
+  return mPlugin->SendKeyEvent( event );
+}
+
+Dali::WebEnginePlugin::WebEnginePageLoadSignalType& WebEngine::PageLoadStartedSignal()
+{
+  return mPlugin->PageLoadStartedSignal();
+}
+
+Dali::WebEnginePlugin::WebEnginePageLoadSignalType& WebEngine::PageLoadFinishedSignal()
+{
+  return mPlugin->PageLoadFinishedSignal();
+}
+
+Dali::WebEnginePlugin::WebEnginePageLoadErrorSignalType& WebEngine::PageLoadErrorSignal()
+{
+  return mPlugin->PageLoadErrorSignal();
+}
+
+} // namespace Adaptor;
+} // namespace Internal;
+} // namespace Dali;
+
diff --git a/dali/internal/web-engine/common/web-engine-impl.h b/dali/internal/web-engine/common/web-engine-impl.h
new file mode 100644 (file)
index 0000000..bf64b23
--- /dev/null
@@ -0,0 +1,317 @@
+#ifndef DALI_WEB_ENGINE_IMPL_H
+#define DALI_WEB_ENGINE_IMPL_H
+
+/*
+ * Copyright (c) 2018 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/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/web-engine.h>
+#include <dali/devel-api/adaptor-framework/web-engine-plugin.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class WebEngine;
+
+typedef IntrusivePtr< WebEngine > WebEnginePtr;
+
+/**
+ * @brief WebEngine class is used for Web.
+ */
+class WebEngine : public Dali::BaseObject
+{
+public:
+
+  /**
+   * @brief Creates a new WebEngine handle
+   *
+   * @return WebEngine pointer
+   */
+  static WebEnginePtr New();
+
+  /**
+   * @copydoc Dali::WebEngine::Create()
+   */
+  void Create( int width, int height, const std::string& locale, const std::string& timezoneId );
+
+  /**
+   * @copydoc Dali::WebEngine::Destroy()
+   */
+  void Destroy();
+
+  /**
+   * @copydoc Dali::WebEngine::GetNativeImageSource()
+   */
+  Dali::NativeImageInterfacePtr GetNativeImageSource();
+
+  /**
+   * @copydoc Dali::WebEngine::LoadUrl()
+   */
+  void LoadUrl( const std::string& url );
+
+  /**
+   * @copydoc Dali::WebEngine::GetUrl()
+   */
+  const std::string& GetUrl();
+
+  /**
+   * @copydoc Dali::WebEngine::LoadHTMLString()
+   */
+  void LoadHTMLString( const std::string& htmlString );
+
+  /**
+   * @copydoc Dali::WebEngine::Reload()
+   */
+  void Reload();
+
+  /**
+   * @copydoc Dali::WebEngine::StopLoading()
+   */
+  void StopLoading();
+
+  /**
+   * @copydoc Dali::WebEngine::Suspend()
+   */
+  void Suspend();
+
+  /**
+   * @copydoc Dali::WebEngine::Resume()
+   */
+  void Resume();
+
+  /**
+   * @copydoc Dali::WebEngine::CanGoForward()
+   */
+  bool CanGoForward();
+
+  /**
+   * @copydoc Dali::WebEngine::GoForward()
+   */
+  void GoForward();
+
+  /**
+   * @copydoc Dali::WebEngine::CanGoBack()
+   */
+  bool CanGoBack();
+
+  /**
+   * @copydoc Dali::WebEngine::GoBack()
+   */
+  void GoBack();
+
+  /**
+   * @copydoc Dali::WebEngine::EvaluateJavaScript()
+   */
+  void EvaluateJavaScript( const std::string& script, std::function< void(const std::string&) > resultHandler );
+
+  /**
+   * @copydoc Dali::WebEngine::AddJavaScriptMessageHandler()
+   */
+  void AddJavaScriptMessageHandler( const std::string& exposedObjectName, std::function< void(const std::string&) > handler );
+
+  /**
+   * @copydoc Dali::WebEngine::ClearHistory()
+   */
+  void ClearHistory();
+
+  /**
+   * @copydoc Dali::WebEngine::ClearCache()
+   */
+  void ClearCache();
+
+  /**
+   * @copydoc Dali::WebEngine::ClearCookies()
+   */
+  void ClearCookies();
+
+  /**
+   * @copydoc Dali::WebEngine::GetCacheModel()
+   */
+  Dali::WebEnginePlugin::CacheModel GetCacheModel() const;
+
+  /**
+   * @copydoc Dali::WebEngine::SetCacheModel()
+   */
+  void SetCacheModel( Dali::WebEnginePlugin::CacheModel cacheModel );
+
+  /**
+   * @copydoc Dali::WebEngine::GetCookieAcceptPolicy()
+   */
+  Dali::WebEnginePlugin::CookieAcceptPolicy GetCookieAcceptPolicy() const;
+
+  /**
+   * @copydoc Dali::WebEngine::SetCookieAcceptPolicy()
+   */
+  void SetCookieAcceptPolicy( Dali::WebEnginePlugin::CookieAcceptPolicy policy );
+
+  /**
+   * @copydoc Dali::WebEngine::GetUserAgent()
+   */
+  const std::string& GetUserAgent() const;
+
+  /**
+   * @copydoc Dali::WebEngine::SetUserAgent()
+   */
+  void SetUserAgent( const std::string& userAgent );
+
+  /**
+   * @copydoc Dali::WebEngine::IsJavaScriptEnabled()
+   */
+  bool IsJavaScriptEnabled() const;
+
+  /**
+   * @copydoc Dali::WebEngine::EnableJavaScript()
+   */
+  void EnableJavaScript( bool enabled );
+
+  /**
+   * @copydoc Dali::WebEngine::AreImagesAutomaticallyLoaded()
+   */
+  bool AreImagesAutomaticallyLoaded() const;
+
+  /**
+   * @copydoc Dali::WebEngine::LoadImagesAutomatically()
+   */
+  void LoadImagesAutomatically( bool automatic );
+
+  /**
+   * @copydoc Dali::WebEngine::GetDefaultTextEncodingName()
+   */
+  const std::string& GetDefaultTextEncodingName() const;
+
+  /**
+   * @copydoc Dali::WebEngine::SetDefaultTextEncodingName()
+   */
+  void SetDefaultTextEncodingName( const std::string& defaultTextEncodingName );
+
+  /**
+   * @copydoc Dali::WebEngine::GetDefaultFontSize()
+   */
+  int GetDefaultFontSize() const;
+
+  /**
+   * @copydoc Dali::WebEngine::SetDefaultFontSize()
+   */
+  void SetDefaultFontSize( int defaultFontSize );
+
+  /**
+   * @copydoc Dali::WebEngine::SetSize()
+   */
+  void SetSize( int width, int height );
+
+  /**
+   * @copydoc Dali::WebEngine::SendTouchEvent()
+   */
+  bool SendTouchEvent( const Dali::TouchData& touch );
+
+  /**
+   * @copydoc Dali::WebEngine::SendKeyEvent()
+   */
+  bool SendKeyEvent( const Dali::KeyEvent& event );
+
+  /**
+   * @copydoc Dali::WebEngine::PageLoadStartedSignal()
+   */
+  Dali::WebEnginePlugin::WebEnginePageLoadSignalType& PageLoadStartedSignal();
+
+  /**
+   * @copydoc Dali::WebEngine::PageLoadFinishedSignal()
+   */
+  Dali::WebEnginePlugin::WebEnginePageLoadSignalType& PageLoadFinishedSignal();
+
+  /**
+   * @copydoc Dali::WebEngine::PageLoadErrorSignal()
+   */
+  Dali::WebEnginePlugin::WebEnginePageLoadErrorSignalType& PageLoadErrorSignal();
+
+private:
+
+  /**
+   * @brief Constructor.
+   */
+  WebEngine();
+
+  /**
+   * @brief Destructor.
+   */
+  virtual ~WebEngine();
+
+  // Undefined copy constructor
+  WebEngine( const WebEngine& WebEngine );
+
+  // Undefined assignment operator
+  WebEngine& operator=( const WebEngine& WebEngine );
+
+  /**
+   * @brief Initializes member data.
+   *
+   * @return Whether the initialization succeed or not.
+   */
+  bool Initialize();
+
+  /**
+   * @brief Initializes library handle by loading web engine plugin.
+   *
+   * @return Whether the initialization succeed or not.
+   */
+  bool InitializePluginHandle();
+
+private:
+
+  typedef Dali::WebEnginePlugin* (*CreateWebEngineFunction)();
+  typedef void (*DestroyWebEngineFunction)( Dali::WebEnginePlugin* plugin );
+
+  Dali::WebEnginePlugin*                                  mPlugin; ///< WebEnginePlugin instance
+  void*                                                   mHandle; ///< Handle for the loaded library
+  CreateWebEngineFunction                                 mCreateWebEnginePtr;  ///< Function to create plugin instance
+  DestroyWebEngineFunction                                mDestroyWebEnginePtr; ///< Function to destroy plugin instance
+};
+
+} // namespace Adaptor
+} // namespace Internal
+
+inline static Internal::Adaptor::WebEngine& GetImplementation( Dali::WebEngine& webEngine )
+{
+  DALI_ASSERT_ALWAYS( webEngine && "WebEngine handle is empty." );
+
+  BaseObject& handle = webEngine.GetBaseObject();
+
+  return static_cast< Internal::Adaptor::WebEngine& >( handle );
+}
+
+inline static const Internal::Adaptor::WebEngine& GetImplementation( const Dali::WebEngine& webEngine )
+{
+  DALI_ASSERT_ALWAYS( webEngine && "WebEngine handle is empty." );
+
+  const BaseObject& handle = webEngine.GetBaseObject();
+
+  return static_cast< const Internal::Adaptor::WebEngine& >( handle );
+}
+
+} // namespace Dali;
+
+#endif
+
diff --git a/dali/internal/web-engine/file.list b/dali/internal/web-engine/file.list
new file mode 100644 (file)
index 0000000..7b74612
--- /dev/null
@@ -0,0 +1,6 @@
+
+# module: web, backend: common
+SET( adaptor_web_engine_common_src_files 
+    ${adaptor_web_engine_dir}/common/web-engine-impl.cpp
+)
+
diff --git a/dali/internal/window-system/android/display-connection-factory-android.cpp b/dali/internal/window-system/android/display-connection-factory-android.cpp
new file mode 100644 (file)
index 0000000..18aa472
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019 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/internal/window-system/android/display-connection-factory-android.h>
+#include <dali/internal/window-system/android/display-connection-impl-android.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+std::unique_ptr<Dali::Internal::Adaptor::DisplayConnection> DisplayConnectionFactoryAndroid::CreateDisplayConnection()
+{
+  return Utils::MakeUnique<DisplayConnectionAndroid>();
+}
+
+// this should be created from somewhere
+std::unique_ptr<DisplayConnectionFactory> GetDisplayConnectionFactory()
+{
+  // returns Android display factory
+  return Utils::MakeUnique<DisplayConnectionFactoryAndroid>();
+}
+
+}
+
+}
+
+}
diff --git a/dali/internal/window-system/android/display-connection-factory-android.h b/dali/internal/window-system/android/display-connection-factory-android.h
new file mode 100644 (file)
index 0000000..50a97af
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_ANDROID_DISPLAY_CONNECTION_FACTORY_ANDROID_H
+#define DALI_INTERNAL_WINDOWSYSTEM_ANDROID_DISPLAY_CONNECTION_FACTORY_ANDROID_H
+
+/*
+ * Copyright (c) 2019 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/internal/window-system/common/display-connection-factory.h>
+#include <dali/internal/window-system/common/display-utils.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class DisplayConnectionFactoryAndroid : public DisplayConnectionFactory
+{
+public:
+  std::unique_ptr<Dali::Internal::Adaptor::DisplayConnection> CreateDisplayConnection() override;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_ANDROID_DISPLAY_CONNECTION_FACTORY_ANDROID_H
diff --git a/dali/internal/window-system/android/display-connection-impl-android.cpp b/dali/internal/window-system/android/display-connection-impl-android.cpp
new file mode 100644 (file)
index 0000000..bcf14ff
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/android/display-connection-impl-android.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+
+// EXTERNAL_HEADERS
+#include <dali/integration-api/debug.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+DisplayConnection* DisplayConnectionAndroid::New()
+{
+  DisplayConnection* pDisplayConnection(new DisplayConnectionAndroid());
+
+  return pDisplayConnection;
+}
+
+DisplayConnectionAndroid::DisplayConnectionAndroid()
+: mDisplay( NULL ),
+  mSurfaceType( RenderSurfaceInterface::WINDOW_RENDER_SURFACE ),
+  mGraphics( nullptr )
+{
+}
+
+DisplayConnectionAndroid::~DisplayConnectionAndroid() = default;
+
+Any DisplayConnectionAndroid::GetDisplay()
+{
+  return Any( mDisplay );
+}
+
+void DisplayConnectionAndroid::ConsumeEvents()
+{
+}
+
+bool DisplayConnectionAndroid::InitializeGraphics()
+{
+  auto eglGraphics = static_cast<EglGraphics*>( mGraphics );
+  EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+
+  if( !eglImpl.InitializeGles( mDisplay ) )
+  {
+    DALI_LOG_ERROR( "Failed to initialize GLES.\n" );
+    return false;
+  }
+
+  return true;
+}
+
+void DisplayConnectionAndroid::SetSurfaceType( Dali::RenderSurfaceInterface::Type type )
+{
+  mSurfaceType = type;
+  mDisplay = EGL_DEFAULT_DISPLAY;
+}
+
+void DisplayConnectionAndroid::SetGraphicsInterface( GraphicsInterface& graphics )
+{
+  mGraphics = &graphics;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/window-system/android/display-connection-impl-android.h b/dali/internal/window-system/android/display-connection-impl-android.h
new file mode 100644 (file)
index 0000000..0f1691c
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_DISPLAY_CONNECTION_IMPL_ANDROID_H
+#define DALI_INTERNAL_WINDOWSYSTEM_DISPLAY_CONNECTION_IMPL_ANDROID_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/window-system/common/display-connection-impl.h>
+
+namespace Dali
+{
+
+class DisplayConnection;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * DisplayConnection implementation
+ */
+class DisplayConnectionAndroid : public Dali::Internal::Adaptor::DisplayConnection
+{
+public:
+
+  /**
+   * @brief Default constructor
+   */
+  DisplayConnectionAndroid();
+
+  /**
+   * @brief Create an initialized DisplayConnection.
+   *
+   * @return A handle to a newly allocated DisplayConnection resource.
+   */
+  static DisplayConnection* New();
+
+public:
+
+  /**
+   * @copydoc Dali::DisplayConnection::GetDisplay
+   */
+  Any GetDisplay();
+
+  /**
+   * @copydoc Dali::DisplayConnection::ConsumeEvents
+   */
+  void ConsumeEvents();
+
+  /**
+   * @copydoc Dali::DisplayConnection::InitializeGraphics
+   */
+  bool InitializeGraphics();
+
+  /**
+   * @brief Sets the surface type
+   * @param[in] type The surface type
+   */
+  void SetSurfaceType( Dali::RenderSurfaceInterface::Type type );
+
+  /**
+   * @brief Sets the graphics interface
+   * @param[in] graphics The graphics interface
+   */
+  void SetGraphicsInterface( GraphicsInterface& graphics );
+
+public:
+
+  /**
+   * Destructor
+   */
+  virtual ~DisplayConnectionAndroid();
+
+protected:
+
+  // Undefined
+  DisplayConnectionAndroid(const DisplayConnectionAndroid&);
+
+  // Undefined
+  DisplayConnectionAndroid& operator=(const DisplayConnectionAndroid& rhs);
+
+private:
+  EGLNativeDisplayType mDisplay;        ///< EGL display for rendering
+  Dali::RenderSurfaceInterface::Type mSurfaceType;     ///< The surface type
+  GraphicsInterface* mGraphics;         ///< The graphics interface
+};
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_DISPLAY_CONNECTION_IMPL_ANDROID_H
diff --git a/dali/internal/window-system/android/render-surface-factory-android.cpp b/dali/internal/window-system/android/render-surface-factory-android.cpp
new file mode 100644 (file)
index 0000000..27b3725
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/android/render-surface-factory-android.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/window-system/common/window-render-surface.h>
+#include <dali/internal/window-system/common/pixmap-render-surface.h>
+#include <dali/internal/window-system/common/display-utils.h>
+#include <dali/integration-api/adaptor-framework/native-render-surface.h>
+
+// EXTERNAL INCLUDES
+#include <memory>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+std::unique_ptr< WindowRenderSurface > RenderSurfaceFactoryAndroid::CreateWindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+{
+  return Utils::MakeUnique< WindowRenderSurface >( positionSize, surface, isTransparent );
+}
+
+std::unique_ptr< PixmapRenderSurface > RenderSurfaceFactoryAndroid::CreatePixmapRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+{
+  return std::unique_ptr< PixmapRenderSurface >( nullptr );
+}
+
+std::unique_ptr< NativeRenderSurface > RenderSurfaceFactoryAndroid::CreateNativeRenderSurface( Dali::PositionSize positionSize, bool isTransparent )
+{
+  return std::unique_ptr< NativeRenderSurface >( nullptr );
+}
+
+// this should be created from somewhere
+std::unique_ptr< RenderSurfaceFactory > GetRenderSurfaceFactory()
+{
+  // returns Window factory
+  return Utils::MakeUnique< RenderSurfaceFactoryAndroid >();
+}
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
diff --git a/dali/internal/window-system/android/render-surface-factory-android.h b/dali/internal/window-system/android/render-surface-factory-android.h
new file mode 100644 (file)
index 0000000..fb820de
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_ANDROID_RENDER_SURFACE_FACTORY_ANDROID_H
+#define DALI_INTERNAL_WINDOWSYSTEM_ANDROID_RENDER_SURFACE_FACTORY_ANDROID_H
+
+/*
+ * Copyright (c) 2018 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/internal/window-system/common/render-surface-factory.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class RenderSurfaceFactoryAndroid : public RenderSurfaceFactory
+{
+public:
+  std::unique_ptr< WindowRenderSurface > CreateWindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent = false ) override;
+
+  std::unique_ptr< PixmapRenderSurface > CreatePixmapRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent = false ) override;
+
+  std::unique_ptr< NativeRenderSurface > CreateNativeRenderSurface( Dali::PositionSize positionSize, bool isTransparent = false ) override;
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_ANDROID_RENDER_SURFACE_FACTORY_ANDROID_H
diff --git a/dali/internal/window-system/android/window-base-android.cpp b/dali/internal/window-system/android/window-base-android.cpp
new file mode 100644 (file)
index 0000000..b894fa0
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/android/window-base-android.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/window-system/common/window-impl.h>
+#include <dali/internal/window-system/common/window-render-surface.h>
+
+// EXTERNAL_HEADERS
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/events/mouse-button.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/adaptor-framework/android/android-framework.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gWindowBaseLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_WINDOW_BASE" );
+#endif
+
+WindowBaseAndroid::WindowBaseAndroid( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+: mWindow( nullptr ),
+  mOwnSurface( false ),
+  mIsTransparent( false ), // Should only be set to true once we actually create a transparent window regardless of what isTransparent is.
+  mRotationAppSet( false )
+{
+  Initialize( positionSize, surface, isTransparent );
+}
+
+WindowBaseAndroid::~WindowBaseAndroid() = default;
+
+void WindowBaseAndroid::Initialize( PositionSize positionSize, Any surface, bool isTransparent )
+{
+  if( !surface.Empty() )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "Initialising using supplied Android native window\n" );
+    mWindow = static_cast< ANativeWindow* >( AnyCast< void* >( surface ) );
+  }
+  else
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "Initialising using default Android native window\n" );
+    mWindow = Dali::Integration::AndroidFramework::Get().GetApplicationWindow();
+  }
+
+  DALI_ASSERT_ALWAYS( mWindow && "Failed to get Android window" );
+  mIsTransparent = true;
+}
+
+void WindowBaseAndroid::OnDeleteRequest()
+{
+  mDeleteRequestSignal.Emit();
+}
+
+void WindowBaseAndroid::OnFocusIn( void* data, int type, void* event )
+{
+}
+
+void WindowBaseAndroid::OnFocusOut( void* data, int type, void* event )
+{
+}
+
+void WindowBaseAndroid::OnWindowDamaged( void* data, int type, void* event )
+{
+}
+
+void WindowBaseAndroid::OnMouseButtonDown( void* data, int type, void* event )
+{
+}
+
+void WindowBaseAndroid::OnMouseButtonUp( void* data, int type, void* event )
+{
+}
+
+void WindowBaseAndroid::OnMouseButtonMove( void* data, int type, void* event )
+{
+}
+
+void WindowBaseAndroid::OnMouseWheel( void* data, int type, void* event )
+{
+}
+
+void WindowBaseAndroid::OnKeyDown( void* data, int type, void* event )
+{
+}
+
+void WindowBaseAndroid::OnKeyUp( void* data, int type, void* event )
+{
+}
+
+void WindowBaseAndroid::OnSelectionClear( void* data, int type, void* event )
+{
+}
+
+void WindowBaseAndroid::OnSelectionNotify( void* data, int type, void* event )
+{
+}
+
+Any WindowBaseAndroid::GetNativeWindow()
+{
+  return static_cast< void* >( mWindow );
+}
+
+int WindowBaseAndroid::GetNativeWindowId()
+{
+  return 0;
+}
+
+EGLNativeWindowType WindowBaseAndroid::CreateEglWindow( int width, int height )
+{
+  // from eglplatform.h header
+  // typedef struct ANativeWindow* EGLNativeWindowType;
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "Returns the window created for us.\n" );
+  return mWindow;
+}
+
+void WindowBaseAndroid::DestroyEglWindow()
+{
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "Does nothing, the window is not owned by us.\n" );
+}
+
+void WindowBaseAndroid::SetEglWindowRotation( int angle )
+{
+}
+
+void WindowBaseAndroid::SetEglWindowBufferTransform( int angle )
+{
+}
+
+void WindowBaseAndroid::SetEglWindowTransform( int angle )
+{
+}
+
+void WindowBaseAndroid::ResizeEglWindow( PositionSize positionSize )
+{
+}
+
+bool WindowBaseAndroid::IsEglWindowRotationSupported()
+{
+  return false;
+}
+
+void WindowBaseAndroid::Move( PositionSize positionSize )
+{
+}
+
+void WindowBaseAndroid::Resize( PositionSize positionSize )
+{
+}
+
+void WindowBaseAndroid::MoveResize( PositionSize positionSize )
+{
+}
+
+void WindowBaseAndroid::SetClass( const std::string& name, const std::string& className )
+{
+}
+
+void WindowBaseAndroid::Raise()
+{
+}
+
+void WindowBaseAndroid::Lower()
+{
+}
+
+void WindowBaseAndroid::Activate()
+{
+}
+
+void WindowBaseAndroid::SetAvailableAnlges( const std::vector< int >& angles )
+{
+}
+
+void WindowBaseAndroid::SetPreferredAngle( int angle )
+{
+}
+
+void WindowBaseAndroid::SetAcceptFocus( bool accept )
+{
+}
+
+void WindowBaseAndroid::Show()
+{
+}
+
+void WindowBaseAndroid::Hide()
+{
+}
+
+unsigned int WindowBaseAndroid::GetSupportedAuxiliaryHintCount() const
+{
+  return 0;
+}
+
+std::string WindowBaseAndroid::GetSupportedAuxiliaryHint( unsigned int index ) const
+{
+  return std::string();
+}
+
+unsigned int WindowBaseAndroid::AddAuxiliaryHint( const std::string& hint, const std::string& value )
+{
+  return 0;
+}
+
+bool WindowBaseAndroid::RemoveAuxiliaryHint( unsigned int id )
+{
+  return false;
+}
+
+bool WindowBaseAndroid::SetAuxiliaryHintValue( unsigned int id, const std::string& value )
+{
+  return false;
+}
+
+std::string WindowBaseAndroid::GetAuxiliaryHintValue( unsigned int id ) const
+{
+  return std::string();
+}
+
+unsigned int WindowBaseAndroid::GetAuxiliaryHintId( const std::string& hint ) const
+{
+  return 0;
+}
+
+void WindowBaseAndroid::SetInputRegion( const Rect< int >& inputRegion )
+{
+}
+
+void WindowBaseAndroid::SetType( Dali::Window::Type type )
+{
+}
+
+bool WindowBaseAndroid::SetNotificationLevel( Dali::Window::NotificationLevel::Type level )
+{
+  return false;
+}
+
+Dali::Window::NotificationLevel::Type WindowBaseAndroid::GetNotificationLevel() const
+{
+  return Dali::Window::NotificationLevel::NONE;
+}
+
+void WindowBaseAndroid::SetOpaqueState( bool opaque )
+{
+}
+
+bool WindowBaseAndroid::SetScreenOffMode(Dali::Window::ScreenOffMode::Type screenOffMode)
+{
+  return false;
+}
+
+Dali::Window::ScreenOffMode::Type WindowBaseAndroid::GetScreenOffMode() const
+{
+  return Dali::Window::ScreenOffMode::TIMEOUT;
+}
+
+bool WindowBaseAndroid::SetBrightness( int brightness )
+{
+  return false;
+}
+
+int WindowBaseAndroid::GetBrightness() const
+{
+  return 0;
+}
+
+bool WindowBaseAndroid::GrabKey( Dali::KEY key, KeyGrab::KeyGrabMode grabMode )
+{
+  return false;
+}
+
+bool WindowBaseAndroid::UngrabKey( Dali::KEY key )
+{
+  return false;
+}
+
+bool WindowBaseAndroid::GrabKeyList( const Dali::Vector< Dali::KEY >& key, const Dali::Vector< KeyGrab::KeyGrabMode >& grabMode, Dali::Vector< bool >& result )
+{
+  return false;
+}
+
+bool WindowBaseAndroid::UngrabKeyList( const Dali::Vector< Dali::KEY >& key, Dali::Vector< bool >& result )
+{
+  return false;
+}
+
+void WindowBaseAndroid::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
+{
+  AConfiguration* config = Dali::Integration::AndroidFramework::Get().GetApplicationConfiguration();
+
+  int32_t density = AConfiguration_getDensity( config );
+  if( density == ACONFIGURATION_DENSITY_ANY )
+  {
+    DALI_LOG_ERROR( "Failed to get Android DPI, use 0 instead." );
+    density = 0;
+  }
+
+  dpiHorizontal = density;
+  dpiVertical   = density;
+}
+
+int WindowBaseAndroid::GetScreenRotationAngle()
+{
+  return 0;
+}
+
+void WindowBaseAndroid::SetWindowRotationAngle( int degree )
+{
+}
+
+void WindowBaseAndroid::WindowRotationCompleted( int degree, int width, int height )
+{
+}
+
+void WindowBaseAndroid::SetTransparency( bool transparent )
+{
+}
+
+void WindowBaseAndroid::SetParent( WindowBase* parentWinBase )
+{
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
diff --git a/dali/internal/window-system/android/window-base-android.h b/dali/internal/window-system/android/window-base-android.h
new file mode 100644 (file)
index 0000000..86e8ddc
--- /dev/null
@@ -0,0 +1,391 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_ANDROID_WINDOW_BASE_ANDROID_H
+#define DALI_INTERNAL_WINDOWSYSTEM_ANDROID_WINDOW_BASE_ANDROID_H
+
+/*
+ * Copyright (c) 2018 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 <dali/internal/window-system/common/window-base.h>
+
+// EXTERNAL HEADERS
+struct ANativeWindow;
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * WindowBaseAndroid class provides an WindowBase Android implementation.
+ */
+class WindowBaseAndroid : public WindowBase
+{
+public:
+
+  /**
+   * @brief Constructor
+   */
+  WindowBaseAndroid( PositionSize positionSize, Any surface, bool isTransparent );
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~WindowBaseAndroid();
+
+public:
+
+  /**
+   * @brief Called when the window property is changed.
+   */
+  bool OnWindowPropertyChanged( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the window receives a delete request
+   */
+  void OnDeleteRequest();
+
+  /**
+   * @brief Called when the window gains focus.
+   */
+  void OnFocusIn( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the window loses focus.
+   */
+  void OnFocusOut( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the window is damaged.
+   */
+  void OnWindowDamaged( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a touch down is received.
+   */
+  void OnMouseButtonDown( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a touch up is received.
+   */
+  void OnMouseButtonUp( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a touch motion is received.
+   */
+  void OnMouseButtonMove( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a mouse wheel is received.
+   */
+  void OnMouseWheel( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a key down is received.
+   */
+  void OnKeyDown( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a key up is received.
+   */
+  void OnKeyUp( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the source window notifies us the content in clipboard is selected.
+   */
+  void OnSelectionClear( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the source window sends us about the selected content.
+   */
+  void OnSelectionNotify( void* data, int type, void* event );
+
+public:
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindow()
+   */
+  virtual Any GetNativeWindow() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindowId()
+   */
+  virtual int GetNativeWindowId() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::CreateEglWindow()
+   */
+  virtual EGLNativeWindowType CreateEglWindow( int width, int height ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::DestroyEglWindow()
+   */
+  virtual void DestroyEglWindow() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetEglWindowRotation()
+   */
+  virtual void SetEglWindowRotation( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetEglWindowBufferTransform()
+   */
+  virtual void SetEglWindowBufferTransform( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetEglWindowTransform()
+   */
+  virtual void SetEglWindowTransform( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::ResizeEglWindow()
+   */
+  virtual void ResizeEglWindow( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::IsEglWindowRotationSupported()
+   */
+  virtual bool IsEglWindowRotationSupported() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Move()
+   */
+  virtual void Move( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Resize()
+   */
+  virtual void Resize( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::MoveResize()
+   */
+  virtual void MoveResize( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetClass()
+   */
+  virtual void SetClass( const std::string& name, const std::string& className ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Raise()
+   */
+  virtual void Raise() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Lower()
+   */
+  virtual void Lower() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Activate()
+   */
+  virtual void Activate() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetAvailableAnlges()
+   */
+  virtual void SetAvailableAnlges( const std::vector< int >& angles  ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetPreferredAngle()
+   */
+  virtual void SetPreferredAngle( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetAcceptFocus()
+   */
+  virtual void SetAcceptFocus( bool accept ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Show()
+   */
+  virtual void Show() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Hide()
+   */
+  virtual void Hide() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetSupportedAuxiliaryHintCount()
+   */
+  virtual unsigned int GetSupportedAuxiliaryHintCount() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetSupportedAuxiliaryHint()
+   */
+  virtual std::string GetSupportedAuxiliaryHint( unsigned int index ) const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::AddAuxiliaryHint()
+   */
+  virtual unsigned int AddAuxiliaryHint( const std::string& hint, const std::string& value ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::RemoveAuxiliaryHint()
+   */
+  virtual bool RemoveAuxiliaryHint( unsigned int id ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetAuxiliaryHintValue()
+   */
+  virtual bool SetAuxiliaryHintValue( unsigned int id, const std::string& value ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetAuxiliaryHintValue()
+   */
+  virtual std::string GetAuxiliaryHintValue( unsigned int id ) const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetAuxiliaryHintId()
+   */
+  virtual unsigned int GetAuxiliaryHintId( const std::string& hint ) const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetInputRegion()
+   */
+  virtual void SetInputRegion( const Rect< int >& inputRegion ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetType()
+   */
+  virtual void SetType( Dali::Window::Type type ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetNotificationLevel()
+   */
+  virtual bool SetNotificationLevel( Dali::Window::NotificationLevel::Type level ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNotificationLevel()
+   */
+  virtual Dali::Window::NotificationLevel::Type GetNotificationLevel() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetOpaqueState()
+   */
+  virtual void SetOpaqueState( bool opaque ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetScreenOffMode()
+   */
+  virtual bool SetScreenOffMode(Dali::Window::ScreenOffMode::Type screenOffMode) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetScreenOffMode()
+   */
+  virtual Dali::Window::ScreenOffMode::Type GetScreenOffMode() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetBrightness()
+   */
+  virtual bool SetBrightness( int brightness ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetBrightness()
+   */
+  virtual int GetBrightness() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GrabKey()
+   */
+  virtual bool GrabKey( Dali::KEY key, KeyGrab::KeyGrabMode grabMode ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::UngrabKey()
+   */
+  virtual bool UngrabKey( Dali::KEY key ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GrabKeyList()
+   */
+  virtual bool GrabKeyList( const Dali::Vector< Dali::KEY >& key, const Dali::Vector< KeyGrab::KeyGrabMode >& grabMode, Dali::Vector< bool >& result ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::UngrabKeyList()
+   */
+  virtual bool UngrabKeyList( const Dali::Vector< Dali::KEY >& key, Dali::Vector< bool >& result ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetDpi()
+   */
+  virtual void GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetScreenRotationAngle()
+   */
+  virtual int GetScreenRotationAngle() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetWindowRotationAngle()
+   */
+  virtual void SetWindowRotationAngle( int degree ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::WindowRotationCompleted()
+   */
+  virtual void WindowRotationCompleted( int degree, int width, int height ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetTransparency()
+   */
+  virtual void SetTransparency( bool transparent ) override;
+
+  /**
+   * @copydoc  Dali::Internal::Adaptor::WindowBase::SetParent()
+   */
+  virtual void SetParent( WindowBase* parentWinBase ) override;
+
+private:
+
+  /**
+   * Second stage initialization
+   */
+  void Initialize( PositionSize positionSize, Any surface, bool isTransparent );
+
+  /**
+   * @brief Get the surface id if the surface parameter is not empty
+   * @param surface Any containing a surface id, or can be empty
+   * @return surface id, or zero if surface is empty
+   */
+  unsigned int GetSurfaceId( Any surface ) const;
+
+protected:
+
+  // Undefined
+  WindowBaseAndroid(const WindowBaseAndroid&) = delete;
+
+  // Undefined
+  WindowBaseAndroid& operator=(const WindowBaseAndroid& rhs) = delete;
+
+private:
+
+  ANativeWindow*                       mWindow;             ///< Native window handle
+  bool                                 mOwnSurface:1;       ///< Whether we own the surface (responsible for deleting it)
+  bool                                 mIsTransparent;      ///< Whether the window is transparent (32 bit or 24 bit)
+  bool                                 mRotationAppSet:1;
+};
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_ANDROID_WINDOW_BASE_ANDROID_H
diff --git a/dali/internal/window-system/android/window-factory-android.cpp b/dali/internal/window-system/android/window-factory-android.cpp
new file mode 100644 (file)
index 0000000..01ec05b
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/android/window-factory-android.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/window-system/android/window-base-android.h>
+#include <dali/internal/window-system/common/display-utils.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+std::unique_ptr< WindowBase > WindowFactoryAndroid::CreateWindowBase( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+{
+  return Utils::MakeUnique< WindowBaseAndroid >( positionSize, surface, isTransparent );
+}
+
+// this should be created from Window impl
+std::unique_ptr< WindowFactory > GetWindowFactory()
+{
+  // returns Window factory
+  return Utils::MakeUnique< WindowFactoryAndroid >();
+}
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
diff --git a/dali/internal/window-system/android/window-factory-android.h b/dali/internal/window-system/android/window-factory-android.h
new file mode 100644 (file)
index 0000000..f267c35
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_ANDROID_WINDOW_FACTORY_ANDROID_H
+#define DALI_INTERNAL_WINDOWSYSTEM_ANDROID_WINDOW_FACTORY_ANDROID_H
+
+/*
+ * Copyright (c) 2018 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/internal/window-system/common/window-factory.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class WindowFactoryAndroid : public WindowFactory
+{
+public:
+  std::unique_ptr< WindowBase > CreateWindowBase( Dali::PositionSize positionSize, Any surface, bool isTransparent ) override;
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_ANDROID_WINDOW_FACTORY_ANDROID_H
diff --git a/dali/internal/window-system/android/window-system-android.cpp b/dali/internal/window-system/android/window-system-android.cpp
new file mode 100644 (file)
index 0000000..e6ba067
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018 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 HEADERS
+#include <dali/internal/adaptor/common/framework.h>
+#include <dali/internal/window-system/common/window-system.h>
+
+// EXTERNAL_HEADERS
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/adaptor-framework/android/android-framework.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace WindowSystem
+{
+
+void Initialize()
+{
+}
+
+void Shutdown()
+{
+}
+
+void GetScreenSize( int& width, int& height )
+{
+  ANativeWindow* window = Dali::Integration::AndroidFramework::Get().GetApplicationWindow();
+  width = ANativeWindow_getWidth( window );
+  height = ANativeWindow_getHeight( window );
+  DALI_LOG_WARNING( "Native window width %d, height %d", width, height );
+}
+
+bool SetKeyboardRepeatInfo( float rate, float delay )
+{
+  return false;
+}
+
+bool GetKeyboardRepeatInfo( float& rate, float& delay )
+{
+  return false;
+}
+
+} // namespace WindowSystem
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
diff --git a/dali/internal/window-system/common/damage-observer.h b/dali/internal/window-system/common/damage-observer.h
new file mode 100644 (file)
index 0000000..b6442a7
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef DALI_INTERNAL_DAMAGE_OBSERVER_H
+#define DALI_INTERNAL_DAMAGE_OBSERVER_H
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/vector-wrapper.h>
+#include <dali/public-api/math/rect.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+typedef Rect<int> DamageArea;
+
+/**
+ * The DamageObserver can be overridden in order to listen to damage events.
+ */
+class DamageObserver
+{
+public:
+
+  /**
+   * Deriving classes should override this to be notified when we receive a damage event.
+   * @param[in]  area  The area that has been damaged.
+   */
+  virtual void OnDamaged( const DamageArea& area ) = 0;
+
+protected:
+
+  /**
+   * Protected Constructor.
+   */
+  DamageObserver()
+  {
+  }
+
+  /**
+   * Protected virtual destructor.
+   */
+  virtual ~DamageObserver()
+  {
+  }
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_DAMAGE_OBSERVER_H
diff --git a/dali/internal/window-system/common/display-connection-factory.h b/dali/internal/window-system/common/display-connection-factory.h
new file mode 100644 (file)
index 0000000..14f5bd0
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_COMMON_DISPLAY_CONNECTION_FACTORY_H
+#define DALI_INTERNAL_WINDOWSYSTEM_COMMON_DISPLAY_CONNECTION_FACTORY_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 <memory>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class DisplayConnection;
+class DisplayConnectionFactory
+{
+public:
+
+  DisplayConnectionFactory() = default;
+  virtual ~DisplayConnectionFactory() = default;
+
+  virtual std::unique_ptr<Dali::Internal::Adaptor::DisplayConnection> CreateDisplayConnection() = 0;
+
+};
+
+extern std::unique_ptr<DisplayConnectionFactory> GetDisplayConnectionFactory();
+
+extern void DisplayConnectionFactoryGetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical);
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_COMMON_DISPLAY_CONNECTION_FACTORY_H
diff --git a/dali/internal/window-system/common/display-connection-impl.h b/dali/internal/window-system/common/display-connection-impl.h
new file mode 100644 (file)
index 0000000..8ced957
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_COMMON_DISPLAY_CONNECTION_IMPL_H
+#define DALI_INTERNAL_WINDOWSYSTEM_COMMON_DISPLAY_CONNECTION_IMPL_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/window-system/common/display-connection.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/internal/graphics/gles/egl-implementation.h>
+
+
+namespace Dali
+{
+
+class DisplayConnection;
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * DisplayConnection implementation
+ */
+class DisplayConnection : public Dali::BaseObject
+{
+public:
+
+  /**
+   * @brief Default constructor
+   */
+  DisplayConnection() = default;
+
+  /**
+   * @brief Create an initialized DisplayConnection.
+   *
+   * @return A handle to a newly allocated DisplayConnection resource.
+   */
+  static DisplayConnection* New();
+
+public:
+
+  /**
+   * @copydoc Dali::DisplayConnection::GetDisplay
+   */
+  virtual Any GetDisplay() = 0;
+
+  /**
+   * @copydoc Dali::DisplayConnection::ConsumeEvents
+   */
+  virtual void ConsumeEvents() = 0;
+
+  /**
+   * @copydoc Dali::DisplayConnection::InitializeGraphics
+   */
+  virtual bool InitializeGraphics() = 0;
+
+  /**
+   * Sets the render surface type
+   * @param[in] type The render surface type
+   */
+  virtual void SetSurfaceType( Dali::RenderSurfaceInterface::Type type ) = 0;
+
+  /**
+   * Sets the graphics interface
+   * @param[in] graphics The graphics interface
+   */
+  virtual void SetGraphicsInterface( GraphicsInterface& graphics ) = 0;
+
+public:
+
+  /**
+   * Destructor
+   */
+  ~DisplayConnection() override = default;
+
+protected:
+
+  // Undefined
+  DisplayConnection(const DisplayConnection&) = delete;
+
+  // Undefined
+  DisplayConnection& operator=(const DisplayConnection& rhs) = delete;
+
+};
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_COMMON_DISPLAY_CONNECTION_IMPL_H
diff --git a/dali/internal/window-system/common/display-connection.cpp b/dali/internal/window-system/common/display-connection.cpp
new file mode 100644 (file)
index 0000000..a91d507
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/common/display-connection.h>
+#include <dali/internal/window-system/common/display-connection-factory.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/window-system/common/display-connection-impl.h>
+#include <dali/internal/window-system/common/display-connection-factory.h>
+
+
+namespace Dali
+{
+
+DisplayConnection* DisplayConnection::New( Dali::Internal::Adaptor::GraphicsInterface& graphics )
+{
+  auto factory = Dali::Internal::Adaptor::GetDisplayConnectionFactory();
+  auto displayConnection = factory->CreateDisplayConnection();
+
+  Internal::Adaptor::DisplayConnection* internal( displayConnection.release() );
+  internal->SetGraphicsInterface( graphics );
+
+  return new DisplayConnection(internal);
+}
+
+DisplayConnection* DisplayConnection::New( Dali::Internal::Adaptor::GraphicsInterface& graphics, Dali::RenderSurfaceInterface::Type type )
+{
+  auto factory = Dali::Internal::Adaptor::GetDisplayConnectionFactory();
+  auto displayConnection = factory->CreateDisplayConnection();
+
+  Internal::Adaptor::DisplayConnection* internal( displayConnection.release() );
+
+  internal->SetGraphicsInterface( graphics );
+  internal->SetSurfaceType( type );
+
+  return new DisplayConnection(internal);
+}
+
+DisplayConnection::DisplayConnection() = default;
+
+DisplayConnection::~DisplayConnection() = default;
+
+DisplayConnection::DisplayConnection(Internal::Adaptor::DisplayConnection* impl)
+{
+  mImpl.reset( impl );
+}
+
+Any DisplayConnection::GetDisplay()
+{
+  return mImpl->GetDisplay();
+}
+
+void DisplayConnection::ConsumeEvents()
+{
+  mImpl->ConsumeEvents();
+}
+
+bool DisplayConnection::Initialize()
+{
+  return mImpl->InitializeGraphics();
+}
+
+}
diff --git a/dali/internal/window-system/common/display-connection.h b/dali/internal/window-system/common/display-connection.h
new file mode 100644 (file)
index 0000000..3982d09
--- /dev/null
@@ -0,0 +1,108 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_COMMON_DISPLAY_CONNECTION_H
+#define DALI_INTERNAL_WINDOWSYSTEM_COMMON_DISPLAY_CONNECTION_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/any.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/render-surface-interface.h>
+#include <dali/internal/graphics/common/graphics-interface.h>
+
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class DisplayConnection;
+}
+}
+
+class DisplayConnection
+{
+public:
+
+  /**
+   * @brief Create an initialized DisplayConnection.
+   *
+   * @param[in] graphics The abstracted graphics interface
+   * @return A handle to a newly allocated DisplayConnection resource.
+   */
+  static DisplayConnection* New( Dali::Internal::Adaptor::GraphicsInterface& graphics );
+
+  /**
+   * @brief Create an initialized DisplayConnection.
+   * Native surface will need this instead of DisplayConnection::New()
+   *
+   * @param[in] graphics The abstracted graphics interface
+   * @param[in] type Render surface type
+   * @return A handle to a newly allocated DisplayConnection resource.
+   */
+  static DisplayConnection* New( Dali::Internal::Adaptor::GraphicsInterface& graphics, Dali::RenderSurfaceInterface::Type type );
+
+  /**
+   * @brief Create a DisplayConnection handle; this can be initialised with DisplayConnection::New().
+   *
+   * Calling member functions with an uninitialised handle is not allowed.
+   */
+  DisplayConnection();
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~DisplayConnection();
+
+  /**
+   * @brief Get display
+   *
+   * @return display
+   */
+  Any GetDisplay();
+
+  /**
+   * @brief Consumes any possible events on the queue so that there is no leaking between frames
+   */
+  void ConsumeEvents();
+
+  /**
+   * @brief Initialize the display
+   */
+  bool Initialize();
+
+public:
+
+  /**
+   * @brief This constructor is used by DisplayConnection New() methods.
+   *
+   * @param [in] handle A pointer to a newly allocated DisplayConnection resource
+   */
+  explicit DALI_INTERNAL DisplayConnection(Internal::Adaptor::DisplayConnection* impl);
+
+private:
+
+  std::unique_ptr<Internal::Adaptor::DisplayConnection> mImpl;
+};
+
+}
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_COMMON_DISPLAY_CONNECTION_H
diff --git a/dali/internal/window-system/common/display-utils.h b/dali/internal/window-system/common/display-utils.h
new file mode 100644 (file)
index 0000000..05d0176
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_COMMON_DISPLAY_UTILs_H
+#define DALI_INTERNAL_WINDOWSYSTEM_COMMON_DISPLAY_UTILs_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 <memory>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+namespace Utils
+{
+
+template<typename T, typename... Args>
+std::unique_ptr<T> MakeUnique(Args&&... args)
+{
+  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
+} // namespace Utils
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_COMMON_DISPLAY_UTILs_H
diff --git a/dali/internal/window-system/common/event-handler.cpp b/dali/internal/window-system/common/event-handler.cpp
new file mode 100755 (executable)
index 0000000..99f1796
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/common/event-handler.h>
+
+// EXTERNAL INCLUDES
+#include <cstring>
+#include <sys/time.h>
+
+#include <dali/public-api/events/touch-point.h>
+#include <dali/public-api/events/key-event.h>
+#include <dali/public-api/events/wheel-event.h>
+#include <dali/integration-api/debug.h>
+#include <dali/integration-api/events/key-event-integ.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+#include <dali/integration-api/events/hover-event-integ.h>
+#include <dali/integration-api/events/wheel-event-integ.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/clipboard/common/clipboard-impl.h>
+#include <dali/internal/styling/common/style-monitor-impl.h>
+#include <dali/internal/window-system/common/window-render-surface.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+#if defined(DEBUG_ENABLED)
+namespace
+{
+Integration::Log::Filter* gSelectionEventLogFilter = Integration::Log::Filter::New(Debug::NoLogging, false, "LOG_ADAPTOR_EVENTS_SELECTION");
+} // unnamed namespace
+#endif
+
+#ifdef DALI_ELDBUS_AVAILABLE
+namespace
+{
+
+// Copied from x server
+static uint32_t GetCurrentMilliSeconds(void)
+{
+  struct timeval tv;
+
+  struct timespec tp;
+  static clockid_t clockid;
+
+  if (!clockid)
+  {
+#ifdef CLOCK_MONOTONIC_COARSE
+    if (clock_getres(CLOCK_MONOTONIC_COARSE, &tp) == 0 &&
+      (tp.tv_nsec / 1000) <= 1000 && clock_gettime(CLOCK_MONOTONIC_COARSE, &tp) == 0)
+    {
+      clockid = CLOCK_MONOTONIC_COARSE;
+    }
+    else
+#endif
+    if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
+    {
+      clockid = CLOCK_MONOTONIC;
+    }
+    else
+    {
+      clockid = ~0L;
+    }
+  }
+  if (clockid != ~0L && clock_gettime(clockid, &tp) == 0)
+  {
+    return static_cast<uint32_t>( (tp.tv_sec * 1000 ) + (tp.tv_nsec / 1000000L) );
+  }
+
+  gettimeofday(&tv, NULL);
+  return static_cast<uint32_t>( (tv.tv_sec * 1000 ) + (tv.tv_usec / 1000) );
+}
+
+} // unnamed namespace
+#endif
+
+EventHandler::EventHandler( WindowRenderSurface* surface, DamageObserver& damageObserver )
+: mStyleMonitor( StyleMonitor::Get() ),
+  mDamageObserver( damageObserver ),
+  mAccessibilityAdaptor( AccessibilityAdaptor::Get() ),
+  mClipboardEventNotifier( ClipboardEventNotifier::Get() ),
+  mClipboard( Clipboard::Get() ),
+  mPaused( false )
+{
+  if( surface )
+  {
+    WindowBase* windowBase = surface->GetWindowBase();
+
+    // Connect signals
+    windowBase->WindowDamagedSignal().Connect( this, &EventHandler::OnWindowDamaged );
+    windowBase->FocusChangedSignal().Connect( this, &EventHandler::OnFocusChanged );
+    windowBase->RotationSignal().Connect( this, &EventHandler::OnRotation );
+    windowBase->TouchEventSignal().Connect( this, &EventHandler::OnTouchEvent );
+    windowBase->WheelEventSignal().Connect( this, &EventHandler::OnWheelEvent );
+    windowBase->KeyEventSignal().Connect( this, &EventHandler::OnKeyEvent );
+    windowBase->SelectionDataSendSignal().Connect( this, &EventHandler::OnSelectionDataSend );
+    windowBase->SelectionDataReceivedSignal().Connect( this, &EventHandler::OnSelectionDataReceived );
+    windowBase->StyleChangedSignal().Connect( this, &EventHandler::OnStyleChanged );
+    windowBase->AccessibilitySignal().Connect( this, &EventHandler::OnAccessibilityNotification );
+  }
+}
+
+EventHandler::~EventHandler()
+{
+}
+
+void EventHandler::SendEvent( StyleChange::Type styleChange )
+{
+  DALI_ASSERT_DEBUG( mStyleMonitor && "StyleMonitor Not Available" );
+  GetImplementation( mStyleMonitor ).StyleChanged(styleChange);
+}
+
+void EventHandler::SendEvent( const DamageArea& area )
+{
+  mDamageObserver.OnDamaged( area );
+}
+
+void EventHandler::Pause()
+{
+  mPaused = true;
+}
+
+void EventHandler::Resume()
+{
+  mPaused = false;
+}
+
+void EventHandler::OnTouchEvent( Integration::Point& point, uint32_t timeStamp )
+{
+  for ( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
+  {
+    (*iter)->OnTouchPoint( point, timeStamp );
+  }
+}
+
+void EventHandler::OnWheelEvent( WheelEvent& wheelEvent )
+{
+  Integration::WheelEvent event( static_cast< Integration::WheelEvent::Type >(wheelEvent.type), wheelEvent.direction, wheelEvent.modifiers, wheelEvent.point, wheelEvent.z, wheelEvent.timeStamp );
+
+  for ( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
+  {
+    (*iter)->OnWheelEvent( event );
+  }
+}
+
+void EventHandler::OnKeyEvent( Integration::KeyEvent& keyEvent )
+{
+  for ( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
+  {
+    (*iter)->OnKeyEvent( keyEvent );
+  }
+}
+
+void EventHandler::OnFocusChanged( bool focusIn )
+{
+  // If the window gains focus and we hid the keyboard then show it again.
+  if( focusIn )
+  {
+    Dali::Clipboard clipboard = Clipboard::Get();
+    if ( clipboard )
+    {
+      clipboard.HideClipboard();
+    }
+  }
+  else
+  {
+    // Hiding clipboard event will be ignored once because window focus out event is always received on showing clipboard
+    Dali::Clipboard clipboard = Clipboard::Get();
+    if ( clipboard )
+    {
+      Clipboard& clipBoardImpl( GetImplementation( clipboard ) );
+      clipBoardImpl.HideClipboard(true);
+    }
+  }
+}
+
+void EventHandler::OnRotation( const RotationEvent& event )
+{
+  for ( ObserverContainer::iterator iter = mObservers.begin(), endIter = mObservers.end(); iter != endIter; ++iter )
+  {
+    (*iter)->OnRotation( event );
+  }
+}
+
+void EventHandler::OnWindowDamaged( const DamageArea& area )
+{
+  SendEvent( area );
+}
+
+void EventHandler::OnSelectionDataSend( void* event )
+{
+  Dali::Clipboard clipboard = Clipboard::Get();
+  if( clipboard )
+  {
+    Clipboard& clipBoardImpl( GetImplementation( clipboard ) );
+    clipBoardImpl.ExcuteBuffered( true, event );
+  }
+}
+
+void EventHandler::OnSelectionDataReceived( void* event )
+{
+  // We have got the selected content, inform the clipboard event listener (if we have one).
+  Dali::Clipboard clipboard = Clipboard::Get();
+  char* selectionData = NULL;
+  if( clipboard )
+  {
+    Clipboard& clipBoardImpl( GetImplementation( clipboard ) );
+    selectionData = clipBoardImpl.ExcuteBuffered( false, event );
+  }
+
+  if( selectionData && mClipboardEventNotifier )
+  {
+    ClipboardEventNotifier& clipboardEventNotifier( ClipboardEventNotifier::GetImplementation( mClipboardEventNotifier ) );
+    std::string content( selectionData, strlen( selectionData ) );
+
+    clipboardEventNotifier.SetContent( content );
+    clipboardEventNotifier.EmitContentSelectedSignal();
+
+    DALI_LOG_INFO( gSelectionEventLogFilter, Debug::General, "EcoreEventSelectionNotify: Content(%d): %s\n" , strlen(selectionData), selectionData );
+  }
+}
+
+void EventHandler::OnStyleChanged( StyleChange::Type styleChange )
+{
+  SendEvent( styleChange );
+}
+
+void EventHandler::OnAccessibilityNotification( const WindowBase::AccessibilityInfo& info )
+{
+#ifdef DALI_ELDBUS_AVAILABLE
+  if( mPaused )
+  {
+    return;
+  }
+
+  if( !mAccessibilityAdaptor )
+  {
+    DALI_LOG_ERROR( "Invalid accessibility adaptor\n" );
+    return;
+  }
+
+  AccessibilityAdaptor* accessibilityAdaptor( &AccessibilityAdaptor::GetImplementation( mAccessibilityAdaptor ) );
+  if( !accessibilityAdaptor )
+  {
+    DALI_LOG_ERROR( "Cannot access accessibility adaptor\n" );
+    return;
+  }
+
+  // Create a touch point object.
+  TouchPoint::State touchPointState( TouchPoint::Down );
+  if( info.state == 0 )
+  {
+    touchPointState = TouchPoint::Down; // Mouse down.
+  }
+  else if( info.state == 1 )
+  {
+    touchPointState = TouchPoint::Motion; // Mouse move.
+  }
+  else if( info.state == 2 )
+  {
+    touchPointState = TouchPoint::Up; // Mouse up.
+  }
+  else
+  {
+    touchPointState = TouchPoint::Interrupted; // Error.
+  }
+
+  // Send touch event to accessibility adaptor.
+  TouchPoint point( 0, touchPointState, static_cast< float >( info.startX ), static_cast< float >( info.startY ) );
+
+  // Perform actions based on received gestures.
+  // Note: This is seperated from the reading so we can have other input readers without changing the below code.
+  switch( info.gestureValue )
+  {
+    case 0: // OneFingerHover
+    {
+      // Focus, read out.
+      accessibilityAdaptor->HandleActionReadEvent( static_cast< unsigned int >( info.startX ), static_cast< unsigned int >( info.startY ), true /* allow read again */ );
+      break;
+    }
+    case 1: // TwoFingersHover
+    {
+      // In accessibility mode, scroll action should be handled when the currently focused actor is contained in scrollable control
+      accessibilityAdaptor->HandleActionScrollEvent( point, GetCurrentMilliSeconds() );
+      break;
+    }
+    case 2: // ThreeFingersHover
+    {
+      // Read from top item on screen continuously.
+      accessibilityAdaptor->HandleActionReadFromTopEvent();
+      break;
+    }
+    case 3: // OneFingerFlickLeft
+    {
+      // Move to previous item.
+      accessibilityAdaptor->HandleActionReadPreviousEvent();
+      break;
+    }
+    case 4: // OneFingerFlickRight
+    {
+      // Move to next item.
+      accessibilityAdaptor->HandleActionReadNextEvent();
+      break;
+    }
+    case 5: // OneFingerFlickUp
+    {
+      // Move to previous item.
+      accessibilityAdaptor->HandleActionPreviousEvent();
+      break;
+    }
+    case 6: // OneFingerFlickDown
+    {
+      // Move to next item.
+      accessibilityAdaptor->HandleActionNextEvent();
+      break;
+    }
+    case 7: // TwoFingersFlickUp
+    {
+      // Scroll up the list.
+      accessibilityAdaptor->HandleActionScrollUpEvent();
+      break;
+    }
+    case 8: // TwoFingersFlickDown
+    {
+      // Scroll down the list.
+      accessibilityAdaptor->HandleActionScrollDownEvent();
+      break;
+    }
+    case 9: // TwoFingersFlickLeft
+    {
+      // Scroll left to the previous page
+      accessibilityAdaptor->HandleActionPageLeftEvent();
+      break;
+    }
+    case 10: // TwoFingersFlickRight
+    {
+      // Scroll right to the next page
+      accessibilityAdaptor->HandleActionPageRightEvent();
+      break;
+    }
+    case 11: // ThreeFingersFlickLeft
+    {
+      // Not exist yet
+      break;
+    }
+    case 12: // ThreeFingersFlickRight
+    {
+      // Not exist yet
+      break;
+    }
+    case 13: // ThreeFingersFlickUp
+    {
+      // Not exist yet
+      break;
+    }
+    case 14: // ThreeFingersFlickDown
+    {
+      // Not exist yet
+      break;
+    }
+    case 15: // OneFingerSingleTap
+    {
+      // Focus, read out.
+      accessibilityAdaptor->HandleActionReadEvent( static_cast< unsigned int >( info.startX ), static_cast< unsigned int >( info.startY ), true /* allow read again */ );
+      break;
+    }
+    case 16: // OneFingerDoubleTap
+    {
+      // Activate selected item / active edit mode.
+      accessibilityAdaptor->HandleActionActivateEvent();
+      break;
+    }
+    case 17: // OneFingerTripleTap
+    {
+      // Zoom
+      accessibilityAdaptor->HandleActionZoomEvent();
+      break;
+    }
+    case 18: // TwoFingersSingleTap
+    {
+      // Pause/Resume current speech
+      accessibilityAdaptor->HandleActionReadPauseResumeEvent();
+      break;
+    }
+    case 19: // TwoFingersDoubleTap
+    {
+      // Start/Stop current action
+      accessibilityAdaptor->HandleActionStartStopEvent();
+      break;
+    }
+    case 20: // TwoFingersTripleTap
+    {
+      // Read information from indicator
+      // Not supported
+      break;
+    }
+    case 21: // ThreeFingersSingleTap
+    {
+      // Read from top item on screen continuously.
+      accessibilityAdaptor->HandleActionReadFromTopEvent();
+      break;
+    }
+    case 22: // ThreeFingersDoubleTap
+    {
+      // Read from next item continuously.
+      accessibilityAdaptor->HandleActionReadFromNextEvent();
+      break;
+    }
+    case 23: // ThreeFingersTripleTap
+    {
+      // Not exist yet
+      break;
+    }
+    case 24: // OneFingerFlickLeftReturn
+    {
+      // Scroll up to the previous page
+      accessibilityAdaptor->HandleActionPageUpEvent();
+      break;
+    }
+    case 25: // OneFingerFlickRightReturn
+    {
+      // Scroll down to the next page
+      accessibilityAdaptor->HandleActionPageDownEvent();
+      break;
+    }
+    case 26: // OneFingerFlickUpReturn
+    {
+      // Move to the first item on screen
+      accessibilityAdaptor->HandleActionMoveToFirstEvent();
+      break;
+    }
+    case 27: // OneFingerFlickDownReturn
+    {
+      // Move to the last item on screen
+      accessibilityAdaptor->HandleActionMoveToLastEvent();
+      break;
+    }
+    case 28: // TwoFingersFlickLeftReturn
+    {
+      // Not exist yet
+      break;
+    }
+    case 29: // TwoFingersFlickRightReturn
+    {
+      // Not exist yet
+      break;
+    }
+    case 30: // TwoFingersFlickUpReturn
+    {
+      // Not exist yet
+      break;
+    }
+    case 31: // TwoFingersFlickDownReturn
+    {
+      // Not exist yet
+      break;
+    }
+    case 32: // ThreeFingersFlickLeftReturn
+    {
+      // Not exist yet
+      break;
+    }
+    case 33: // ThreeFingersFlickRightReturn
+    {
+      // Not exist yet
+      break;
+    }
+    case 34: // ThreeFingersFlickUpReturn
+    {
+      // Not exist yet
+      break;
+    }
+    case 35: // ThreeFingersFlickDownReturn
+    {
+      // Not exist yet
+      break;
+    }
+  }
+#endif
+}
+
+void EventHandler::AddObserver( Observer& observer )
+{
+  ObserverContainer::iterator match ( find(mObservers.begin(), mObservers.end(), &observer) );
+
+  if ( match == mObservers.end() )
+  {
+    mObservers.push_back( &observer );
+  }
+}
+
+void EventHandler::RemoveObserver( Observer& observer )
+{
+  ObserverContainer::iterator match ( find(mObservers.begin(), mObservers.end(), &observer) );
+
+  if ( match != mObservers.end() )
+  {
+    mObservers.erase( match );
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/window-system/common/event-handler.h b/dali/internal/window-system/common/event-handler.h
new file mode 100755 (executable)
index 0000000..795a919
--- /dev/null
@@ -0,0 +1,241 @@
+#ifndef DALI_INTERNAL_EVENT_HANDLER_H
+#define DALI_INTERNAL_EVENT_HANDLER_H
+
+/*
+ * Copyright (c) 2019 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 <cstdint> // uint32_t
+#include <dali/public-api/common/intrusive-ptr.h>
+
+#include <dali/devel-api/adaptor-framework/clipboard.h>
+#include <dali/devel-api/adaptor-framework/style-monitor.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/accessibility/common/accessibility-adaptor-impl.h>
+#include <dali/internal/clipboard/common/clipboard-event-notifier-impl.h>
+#include <dali/internal/window-system/common/damage-observer.h>
+#include <dali/internal/window-system/common/window-base.h>
+
+namespace Dali
+{
+
+namespace Integration
+{
+
+struct Point;
+struct KeyEvent;
+struct WheelEvent;
+
+}
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class StyleMonitor;
+class WindowRenderSurface;
+
+/**
+ * The Event Handler class is responsible for setting up receiving of Ecore events and then converts them
+ * to TouchEvents when it does receive them.
+ *
+ * These TouchEvents are then passed on to Core.
+ */
+class EventHandler : public ConnectionTracker, public Dali::RefObject
+{
+public:
+
+  /**
+   * The observer can be overridden in order to listen to the events.
+   */
+  class Observer
+  {
+  public:
+
+    /**
+     * Deriving classes should override this to be notified when we receive a touch point event.
+     * @param[in] point The touch point
+     * @param[in] timeStamp The time stamp
+     */
+    virtual void OnTouchPoint( Dali::Integration::Point& point, int timeStamp ) = 0;
+
+    /**
+     * Deriving classes should override this to be notified when we receive a wheel event.
+     * @param[in] wheelEvent The wheel event
+     */
+    virtual void OnWheelEvent( Dali::Integration::WheelEvent& wheelEvent ) = 0;
+
+    /**
+     * Deriving classes should override this to be notified when we receive a key event.
+     * @param[in] keyEvent The key event holding the key information.
+     */
+    virtual void OnKeyEvent( Dali::Integration::KeyEvent& keyEvent ) = 0;
+
+    /**
+     * Deriving classes should override this to be notified when the window is rotated.
+     * @param[in] rotation The rotation event.
+     */
+    virtual void OnRotation( const RotationEvent& rotation ) = 0;
+
+  protected:
+
+    /**
+     * Protected Constructor.
+     */
+    Observer() {}
+
+    /**
+     * Protected virtual destructor.
+     */
+    virtual ~Observer() {}
+  };
+
+public:
+
+  /**
+   * Constructor.
+   * @param[in]  surface                  The render surface of the window.
+   * @param[in]  damageObserver           The damage observer (to pass damage events to).
+   */
+  EventHandler( WindowRenderSurface* surface, DamageObserver& damageObserver );
+
+  /**
+   * Destructor.
+   */
+  ~EventHandler();
+
+  /**
+   * Called when the adaptor is paused.
+   */
+  void Pause();
+
+  /**
+   * Called when the adaptor is resumed (from pause).
+   */
+  void Resume();
+
+  /**
+   * Adds an observer so that we can observe the events.
+   * @param[in] observer The observer.
+   */
+  void AddObserver( Observer& observer );
+
+  /**
+   * Removes the observer from the EventHandler.
+   * @param[in] observer The observer to remove.
+   * @note Observers should remove themselves when they are destroyed.
+   */
+  void RemoveObserver( Observer& observer );
+
+private:
+
+  /**
+   * Send a style change event to the style monitor.
+   * @param[in]  styleChange  The style that has changed.
+   */
+  void SendEvent( StyleChange::Type styleChange );
+
+  /**
+   * Send a window damage event to the observer.
+   * @param[in]  area  Damaged area.
+   */
+  void SendEvent( const DamageArea& area );
+
+  /**
+   * Called when a touch event is received.
+   */
+  void OnTouchEvent( Integration::Point& point, uint32_t timeStamp );
+
+  /**
+   * Called when a mouse wheel is received.
+   */
+  void OnWheelEvent( WheelEvent& wheelEvent );
+
+  /**
+   * Called when a key event is received.
+   */
+  void OnKeyEvent( Integration::KeyEvent& keyEvent );
+
+  /**
+   * Called when the window focus is changed.
+   */
+  void OnFocusChanged( bool focusIn );
+
+  /**
+   * Called when the window is rotated.
+   * @param[in] event The rotation event
+   */
+  void OnRotation( const RotationEvent& event );
+
+  /**
+   * Called when the window is damaged.
+   */
+  void OnWindowDamaged( const DamageArea& area );
+
+  /**
+   * Called when the source window notifies us the content in clipboard is selected.
+   */
+  void OnSelectionDataSend( void* event );
+
+  /**
+   * Called when the source window sends us about the selected content.
+   */
+  void OnSelectionDataReceived( void* event );
+
+  /**
+   * Called when the style is changed.
+   */
+  void OnStyleChanged( StyleChange::Type styleChange );
+
+  /**
+   * Called when Ecore ElDBus accessibility event is received.
+   */
+  void OnAccessibilityNotification( const WindowBase::AccessibilityInfo& info );
+
+private:
+
+  // Undefined
+  EventHandler( const EventHandler& eventHandler );
+
+  // Undefined
+  EventHandler& operator=( const EventHandler& eventHandler );
+
+private:
+
+  Dali::StyleMonitor mStyleMonitor; ///< Handle to the style monitor, set on construction, to send font size and font change events to.
+  DamageObserver& mDamageObserver; ///< Reference to the DamageObserver, set on construction, to sent damage events to.
+
+  Dali::AccessibilityAdaptor mAccessibilityAdaptor; ///< Pointer to the accessibility adaptor
+  Dali::ClipboardEventNotifier mClipboardEventNotifier; ///< Pointer to the clipboard event notifier
+  Dali::Clipboard mClipboard;///< Pointer to the clipboard
+
+  using ObserverContainer = std::vector<Observer*>;
+  ObserverContainer mObservers;   ///< A list of event observer pointers
+
+  bool mPaused; ///< The paused state of the adaptor.
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_EVENT_HANDLER_H
diff --git a/dali/internal/window-system/common/native-render-surface-factory.cpp b/dali/internal/window-system/common/native-render-surface-factory.cpp
new file mode 100644 (file)
index 0000000..3b07c24
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2019 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 <dali/integration-api/adaptor-framework/native-render-surface.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/window-system/common/render-surface-factory.h>
+
+namespace Dali
+{
+
+DALI_ADAPTOR_API NativeRenderSurface* CreateNativeSurface( PositionSize positionSize, bool isTransparent )
+{
+  auto renderSurfaceFactory = Dali::Internal::Adaptor::GetRenderSurfaceFactory();
+  auto nativeRenderSurface =  renderSurfaceFactory->CreateNativeRenderSurface( positionSize, isTransparent );
+  return nativeRenderSurface.release();
+}
+
+} // namespace Dali
diff --git a/dali/internal/window-system/common/orientation-impl.cpp b/dali/internal/window-system/common/orientation-impl.cpp
new file mode 100644 (file)
index 0000000..70af3c4
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/common/orientation-impl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/window-system/common/window-impl.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+Orientation* Orientation::New(Window* window)
+{
+  Orientation* orientation = new Orientation(window);
+
+  return orientation;
+}
+
+Orientation::Orientation(Window* window)
+: mWindow(window),
+  mOrientation(0),
+  mWindowWidth(0),
+  mWindowHeight(0)
+{
+}
+
+Orientation::~Orientation()
+{
+  // Note, there is only one orientation object that's owned by window,
+  // so it will live longer than adaptor. (hence, no need to remove rotation observer)
+}
+
+int Orientation::GetDegrees() const
+{
+  return mOrientation;
+}
+
+float Orientation::GetRadians() const
+{
+  return Math::PI * float(mOrientation) / 180.0f;
+}
+
+Orientation::OrientationSignalType& Orientation::ChangedSignal()
+{
+  return mChangedSignal;
+}
+
+void Orientation::OnOrientationChange( const RotationEvent& rotation )
+{
+  mOrientation  = rotation.angle;
+  mWindowWidth  = rotation.width;
+  mWindowHeight = rotation.height;
+
+  // Emit signal
+  if( !mChangedSignal.Empty() )
+  {
+    Dali::Orientation handle( this );
+    mChangedSignal.Emit( handle );
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/window-system/common/orientation-impl.h b/dali/internal/window-system/common/orientation-impl.h
new file mode 100644 (file)
index 0000000..2b16f2e
--- /dev/null
@@ -0,0 +1,130 @@
+#ifndef DALI_INTERNAL_ORIENTATION_H
+#define DALI_INTERNAL_ORIENTATION_H
+
+/*
+ * Copyright (c) 2019 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 <cmath>
+#include <dali/public-api/common/constants.h>
+#include <dali/public-api/object/base-object.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/adaptor-framework/orientation.h>
+#include <dali/internal/window-system/common/rotation-event.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class Window;
+class Orientation;
+
+typedef IntrusivePtr<Orientation> OrientationPtr;
+
+class Orientation : public BaseObject
+{
+public:
+
+  typedef Dali::Orientation::OrientationSignalType OrientationSignalType;
+
+  static Orientation* New(Window* window);
+
+  /**
+   * Constructor
+   */
+  Orientation(Window* window);
+
+protected:
+  /**
+   * Destructor
+   */
+  virtual ~Orientation();
+
+public:
+
+  /**
+   * Returns the actual orientation in degrees
+   * @return The device's orientation
+   */
+  int GetDegrees() const;
+
+  /**
+   * Returns the actual orientation in radians
+   * @return The device's orientation
+   */
+  float GetRadians() const;
+
+  /**
+   * Called by the Window when orientation is changed
+   * @param[in] rotation The rotation event
+   */
+  void OnOrientationChange( const RotationEvent& rotation );
+
+public: // Signals
+
+  /**
+   * @copydoc Dali::Orientation::ChangedSignal()
+   */
+  OrientationSignalType& ChangedSignal();
+
+private:
+
+  // Undefined
+  Orientation(const Orientation&);
+  Orientation& operator=(Orientation&);
+
+private:
+
+  Window*                                  mWindow;
+
+  OrientationSignalType mChangedSignal;
+
+  int                                      mOrientation;
+  int                                      mWindowWidth;
+  int                                      mWindowHeight;
+};
+
+inline Orientation& GetImplementation (Dali::Orientation& orientation)
+{
+  DALI_ASSERT_ALWAYS(orientation && "Orientation handle is empty");
+
+  BaseObject& handle = orientation.GetBaseObject();
+
+  return static_cast<Orientation&>(handle);
+}
+
+inline const Orientation& GetImplementation(const Dali::Orientation& orientation)
+{
+  DALI_ASSERT_ALWAYS(orientation && "Orientation handle is empty");
+
+  const BaseObject& handle = orientation.GetBaseObject();
+
+  return static_cast<const Orientation&>(handle);
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ORIENTATION_H
diff --git a/dali/internal/window-system/common/pixmap-render-surface.h b/dali/internal/window-system/common/pixmap-render-surface.h
new file mode 100644 (file)
index 0000000..53f03b5
--- /dev/null
@@ -0,0 +1,116 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_COMMON_PIXMAP_RENDER_SURFACE_H
+#define DALI_INTERNAL_WINDOWSYSTEM_COMMON_PIXMAP_RENDER_SURFACE_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/render-surface-interface.h>
+#include <dali/internal/graphics/common/graphics-interface.h>
+
+namespace Dali
+{
+
+class TriggerEventInterface;
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * Pixmap interface of render surface.
+ */
+class PixmapRenderSurface : public Dali::RenderSurfaceInterface
+{
+public:
+
+  /**
+   * @brief Default constructor
+   */
+  PixmapRenderSurface() = default;
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~PixmapRenderSurface() = default;
+
+public: // API
+
+  /**
+   * @brief Get the render surface the adaptor is using to render to.
+   * @return reference to current render surface
+   */
+  virtual Any GetSurface() = 0;
+
+  /**
+   * @brief Sets the render notification trigger to call when render thread is completed a frame
+   * @param renderNotification to use
+   */
+  virtual void SetRenderNotification( TriggerEventInterface* renderNotification ) = 0;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::GetDepthBufferRequired()
+   */
+  Integration::DepthBufferAvailable GetDepthBufferRequired() override
+  {
+    return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
+  }
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::GetStencilBufferRequired()
+   */
+  Integration::StencilBufferAvailable GetStencilBufferRequired() override
+  {
+    return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
+  }
+
+private:
+
+  /**
+   * Second stage construction
+   */
+  virtual void Initialize( Any surface ) = 0;
+
+  /**
+   * @brief Create a renderable
+   */
+  virtual void CreateRenderable() = 0;
+
+  /**
+   * @brief Use an existing render surface
+   * @param surfaceId the id of the surface
+   */
+  virtual void UseExistingRenderable( unsigned int surfaceId ) = 0;
+
+protected:
+
+  // Undefined
+  PixmapRenderSurface(const PixmapRenderSurface&) = delete;
+
+  // Undefined
+  PixmapRenderSurface& operator=(const PixmapRenderSurface& rhs) = delete;
+
+};
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_COMMON_PIXMAP_RENDER_SURFACE_H
diff --git a/dali/internal/window-system/common/render-surface-factory.h b/dali/internal/window-system/common/render-surface-factory.h
new file mode 100644 (file)
index 0000000..408ae14
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_COMMON_RENDER_SURFACE_FACTORY_H
+#define DALI_INTERNAL_WINDOWSYSTEM_COMMON_RENDER_SURFACE_FACTORY_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/render-surface-interface.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/any.h>
+#include <memory>
+
+namespace Dali
+{
+
+class NativeRenderSurface;
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+class WindowRenderSurface;
+class PixmapRenderSurface;
+
+class RenderSurfaceFactory
+{
+public:
+
+  RenderSurfaceFactory() = default;
+  virtual ~RenderSurfaceFactory() = default;
+
+  virtual std::unique_ptr< WindowRenderSurface > CreateWindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent = false ) = 0;
+
+  virtual std::unique_ptr< PixmapRenderSurface > CreatePixmapRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent = false ) = 0;
+
+  virtual std::unique_ptr< NativeRenderSurface > CreateNativeRenderSurface( Dali::PositionSize positionSize, bool isTransparent = false ) = 0;
+};
+
+extern std::unique_ptr< RenderSurfaceFactory > GetRenderSurfaceFactory();
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_COMMON_RENDER_SURFACE_FACTORY_H
diff --git a/dali/internal/window-system/common/rotation-event.h b/dali/internal/window-system/common/rotation-event.h
new file mode 100644 (file)
index 0000000..4972eff
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef DALI_INTERNAL_ROTATION_EVENT_H
+#define DALI_INTERNAL_ROTATION_EVENT_H
+
+/*
+ * Copyright (c) 2019 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
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+struct RotationEvent
+{
+  int angle;     ///< one of 0, 90, 180, 270
+  int winResize; ///< true if the window should be resized
+  int width;     ///< new window width
+  int height;    ///< new window height
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ROTATION_EVENT_H
diff --git a/dali/internal/window-system/common/window-base.cpp b/dali/internal/window-system/common/window-base.cpp
new file mode 100644 (file)
index 0000000..f3101b6
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/common/window-base.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+WindowBase::WindowBase()
+: mIconifyChangedSignal(),
+  mFocusChangedSignal(),
+  mOutputTransformedSignal(),
+  mDeleteRequestSignal(),
+  mWindowDamagedSignal(),
+  mRotationSignal(),
+  mTouchEventSignal(),
+  mWheelEventSignal(),
+  mKeyEventSignal(),
+  mSelectionDataSendSignal(),
+  mSelectionDataReceivedSignal(),
+  mStyleChangedSignal(),
+  mAccessibilitySignal(),
+  mTransitionEffectEventSignal()
+{
+}
+
+WindowBase::~WindowBase()
+{
+}
+
+WindowBase::IconifySignalType& WindowBase::IconifyChangedSignal()
+{
+  return mIconifyChangedSignal;
+}
+
+WindowBase::FocusSignalType& WindowBase::FocusChangedSignal()
+{
+  return mFocusChangedSignal;
+}
+
+WindowBase::OutputSignalType& WindowBase::OutputTransformedSignal()
+{
+  return mOutputTransformedSignal;
+}
+
+WindowBase::DeleteSignalType& WindowBase::DeleteRequestSignal()
+{
+  return mDeleteRequestSignal;
+}
+
+WindowBase::DamageSignalType& WindowBase::WindowDamagedSignal()
+{
+  return mWindowDamagedSignal;
+}
+
+WindowBase::RotationSignalType& WindowBase::RotationSignal()
+{
+  return mRotationSignal;
+}
+
+WindowBase::TouchEventSignalType& WindowBase::TouchEventSignal()
+{
+  return mTouchEventSignal;
+}
+
+WindowBase::WheelEventSignalType& WindowBase::WheelEventSignal()
+{
+  return mWheelEventSignal;
+}
+
+WindowBase::KeyEventSignalType& WindowBase::KeyEventSignal()
+{
+  return mKeyEventSignal;
+}
+
+WindowBase::SelectionSignalType& WindowBase::SelectionDataSendSignal()
+{
+  return mSelectionDataSendSignal;
+}
+
+WindowBase::SelectionSignalType& WindowBase::SelectionDataReceivedSignal()
+{
+  return mSelectionDataReceivedSignal;
+}
+
+WindowBase::StyleSignalType& WindowBase::StyleChangedSignal()
+{
+  return mStyleChangedSignal;
+}
+
+WindowBase::AccessibilitySignalType& WindowBase::AccessibilitySignal()
+{
+  return mAccessibilitySignal;
+}
+
+WindowBase::TransitionEffectEventSignalType& WindowBase::TransitionEffectEventSignal()
+{
+  return mTransitionEffectEventSignal;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/window-system/common/window-base.h b/dali/internal/window-system/common/window-base.h
new file mode 100644 (file)
index 0000000..9871611
--- /dev/null
@@ -0,0 +1,442 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_BASE_H
+#define DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_BASE_H
+
+/*
+ * Copyright (c) 2019 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/events/key-event-integ.h>
+#include <dali/integration-api/events/point.h>
+#include <dali/public-api/events/wheel-event.h>
+#include <string>
+#include <vector>
+#include <cstdint>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/window.h>
+#include <dali/public-api/adaptor-framework/key-grab.h>
+#include <dali/public-api/adaptor-framework/style-change.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
+#include <dali/internal/window-system/common/damage-observer.h>
+#include <dali/internal/window-system/common/rotation-event.h>
+#include <dali/internal/graphics/gles/egl-implementation.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * WindowBase interface
+ */
+class WindowBase
+{
+public:
+
+  /**
+   * @brief Struct used to retrieve accessibility information
+   */
+  struct AccessibilityInfo
+  {
+    int gestureValue;
+    int startX;
+    int startY;
+    int endX;
+    int endY;
+    int state;
+    int eventTime;
+  };
+
+  // Window
+  typedef Signal< void ( bool ) > IconifySignalType;
+  typedef Signal< void ( bool ) > FocusSignalType;
+  typedef Signal< void ( ) > OutputSignalType;
+  typedef Signal< void ( ) > DeleteSignalType;
+  typedef Signal< void ( const DamageArea& ) > DamageSignalType;
+  typedef Signal< void ( const RotationEvent& ) > RotationSignalType;
+  typedef Signal< void ( DevelWindow::EffectState, DevelWindow::EffectType ) > TransitionEffectEventSignalType;
+
+  // Input events
+  typedef Signal< void ( Integration::Point&, uint32_t ) > TouchEventSignalType;
+  typedef Signal< void ( WheelEvent& ) > WheelEventSignalType;
+  typedef Signal< void( Integration::KeyEvent& ) > KeyEventSignalType;
+
+  // Clipboard
+  typedef Signal< void ( void* ) > SelectionSignalType;
+
+  // Accessibility
+  typedef Signal< void ( StyleChange::Type ) > StyleSignalType;
+  typedef Signal< void ( const AccessibilityInfo& ) > AccessibilitySignalType;
+
+  /**
+   * @brief Default constructor
+   */
+  WindowBase();
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~WindowBase();
+
+public:
+
+  /**
+   * @brief Get the native window handle
+   * @return The native window handle
+   */
+  virtual Any GetNativeWindow() = 0;
+
+  /**
+   * @brief Get the native window id
+   * @return The native window id
+   */
+  virtual int GetNativeWindowId() = 0;
+
+  /**
+   * @brief Create the egl window
+   */
+  virtual EGLNativeWindowType CreateEglWindow( int width, int height ) = 0;
+
+  /**
+   * @brief Destroy the egl window
+   */
+  virtual void DestroyEglWindow() = 0;
+
+  /**
+   * @brief Set the egl window rotation
+   */
+  virtual void SetEglWindowRotation( int angle ) = 0;
+
+  /**
+   * @brief Set the egl window buffer transform
+   */
+  virtual void SetEglWindowBufferTransform( int angle ) = 0;
+
+  /**
+   * @brief Set the egl window transform
+   */
+  virtual void SetEglWindowTransform( int angle ) = 0;
+
+  /**
+   * @brief Resize the egl window
+   */
+  virtual void ResizeEglWindow( Dali::PositionSize positionSize ) = 0;
+
+  /**
+   * @brief Returns whether the egl window support rotation or not
+   */
+  virtual bool IsEglWindowRotationSupported() = 0;
+
+  /**
+   * @brief Move the window
+   */
+  virtual void Move( Dali::PositionSize positionSize ) = 0;
+
+  /**
+   * @brief Resize the window
+   */
+  virtual void Resize( Dali::PositionSize positionSize ) = 0;
+
+  /**
+   * @brief Move and resize the window
+   */
+  virtual void MoveResize( Dali::PositionSize positionSize ) = 0;
+
+  /**
+   * @copydoc Dali::Window::SetClass()
+   */
+  virtual void SetClass( const std::string& name, const std::string& className ) = 0;
+
+  /**
+   * @copydoc Dali::Window::Raise()
+   */
+  virtual void Raise() = 0;
+
+  /**
+   * @copydoc Dali::Window::Lower()
+   */
+  virtual void Lower() = 0;
+
+  /**
+   * @copydoc Dali::Window::Activate()
+   */
+  virtual void Activate() = 0;
+
+  /**
+   * @copydoc Dali::Window::SetAvailableOrientations()
+   */
+  virtual void SetAvailableAnlges( const std::vector< int >& angles ) = 0;
+
+  /**
+   * @copydoc Dali::Window::SetPreferredOrientation()
+   */
+  virtual void SetPreferredAngle( int angle ) = 0;
+
+  /**
+   * @copydoc Dali::Window::SetAcceptFocus()
+   */
+  virtual void SetAcceptFocus( bool accept ) = 0;
+
+  /**
+   * @copydoc Dali::Window::Show()
+   */
+  virtual void Show() = 0;
+
+  /**
+   * @copydoc Dali::Window::Hide()
+   */
+  virtual void Hide() = 0;
+
+  /**
+   * @copydoc Dali::Window::GetSupportedAuxiliaryHintCount()
+   */
+  virtual unsigned int GetSupportedAuxiliaryHintCount() const = 0;
+
+  /**
+   * @copydoc Dali::Window::GetSupportedAuxiliaryHint()
+   */
+  virtual std::string GetSupportedAuxiliaryHint( unsigned int index ) const = 0;
+
+  /**
+   * @copydoc Dali::Window::AddAuxiliaryHint()
+   */
+  virtual unsigned int AddAuxiliaryHint( const std::string& hint, const std::string& value ) = 0;
+
+  /**
+   * @copydoc Dali::Window::RemoveAuxiliaryHint()
+   */
+  virtual bool RemoveAuxiliaryHint( unsigned int id ) = 0;
+
+  /**
+   * @copydoc Dali::Window::SetAuxiliaryHintValue()
+   */
+  virtual bool SetAuxiliaryHintValue( unsigned int id, const std::string& value ) = 0;
+
+  /**
+   * @copydoc Dali::Window::GetAuxiliaryHintValue()
+   */
+  virtual std::string GetAuxiliaryHintValue( unsigned int id ) const = 0;
+
+  /**
+   * @copydoc Dali::Window::GetAuxiliaryHintId()
+   */
+  virtual unsigned int GetAuxiliaryHintId( const std::string& hint ) const = 0;
+
+  /**
+   * @copydoc Dali::Window::SetInputRegion()
+   */
+  virtual void SetInputRegion( const Rect< int >& inputRegion ) = 0;
+
+  /**
+   * @copydoc Dali::Window::SetType()
+   */
+  virtual void SetType( Dali::Window::Type type ) = 0;
+
+  /**
+   * @copydoc Dali::Window::SetNotificationLevel()
+   */
+  virtual bool SetNotificationLevel( Dali::Window::NotificationLevel::Type level ) = 0;
+
+  /**
+   * @copydoc Dali::Window::GetNotificationLevel()
+   */
+  virtual Dali::Window::NotificationLevel::Type GetNotificationLevel() const = 0;
+
+  /**
+   * @copydoc Dali::Window::SetOpaqueState()
+   */
+  virtual void SetOpaqueState( bool opaque ) = 0;
+
+  /**
+   * @copydoc Dali::Window::SetScreenOffMode()
+   */
+  virtual bool SetScreenOffMode(Dali::Window::ScreenOffMode::Type screenOffMode) = 0;
+
+  /**
+   * @copydoc Dali::Window::GetScreenOffMode()
+   */
+  virtual Dali::Window::ScreenOffMode::Type GetScreenOffMode() const = 0;
+
+  /**
+   * @copydoc Dali::Window::SetBrightness()
+   */
+  virtual bool SetBrightness( int brightness ) = 0;
+
+  /**
+   * @copydoc Dali::Window::GetBrightness()
+   */
+  virtual int GetBrightness() const = 0;
+
+  /**
+   * @copydoc Dali::KeyGrab::GrabKey()
+   */
+  virtual bool GrabKey( Dali::KEY key, KeyGrab::KeyGrabMode grabMode ) = 0;
+
+  /**
+   * @copydoc Dali::KeyGrab::UngrabKey()
+   */
+  virtual bool UngrabKey( Dali::KEY key ) = 0;
+
+  /**
+   * @copydoc Dali::KeyGrab::GrabKeyList()
+   */
+  virtual bool GrabKeyList( const Dali::Vector< Dali::KEY >& key, const Dali::Vector< KeyGrab::KeyGrabMode >& grabMode, Dali::Vector< bool >& result ) = 0;
+
+  /**
+   * @copydoc Dali::KeyGrab::UngrabKeyList()
+   */
+  virtual bool UngrabKeyList( const Dali::Vector< Dali::KEY >& key, Dali::Vector< bool >& result ) = 0;
+
+  /**
+   * @brief Get DPI
+   * @param[out] dpiHorizontal set to the horizontal dpi
+   * @param[out] dpiVertical set to the vertical dpi
+   */
+  virtual void GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical ) = 0;
+
+  /**
+   * @brief Get the screen rotation angle of the window
+   */
+  virtual int GetScreenRotationAngle() = 0;
+
+  /**
+   * @brief Set the rotation angle of the window
+   */
+  virtual void SetWindowRotationAngle( int degree ) = 0;
+
+  /**
+   * @brief Inform the window rotation is completed
+   */
+  virtual void WindowRotationCompleted( int degree, int width, int height ) = 0;
+
+  /**
+   * @copydoc Dali::Window::SetTransparency()
+   */
+  virtual void SetTransparency( bool transparent ) = 0;
+
+  /**
+   * @copydoc Dali::Window::SetParent()
+   */
+  virtual void SetParent( WindowBase* parentWinBase ) = 0;
+
+  // Signals
+
+  /**
+   * @brief This signal is emitted when the window becomes iconified or deiconified.
+   */
+   IconifySignalType& IconifyChangedSignal();
+
+  /**
+   * @brief This signal is emitted when the window focus is changed.
+   */
+  FocusSignalType& FocusChangedSignal();
+
+  /**
+   * @brief This signal is emitted when the output is transformed.
+   */
+  OutputSignalType& OutputTransformedSignal();
+
+  /**
+   * @brief This signal is emitted when the window receives a delete request.
+   */
+  DeleteSignalType& DeleteRequestSignal();
+
+  /**
+   * @brief This signal is emitted when the window is damaged.
+   */
+  DamageSignalType& WindowDamagedSignal();
+
+  /**
+   * @brief This signal is emitted when a rotation event is recevied.
+   */
+  RotationSignalType& RotationSignal();
+
+  /**
+   * @brief This signal is emitted when a touch event is received.
+   */
+  TouchEventSignalType& TouchEventSignal();
+
+  /**
+   * @brief This signal is emitted when a mouse wheel is received.
+   */
+  WheelEventSignalType& WheelEventSignal();
+
+  /**
+   * @brief This signal is emitted when a key event is received.
+   */
+  KeyEventSignalType& KeyEventSignal();
+
+  /**
+   * @brief This signal is emitted when the source window notifies us the content in clipboard is selected.
+   */
+  SelectionSignalType& SelectionDataSendSignal();
+
+  /**
+   * @brief This signal is emitted when the source window sends us about the selected content.
+   */
+  SelectionSignalType& SelectionDataReceivedSignal();
+
+  /**
+   * @brief This signal is emitted when the style is changed.
+   */
+  StyleSignalType& StyleChangedSignal();
+
+  /**
+   * @brief This signal is emitted when an accessibility event is received.
+   */
+  AccessibilitySignalType& AccessibilitySignal();
+
+  /**
+   * @brief This signal is emitted when window's transition animation is started or ended.
+   */
+  TransitionEffectEventSignalType& TransitionEffectEventSignal();
+
+protected:
+
+  // Undefined
+  WindowBase(const WindowBase&) = delete;
+
+  // Undefined
+  WindowBase& operator=(const WindowBase& rhs) = delete;
+
+protected:
+
+  IconifySignalType                    mIconifyChangedSignal;
+  FocusSignalType                      mFocusChangedSignal;
+  OutputSignalType                     mOutputTransformedSignal;
+  DeleteSignalType                     mDeleteRequestSignal;
+  DamageSignalType                     mWindowDamagedSignal;
+  RotationSignalType                   mRotationSignal;
+  TouchEventSignalType                 mTouchEventSignal;
+  WheelEventSignalType                 mWheelEventSignal;
+  KeyEventSignalType                   mKeyEventSignal;
+  SelectionSignalType                  mSelectionDataSendSignal;
+  SelectionSignalType                  mSelectionDataReceivedSignal;
+  StyleSignalType                      mStyleChangedSignal;
+  AccessibilitySignalType              mAccessibilitySignal;
+  TransitionEffectEventSignalType      mTransitionEffectEventSignal;
+};
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_BASE_H
diff --git a/dali/internal/window-system/common/window-event-interface.h b/dali/internal/window-system/common/window-event-interface.h
new file mode 100644 (file)
index 0000000..c9d9c8b
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef DALI_INTERNAL_BASE_WINDOW_EVENT_INTERFACE_H
+#define DALI_INTERNAL_BASE_WINDOW_EVENT_INTERFACE_H
+
+/*
+ * Copyright (c) 2019 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/events/key-event.h>
+#include <dali/public-api/events/wheel-event.h>
+#include <dali/integration-api/events/key-event-integ.h>
+#include <dali/integration-api/events/point.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * @brief Abstract interface for handling DALi events received from the native window system
+ *
+ */
+class WindowEventInterface
+{
+
+public:
+
+  /**
+   * @brief Touch Event callback
+   * @param[in] point touch point
+   * @param[in] timeStamp time stamp
+   */
+  virtual void TouchEvent( Dali::Integration::Point& point, unsigned long timeStamp ) = 0;
+
+  /**
+   * @brief Key Event callback
+   * @param[in] keyEvent key event
+   */
+  virtual void KeyEvent( Dali::Integration::KeyEvent& keyEvent ) = 0;
+
+  /**
+   * @brief Wheel Event callback
+   * @param[in] wheelEvent wheel event
+   */
+  virtual void WheelEvent( Dali::WheelEvent& wheelEvent ) = 0;
+
+  /**
+   * @brief Window damage callback
+   * @param[in] damageArea Window damage area
+   */
+  virtual void DamageEvent( Dali::Rect<int>& damageArea ) = 0;
+
+  /**
+   * @brief Window Focused
+   */
+  virtual void WindowFocusIn() = 0;
+
+  /**
+   * @brief Window lost focus
+   */
+  virtual void WindowFocusOut() = 0;
+
+protected:
+
+  /**
+   * @brief Constructor
+   */
+  WindowEventInterface()
+  {
+  }
+
+  /**
+   * Virtual destructor
+   */
+  virtual ~WindowEventInterface()
+  {
+  }
+
+  // Undefined copy constructor.
+  WindowEventInterface( const WindowEventInterface& );
+
+  // Undefined assignment operator.
+  WindowEventInterface& operator=( const WindowEventInterface& );
+
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_BASE_WINDOW_EVENT_INTERFACE_H
diff --git a/dali/internal/window-system/common/window-factory.h b/dali/internal/window-system/common/window-factory.h
new file mode 100644 (file)
index 0000000..741e744
--- /dev/null
@@ -0,0 +1,53 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_FACTORY_H
+#define DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_FACTORY_H
+
+/*
+ * Copyright (c) 2018 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 <dali/public-api/adaptor-framework/window.h>
+
+// EXTERNAL INCLUDES
+#include <memory>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class Adaptor;
+class WindowBase;
+
+class WindowFactory
+{
+public:
+
+  WindowFactory() = default;
+  virtual ~WindowFactory() = default;
+
+  virtual std::unique_ptr< WindowBase > CreateWindowBase( Dali::PositionSize positionSize, Any surface, bool isTransparent ) = 0;
+};
+
+extern std::unique_ptr< WindowFactory > GetWindowFactory();
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_FACTORY_H
diff --git a/dali/internal/window-system/common/window-impl.cpp b/dali/internal/window-system/common/window-impl.cpp
new file mode 100644 (file)
index 0000000..a0fd809
--- /dev/null
@@ -0,0 +1,924 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/common/window-impl.h>
+
+// EXTERNAL HEADERS
+#include <thread>
+#include <dali/integration-api/core.h>
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/actors/camera-actor.h>
+#include <dali/public-api/render-tasks/render-task.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+#include <dali/public-api/rendering/frame-buffer.h>
+#include <dali/devel-api/adaptor-framework/orientation.h>
+#include <dali/integration-api/events/touch-event-integ.h>
+
+// INTERNAL HEADERS
+#include <dali/integration-api/adaptor-framework/render-surface-interface.h>
+#include <dali/internal/window-system/common/event-handler.h>
+#include <dali/internal/window-system/common/orientation-impl.h>
+#include <dali/internal/window-system/common/render-surface-factory.h>
+#include <dali/internal/window-system/common/window-factory.h>
+#include <dali/internal/window-system/common/window-base.h>
+#include <dali/internal/window-system/common/window-system.h>
+#include <dali/internal/window-system/common/window-render-surface.h>
+#include <dali/internal/window-system/common/window-visibility-observer.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gWindowLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_WINDOW" );
+#endif
+
+} // unnamed namespace
+
+Window* Window::New(const PositionSize& positionSize, const std::string& name, const std::string& className, bool isTransparent)
+{
+  Any surface;
+  return Window::New(surface, positionSize, name, className, isTransparent);
+}
+
+Window* Window::New(Any surface, const PositionSize& positionSize, const std::string& name, const std::string& className, bool isTransparent)
+{
+  Window* window = new Window();
+  window->mIsTransparent = isTransparent;
+  window->Initialize(surface, positionSize, name, className);
+  return window;
+}
+
+Window::Window()
+: mWindowSurface( nullptr ),
+  mWindowBase(),
+  mIsTransparent( false ),
+  mIsFocusAcceptable( true ),
+  mIconified( false ),
+  mOpaqueState( false ),
+  mResizeEnabled( false ),
+  mType( Dali::Window::NORMAL ),
+  mParentWindow( NULL ),
+  mPreferredAngle( Dali::Window::NO_ORIENTATION_PREFERENCE ),
+  mRotationAngle( -1 ),
+  mWindowWidth( 0 ),
+  mWindowHeight( 0 ),
+  mOrientationMode( Internal::Adaptor::Window::OrientationMode::PORTRAIT ),
+  mNativeWindowId( -1 ),
+  mFocusChangedSignal(),
+  mResizedSignal(),
+  mDeleteRequestSignal(),
+  mFocusChangeSignal(),
+  mResizeSignal(),
+  mVisibilityChangedSignal(),
+  mTransitionEffectEventSignal()
+{
+}
+
+Window::~Window()
+{
+  mIsBeingDeleted = true;
+
+  while ( mAdaptor && mAdaptor->IsRenderingWindows() )
+  {
+    std::this_thread::yield(); // to allow other threads to run
+  }
+
+  if ( mEventHandler )
+  {
+    mEventHandler->RemoveObserver( *this );
+  }
+}
+
+void Window::Initialize(Any surface, const PositionSize& positionSize, const std::string& name, const std::string& className)
+{
+  // Create a window render surface
+  auto renderSurfaceFactory = Dali::Internal::Adaptor::GetRenderSurfaceFactory();
+  mSurface = renderSurfaceFactory->CreateWindowRenderSurface( positionSize, surface, mIsTransparent );
+  mWindowSurface = static_cast<WindowRenderSurface*>( mSurface.get() );
+
+  // Get a window base
+  mWindowBase = mWindowSurface->GetWindowBase();
+
+  // Connect signals
+  mWindowBase->IconifyChangedSignal().Connect( this, &Window::OnIconifyChanged );
+  mWindowBase->FocusChangedSignal().Connect( this, &Window::OnFocusChanged );
+  mWindowBase->DeleteRequestSignal().Connect( this, &Window::OnDeleteRequest );
+  mWindowBase->TransitionEffectEventSignal().Connect( this, &Window::OnTransitionEffectEvent );
+
+  mWindowSurface->OutputTransformedSignal().Connect( this, &Window::OnOutputTransformed );
+
+  if( !positionSize.IsEmpty() )
+  {
+    AddAuxiliaryHint( "wm.policy.win.user.geometry", "1" );
+    mResizeEnabled = true;
+  }
+
+  SetClass( name, className );
+
+  mWindowSurface->Map();
+
+  mOrientation = Orientation::New( this );
+
+  // Get OrientationMode
+  int screenWidth, screenHeight;
+  WindowSystem::GetScreenSize( screenWidth, screenHeight );
+  if( screenWidth > screenHeight )
+  {
+    mOrientationMode = Internal::Adaptor::Window::OrientationMode::LANDSCAPE;
+  }
+  else
+  {
+    mOrientationMode = Internal::Adaptor::Window::OrientationMode::PORTRAIT;
+  }
+  // For Debugging
+  mNativeWindowId = mWindowBase->GetNativeWindowId();
+}
+
+void Window::OnAdaptorSet(Dali::Adaptor& adaptor)
+{
+  mEventHandler = EventHandlerPtr(new EventHandler( mWindowSurface, *mAdaptor ) );
+  mEventHandler->AddObserver( *this );
+}
+
+void Window::OnSurfaceSet( Dali::RenderSurfaceInterface* surface )
+{
+  mWindowSurface = static_cast<WindowRenderSurface*>( surface );
+}
+
+void Window::ShowIndicator( Dali::Window::IndicatorVisibleMode visibleMode )
+{
+}
+
+void Window::SetIndicatorBgOpacity( Dali::Window::IndicatorBgOpacity opacityMode )
+{
+}
+
+void Window::RotateIndicator( Dali::Window::WindowOrientation orientation )
+{
+}
+
+void Window::SetClass( std::string name, std::string className )
+{
+  mName = name;
+  mClassName = className;
+  mWindowBase->SetClass( name, className );
+}
+
+std::string Window::GetClassName() const
+{
+  return mClassName;
+}
+
+void Window::Raise()
+{
+  mWindowBase->Raise();
+  DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Raise() \n", this, mNativeWindowId );
+}
+
+void Window::Lower()
+{
+  mWindowBase->Lower();
+  DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Lower() \n", this, mNativeWindowId );
+}
+
+void Window::Activate()
+{
+  mWindowBase->Activate();
+  DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Activate() \n", this, mNativeWindowId );
+}
+
+uint32_t Window::GetLayerCount() const
+{
+  return mScene.GetLayerCount();
+}
+
+Dali::Layer Window::GetLayer( uint32_t depth ) const
+{
+  return mScene.GetLayer( depth );
+}
+
+Dali::RenderTaskList Window::GetRenderTaskList() const
+{
+  return mScene.GetRenderTaskList();
+}
+
+void Window::AddAvailableOrientation( Dali::Window::WindowOrientation orientation )
+{
+  if( IsOrientationAvailable( orientation ) == false )
+  {
+    return;
+  }
+
+  bool found = false;
+  int convertedAngle = ConvertToAngle( orientation );
+  DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), AddAvailableOrientation: %d\n", this, mNativeWindowId, convertedAngle );
+  for( std::size_t i = 0; i < mAvailableAngles.size(); i++ )
+  {
+    if( mAvailableAngles[i] == convertedAngle )
+    {
+      found = true;
+      break;
+    }
+  }
+
+  if( !found )
+  {
+    mAvailableAngles.push_back( convertedAngle );
+    SetAvailableAnlges( mAvailableAngles );
+  }
+}
+
+void Window::RemoveAvailableOrientation( Dali::Window::WindowOrientation orientation )
+{
+  if( IsOrientationAvailable( orientation ) == false )
+  {
+    return;
+  }
+
+  int convertedAngle = ConvertToAngle( orientation );
+  DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), RemoveAvailableOrientation: %d\n", this, mNativeWindowId, convertedAngle );
+  for( std::vector< int >::iterator iter = mAvailableAngles.begin();
+       iter != mAvailableAngles.end(); ++iter )
+  {
+    if( *iter == convertedAngle )
+    {
+      mAvailableAngles.erase( iter );
+      break;
+    }
+  }
+
+  SetAvailableAnlges( mAvailableAngles );
+}
+
+void Window::SetPreferredOrientation( Dali::Window::WindowOrientation orientation )
+{
+  if( orientation < Dali::Window::NO_ORIENTATION_PREFERENCE || orientation > Dali::Window::LANDSCAPE_INVERSE )
+  {
+    DALI_LOG_INFO( gWindowLogFilter, Debug::Verbose, "Window::CheckOrientation: Invalid input orientation [%d]\n", orientation );
+    return;
+  }
+  mPreferredAngle = ConvertToAngle( orientation );
+  DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), SetPreferredOrientation: %d\n", this, mNativeWindowId, mPreferredAngle );
+  mWindowBase->SetPreferredAngle( mPreferredAngle );
+}
+
+Dali::Window::WindowOrientation Window::GetPreferredOrientation()
+{
+  DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), GetPreferredOrientation: %d\n", this, mNativeWindowId, mPreferredAngle );
+  Dali::Window::WindowOrientation preferredOrientation = ConvertToOrientation( mPreferredAngle );
+  return preferredOrientation;
+}
+
+void Window::SetAvailableAnlges( const std::vector< int >& angles )
+{
+  if( angles.size() > 4 )
+  {
+    DALI_LOG_INFO( gWindowLogFilter, Debug::Verbose, "Window::SetAvailableAnlges: Invalid vector size! [%d]\n", angles.size() );
+    return;
+  }
+
+  mWindowBase->SetAvailableAnlges( angles );
+}
+
+int Window::ConvertToAngle( Dali::Window::WindowOrientation orientation )
+{
+  int convertAngle = static_cast< int >( orientation );
+  if( mOrientationMode == Internal::Adaptor::Window::OrientationMode::LANDSCAPE )
+  {
+    switch( orientation )
+    {
+      case Dali::Window::LANDSCAPE:
+      {
+        convertAngle = 0;
+        break;
+      }
+      case Dali::Window::PORTRAIT:
+      {
+        convertAngle = 90;
+        break;
+      }
+      case Dali::Window::LANDSCAPE_INVERSE:
+      {
+        convertAngle = 180;
+        break;
+      }
+      case Dali::Window::PORTRAIT_INVERSE:
+      {
+        convertAngle = 270;
+        break;
+      }
+      case Dali::Window::NO_ORIENTATION_PREFERENCE:
+      {
+        convertAngle = -1;
+        break;
+      }
+    }
+  }
+  return convertAngle;
+}
+
+Dali::Window::WindowOrientation Window::ConvertToOrientation( int angle ) const
+{
+  Dali::Window::WindowOrientation orientation = static_cast< Dali::Window::WindowOrientation >( angle );
+  if( mOrientationMode == Internal::Adaptor::Window::OrientationMode::LANDSCAPE )
+  {
+    switch( angle )
+    {
+      case 0:
+      {
+        orientation = Dali::Window::LANDSCAPE;
+        break;
+      }
+      case 90:
+      {
+        orientation = Dali::Window::PORTRAIT;
+        break;
+      }
+      case 180:
+      {
+        orientation = Dali::Window::LANDSCAPE_INVERSE;
+        break;
+      }
+      case 270:
+      {
+        orientation = Dali::Window::PORTRAIT_INVERSE;
+        break;
+      }
+      case -1:
+      {
+        orientation = Dali::Window::NO_ORIENTATION_PREFERENCE;
+        break;
+      }
+    }
+  }
+  return orientation;
+}
+
+bool Window::IsOrientationAvailable( Dali::Window::WindowOrientation orientation ) const
+{
+  if( orientation <= Dali::Window::NO_ORIENTATION_PREFERENCE || orientation > Dali::Window::LANDSCAPE_INVERSE )
+  {
+    DALI_LOG_INFO( gWindowLogFilter, Debug::Verbose, "Window::IsOrientationAvailable: Invalid input orientation [%d]\n", orientation );
+    return false;
+  }
+  return true;
+}
+
+Dali::Any Window::GetNativeHandle() const
+{
+  return mWindowSurface->GetNativeWindow();
+}
+
+void Window::SetAcceptFocus( bool accept )
+{
+  mIsFocusAcceptable = accept;
+
+  mWindowBase->SetAcceptFocus( accept );
+}
+
+bool Window::IsFocusAcceptable() const
+{
+  return mIsFocusAcceptable;
+}
+
+void Window::Show()
+{
+  mVisible = true;
+
+  mWindowBase->Show();
+
+  if( !mIconified )
+  {
+    WindowVisibilityObserver* observer( mAdaptor );
+    observer->OnWindowShown();
+
+    Dali::Window handle( this );
+    mVisibilityChangedSignal.Emit( handle, true );
+  }
+
+  DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Show(): iconified = %d, visible = %d\n", this, mNativeWindowId, mIconified, mVisible );
+}
+
+void Window::Hide()
+{
+  mVisible = false;
+
+  mWindowBase->Hide();
+
+  if( !mIconified )
+  {
+    WindowVisibilityObserver* observer( mAdaptor );
+    observer->OnWindowHidden();
+
+    Dali::Window handle( this );
+    mVisibilityChangedSignal.Emit( handle, false );
+  }
+
+  DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Hide(): iconified = %d, visible = %d\n", this, mNativeWindowId, mIconified, mVisible );
+}
+
+bool Window::IsVisible() const
+{
+  DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), IsVisible(): iconified = %d, visible = %d\n", this, mNativeWindowId, mIconified, mVisible );
+  return mVisible && !mIconified;
+}
+
+unsigned int Window::GetSupportedAuxiliaryHintCount() const
+{
+  return mWindowBase->GetSupportedAuxiliaryHintCount();
+}
+
+std::string Window::GetSupportedAuxiliaryHint( unsigned int index ) const
+{
+  return mWindowBase->GetSupportedAuxiliaryHint( index );
+}
+
+unsigned int Window::AddAuxiliaryHint( const std::string& hint, const std::string& value )
+{
+  return mWindowBase->AddAuxiliaryHint( hint, value );
+}
+
+bool Window::RemoveAuxiliaryHint( unsigned int id )
+{
+  return mWindowBase->RemoveAuxiliaryHint( id );
+}
+
+bool Window::SetAuxiliaryHintValue( unsigned int id, const std::string& value )
+{
+  return mWindowBase->SetAuxiliaryHintValue( id, value );
+}
+
+std::string Window::GetAuxiliaryHintValue( unsigned int id ) const
+{
+  return mWindowBase->GetAuxiliaryHintValue( id );
+}
+
+unsigned int Window::GetAuxiliaryHintId( const std::string& hint ) const
+{
+  return mWindowBase->GetAuxiliaryHintId( hint );
+}
+
+void Window::SetInputRegion( const Rect< int >& inputRegion )
+{
+  mWindowBase->SetInputRegion( inputRegion );
+
+  DALI_LOG_INFO( gWindowLogFilter, Debug::Verbose, "Window::SetInputRegion: x = %d, y = %d, w = %d, h = %d\n", inputRegion.x, inputRegion.y, inputRegion.width, inputRegion.height );
+}
+
+void Window::SetType( Dali::Window::Type type )
+{
+  if( type != mType )
+  {
+    mWindowBase->SetType( type );
+
+    mType = type;
+  }
+}
+
+Dali::Window::Type Window::GetType() const
+{
+  return mType;
+}
+
+bool Window::SetNotificationLevel( Dali::Window::NotificationLevel::Type level )
+{
+  if( mType != Dali::Window::NOTIFICATION )
+  {
+    DALI_LOG_INFO( gWindowLogFilter, Debug::Verbose, "Window::SetNotificationLevel: Not supported window type [%d]\n", mType );
+    return false;
+  }
+
+  return mWindowBase->SetNotificationLevel( level );
+}
+
+Dali::Window::NotificationLevel::Type Window::GetNotificationLevel() const
+{
+  if( mType != Dali::Window::NOTIFICATION )
+  {
+    DALI_LOG_INFO( gWindowLogFilter, Debug::Verbose, "Window::GetNotificationLevel: Not supported window type [%d]\n", mType );
+    return Dali::Window::NotificationLevel::NONE;
+  }
+
+  return mWindowBase->GetNotificationLevel();
+}
+
+void Window::SetOpaqueState( bool opaque )
+{
+  mOpaqueState = opaque;
+
+  mWindowBase->SetOpaqueState( opaque );
+
+  DALI_LOG_INFO( gWindowLogFilter, Debug::Verbose, "Window::SetOpaqueState: opaque = %d\n", opaque );
+}
+
+bool Window::IsOpaqueState() const
+{
+  return mOpaqueState;
+}
+
+bool Window::SetScreenOffMode(Dali::Window::ScreenOffMode::Type screenOffMode)
+{
+  return mWindowBase->SetScreenOffMode( screenOffMode );
+}
+
+Dali::Window::ScreenOffMode::Type Window::GetScreenOffMode() const
+{
+  return mWindowBase->GetScreenOffMode();
+}
+
+bool Window::SetBrightness( int brightness )
+{
+  if( brightness < 0 || brightness > 100 )
+  {
+    DALI_LOG_INFO( gWindowLogFilter, Debug::Verbose, "Window::SetBrightness: Invalid brightness value [%d]\n", brightness );
+    return false;
+  }
+
+  return mWindowBase->SetBrightness( brightness );
+}
+
+int Window::GetBrightness() const
+{
+  return mWindowBase->GetBrightness();
+}
+
+void Window::SetSize( Dali::Window::WindowSize size )
+{
+  if( !mResizeEnabled )
+  {
+    AddAuxiliaryHint( "wm.policy.win.user.geometry", "1" );
+    mResizeEnabled = true;
+  }
+
+  PositionSize oldRect = mSurface->GetPositionSize();
+
+  mWindowSurface->MoveResize( PositionSize( oldRect.x, oldRect.y, size.GetWidth(), size.GetHeight() ) );
+
+  PositionSize newRect = mSurface->GetPositionSize();
+
+  // When surface size is updated, inform adaptor of resizing and emit ResizeSignal
+  if( ( oldRect.width != newRect.width ) || ( oldRect.height != newRect.height ) )
+  {
+    Uint16Pair newSize( newRect.width, newRect.height );
+
+    SurfaceResized();
+
+    mAdaptor->SurfaceResizePrepare( mSurface.get(), newSize );
+
+    DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), SetSize(): resize signal [%d x %d]\n", this, mNativeWindowId, newRect.width, newRect.height );
+
+    Dali::Window handle( this );
+    mResizedSignal.Emit( newSize );
+    mResizeSignal.Emit( handle, newSize );
+
+    mAdaptor->SurfaceResizeComplete( mSurface.get(), newSize );
+  }
+}
+
+Dali::Window::WindowSize Window::GetSize() const
+{
+  PositionSize positionSize = mSurface->GetPositionSize();
+
+  return Dali::Window::WindowSize( positionSize.width, positionSize.height );
+}
+
+void Window::SetPosition( Dali::Window::WindowPosition position )
+{
+  if( !mResizeEnabled )
+  {
+    AddAuxiliaryHint( "wm.policy.win.user.geometry", "1" );
+    mResizeEnabled = true;
+  }
+
+  PositionSize oldRect = mSurface->GetPositionSize();
+
+  mWindowSurface->MoveResize( PositionSize( position.GetX(), position.GetY(), oldRect.width, oldRect.height ) );
+}
+
+Dali::Window::WindowPosition Window::GetPosition() const
+{
+  PositionSize positionSize = mSurface->GetPositionSize();
+
+  return Dali::Window::WindowPosition( positionSize.x, positionSize.y );
+}
+
+void Window::SetPositionSize( PositionSize positionSize )
+{
+  if( !mResizeEnabled )
+  {
+    AddAuxiliaryHint( "wm.policy.win.user.geometry", "1" );
+    mResizeEnabled = true;
+  }
+
+  PositionSize oldRect = mSurface->GetPositionSize();
+
+  mWindowSurface->MoveResize( positionSize );
+
+  PositionSize newRect = mSurface->GetPositionSize();
+
+  // When surface size is updated, inform adaptor of resizing and emit ResizeSignal
+  if( ( oldRect.width != newRect.width ) || ( oldRect.height != newRect.height ) )
+  {
+    Uint16Pair newSize( newRect.width, newRect.height );
+
+    SurfaceResized();
+
+    mAdaptor->SurfaceResizePrepare( mSurface.get(), newSize );
+
+    DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), SetPositionSize():resize signal [%d x %d]\n", this, mNativeWindowId, newRect.width, newRect.height );
+    Dali::Window handle( this );
+    mResizedSignal.Emit( newSize );
+    mResizeSignal.Emit( handle, newSize );
+    mAdaptor->SurfaceResizeComplete( mSurface.get(), newSize );
+  }
+}
+
+Dali::Layer Window::GetRootLayer() const
+{
+  return mScene.GetRootLayer();
+}
+
+void Window::SetTransparency( bool transparent )
+{
+  mWindowSurface->SetTransparency( transparent );
+}
+
+bool Window::GrabKey( Dali::KEY key, KeyGrab::KeyGrabMode grabMode )
+{
+  return mWindowBase->GrabKey( key, grabMode );
+}
+
+bool Window::UngrabKey( Dali::KEY key )
+{
+  return mWindowBase->UngrabKey( key );
+}
+
+bool Window::GrabKeyList( const Dali::Vector< Dali::KEY >& key, const Dali::Vector< KeyGrab::KeyGrabMode >& grabMode, Dali::Vector< bool >& result )
+{
+  return mWindowBase->GrabKeyList( key, grabMode, result );
+}
+
+bool Window::UngrabKeyList( const Dali::Vector< Dali::KEY >& key, Dali::Vector< bool >& result )
+{
+  return mWindowBase->UngrabKeyList( key, result );
+}
+
+void Window::OnIconifyChanged( bool iconified )
+{
+  if( iconified )
+  {
+    mIconified = true;
+
+    if( mVisible )
+    {
+      WindowVisibilityObserver* observer( mAdaptor );
+      observer->OnWindowHidden();
+
+      Dali::Window handle( this );
+      mVisibilityChangedSignal.Emit( handle, false );
+    }
+
+    DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Iconified: visible = %d\n", this, mNativeWindowId, mVisible );
+  }
+  else
+  {
+    mIconified = false;
+
+    if( mVisible )
+    {
+      WindowVisibilityObserver* observer( mAdaptor );
+      observer->OnWindowShown();
+
+      Dali::Window handle( this );
+      mVisibilityChangedSignal.Emit( handle, true );
+    }
+
+    DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), Deiconified: visible = %d\n", this, mNativeWindowId, mVisible );
+  }
+}
+
+void Window::OnFocusChanged( bool focusIn )
+{
+  Dali::Window handle( this );
+  mFocusChangedSignal.Emit( focusIn );
+  mFocusChangeSignal.Emit( handle, focusIn );
+}
+
+void Window::OnOutputTransformed()
+{
+  PositionSize positionSize = mSurface->GetPositionSize();
+  SurfaceResized();
+  mAdaptor->SurfaceResizePrepare( mSurface.get(), Adaptor::SurfaceSize( positionSize.width, positionSize.height ) );
+  mAdaptor->SurfaceResizeComplete( mSurface.get(), Adaptor::SurfaceSize( positionSize.width, positionSize.height ) );
+}
+
+void Window::OnDeleteRequest()
+{
+  mDeleteRequestSignal.Emit();
+}
+
+void Window::OnTransitionEffectEvent( DevelWindow::EffectState state, DevelWindow::EffectType type )
+{
+  Dali::Window handle( this );
+  mTransitionEffectEventSignal.Emit( handle, state, type );
+}
+
+void Window::OnTouchPoint( Dali::Integration::Point& point, int timeStamp )
+{
+  FeedTouchPoint( point, timeStamp );
+}
+
+void Window::OnWheelEvent( Dali::Integration::WheelEvent& wheelEvent )
+{
+  FeedWheelEvent( wheelEvent );
+}
+
+void Window::OnKeyEvent( Dali::Integration::KeyEvent& keyEvent )
+{
+  FeedKeyEvent( keyEvent );
+}
+
+void Window::OnRotation( const RotationEvent& rotation )
+{
+  mRotationAngle = rotation.angle;
+  mWindowWidth = rotation.width;
+  mWindowHeight = rotation.height;
+
+  // Notify that the orientation is changed
+  mOrientation->OnOrientationChange( rotation );
+
+  mWindowSurface->RequestRotation( mRotationAngle, mWindowWidth, mWindowHeight );
+
+  SurfaceResized();
+
+  mAdaptor->SurfaceResizePrepare( mSurface.get(), Adaptor::SurfaceSize( mWindowWidth, mWindowHeight ) );
+
+  DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), OnRotation(): resize signal emit [%d x %d]\n", this, mNativeWindowId, mWindowWidth, mWindowHeight );
+  // Emit signal
+  Dali::Window handle( this );
+  mResizedSignal.Emit( Dali::Window::WindowSize( mWindowWidth, mWindowHeight ) );
+  mResizeSignal.Emit( handle, Dali::Window::WindowSize( mWindowWidth, mWindowHeight ) );
+
+  mAdaptor->SurfaceResizeComplete( mSurface.get(), Adaptor::SurfaceSize( mWindowWidth, mWindowHeight ) );
+}
+
+void Window::OnPause()
+{
+  if( mEventHandler )
+  {
+    mEventHandler->Pause();
+  }
+}
+
+void Window::OnResume()
+{
+  if( mEventHandler )
+  {
+    mEventHandler->Resume();
+  }
+}
+
+void Window::RecalculateTouchPosition( Integration::Point& point )
+{
+  Vector2 position = point.GetScreenPosition();
+  Vector2 convertedPosition;
+
+  switch( mRotationAngle )
+  {
+    case 90:
+    {
+      convertedPosition.x = static_cast<float>( mWindowWidth ) - position.y;
+      convertedPosition.y = position.x;
+      break;
+    }
+    case 180:
+    {
+      convertedPosition.x = static_cast<float>( mWindowWidth ) - position.x;
+      convertedPosition.y = static_cast<float>( mWindowHeight ) - position.y;
+      break;
+    }
+    case 270:
+    {
+      convertedPosition.x = position.y;
+      convertedPosition.y = static_cast<float>( mWindowHeight ) - position.x;
+      break;
+    }
+    default:
+    {
+      convertedPosition = position;
+      break;
+    }
+  }
+
+  point.SetScreenPosition( convertedPosition );
+}
+
+Dali::Window Window::Get( Dali::Actor actor )
+{
+  Internal::Adaptor::Window* windowImpl = nullptr;
+
+  if ( Internal::Adaptor::Adaptor::IsAvailable() )
+  {
+    Dali::Internal::Adaptor::Adaptor& adaptor = Internal::Adaptor::Adaptor::GetImplementation( Internal::Adaptor::Adaptor::Get() );
+    windowImpl = dynamic_cast<Internal::Adaptor::Window*>( adaptor.GetWindow( actor ) );
+    if( windowImpl )
+    {
+      return Dali::Window( windowImpl );
+    }
+  }
+
+  return Dali::Window();
+}
+
+void Window::SetParent( Dali::Window& parent )
+{
+  if ( DALI_UNLIKELY( parent ) )
+  {
+    mParentWindow = parent;
+    Dali::Window self = Dali::Window( this );
+    // check circular parent window setting
+    if ( Dali::DevelWindow::GetParent( parent ) == self )
+    {
+      Dali::DevelWindow::Unparent( parent );
+    }
+    mWindowBase->SetParent( GetImplementation( mParentWindow ).mWindowBase );
+  }
+}
+
+void Window::Unparent()
+{
+  mWindowBase->SetParent( nullptr );
+  mParentWindow.Reset();
+}
+
+Dali::Window Window::GetParent()
+{
+  return mParentWindow;
+}
+
+Dali::Window::WindowOrientation Window::GetCurrentOrientation() const
+{
+  DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), GetCurrentOrientation(): %d\n", this, mNativeWindowId, mRotationAngle );
+  return ConvertToOrientation( mRotationAngle );
+}
+
+void Window::SetAvailableOrientations( const Dali::Vector<Dali::Window::WindowOrientation>& orientations )
+{
+  Dali::Vector<float>::SizeType count = orientations.Count();
+  for( Dali::Vector<float>::SizeType index = 0; index < count; ++index )
+  {
+    if( IsOrientationAvailable( orientations[index] ) == false )
+    {
+      DALI_LOG_ERROR("Window::SetAvailableOrientations, invalid orientation: %d\n", orientations[index]);
+      continue;
+    }
+
+    bool found = false;
+    int convertedAngle = ConvertToAngle( orientations[index] );
+
+    for( std::size_t i = 0; i < mAvailableAngles.size(); i++ )
+    {
+      if( mAvailableAngles[i] == convertedAngle )
+      {
+        found = true;
+        break;
+      }
+    }
+
+    if( !found )
+    {
+      DALI_LOG_RELEASE_INFO( "Window (%p), WinId (%d), SetAvailableOrientations: %d\n", this, mNativeWindowId, convertedAngle );
+      mAvailableAngles.push_back( convertedAngle );
+    }
+  }
+  SetAvailableAnlges( mAvailableAngles );
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/dali/internal/window-system/common/window-impl.h b/dali/internal/window-system/common/window-impl.h
new file mode 100644 (file)
index 0000000..0d4a4e1
--- /dev/null
@@ -0,0 +1,604 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_IMPL_H
+#define DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_IMPL_H
+
+/*
+ * Copyright (c) 2019 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/object/ref-object.h>
+#include <dali/public-api/object/base-object.h>
+#include <dali/public-api/actors/layer.h>
+#include <dali/public-api/render-tasks/render-task-list.h>
+#include <dali/public-api/object/property-array.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/window.h>
+#include <dali/public-api/adaptor-framework/key-grab.h>
+#include <dali/devel-api/adaptor-framework/window-devel.h>
+#include <dali/integration-api/adaptor-framework/scene-holder-impl.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/window-system/common/event-handler.h>
+
+namespace Dali
+{
+class Adaptor;
+class Actor;
+class RenderSurfaceInterface;
+
+namespace Internal
+{
+namespace Adaptor
+{
+class Orientation;
+class WindowRenderSurface;
+class WindowBase;
+
+class Window;
+using WindowPtr = IntrusivePtr< Window >;
+using OrientationPtr = IntrusivePtr< Orientation >;
+using EventHandlerPtr = IntrusivePtr< EventHandler >;
+
+/**
+ * Window provides a surface to render onto with orientation & indicator properties.
+ */
+class Window : public Dali::Internal::Adaptor::SceneHolder, public EventHandler::Observer, public ConnectionTracker
+{
+public:
+  typedef Dali::Window::IndicatorSignalType IndicatorSignalType;
+  typedef Dali::Window::FocusSignalType FocusSignalType;
+  typedef Dali::Window::ResizedSignalType ResizedSignalType;
+  typedef Dali::Window::FocusChangeSignalType FocusChangeSignalType;
+  typedef Dali::Window::ResizeSignalType ResizeSignalType;
+  typedef Dali::DevelWindow::VisibilityChangedSignalType VisibilityChangedSignalType;
+  typedef Dali::DevelWindow::TransitionEffectEventSignalType TransitionEffectEventSignalType;
+  typedef Signal< void () > SignalType;
+
+  /**
+   * @brief Create a new Window. This should only be called once by the Application class
+   * @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& positionSize, const std::string& name, const std::string& className, bool isTransparent = false);
+
+  /**
+   * @brief Create a new Window. This should only be called once by the Application class
+   * @param[in] surface The surface used to render on.
+   * @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(Any surface, const PositionSize& positionSize, const std::string& name, const std::string& className, bool isTransparent = false);
+
+  /**
+   * @copydoc Dali::Window::ShowIndicator()
+   */
+  void ShowIndicator( Dali::Window::IndicatorVisibleMode visibleMode );
+
+  /**
+   * @copydoc Dali::Window::SetIndicatorBgOpacity()
+   */
+  void SetIndicatorBgOpacity( Dali::Window::IndicatorBgOpacity opacity );
+
+  /**
+   * @copydoc Dali::Window::RotateIndicator()
+   */
+  void RotateIndicator( Dali::Window::WindowOrientation orientation );
+
+  /**
+   * @copydoc Dali::Window::SetClass()
+   */
+  void SetClass( std::string name, std::string className );
+
+  /**
+   * @brief Gets the window class name.
+   * @return The class of the window
+   */
+  std::string GetClassName() const;
+
+  /**
+   * @copydoc Dali::Window::Raise()
+   */
+  void Raise();
+
+  /**
+   * @copydoc Dali::Window::Lower()
+   */
+  void Lower();
+
+  /**
+   * @copydoc Dali::Window::Activate()
+   */
+  void Activate();
+
+  /**
+   * @copydoc Dali::Window::GetLayerCount()
+   */
+  uint32_t GetLayerCount() const;
+
+  /**
+   * @copydoc Dali::Window::GetLayer()
+   */
+  Dali::Layer GetLayer( uint32_t depth ) const;
+
+  /**
+   * @copydoc Dali::DevelWindow::GetRenderTaskList()
+   */
+  Dali::RenderTaskList GetRenderTaskList() const;
+
+  /**
+   * @copydoc Dali::Window::AddAvailableOrientation()
+   */
+  void AddAvailableOrientation(Dali::Window::WindowOrientation orientation);
+
+  /**
+   * @copydoc Dali::Window::RemoveAvailableOrientation()
+   */
+  void RemoveAvailableOrientation(Dali::Window::WindowOrientation orientation);
+
+  /**
+   * @copydoc Dali::Window::SetPreferredOrientation()
+   */
+  void SetPreferredOrientation(Dali::Window::WindowOrientation orientation);
+
+  /**
+   * @copydoc Dali::Window::GetPreferredOrientation()
+   */
+  Dali::Window::WindowOrientation GetPreferredOrientation();
+
+  /**
+   * @copydoc Dali::Window::SetAcceptFocus()
+   */
+  void SetAcceptFocus( bool accept );
+
+  /**
+   * @copydoc Dali::Window::IsFocusAcceptable()
+   */
+  bool IsFocusAcceptable() const;
+
+  /**
+   * @copydoc Dali::Window::Show()
+   */
+  void Show();
+
+  /**
+   * @copydoc Dali::Window::Hide()
+   */
+  void Hide();
+
+  /**
+   * @copydoc Dali::Window::GetSupportedAuxiliaryHintCount()
+   */
+  unsigned int GetSupportedAuxiliaryHintCount() const;
+
+  /**
+   * @copydoc Dali::Window::GetSupportedAuxiliaryHint()
+   */
+  std::string GetSupportedAuxiliaryHint( unsigned int index ) const;
+
+  /**
+   * @copydoc Dali::Window::AddAuxiliaryHint()
+   */
+  unsigned int AddAuxiliaryHint( const std::string& hint, const std::string& value );
+
+  /**
+   * @copydoc Dali::Window::RemoveAuxiliaryHint()
+   */
+  bool RemoveAuxiliaryHint( unsigned int id );
+
+  /**
+   * @copydoc Dali::Window::SetAuxiliaryHintValue()
+   */
+  bool SetAuxiliaryHintValue( unsigned int id, const std::string& value );
+
+  /**
+   * @copydoc Dali::Window::GetAuxiliaryHintValue()
+   */
+  std::string GetAuxiliaryHintValue( unsigned int id ) const;
+
+  /**
+   * @copydoc Dali::Window::GetAuxiliaryHintId()
+   */
+  unsigned int GetAuxiliaryHintId( const std::string& hint ) const;
+
+  /**
+   * @copydoc Dali::Window::SetInputRegion()
+   */
+  void SetInputRegion( const Rect< int >& inputRegion );
+
+  /**
+   * @copydoc Dali::Window::SetType()
+   */
+  void SetType( Dali::Window::Type type );
+
+  /**
+   * @copydoc Dali::Window::GetType() const
+   */
+  Dali::Window::Type GetType() const;
+
+  /**
+   * @copydoc Dali::Window::SetNotificationLevel()
+   */
+  bool SetNotificationLevel( Dali::Window::NotificationLevel::Type level );
+
+  /**
+   * @copydoc Dali::Window::GetNotificationLevel()
+   */
+  Dali::Window::NotificationLevel::Type GetNotificationLevel() const;
+
+  /**
+   * @copydoc Dali::Window::SetOpaqueState()
+   */
+  void SetOpaqueState( bool opaque );
+
+  /**
+   * @copydoc Dali::Window::IsOpaqueState()
+   */
+  bool IsOpaqueState() const;
+
+  /**
+   * @copydoc Dali::Window::SetScreenOffMode()
+   */
+  bool SetScreenOffMode(Dali::Window::ScreenOffMode::Type screenOffMode);
+
+  /**
+   * @copydoc Dali::Window::GetScreenOffMode()
+   */
+  Dali::Window::ScreenOffMode::Type GetScreenOffMode() const;
+
+  /**
+   * @copydoc Dali::Window::SetBrightness()
+   */
+  bool SetBrightness( int brightness );
+
+  /**
+   * @copydoc Dali::Window::GetBrightness()
+   */
+  int GetBrightness() const;
+
+  /**
+   * @copydoc Dali::Window::SetSize()
+   */
+  void SetSize( Dali::Window::WindowSize size );
+
+  /**
+   * @copydoc Dali::Window::GetSize()
+   */
+  Dali::Window::WindowSize GetSize() const;
+
+  /**
+   * @copydoc Dali::Window::SetPosition()
+   */
+  void SetPosition( Dali::Window::WindowPosition position );
+
+  /**
+   * @copydoc Dali::Window::GetPosition()
+   */
+  Dali::Window::WindowPosition GetPosition() const;
+
+  /**
+   * @copydoc Dali::DevelWindow::SetPositionSize()
+   */
+  void SetPositionSize( PositionSize positionSize );
+
+  /**
+   * @copydoc Dali::Window::GetRootLayer()
+   */
+  Dali::Layer GetRootLayer() const;
+
+  /**
+   * @copydoc Dali::Window::SetTransparency()
+   */
+  void SetTransparency( bool transparent );
+
+  /**
+   * @copydoc Dali::KeyGrab::GrabKey()
+   */
+  bool GrabKey( Dali::KEY key, KeyGrab::KeyGrabMode grabMode );
+
+  /**
+   * @copydoc Dali::KeyGrab::UngrabKey()
+   */
+  bool UngrabKey( Dali::KEY key );
+
+  /**
+   * @copydoc Dali::KeyGrab::GrabKeyList()
+   */
+  bool GrabKeyList( const Dali::Vector< Dali::KEY >& key, const Dali::Vector< KeyGrab::KeyGrabMode >& grabMode, Dali::Vector< bool >& result );
+
+  /**
+   * @copydoc Dali::KeyGrab::UngrabKeyList()
+   */
+  bool UngrabKeyList( const Dali::Vector< Dali::KEY >& key, Dali::Vector< bool >& result );
+
+  /**
+   * @copydoc Dali::DevelWindow::Get()
+   */
+  static Dali::Window Get( Dali::Actor actor );
+
+  /**
+   * @copydoc Dali::DevelWindow::SetParent()
+   */
+  void SetParent( Dali::Window& parent );
+
+  /**
+   * @copydoc Dali::DevelWindow::Unparent()
+   */
+  void Unparent();
+
+  /**
+   * @copydoc Dali::DevelWindow::GetParent()
+   */
+  Dali::Window GetParent();
+
+  /**
+   * @copydoc Dali::DevelWindow::GetCurrentOrientation()
+   */
+  Dali::Window::WindowOrientation GetCurrentOrientation() const;
+
+  /**
+   * @copydoc Dali::DevelWindow::SetAvailableOrientations()
+   */
+  void SetAvailableOrientations( const Dali::Vector<Dali::Window::WindowOrientation>& orientations );
+
+public: // Dali::Internal::Adaptor::SceneHolder
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SceneHolder::GetNativeHandle
+   */
+  Dali::Any GetNativeHandle() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SceneHolder::IsVisible
+   */
+  bool IsVisible() const override;
+
+private:
+
+  /**
+   * @brief Enumeration for orietation mode.
+   * The Orientation Mode is related to screen size.
+   * If screen width is longer than height, the Orientation Mode will have LANDSCAPE.
+   * Otherwise screen width is shorter than height or same, the Orientation Mode will have PORTRAIT.
+   */
+  enum class OrientationMode
+  {
+    PORTRAIT = 0,
+    LANDSCAPE
+  };
+
+  /**
+   * Private constructor.
+   * @sa Window::New()
+   */
+  Window();
+
+  /**
+   * Destructor
+   */
+  virtual ~Window();
+
+  /**
+   * Second stage initialization
+   */
+  void Initialize(Any surface, const PositionSize& positionSize, const std::string& name, const std::string& className);
+
+  /**
+   * Called when the window becomes iconified or deiconified.
+   */
+  void OnIconifyChanged( bool iconified );
+
+  /**
+   * Called when the window focus is changed.
+   */
+  void OnFocusChanged( bool focusIn );
+
+  /**
+   * Called when the output is transformed.
+   */
+  void OnOutputTransformed();
+
+  /**
+   * Called when the window receives a delete request.
+   */
+  void OnDeleteRequest();
+
+  /**
+   * Called when the window receives a Transition effect-start/end event.
+   */
+  void OnTransitionEffectEvent( DevelWindow::EffectState state, DevelWindow::EffectType type );
+
+  /**
+   * @brief Set available orientation to window base.
+   */
+  void SetAvailableAnlges( const std::vector< int >& angles );
+
+  /**
+   * @brief Convert from window orientation to angle using OrientationMode.
+   */
+  int ConvertToAngle( Dali::Window::WindowOrientation orientation );
+
+  /**
+   * @brief Convert from angle to window orientation using OrientationMode.
+   */
+  Dali::Window::WindowOrientation ConvertToOrientation( int angle ) const;
+
+  /**
+   * @brief Check available window orientation for Available orientation.
+   */
+  bool IsOrientationAvailable( Dali::Window::WindowOrientation orientation ) const;
+
+private: // Dali::Internal::Adaptor::SceneHolder
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SceneHolder::OnAdaptorSet
+   */
+  void OnAdaptorSet( Dali::Adaptor& adaptor ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SceneHolder::OnSurfaceSet
+   */
+  void OnSurfaceSet( Dali::RenderSurfaceInterface* surface ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SceneHolder::OnPause
+   */
+  void OnPause() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SceneHolder::OnResume
+   */
+  void OnResume() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::SceneHolder::RecalculateTouchPosition
+   */
+  void RecalculateTouchPosition( Integration::Point& point ) override;
+
+private: // Dali::Internal::Adaptor::EventHandler::Observer
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::EventHandler::Observer::OnTouchPoint
+   */
+  void OnTouchPoint( Dali::Integration::Point& point, int timeStamp ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::EventHandler::Observer::OnWheelEvent
+   */
+  void OnWheelEvent( Dali::Integration::WheelEvent& wheelEvent ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::EventHandler::Observer::OnKeyEvent
+   */
+  void OnKeyEvent( Dali::Integration::KeyEvent& keyEvent ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::EventHandler::Observer::OnRotation
+   */
+  void OnRotation( const RotationEvent& rotation ) override;
+
+public: // Signals
+
+  /**
+   * The user should connect to this signal to get a timing when indicator was shown / hidden.
+   */
+  IndicatorSignalType& IndicatorVisibilityChangedSignal() { return mIndicatorVisibilityChangedSignal; }
+
+  /**
+   * @copydoc Dali::Window::FocusChangedSignal()
+   */
+  FocusSignalType& FocusChangedSignal() { return mFocusChangedSignal; }
+
+  /**
+   * @copydoc Dali::Window::WindowFocusChangedSignal()
+   */
+  FocusChangeSignalType& FocusChangeSignal() { return mFocusChangeSignal; }
+  /**
+   * @copydoc Dali::Window::ResizedSignal()
+   */
+  ResizedSignalType& ResizedSignal() { return mResizedSignal; }
+
+  /**
+   * @copydoc Dali::Window::ResizedSignal()
+   */
+  ResizeSignalType& ResizeSignal() { return mResizeSignal; }
+
+  /**
+   * This signal is emitted when the window is requesting to be deleted
+   */
+  SignalType& DeleteRequestSignal() { return mDeleteRequestSignal; }
+
+  /**
+   * @copydoc Dali::DevelWindow::VisibilityChangedSignal()
+   */
+  VisibilityChangedSignalType& VisibilityChangedSignal() { return mVisibilityChangedSignal; }
+
+  /**
+   * @copydoc Dali::Window::SignalEventProcessingFinished()
+   */
+  Dali::DevelWindow::EventProcessingFinishedSignalType& EventProcessingFinishedSignal() { return mScene.EventProcessingFinishedSignal(); }
+
+  /**
+   * @copydoc Dali::DevelWindow::TransitionEffectEventSignal()
+   */
+  TransitionEffectEventSignalType& TransitionEffectEventSignal() { return mTransitionEffectEventSignal; }
+
+private:
+
+  WindowRenderSurface*                  mWindowSurface;      ///< The window rendering surface
+  WindowBase*                           mWindowBase;
+  std::string                           mName;
+  std::string                           mClassName;
+  bool                                  mIsTransparent:1;
+  bool                                  mIsFocusAcceptable:1;
+  bool                                  mIconified:1;
+  bool                                  mOpaqueState:1;
+  bool                                  mResizeEnabled:1;
+  Dali::Window::Type                    mType;
+  Dali::Window                          mParentWindow;
+
+  OrientationPtr                        mOrientation;
+  std::vector< int >                    mAvailableAngles;
+  int                                   mPreferredAngle;
+
+  int                                   mRotationAngle;     ///< The angle of the rotation
+  int                                   mWindowWidth;       ///< The width of the window
+  int                                   mWindowHeight;      ///< The height of the window
+
+  EventHandlerPtr                       mEventHandler;      ///< The window events handler
+
+  OrientationMode                       mOrientationMode;
+
+  int                                   mNativeWindowId;          ///< The Native Window Id
+
+  // Signals
+  IndicatorSignalType                   mIndicatorVisibilityChangedSignal;
+  FocusSignalType                       mFocusChangedSignal;
+  ResizedSignalType                     mResizedSignal;
+  SignalType                            mDeleteRequestSignal;
+  FocusChangeSignalType                 mFocusChangeSignal;
+  ResizeSignalType                      mResizeSignal;
+  VisibilityChangedSignalType           mVisibilityChangedSignal;
+  TransitionEffectEventSignalType       mTransitionEffectEventSignal;
+};
+
+} // namespace Adaptor
+} // namepsace Internal
+
+// Helpers for public-api forwarding methods
+
+inline Internal::Adaptor::Window& GetImplementation(Dali::Window& window)
+{
+  DALI_ASSERT_ALWAYS( window && "Window handle is empty" );
+  BaseObject& object = window.GetBaseObject();
+  return static_cast<Internal::Adaptor::Window&>(object);
+}
+
+inline const Internal::Adaptor::Window& GetImplementation(const Dali::Window& window)
+{
+  DALI_ASSERT_ALWAYS( window && "Window handle is empty" );
+  const BaseObject& object = window.GetBaseObject();
+  return static_cast<const Internal::Adaptor::Window&>(object);
+}
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_IMPL_H
diff --git a/dali/internal/window-system/common/window-render-surface.cpp b/dali/internal/window-system/common/window-render-surface.cpp
new file mode 100644 (file)
index 0000000..f86d7c2
--- /dev/null
@@ -0,0 +1,522 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/common/window-render-surface.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/thread-synchronization-interface.h>
+#include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/adaptor/common/adaptor-internal-services.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+#include <dali/internal/graphics/gles/egl-implementation.h>
+#include <dali/internal/window-system/common/window-base.h>
+#include <dali/internal/window-system/common/window-factory.h>
+#include <dali/internal/window-system/common/window-system.h>
+#include <dali/internal/system/common/environment-variables.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+namespace
+{
+
+const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE");
+#endif
+
+} // unnamed namespace
+
+WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+: mEGL( nullptr ),
+  mDisplayConnection( nullptr ),
+  mPositionSize( positionSize ),
+  mWindowBase(),
+  mThreadSynchronization( NULL ),
+  mRenderNotification( NULL ),
+  mRotationTrigger( NULL ),
+  mGraphics( nullptr ),
+  mEGLSurface( nullptr ),
+  mEGLContext( nullptr ),
+  mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
+  mOutputTransformedSignal(),
+  mRotationAngle( 0 ),
+  mScreenRotationAngle( 0 ),
+  mOwnSurface( false ),
+  mRotationSupported( false ),
+  mRotationFinished( true ),
+  mScreenRotationFinished( true ),
+  mResizeFinished( true ),
+  mDpiHorizontal( 0 ),
+  mDpiVertical( 0 )
+{
+  DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
+  Initialize( surface );
+}
+
+WindowRenderSurface::~WindowRenderSurface()
+{
+  if( mRotationTrigger )
+  {
+    delete mRotationTrigger;
+  }
+
+  if ( mEGLSurface )
+  {
+    DestroySurface();
+  }
+}
+
+void WindowRenderSurface::Initialize( Any surface )
+{
+  // If width or height are zero, go full screen.
+  if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
+  {
+    // Default window size == screen size
+    mPositionSize.x = 0;
+    mPositionSize.y = 0;
+    WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
+  }
+
+  // Create a window base
+  auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
+  mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
+
+  // Connect signals
+  mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
+
+  // Check screen rotation
+  mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
+  if( mScreenRotationAngle != 0 )
+  {
+    mScreenRotationFinished = false;
+  }
+}
+
+Any WindowRenderSurface::GetNativeWindow()
+{
+  return mWindowBase->GetNativeWindow();
+}
+
+int WindowRenderSurface::GetNativeWindowId()
+{
+  return mWindowBase->GetNativeWindowId();
+}
+
+void WindowRenderSurface::Map()
+{
+  mWindowBase->Show();
+}
+
+void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
+{
+  mRenderNotification = renderNotification;
+}
+
+void WindowRenderSurface::SetTransparency( bool transparent )
+{
+  mWindowBase->SetTransparency( transparent );
+}
+
+void WindowRenderSurface::RequestRotation( int angle, int width, int height )
+{
+  if( !mRotationSupported )
+  {
+    DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: Rotation is not supported!\n" );
+    return;
+  }
+
+  if( !mRotationTrigger )
+  {
+    mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
+  }
+
+  mPositionSize.width = width;
+  mPositionSize.height = height;
+
+  mRotationAngle = angle;
+  mRotationFinished = false;
+
+  mWindowBase->SetWindowRotationAngle( mRotationAngle );
+
+  DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
+}
+
+WindowBase* WindowRenderSurface::GetWindowBase()
+{
+  return mWindowBase.get();
+}
+
+WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
+{
+  return mOutputTransformedSignal;
+}
+
+PositionSize WindowRenderSurface::GetPositionSize() const
+{
+  return mPositionSize;
+}
+
+void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
+{
+  if( mDpiHorizontal == 0 || mDpiVertical == 0 )
+  {
+    const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
+    mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
+
+    const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
+    mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
+
+    if( mDpiHorizontal == 0 || mDpiVertical == 0 )
+    {
+      mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
+    }
+  }
+
+  dpiHorizontal = mDpiHorizontal;
+  dpiVertical = mDpiVertical;
+}
+
+void WindowRenderSurface::InitializeGraphics()
+{
+
+  mGraphics = &mAdaptor->GetGraphicsInterface();
+
+  auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+  mEGL = &eglGraphics->GetEglInterface();
+
+  if ( mEGLContext == NULL )
+  {
+    // Create the OpenGL context for this window
+    Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
+    eglImpl.ChooseConfig(true, mColorDepth);
+    eglImpl.CreateWindowContext( mEGLContext );
+
+    // Create the OpenGL surface
+    CreateSurface();
+  }
+}
+
+void WindowRenderSurface::CreateSurface()
+{
+  DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
+
+  int width, height;
+  if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
+  {
+    width = mPositionSize.width;
+    height = mPositionSize.height;
+  }
+  else
+  {
+    width = mPositionSize.height;
+    height = mPositionSize.width;
+  }
+
+  // Create the EGL window
+  EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
+
+  auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+
+  Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+  mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
+
+  // Check rotation capability
+  mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
+
+  DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
+      mWindowBase->GetNativeWindowId(), mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
+}
+
+void WindowRenderSurface::DestroySurface()
+{
+  DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
+
+  auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+
+  DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
+
+  Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+  eglImpl.DestroySurface( mEGLSurface );
+
+  mWindowBase->DestroyEglWindow();
+}
+
+bool WindowRenderSurface::ReplaceGraphicsSurface()
+{
+  DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
+
+  // Destroy the old one
+  mWindowBase->DestroyEglWindow();
+
+  int width, height;
+  if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
+  {
+    width = mPositionSize.width;
+    height = mPositionSize.height;
+  }
+  else
+  {
+    width = mPositionSize.height;
+    height = mPositionSize.width;
+  }
+
+  // Create the EGL window
+  EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
+
+  // Set screen rotation
+  mScreenRotationFinished = false;
+
+  auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+
+  Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+  return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
+}
+
+void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
+{
+  bool needToMove = false;
+  bool needToResize = false;
+
+  // Check moving
+  if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
+      (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
+  {
+    needToMove = true;
+  }
+
+  // Check resizing
+  if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
+      (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
+  {
+    needToResize = true;
+  }
+
+  if( needToResize )
+  {
+    if( needToMove )
+    {
+      mWindowBase->MoveResize( positionSize );
+    }
+    else
+    {
+      mWindowBase->Resize( positionSize );
+    }
+
+    mResizeFinished = false;
+    mPositionSize = positionSize;
+  }
+  else
+  {
+    if( needToMove )
+    {
+      mWindowBase->Move( positionSize );
+
+      mPositionSize = positionSize;
+    }
+  }
+
+  DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
+}
+
+void WindowRenderSurface::StartRender()
+{
+}
+
+bool WindowRenderSurface::PreRender( bool resizingSurface )
+{
+  MakeContextCurrent();
+
+  if( resizingSurface )
+  {
+    // Window rotate or screen rotate
+    if( !mRotationFinished || !mScreenRotationFinished )
+    {
+      int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
+
+      mWindowBase->SetEglWindowRotation( totalAngle );
+      mWindowBase->SetEglWindowBufferTransform( totalAngle );
+
+      // Reset only screen rotation flag
+      mScreenRotationFinished = true;
+
+      DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
+    }
+
+    // Only window rotate
+    if( !mRotationFinished )
+    {
+      mWindowBase->SetEglWindowTransform( mRotationAngle );
+    }
+
+    // Resize case
+    if( !mResizeFinished )
+    {
+      mWindowBase->ResizeEglWindow( mPositionSize );
+      mResizeFinished = true;
+
+      DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
+    }
+  }
+
+  auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+  if ( eglGraphics )
+  {
+    GlImplementation& mGLES = eglGraphics->GetGlesInterface();
+    mGLES.PreRender();
+  }
+
+  return true;
+}
+
+void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface )
+{
+  // Inform the gl implementation that rendering has finished before informing the surface
+  auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+  if ( eglGraphics )
+  {
+    GlImplementation& mGLES = eglGraphics->GetGlesInterface();
+    mGLES.PostRender();
+
+    if( renderToFbo )
+    {
+      mGLES.Flush();
+      mGLES.Finish();
+    }
+    else
+    {
+      if( resizingSurface )
+      {
+        if( !mRotationFinished )
+        {
+          if( mThreadSynchronization )
+          {
+            // Enable PostRender flag
+            mThreadSynchronization->PostRenderStarted();
+          }
+
+          DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
+
+          mRotationTrigger->Trigger();
+
+          if( mThreadSynchronization )
+          {
+            // Wait until the event-thread complete the rotation event processing
+            mThreadSynchronization->PostRenderWaitForCompletion();
+          }
+        }
+      }
+    }
+
+    Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+    eglImpl.SwapBuffers( mEGLSurface );
+
+    if( mRenderNotification )
+    {
+      mRenderNotification->Trigger();
+    }
+  }
+}
+
+void WindowRenderSurface::StopRender()
+{
+}
+
+void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
+{
+  DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
+
+  mThreadSynchronization = &threadSynchronization;
+}
+
+void WindowRenderSurface::ReleaseLock()
+{
+  // Nothing to do.
+}
+
+Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
+{
+  return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
+}
+
+void WindowRenderSurface::MakeContextCurrent()
+{
+  if ( mEGL != nullptr )
+  {
+    mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
+  }
+}
+
+Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
+{
+  return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
+}
+
+Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
+{
+  return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
+}
+
+void WindowRenderSurface::OutputTransformed()
+{
+  int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
+
+  if( mScreenRotationAngle != screenRotationAngle )
+  {
+    mScreenRotationAngle = screenRotationAngle;
+    mScreenRotationFinished = false;
+
+    mOutputTransformedSignal.Emit();
+
+    DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
+  }
+  else
+  {
+    DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
+  }
+}
+
+void WindowRenderSurface::ProcessRotationRequest()
+{
+  mRotationFinished = true;
+
+  mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
+
+  DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
+
+  if( mThreadSynchronization )
+  {
+    mThreadSynchronization->PostRenderComplete();
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
diff --git a/dali/internal/window-system/common/window-render-surface.h b/dali/internal/window-system/common/window-render-surface.h
new file mode 100644 (file)
index 0000000..f8160b8
--- /dev/null
@@ -0,0 +1,259 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_RENDER_SURFACE_H
+#define DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_RENDER_SURFACE_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/signals/connection-tracker.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/egl-interface.h>
+#include <dali/integration-api/adaptor-framework/render-surface-interface.h>
+#include <dali/internal/graphics/common/graphics-interface.h>
+
+namespace Dali
+{
+
+class TriggerEventInterface;
+
+namespace Internal
+{
+namespace Adaptor
+{
+
+class WindowBase;
+class AdaptorInternalServices;
+
+/**
+ * Window interface of render surface.
+ */
+class WindowRenderSurface : public Dali::RenderSurfaceInterface, public ConnectionTracker
+{
+public:
+
+  typedef Signal< void ( ) > OutputSignalType;
+
+  /**
+    * Uses an window surface to render to.
+    * @param [in] positionSize the position and size of the surface
+    * @param [in] surface can be a window or pixmap.
+    * @param [in] isTransparent if it is true, surface has 32 bit color depth, otherwise, 24 bit
+    */
+  WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent = false );
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~WindowRenderSurface();
+
+public: // API
+
+  /**
+   * @brief Get the native window handle
+   * @return The native window handle
+   */
+  Any GetNativeWindow();
+
+  /**
+   * @brief Get the native window id
+   * @return The native window id
+   */
+  int GetNativeWindowId();
+
+  /**
+   * @brief Map window
+   */
+  void Map();
+
+  /**
+   * @brief Sets the render notification trigger to call when render thread is completed a frame
+   * @param renderNotification to use
+   */
+  void SetRenderNotification( TriggerEventInterface* renderNotification );
+
+  /**
+   * @brief Sets whether the surface is transparent or not.
+   * @param[in] transparent Whether the surface is transparent
+   */
+  void SetTransparency( bool transparent );
+
+  /**
+   * Request surface rotation
+   * @param[in] angle A new angle of the surface
+   * @param[in] width A new width of the surface
+   * @param[in] height A new height of the surface
+   */
+  void RequestRotation( int angle, int width, int height );
+
+  /**
+   * @brief Gets the window base object
+   * @return The window base object
+   */
+  WindowBase* GetWindowBase();
+
+  /**
+   * @brief This signal is emitted when the output is transformed.
+   */
+  OutputSignalType& OutputTransformedSignal();
+
+public: // from Dali::RenderSurfaceInterface
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::GetPositionSize()
+   */
+  virtual PositionSize GetPositionSize() const override;
+
+  /**
+   */
+  virtual void GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical ) override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::InitializeGraphics()
+   */
+  virtual void InitializeGraphics() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::CreateSurface()
+   */
+  virtual void CreateSurface() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::DestroySurface()
+   */
+  virtual void DestroySurface() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::ReplaceGraphicsSurface()
+   */
+  virtual bool ReplaceGraphicsSurface() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::MoveResize()
+   */
+  virtual void MoveResize( Dali::PositionSize positionSize) override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::StartRender()
+   */
+  virtual void StartRender() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::PreRender()
+   */
+  virtual bool PreRender( bool resizingSurface ) override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::PostRender()
+   */
+  virtual void PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface );
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::StopRender()
+   */
+  virtual void StopRender() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::SetThreadSynchronization
+   */
+  virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization ) override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::ReleaseLock()
+   */
+  virtual void ReleaseLock() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::GetSurfaceType()
+   */
+  virtual Dali::RenderSurfaceInterface::Type GetSurfaceType() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::MakeContextCurrent()
+   */
+  virtual void MakeContextCurrent() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::GetDepthBufferRequired()
+   */
+  virtual Integration::DepthBufferAvailable GetDepthBufferRequired() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::GetStencilBufferRequired()
+   */
+  virtual Integration::StencilBufferAvailable GetStencilBufferRequired() override;
+
+private:
+
+  /**
+   * @brief Second stage construction
+   */
+  void Initialize( Any surface );
+
+  /**
+   * Notify output is transformed.
+   */
+  void OutputTransformed();
+
+  /**
+   * @brief Used as the callback for the rotation-trigger.
+   */
+  void ProcessRotationRequest();
+
+protected:
+
+  // Undefined
+  WindowRenderSurface(const WindowRenderSurface&) = delete;
+
+  // Undefined
+  WindowRenderSurface& operator=(const WindowRenderSurface& rhs) = delete;
+
+private: // Data
+
+  EglInterface*                   mEGL;
+  Dali::DisplayConnection*        mDisplayConnection;
+  PositionSize                    mPositionSize;       ///< Position
+  std::unique_ptr< WindowBase >   mWindowBase;
+  ThreadSynchronizationInterface* mThreadSynchronization;
+  TriggerEventInterface*          mRenderNotification; ///< Render notification trigger
+  TriggerEventInterface*          mRotationTrigger;
+  GraphicsInterface*              mGraphics;           ///< Graphics interface
+  EGLSurface                      mEGLSurface;
+  EGLContext                      mEGLContext;
+  ColorDepth                      mColorDepth;         ///< Color depth of surface (32 bit or 24 bit)
+  OutputSignalType                mOutputTransformedSignal;
+  int                             mRotationAngle;
+  int                             mScreenRotationAngle;
+  bool                            mOwnSurface;         ///< Whether we own the surface (responsible for deleting it)
+  bool                            mRotationSupported;
+  bool                            mRotationFinished;
+  bool                            mScreenRotationFinished;
+  bool                            mResizeFinished;
+
+  uint32_t                        mDpiHorizontal;
+  uint32_t                        mDpiVertical;
+
+}; // class WindowRenderSurface
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_RENDER_SURFACE_H
diff --git a/dali/internal/window-system/common/window-system.h b/dali/internal/window-system/common/window-system.h
new file mode 100644 (file)
index 0000000..978e334
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_SYSTEM_H
+#define DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_SYSTEM_H
+
+/*
+ * Copyright (c) 2018 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.
+ *
+ */
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+namespace WindowSystem
+{
+
+/**
+ * @brief Initialize a window system
+ */
+void Initialize();
+
+/**
+ * @brief Shutdown a window system
+ */
+void Shutdown();
+
+/**
+ * @brief Get the screen size
+ */
+void GetScreenSize( int& width, int& height );
+
+/**
+ * @copydoc Dali::Keyboard::SetRepeatInfo()
+ */
+bool SetKeyboardRepeatInfo( float rate, float delay );
+
+/**
+ * @copydoc Dali::Keyboard::GetRepeatInfo()
+ */
+bool GetKeyboardRepeatInfo( float& rate, float& delay );
+
+} // namespace WindowSystem
+
+} // namespace Adaptor
+} // namespace internal
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_COMMON_WINDOW_SYSTEM_H
diff --git a/dali/internal/window-system/common/window-visibility-observer.h b/dali/internal/window-system/common/window-visibility-observer.h
new file mode 100644 (file)
index 0000000..179c0de
--- /dev/null
@@ -0,0 +1,70 @@
+#ifndef DALI_INTERNAL_WINDOW_VISIBILITY_OBSERVER_H
+#define DALI_INTERNAL_WINDOW_VISIBILITY_OBSERVER_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * An interface used to observe when the application's window is shown/hidden.
+ */
+class WindowVisibilityObserver
+{
+public:
+
+  /**
+   * Called when the window becomes fully or partially visible.
+   */
+  virtual void OnWindowShown() = 0;
+
+  /**
+   * Called when the window is fully hidden.
+   */
+  virtual void OnWindowHidden() = 0;
+
+protected:
+
+  /**
+   * Protected Constructor.
+   */
+  WindowVisibilityObserver()
+  {
+  }
+
+  /**
+   * Protected virtual destructor.
+   */
+  virtual ~WindowVisibilityObserver()
+  {
+  }
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOW_VISIBILITY_OBSERVER_H
diff --git a/dali/internal/window-system/file.list b/dali/internal/window-system/file.list
new file mode 100644 (file)
index 0000000..7dffb60
--- /dev/null
@@ -0,0 +1,67 @@
+
+# module: window-system, backend: common
+SET( adaptor_window_system_common_src_files 
+    ${adaptor_window_system_dir}/common/display-connection.cpp 
+    ${adaptor_window_system_dir}/common/event-handler.cpp 
+    ${adaptor_window_system_dir}/common/native-render-surface-factory.cpp 
+    ${adaptor_window_system_dir}/common/orientation-impl.cpp 
+    ${adaptor_window_system_dir}/common/window-base.cpp 
+    ${adaptor_window_system_dir}/common/window-impl.cpp 
+    ${adaptor_window_system_dir}/common/window-render-surface.cpp
+)
+
+# module: window-system, backend: tizen-wayland
+SET( adaptor_window_system_tizen_wayland_src_files 
+    ${adaptor_window_system_dir}/tizen-wayland/display-connection-factory-ecore-wl.cpp 
+    ${adaptor_window_system_dir}/tizen-wayland/display-connection-impl-ecore-wl.cpp 
+    ${adaptor_window_system_dir}/tizen-wayland/native-render-surface-ecore-wl.cpp
+)
+
+# module: window-system, backend: ecore-wl
+SET( adaptor_window_system_ecore_wl_src_files 
+    ${adaptor_window_system_dir}/tizen-wayland/ecore-wl/render-surface-factory-ecore-wl.cpp 
+    ${adaptor_window_system_dir}/tizen-wayland/ecore-wl/window-base-ecore-wl.cpp 
+    ${adaptor_window_system_dir}/tizen-wayland/ecore-wl/window-factory-ecore-wl.cpp 
+    ${adaptor_window_system_dir}/tizen-wayland/ecore-wl/window-system-ecore-wl.cpp
+)
+
+# module: window-system, backend: ecore-wl2
+SET( adaptor_window_system_ecore_wl2_src_files 
+    ${adaptor_window_system_dir}/tizen-wayland/ecore-wl2/render-surface-factory-ecore-wl2.cpp 
+    ${adaptor_window_system_dir}/tizen-wayland/ecore-wl2/window-base-ecore-wl2.cpp 
+    ${adaptor_window_system_dir}/tizen-wayland/ecore-wl2/window-factory-ecore-wl2.cpp 
+    ${adaptor_window_system_dir}/tizen-wayland/ecore-wl2/window-system-ecore-wl2.cpp
+)
+
+# module: window-system, backend: ubuntu-x11
+SET( adaptor_window_system_ubuntu_x11_src_files 
+    ${adaptor_window_system_dir}/ubuntu-x11/display-connection-factory-x.cpp 
+    ${adaptor_window_system_dir}/ubuntu-x11/display-connection-impl-x.cpp 
+    ${adaptor_window_system_dir}/ubuntu-x11/pixmap-render-surface-ecore-x.cpp 
+    ${adaptor_window_system_dir}/ubuntu-x11/render-surface-factory-ecore-x.cpp 
+    ${adaptor_window_system_dir}/ubuntu-x11/window-interface-ecore-x.cpp 
+    ${adaptor_window_system_dir}/ubuntu-x11/window-base-ecore-x.cpp 
+    ${adaptor_window_system_dir}/ubuntu-x11/window-factory-ecore-x.cpp 
+    ${adaptor_window_system_dir}/ubuntu-x11/window-system-ecore-x.cpp
+)
+
+# module: window-system, backend: android
+SET( adaptor_window_system_android_src_files
+    ${adaptor_window_system_dir}/android/display-connection-factory-android.cpp
+    ${adaptor_window_system_dir}/android/display-connection-impl-android.cpp
+    ${adaptor_window_system_dir}/android/render-surface-factory-android.cpp
+    ${adaptor_window_system_dir}/android/window-base-android.cpp
+    ${adaptor_window_system_dir}/android/window-factory-android.cpp
+    ${adaptor_window_system_dir}/android/window-system-android.cpp
+)
+
+# module: window-system, backend: windows
+SET( adaptor_window_system_windows_src_files
+    ${adaptor_window_system_dir}/windows/display-connection-factory-win.cpp
+    ${adaptor_window_system_dir}/windows/display-connection-impl-win.cpp
+    ${adaptor_window_system_dir}/windows/platform-implement-win.cpp
+    ${adaptor_window_system_dir}/windows/render-surface-factory-win.cpp
+    ${adaptor_window_system_dir}/windows/window-base-win.cpp
+    ${adaptor_window_system_dir}/windows/window-factory-win.cpp
+    ${adaptor_window_system_dir}/windows/window-system-win.cpp
+)
diff --git a/dali/internal/window-system/tizen-wayland/display-connection-factory-ecore-wl.cpp b/dali/internal/window-system/tizen-wayland/display-connection-factory-ecore-wl.cpp
new file mode 100644 (file)
index 0000000..488835c
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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/internal/window-system/tizen-wayland/display-connection-factory-ecore-wl.h>
+#include <dali/internal/window-system/tizen-wayland/display-connection-impl-ecore-wl.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+std::unique_ptr<Dali::Internal::Adaptor::DisplayConnection> DisplayConnectionFactoryEcoreWl::CreateDisplayConnection()
+{
+  return Utils::MakeUnique<DisplayConnectionEcoreWl>();
+}
+
+// this should be created from somewhere
+std::unique_ptr<DisplayConnectionFactory> GetDisplayConnectionFactory()
+{
+  // returns X display factory
+  return Utils::MakeUnique<DisplayConnectionFactoryEcoreWl>();
+}
+
+}
+}
+}
diff --git a/dali/internal/window-system/tizen-wayland/display-connection-factory-ecore-wl.h b/dali/internal/window-system/tizen-wayland/display-connection-factory-ecore-wl.h
new file mode 100644 (file)
index 0000000..e156313
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_ECOREWL_DISPLAY_CONNECTION_FACTORY_ECORE_WL_H
+#define DALI_INTERNAL_WINDOWSYSTEM_ECOREWL_DISPLAY_CONNECTION_FACTORY_ECORE_WL_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/internal/window-system/common/display-connection-factory.h>
+#include <dali/internal/window-system/common/display-utils.h>
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+class DisplayConnectionFactoryEcoreWl : public DisplayConnectionFactory
+{
+public:
+  std::unique_ptr<Dali::Internal::Adaptor::DisplayConnection> CreateDisplayConnection() override;
+};
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
+
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_ECOREWL_DISPLAY_CONNECTION_FACTORY_ECORE_WL_H
diff --git a/dali/internal/window-system/tizen-wayland/display-connection-impl-ecore-wl.cpp b/dali/internal/window-system/tizen-wayland/display-connection-impl-ecore-wl.cpp
new file mode 100755 (executable)
index 0000000..3d9911b
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/tizen-wayland/display-connection-impl-ecore-wl.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+
+// EXTERNAL_HEADERS
+#include <tbm_dummy_display.h>
+#include <dali/integration-api/debug.h>
+
+#ifdef ECORE_WAYLAND2
+#include <Ecore_Wl2.h>
+#else
+#include <Ecore_Wayland.h>
+#endif
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+DisplayConnection* DisplayConnectionEcoreWl::New()
+{
+  DisplayConnection* pDisplayConnection(new DisplayConnectionEcoreWl());
+
+  return pDisplayConnection;
+}
+
+DisplayConnectionEcoreWl::DisplayConnectionEcoreWl()
+: mDisplay( NULL ),
+  mSurfaceType( RenderSurfaceInterface::WINDOW_RENDER_SURFACE ),
+  mGraphics( nullptr )
+{
+}
+
+DisplayConnectionEcoreWl::~DisplayConnectionEcoreWl()
+{
+  if( mSurfaceType == RenderSurfaceInterface::NATIVE_RENDER_SURFACE )
+  {
+    ReleaseNativeDisplay();
+  }
+}
+
+Any DisplayConnectionEcoreWl::GetDisplay()
+{
+  return Any( mDisplay );
+}
+
+void DisplayConnectionEcoreWl::ConsumeEvents()
+{
+}
+
+bool DisplayConnectionEcoreWl::InitializeGraphics()
+{
+  auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+  EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+
+  if( !eglImpl.InitializeGles( mDisplay ) )
+  {
+    DALI_LOG_ERROR("Failed to initialize GLES.\n");
+    return false;
+  }
+
+  return true;
+}
+
+void DisplayConnectionEcoreWl::SetSurfaceType( Dali::RenderSurfaceInterface::Type type )
+{
+  mSurfaceType = type;
+
+  if( mSurfaceType == Dali::RenderSurfaceInterface::NATIVE_RENDER_SURFACE )
+  {
+    mDisplay = GetNativeDisplay();
+  }
+  else
+  {
+#ifdef ECORE_WAYLAND2
+    Ecore_Wl2_Display* display = ecore_wl2_connected_display_get( NULL );
+    mDisplay = reinterpret_cast< EGLNativeDisplayType >( ecore_wl2_display_get( display ) );
+#else
+    mDisplay = reinterpret_cast< EGLNativeDisplayType >( ecore_wl_display_get() );
+#endif
+  }
+}
+
+void DisplayConnectionEcoreWl::SetGraphicsInterface( GraphicsInterface& graphics )
+{
+  mGraphics = &graphics;
+}
+
+EGLNativeDisplayType DisplayConnectionEcoreWl::GetNativeDisplay()
+{
+  return reinterpret_cast< EGLNativeDisplayType >( tbm_dummy_display_create() );
+}
+
+void DisplayConnectionEcoreWl::ReleaseNativeDisplay()
+{
+  if( mDisplay )
+  {
+     tbm_dummy_display_destroy( reinterpret_cast< tbm_dummy_display* >( mDisplay ) );
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/window-system/tizen-wayland/display-connection-impl-ecore-wl.h b/dali/internal/window-system/tizen-wayland/display-connection-impl-ecore-wl.h
new file mode 100644 (file)
index 0000000..d3471f2
--- /dev/null
@@ -0,0 +1,120 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_ECOREWL_DISPLAY_CONNECTION_IMPL_ECORE_WL_H
+#define DALI_INTERNAL_WINDOWSYSTEM_ECOREWL_DISPLAY_CONNECTION_IMPL_ECORE_WL_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/window-system/common/display-connection-impl.h>
+
+namespace Dali
+{
+
+class DisplayConnection;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+/**
+ * DisplayConnection implementation
+ */
+class DisplayConnectionEcoreWl : public Dali::Internal::Adaptor::DisplayConnection
+{
+public:
+
+  /**
+   * @brief Default constructor
+   */
+  DisplayConnectionEcoreWl();
+
+  /**
+   * @brief Create an initialized DisplayConnection.
+   *
+   * @return A handle to a newly allocated DisplayConnection resource.
+   */
+  static DisplayConnection* New();
+
+public:
+
+  /**
+   * @copydoc Dali::DisplayConnection::GetDisplay
+   */
+  Any GetDisplay();
+
+  /**
+   * @copydoc Dali::DisplayConnection::ConsumeEvents
+   */
+  void ConsumeEvents();
+
+  /**
+   * @copydoc Dali::DisplayConnection::InitializeGraphics
+   */
+  bool InitializeGraphics();
+
+  /**
+   * @brief Sets the surface type
+   * @param[in] type The surface type
+   */
+  void SetSurfaceType( Dali::RenderSurfaceInterface::Type type );
+
+  /**
+   * @brief Sets the graphics interface
+   * @param[in] graphics The graphics interface
+   */
+  void SetGraphicsInterface( GraphicsInterface& graphics );
+
+public:
+
+  /**
+   * Destructor
+   */
+  virtual ~DisplayConnectionEcoreWl();
+
+protected:
+
+  /**
+   * @brief Gets display connection for native surface
+   */
+  EGLNativeDisplayType GetNativeDisplay();
+
+  /**
+   * @brief Release display connection for native surface
+   */
+  void ReleaseNativeDisplay();
+
+  // Undefined
+  DisplayConnectionEcoreWl(const DisplayConnectionEcoreWl&);
+
+  // Undefined
+  DisplayConnectionEcoreWl& operator=(const DisplayConnectionEcoreWl& rhs);
+
+private:
+  EGLNativeDisplayType mDisplay;        ///< Wayland-display for rendering
+  Dali::RenderSurfaceInterface::Type mSurfaceType;     ///< The surface type
+  GraphicsInterface* mGraphics;         ///< The graphics interface
+};
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_ECOREWL_DISPLAY_CONNECTION_IMPL_ECORE_WL_H
diff --git a/dali/internal/window-system/tizen-wayland/ecore-wl/render-surface-factory-ecore-wl.cpp b/dali/internal/window-system/tizen-wayland/ecore-wl/render-surface-factory-ecore-wl.cpp
new file mode 100644 (file)
index 0000000..ef2f93b
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/tizen-wayland/ecore-wl/render-surface-factory-ecore-wl.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/window-system/common/window-render-surface.h>
+#include <dali/internal/window-system/tizen-wayland/native-render-surface-ecore-wl.h>
+#include <dali/internal/window-system/common/pixmap-render-surface.h>
+#include <dali/internal/window-system/common/display-utils.h>
+
+// EXTERNAL INCLUDES
+#include <memory>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+std::unique_ptr< WindowRenderSurface > RenderSurfaceFactoryEcoreWl::CreateWindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+{
+  return Utils::MakeUnique< WindowRenderSurface >( positionSize, surface, isTransparent );
+}
+
+std::unique_ptr< PixmapRenderSurface > RenderSurfaceFactoryEcoreWl::CreatePixmapRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+{
+  return std::unique_ptr< PixmapRenderSurface >( nullptr );
+}
+
+std::unique_ptr< NativeRenderSurface > RenderSurfaceFactoryEcoreWl::CreateNativeRenderSurface( Dali::PositionSize positionSize, bool isTransparent )
+{
+  return Utils::MakeUnique< NativeRenderSurfaceEcoreWl >( positionSize, isTransparent );
+}
+
+// this should be created from somewhere
+std::unique_ptr< RenderSurfaceFactory > GetRenderSurfaceFactory()
+{
+  // returns Window factory
+  return Utils::MakeUnique< RenderSurfaceFactoryEcoreWl >();
+}
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
diff --git a/dali/internal/window-system/tizen-wayland/ecore-wl/render-surface-factory-ecore-wl.h b/dali/internal/window-system/tizen-wayland/ecore-wl/render-surface-factory-ecore-wl.h
new file mode 100644 (file)
index 0000000..8db3813
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_RENDER_SURFACE_FACTORY_ECORE_WL_H
+#define DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_RENDER_SURFACE_FACTORY_ECORE_WL_H
+
+/*
+ * Copyright (c) 2018 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/internal/window-system/common/render-surface-factory.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class RenderSurfaceFactoryEcoreWl : public RenderSurfaceFactory
+{
+public:
+  std::unique_ptr< WindowRenderSurface > CreateWindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent = false ) override;
+
+  std::unique_ptr< PixmapRenderSurface > CreatePixmapRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent = false ) override;
+
+  std::unique_ptr< NativeRenderSurface > CreateNativeRenderSurface( Dali::PositionSize positionSize, bool isTransparent = false ) override;
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_RENDER_SURFACE_FACTORY_ECORE_WL_H
diff --git a/dali/internal/window-system/tizen-wayland/ecore-wl/window-base-ecore-wl.cpp b/dali/internal/window-system/tizen-wayland/ecore-wl/window-base-ecore-wl.cpp
new file mode 100644 (file)
index 0000000..509ddd4
--- /dev/null
@@ -0,0 +1,2155 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// Ecore is littered with C style cast
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+
+// CLASS HEADER
+#include <dali/internal/window-system/tizen-wayland/ecore-wl/window-base-ecore-wl.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/window-system/common/window-impl.h>
+#include <dali/internal/window-system/common/window-system.h>
+#include <dali/internal/window-system/common/window-render-surface.h>
+#include <dali/internal/input/common/key-impl.h>
+
+// EXTERNAL_HEADERS
+#include <dali/public-api/object/any.h>
+#include <dali/integration-api/debug.h>
+#include <Ecore_Input.h>
+#include <vconf.h>
+#include <vconf-keys.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gWindowBaseLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_WINDOW_BASE" );
+#endif
+
+const uint32_t MAX_TIZEN_CLIENT_VERSION = 7;
+const unsigned int PRIMARY_TOUCH_BUTTON_ID = 1;
+
+const char* DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME = "db/setting/accessibility/font_name";  // It will be update at vconf-key.h and replaced.
+
+// DBUS accessibility
+const char* BUS = "org.enlightenment.wm-screen-reader";
+const char* INTERFACE = "org.tizen.GestureNavigation";
+const char* PATH = "/org/tizen/GestureNavigation";
+
+/**
+ * Get the device name from the provided ecore key event
+ */
+void GetDeviceName( Ecore_Event_Key* keyEvent, std::string& result )
+{
+  const char* ecoreDeviceName = ecore_device_name_get( keyEvent->dev );
+
+  if( ecoreDeviceName )
+  {
+    result = ecoreDeviceName;
+  }
+}
+
+/**
+ * Get the device class from the provided ecore event
+ */
+void GetDeviceClass( Ecore_Device_Class ecoreDeviceClass, Device::Class::Type& deviceClass )
+{
+  switch( ecoreDeviceClass )
+  {
+    case ECORE_DEVICE_CLASS_SEAT:
+    {
+      deviceClass = Device::Class::USER;
+      break;
+    }
+    case ECORE_DEVICE_CLASS_KEYBOARD:
+    {
+      deviceClass = Device::Class::KEYBOARD;
+      break;
+    }
+    case ECORE_DEVICE_CLASS_MOUSE:
+    {
+      deviceClass = Device::Class::MOUSE;
+      break;
+    }
+    case ECORE_DEVICE_CLASS_TOUCH:
+    {
+      deviceClass = Device::Class::TOUCH;
+      break;
+    }
+    case ECORE_DEVICE_CLASS_PEN:
+    {
+      deviceClass = Device::Class::PEN;
+      break;
+    }
+    case ECORE_DEVICE_CLASS_POINTER:
+    {
+      deviceClass = Device::Class::POINTER;
+      break;
+    }
+    case ECORE_DEVICE_CLASS_GAMEPAD:
+    {
+      deviceClass = Device::Class::GAMEPAD;
+      break;
+    }
+    default:
+    {
+      deviceClass = Device::Class::NONE;
+      break;
+    }
+  }
+}
+
+void GetDeviceSubclass( Ecore_Device_Subclass ecoreDeviceSubclass, Device::Subclass::Type& deviceSubclass )
+{
+  switch( ecoreDeviceSubclass )
+  {
+    case ECORE_DEVICE_SUBCLASS_FINGER:
+    {
+      deviceSubclass = Device::Subclass::FINGER;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_FINGERNAIL:
+    {
+      deviceSubclass = Device::Subclass::FINGERNAIL;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_KNUCKLE:
+    {
+      deviceSubclass = Device::Subclass::KNUCKLE;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_PALM:
+    {
+      deviceSubclass = Device::Subclass::PALM;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_HAND_SIZE:
+    {
+      deviceSubclass = Device::Subclass::HAND_SIDE;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_HAND_FLAT:
+    {
+      deviceSubclass = Device::Subclass::HAND_FLAT;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_PEN_TIP:
+    {
+      deviceSubclass = Device::Subclass::PEN_TIP;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_TRACKPAD:
+    {
+      deviceSubclass = Device::Subclass::TRACKPAD;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_TRACKPOINT:
+    {
+      deviceSubclass = Device::Subclass::TRACKPOINT;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_TRACKBALL:
+    {
+      deviceSubclass = Device::Subclass::TRACKBALL;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_REMOCON:
+    {
+      deviceSubclass = Device::Subclass::REMOCON;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_VIRTUAL_KEYBOARD:
+    {
+      deviceSubclass = Device::Subclass::VIRTUAL_KEYBOARD;
+      break;
+    }
+    default:
+    {
+      deviceSubclass = Device::Subclass::NONE;
+      break;
+    }
+  }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Window Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+/// Called when the window iconify state is changed.
+static Eina_Bool EcoreEventWindowIconifyStateChanged( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    return windowBase->OnIconifyStateChanged( data, type, event );
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/// Called when the window gains focus
+static Eina_Bool EcoreEventWindowFocusIn( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    return windowBase->OnFocusIn( data, type, event );
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/// Called when the window loses focus
+static Eina_Bool EcoreEventWindowFocusOut( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    return windowBase->OnFocusOut( data, type, event );
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/// Called when the output is transformed
+static Eina_Bool EcoreEventOutputTransform( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    return windowBase->OnOutputTransform( data, type, event );
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/// Called when the output transform should be ignored
+static Eina_Bool EcoreEventIgnoreOutputTransform( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    return windowBase->OnIgnoreOutputTransform( data, type, event );
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when rotate event is recevied.
+ */
+static Eina_Bool EcoreEventRotate( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    DALI_LOG_RELEASE_INFO( "WindowBaseEcoreWl::EcoreEventRotate\n" );
+    windowBase->OnRotation( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Touch Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Called when a touch down is received.
+ */
+static Eina_Bool EcoreEventMouseButtonDown( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    windowBase->OnMouseButtonDown( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when a touch up is received.
+ */
+static Eina_Bool EcoreEventMouseButtonUp( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    windowBase->OnMouseButtonUp( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when a touch motion is received.
+ */
+static Eina_Bool EcoreEventMouseButtonMove( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    windowBase->OnMouseButtonMove( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when a touch is canceled.
+ */
+static Eina_Bool EcoreEventMouseButtonCancel( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    windowBase->OnMouseButtonCancel( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when a mouse wheel is received.
+ */
+static Eina_Bool EcoreEventMouseWheel( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    windowBase->OnMouseWheel( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when a detent rotation event is recevied.
+ */
+static Eina_Bool EcoreEventDetentRotation( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    windowBase->OnDetentRotation( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Key Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Called when a key down is received.
+ */
+static Eina_Bool EcoreEventKeyDown( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    windowBase->OnKeyDown( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when a key up is received.
+ */
+static Eina_Bool EcoreEventKeyUp( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    windowBase->OnKeyUp( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Selection Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Called when the source window notifies us the content in clipboard is selected.
+ */
+static Eina_Bool EcoreEventDataSend( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    windowBase->OnDataSend( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+* Called when the source window sends us about the selected content.
+* For example, when item is selected in the clipboard.
+*/
+static Eina_Bool EcoreEventDataReceive( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    windowBase->OnDataReceive( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Font Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Called when a font name is changed.
+ */
+static void VconfNotifyFontNameChanged( keynode_t* node, void* data )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    windowBase->OnFontNameChanged();
+  }
+}
+
+/**
+ * Called when a font size is changed.
+ */
+static void VconfNotifyFontSizeChanged( keynode_t* node, void* data )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    windowBase->OnFontSizeChanged();
+  }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// ElDBus Accessibility Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef DALI_ELDBUS_AVAILABLE
+// Callback for Ecore ElDBus accessibility events.
+static void EcoreElDBusAccessibilityNotification( void* context, const Eldbus_Message* message )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( context );
+  if( windowBase )
+  {
+    windowBase->OnEcoreElDBusAccessibilityNotification( context, message );
+  }
+}
+#endif // DALI_ELDBUS_AVAILABLE
+
+static void RegistryGlobalCallback( void* data, struct wl_registry *registry, uint32_t name, const char* interface, uint32_t version )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    windowBase->RegistryGlobalCallback( data, registry, name, interface, version );
+  }
+}
+
+static void RegistryGlobalCallbackRemove( void* data, struct wl_registry* registry, uint32_t id )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    windowBase->RegistryGlobalCallbackRemove( data, registry, id );
+  }
+}
+
+static void TizenPolicyConformant( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, uint32_t isConformant )
+{
+}
+
+static void TizenPolicyConformantArea( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, uint32_t conformantPart, uint32_t state, int32_t x, int32_t y, int32_t w, int32_t h )
+{
+}
+
+static void TizenPolicyNotificationChangeDone(void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, int32_t level, uint32_t state )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    windowBase->TizenPolicyNotificationChangeDone( data, tizenPolicy, surface, level, state );
+  }
+}
+
+static void TizenPolicyTransientForDone( void* data, struct tizen_policy* tizenPolicy, uint32_t childId )
+{
+}
+
+static void TizenPolicyScreenModeChangeDone( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, uint32_t mode, uint32_t state )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    windowBase->TizenPolicyScreenModeChangeDone( data, tizenPolicy, surface, mode, state );
+  }
+}
+
+static void TizenPolicyIconifyStateChanged( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, uint32_t iconified, uint32_t force )
+{
+}
+
+static void TizenPolicySupportedAuxiliaryHints( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, struct wl_array* hints, uint32_t numNints )
+{
+}
+
+static void TizenPolicyAllowedAuxiliaryHint( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, int id )
+{
+}
+
+static void TizenPolicyAuxiliaryMessage( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, const char* key, const char* val, struct wl_array* options )
+{
+}
+
+static void TizenPolicyConformantRegion( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, uint32_t conformantPart, uint32_t state, int32_t x, int32_t y, int32_t w, int32_t h, uint32_t serial )
+{
+}
+
+static void DisplayPolicyBrightnessChangeDone( void* data, struct tizen_display_policy *displayPolicy, struct wl_surface* surface, int32_t brightness, uint32_t state )
+{
+  WindowBaseEcoreWl* windowBase = static_cast< WindowBaseEcoreWl* >( data );
+  if( windowBase )
+  {
+    windowBase->DisplayPolicyBrightnessChangeDone( data, displayPolicy, surface, brightness, state );
+  }
+}
+
+const struct wl_registry_listener registryListener =
+{
+   RegistryGlobalCallback,
+   RegistryGlobalCallbackRemove
+};
+
+const struct tizen_policy_listener tizenPolicyListener =
+{
+   TizenPolicyConformant,
+   TizenPolicyConformantArea,
+   TizenPolicyNotificationChangeDone,
+   TizenPolicyTransientForDone,
+   TizenPolicyScreenModeChangeDone,
+   TizenPolicyIconifyStateChanged,
+   TizenPolicySupportedAuxiliaryHints,
+   TizenPolicyAllowedAuxiliaryHint,
+   TizenPolicyAuxiliaryMessage,
+   TizenPolicyConformantRegion
+};
+
+const struct tizen_display_policy_listener tizenDisplayPolicyListener =
+{
+  DisplayPolicyBrightnessChangeDone
+};
+
+} // unnamed namespace
+
+WindowBaseEcoreWl::WindowBaseEcoreWl( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+: mEcoreEventHandler(),
+  mEcoreWindow( NULL ),
+  mWlSurface( NULL ),
+  mEglWindow( NULL ),
+  mDisplay( NULL ),
+  mEventQueue( NULL ),
+  mTizenPolicy( NULL ),
+  mTizenDisplayPolicy( NULL ),
+  mSupportedAuxiliaryHints(),
+  mAuxiliaryHints(),
+  mNotificationLevel( -1 ),
+  mNotificationChangeState( 0 ),
+  mNotificationLevelChangeDone( true ),
+  mScreenOffMode( 0 ),
+  mScreenOffModeChangeState( 0 ),
+  mScreenOffModeChangeDone( true ),
+  mBrightness( 0 ),
+  mBrightnessChangeState( 0 ),
+  mBrightnessChangeDone( true ),
+  mOwnSurface( false )
+#ifdef DALI_ELDBUS_AVAILABLE
+  , mSystemConnection( NULL )
+#endif
+{
+  Initialize( positionSize, surface, isTransparent );
+}
+
+WindowBaseEcoreWl::~WindowBaseEcoreWl()
+{
+#ifdef DALI_ELDBUS_AVAILABLE
+    // Close down ElDBus connections.
+    if( mSystemConnection )
+    {
+      eldbus_connection_unref( mSystemConnection );
+    }
+#endif // DALI_ELDBUS_AVAILABLE
+
+  vconf_ignore_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged );
+  vconf_ignore_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged );
+
+  for( Dali::Vector< Ecore_Event_Handler* >::Iterator iter = mEcoreEventHandler.Begin(), endIter = mEcoreEventHandler.End(); iter != endIter; ++iter )
+  {
+    ecore_event_handler_del( *iter );
+  }
+  mEcoreEventHandler.Clear();
+
+  if( mEventQueue )
+  {
+    wl_event_queue_destroy( mEventQueue );
+  }
+
+  mSupportedAuxiliaryHints.clear();
+  mAuxiliaryHints.clear();
+
+  if( mEglWindow != NULL )
+  {
+    wl_egl_window_destroy( mEglWindow );
+    mEglWindow = NULL;
+  }
+
+  if( mOwnSurface )
+  {
+    ecore_wl_window_free( mEcoreWindow );
+
+    WindowSystem::Shutdown();
+  }
+}
+
+void WindowBaseEcoreWl::Initialize( PositionSize positionSize, Any surface, bool isTransparent )
+{
+  if( surface.Empty() == false )
+  {
+    // check we have a valid type
+    DALI_ASSERT_ALWAYS( ( surface.GetType() == typeid (Ecore_Wl_Window *) ) && "Surface type is invalid" );
+
+    mEcoreWindow = AnyCast< Ecore_Wl_Window* >( surface );
+  }
+  else
+  {
+    // we own the surface about to created
+    WindowSystem::Initialize();
+
+    mOwnSurface = true;
+    CreateWindow( positionSize );
+  }
+
+  mWlSurface = ecore_wl_window_surface_create( mEcoreWindow );
+
+  SetTransparency( isTransparent );
+
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL_EVENT_WINDOW_ICONIFY_STATE_CHANGE, EcoreEventWindowIconifyStateChanged, this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL_EVENT_FOCUS_IN,                    EcoreEventWindowFocusIn,             this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL_EVENT_FOCUS_OUT,                   EcoreEventWindowFocusOut,            this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL_EVENT_OUTPUT_TRANSFORM,            EcoreEventOutputTransform,           this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL_EVENT_IGNORE_OUTPUT_TRANSFORM,     EcoreEventIgnoreOutputTransform,     this ) );
+
+  // Register Rotate event
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL_EVENT_WINDOW_ROTATE,               EcoreEventRotate,                    this ) );
+
+  // Register Touch events
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_MOUSE_BUTTON_DOWN,              EcoreEventMouseButtonDown,           this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_MOUSE_BUTTON_UP,                EcoreEventMouseButtonUp,             this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_MOUSE_MOVE,                     EcoreEventMouseButtonMove,           this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_MOUSE_BUTTON_CANCEL,            EcoreEventMouseButtonCancel,         this ) );
+
+  // Register Mouse wheel events
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_MOUSE_WHEEL,                    EcoreEventMouseWheel,                this ) );
+
+  // Register Detent event
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_DETENT_ROTATE,                  EcoreEventDetentRotation,            this ) );
+
+  // Register Key events
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_KEY_DOWN,                       EcoreEventKeyDown,                   this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_KEY_UP,                         EcoreEventKeyUp,                     this ) );
+
+  // Register Selection event - clipboard selection
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL_EVENT_DATA_SOURCE_SEND,            EcoreEventDataSend,                  this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL_EVENT_SELECTION_DATA_READY,        EcoreEventDataReceive,               this ) );
+
+  // Register Vconf notify - font name and size
+  vconf_notify_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged, this );
+  vconf_notify_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged, this );
+
+  InitializeEcoreElDBus();
+
+  mDisplay = ecore_wl_display_get();
+
+  if( mDisplay )
+  {
+    wl_display* displayWrapper = static_cast< wl_display* >( wl_proxy_create_wrapper( mDisplay ) );
+    if( displayWrapper )
+    {
+      mEventQueue = wl_display_create_queue( mDisplay );
+      if( mEventQueue )
+      {
+        wl_proxy_set_queue( reinterpret_cast< wl_proxy* >( displayWrapper ), mEventQueue );
+
+        wl_registry* registry = wl_display_get_registry( displayWrapper );
+        wl_registry_add_listener( registry, &registryListener, this );
+      }
+
+      wl_proxy_wrapper_destroy( displayWrapper );
+    }
+  }
+
+  // get auxiliary hint
+  Eina_List* hints = ecore_wl_window_aux_hints_supported_get( mEcoreWindow );
+  if( hints )
+  {
+    Eina_List* l = NULL;
+    char* hint = NULL;
+
+    for( l = hints, ( hint =  static_cast< char* >( eina_list_data_get(l) ) ); l; l = eina_list_next(l), ( hint = static_cast< char* >( eina_list_data_get(l) ) ) )
+    {
+      mSupportedAuxiliaryHints.push_back( hint );
+
+      DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::Initialize: %s\n", hint );
+    }
+  }
+}
+
+Eina_Bool WindowBaseEcoreWl::OnIconifyStateChanged( void* data, int type, void* event )
+{
+  Ecore_Wl_Event_Window_Iconify_State_Change* iconifyChangedEvent( static_cast< Ecore_Wl_Event_Window_Iconify_State_Change* >( event ) );
+  Eina_Bool handled( ECORE_CALLBACK_PASS_ON );
+
+  if( iconifyChangedEvent->win == static_cast< unsigned int>( ecore_wl_window_id_get( mEcoreWindow ) ) )
+  {
+    if( iconifyChangedEvent->iconified == EINA_TRUE )
+    {
+      mIconifyChangedSignal.Emit( true );
+    }
+    else
+    {
+      mIconifyChangedSignal.Emit( false );
+    }
+    handled = ECORE_CALLBACK_DONE;
+  }
+
+  return handled;
+}
+
+Eina_Bool WindowBaseEcoreWl::OnFocusIn( void* data, int type, void* event )
+{
+  Ecore_Wl_Event_Focus_In* focusInEvent( static_cast< Ecore_Wl_Event_Focus_In* >( event ) );
+
+  if( focusInEvent->win == static_cast< unsigned int >( ecore_wl_window_id_get( mEcoreWindow ) ) )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "Window EcoreEventWindowFocusIn\n" );
+
+    mFocusChangedSignal.Emit( true );
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+Eina_Bool WindowBaseEcoreWl::OnFocusOut( void* data, int type, void* event )
+{
+  Ecore_Wl_Event_Focus_Out* focusOutEvent( static_cast< Ecore_Wl_Event_Focus_Out* >( event ) );
+
+  if( focusOutEvent->win == static_cast< unsigned int >( ecore_wl_window_id_get( mEcoreWindow ) ) )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "Window EcoreEventWindowFocusOut\n" );
+
+    mFocusChangedSignal.Emit( false );
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+Eina_Bool WindowBaseEcoreWl::OnOutputTransform( void* data, int type, void* event )
+{
+  Ecore_Wl_Event_Output_Transform* transformEvent( static_cast< Ecore_Wl_Event_Output_Transform* >( event ) );
+
+  if( transformEvent->output == ecore_wl_window_output_find( mEcoreWindow ) )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "Window (%p) EcoreEventOutputTransform\n", mEcoreWindow );
+
+    mOutputTransformedSignal.Emit();
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+Eina_Bool WindowBaseEcoreWl::OnIgnoreOutputTransform( void* data, int type, void* event )
+{
+  Ecore_Wl_Event_Ignore_Output_Transform* ignoreTransformEvent( static_cast< Ecore_Wl_Event_Ignore_Output_Transform* >( event ) );
+
+  if( ignoreTransformEvent->win == mEcoreWindow )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "Window (%p) EcoreEventIgnoreOutputTransform\n", mEcoreWindow );
+
+    mOutputTransformedSignal.Emit();
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+void WindowBaseEcoreWl::OnRotation( void* data, int type, void* event )
+{
+  Ecore_Wl_Event_Window_Rotate* ev( static_cast< Ecore_Wl_Event_Window_Rotate* >( event ) );
+
+  if( ev->win == static_cast< unsigned int >( ecore_wl_window_id_get( mEcoreWindow ) ) )
+  {
+    DALI_LOG_RELEASE_INFO( "WindowBaseEcoreWl::OnRotation, angle: %d, width: %d, height: %d\n", ev->angle, ev->w, ev->h );
+
+    RotationEvent rotationEvent;
+    rotationEvent.angle = ev->angle;
+    rotationEvent.winResize = 0;
+
+    if( ev->angle == 0 || ev->angle == 180 )
+    {
+      rotationEvent.width = ev->w;
+      rotationEvent.height = ev->h;
+    }
+    else
+    {
+      rotationEvent.width = ev->h;
+      rotationEvent.height = ev->w;
+    }
+
+    mRotationSignal.Emit( rotationEvent );
+  }
+}
+
+void WindowBaseEcoreWl::OnMouseButtonDown( void* data, int type, void* event )
+{
+  Ecore_Event_Mouse_Button* touchEvent = static_cast< Ecore_Event_Mouse_Button* >( event );
+
+  if( touchEvent->window == static_cast< unsigned int >( ecore_wl_window_id_get( mEcoreWindow ) ) )
+  {
+    PointState::Type state ( PointState::DOWN );
+
+    // Check if the buttons field is set and ensure it's the primary touch button.
+    // If this event was triggered by buttons other than the primary button (used for touch), then
+    // just send an interrupted event to Core.
+    if( touchEvent->buttons && (touchEvent->buttons != PRIMARY_TOUCH_BUTTON_ID ) )
+    {
+      state = PointState::INTERRUPTED;
+    }
+
+    Device::Class::Type deviceClass;
+    Device::Subclass::Type deviceSubclass;
+
+    GetDeviceClass( ecore_device_class_get( touchEvent->dev ), deviceClass );
+    GetDeviceSubclass( ecore_device_subclass_get( touchEvent->dev ), deviceSubclass );
+
+    Integration::Point point;
+    point.SetDeviceId( touchEvent->multi.device );
+    point.SetState( state );
+    point.SetScreenPosition( Vector2( touchEvent->x, touchEvent->y ) );
+    point.SetRadius( touchEvent->multi.radius, Vector2( touchEvent->multi.radius_x, touchEvent->multi.radius_y ) );
+    point.SetPressure( touchEvent->multi.pressure );
+    point.SetAngle( Degree( touchEvent->multi.angle ) );
+    point.SetDeviceClass( deviceClass );
+    point.SetDeviceSubclass( deviceSubclass );
+
+    mTouchEventSignal.Emit( point, touchEvent->timestamp );
+  }
+}
+
+void WindowBaseEcoreWl::OnMouseButtonUp( void* data, int type, void* event )
+{
+  Ecore_Event_Mouse_Button* touchEvent = static_cast< Ecore_Event_Mouse_Button* >( event );
+
+  if( touchEvent->window == static_cast< unsigned int >( ecore_wl_window_id_get( mEcoreWindow ) ) )
+  {
+    Device::Class::Type deviceClass;
+    Device::Subclass::Type deviceSubclass;
+
+    GetDeviceClass( ecore_device_class_get( touchEvent->dev ), deviceClass );
+    GetDeviceSubclass( ecore_device_subclass_get( touchEvent->dev ), deviceSubclass );
+
+    Integration::Point point;
+    point.SetDeviceId( touchEvent->multi.device );
+    point.SetState( PointState::UP );
+    point.SetScreenPosition( Vector2( touchEvent->x, touchEvent->y ) );
+    point.SetRadius( touchEvent->multi.radius, Vector2( touchEvent->multi.radius_x, touchEvent->multi.radius_y ) );
+    point.SetPressure( touchEvent->multi.pressure );
+    point.SetAngle( Degree( touchEvent->multi.angle ) );
+    point.SetDeviceClass( deviceClass );
+    point.SetDeviceSubclass( deviceSubclass );
+
+    mTouchEventSignal.Emit( point, touchEvent->timestamp );
+  }
+}
+
+void WindowBaseEcoreWl::OnMouseButtonMove( void* data, int type, void* event )
+{
+  Ecore_Event_Mouse_Move* touchEvent = static_cast< Ecore_Event_Mouse_Move* >( event );
+
+  if( touchEvent->window == static_cast< unsigned int >( ecore_wl_window_id_get( mEcoreWindow ) ) )
+  {
+    Device::Class::Type deviceClass;
+    Device::Subclass::Type deviceSubclass;
+
+    GetDeviceClass( ecore_device_class_get( touchEvent->dev ), deviceClass );
+    GetDeviceSubclass( ecore_device_subclass_get( touchEvent->dev ), deviceSubclass );
+
+    Integration::Point point;
+    point.SetDeviceId( touchEvent->multi.device );
+    point.SetState( PointState::MOTION );
+    point.SetScreenPosition( Vector2( touchEvent->x, touchEvent->y ) );
+    point.SetRadius( touchEvent->multi.radius, Vector2( touchEvent->multi.radius_x, touchEvent->multi.radius_y ) );
+    point.SetPressure( touchEvent->multi.pressure );
+    point.SetAngle( Degree( touchEvent->multi.angle ) );
+    point.SetDeviceClass( deviceClass );
+    point.SetDeviceSubclass( deviceSubclass );
+
+    mTouchEventSignal.Emit( point, touchEvent->timestamp );
+  }
+}
+
+void WindowBaseEcoreWl::OnMouseButtonCancel( void* data, int type, void* event )
+{
+  Ecore_Event_Mouse_Button* touchEvent = static_cast< Ecore_Event_Mouse_Button* >( event );
+
+  if( touchEvent->window == static_cast< unsigned int >( ecore_wl_window_id_get( mEcoreWindow ) ) )
+  {
+    Integration::Point point;
+    point.SetDeviceId( touchEvent->multi.device );
+    point.SetState( PointState::INTERRUPTED );
+    point.SetScreenPosition( Vector2( 0.0f, 0.0f ) );
+
+    mTouchEventSignal.Emit( point, touchEvent->timestamp );
+
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl::OnMouseButtonCancel\n" );
+  }
+}
+
+void WindowBaseEcoreWl::OnMouseWheel( void* data, int type, void* event )
+{
+  Ecore_Event_Mouse_Wheel* mouseWheelEvent = static_cast< Ecore_Event_Mouse_Wheel* >( event );
+
+  if( mouseWheelEvent->window == static_cast< unsigned int >( ecore_wl_window_id_get( mEcoreWindow ) ) )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl::OnMouseWheel: direction: %d, modifiers: %d, x: %d, y: %d, z: %d\n", mouseWheelEvent->direction, mouseWheelEvent->modifiers, mouseWheelEvent->x, mouseWheelEvent->y, mouseWheelEvent->z );
+
+    WheelEvent wheelEvent( WheelEvent::MOUSE_WHEEL, mouseWheelEvent->direction, mouseWheelEvent->modifiers, Vector2( mouseWheelEvent->x, mouseWheelEvent->y ), mouseWheelEvent->z, mouseWheelEvent->timestamp );
+
+    mWheelEventSignal.Emit( wheelEvent );
+  }
+}
+
+void WindowBaseEcoreWl::OnDetentRotation( void* data, int type, void* event )
+{
+  Ecore_Event_Detent_Rotate* detentEvent = static_cast< Ecore_Event_Detent_Rotate* >( event );
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Concise, "WindowBaseEcoreWl::OnDetentRotation\n" );
+
+  int direction = ( detentEvent->direction == ECORE_DETENT_DIRECTION_CLOCKWISE ) ? 1 : -1;
+  int timeStamp = detentEvent->timestamp;
+
+  WheelEvent wheelEvent( WheelEvent::CUSTOM_WHEEL, 0, 0, Vector2( 0.0f, 0.0f ), direction, timeStamp );
+
+  mWheelEventSignal.Emit( wheelEvent );
+}
+
+void WindowBaseEcoreWl::OnKeyDown( void* data, int type, void* event )
+{
+  Ecore_Event_Key* keyEvent = static_cast< Ecore_Event_Key* >( event );
+
+  if( keyEvent->window == static_cast< unsigned int >( ecore_wl_window_id_get( mEcoreWindow ) ) )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl::OnKeyDown\n" );
+
+    std::string keyName( keyEvent->keyname );
+    std::string logicalKey( "" );
+    std::string keyString( "" );
+    std::string compose( "" );
+
+    // Ensure key compose string is not NULL as keys like SHIFT or arrow have a null string.
+    if( keyEvent->compose )
+    {
+      compose = keyEvent->compose;
+    }
+
+    // Ensure key symbol is not NULL as keys like SHIFT have a null string.
+    if( keyEvent->key )
+    {
+      logicalKey = keyEvent->key;
+    }
+
+    int keyCode = KeyLookup::GetDaliKeyCode( keyEvent->keyname );
+    keyCode = ( keyCode == -1 ) ? 0 : keyCode;
+    int modifier( keyEvent->modifiers );
+    unsigned long time = keyEvent->timestamp;
+    if( !strncmp( keyEvent->keyname, "Keycode-", 8 ) )
+    {
+      keyCode = atoi( keyEvent->keyname + 8 );
+    }
+
+    // Ensure key event string is not NULL as keys like SHIFT have a null string.
+    if( keyEvent->string )
+    {
+      keyString = keyEvent->string;
+    }
+
+    std::string deviceName;
+    Device::Class::Type deviceClass;
+    Device::Subclass::Type deviceSubclass;
+
+    GetDeviceName( keyEvent, deviceName );
+    GetDeviceClass( ecore_device_class_get( keyEvent->dev ), deviceClass );
+    GetDeviceSubclass( ecore_device_subclass_get( keyEvent->dev ), deviceSubclass );
+
+    Integration::KeyEvent keyEvent( keyName, logicalKey, keyString, keyCode, modifier, time, Integration::KeyEvent::Down, compose, deviceName, deviceClass, deviceSubclass );
+
+     mKeyEventSignal.Emit( keyEvent );
+  }
+}
+
+void WindowBaseEcoreWl::OnKeyUp( void* data, int type, void* event )
+{
+  Ecore_Event_Key* keyEvent = static_cast< Ecore_Event_Key* >( event );
+
+  if( keyEvent->window == static_cast< unsigned int >( ecore_wl_window_id_get( mEcoreWindow ) ) )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl::OnKeyUp\n" );
+
+    std::string keyName( keyEvent->keyname );
+    std::string logicalKey( "" );
+    std::string keyString( "" );
+    std::string compose( "" );
+
+    // Ensure key compose string is not NULL as keys like SHIFT or arrow have a null string.
+    if( keyEvent->compose )
+    {
+      compose = keyEvent->compose;
+    }
+
+    // Ensure key symbol is not NULL as keys like SHIFT have a null string.
+    if( keyEvent->key )
+    {
+      logicalKey = keyEvent->key;
+    }
+
+    int keyCode = KeyLookup::GetDaliKeyCode( keyEvent->keyname );
+    keyCode = ( keyCode == -1 ) ? 0 : keyCode;
+    int modifier( keyEvent->modifiers );
+    unsigned long time = keyEvent->timestamp;
+    if( !strncmp( keyEvent->keyname, "Keycode-", 8 ) )
+    {
+      keyCode = atoi( keyEvent->keyname + 8 );
+    }
+
+    // Ensure key event string is not NULL as keys like SHIFT have a null string.
+    if( keyEvent->string )
+    {
+      keyString = keyEvent->string;
+    }
+
+    std::string deviceName;
+    Device::Class::Type deviceClass;
+    Device::Subclass::Type deviceSubclass;
+
+    GetDeviceName( keyEvent, deviceName );
+    GetDeviceClass( ecore_device_class_get( keyEvent->dev ), deviceClass );
+    GetDeviceSubclass( ecore_device_subclass_get( keyEvent->dev ), deviceSubclass );
+
+    Integration::KeyEvent keyEvent( keyName, logicalKey, keyString, keyCode, modifier, time, Integration::KeyEvent::Up, compose, deviceName, deviceClass, deviceSubclass );
+
+     mKeyEventSignal.Emit( keyEvent );
+  }
+}
+
+void WindowBaseEcoreWl::OnDataSend( void* data, int type, void* event )
+{
+  mSelectionDataSendSignal.Emit( event );
+}
+
+void WindowBaseEcoreWl::OnDataReceive( void* data, int type, void* event )
+{
+  mSelectionDataReceivedSignal.Emit( event  );
+}
+
+void WindowBaseEcoreWl::OnFontNameChanged()
+{
+  mStyleChangedSignal.Emit( StyleChange::DEFAULT_FONT_CHANGE );
+}
+
+void WindowBaseEcoreWl::OnFontSizeChanged()
+{
+  mStyleChangedSignal.Emit( StyleChange::DEFAULT_FONT_SIZE_CHANGE );
+}
+
+void WindowBaseEcoreWl::OnEcoreElDBusAccessibilityNotification( void* context, const Eldbus_Message* message )
+{
+#ifdef DALI_ELDBUS_AVAILABLE
+  AccessibilityInfo info;
+
+  // The string defines the arg-list's respective types.
+  if( !eldbus_message_arguments_get( message, "iiiiiiu", &info.gestureValue, &info.startX, &info.startY, &info.endX, &info.endY, &info.state, &info.eventTime ) )
+  {
+    DALI_LOG_ERROR( "OnEcoreElDBusAccessibilityNotification: Error getting arguments\n" );
+  }
+
+  mAccessibilitySignal.Emit( info );
+#endif
+}
+
+void WindowBaseEcoreWl::RegistryGlobalCallback( void* data, struct wl_registry *registry, uint32_t name, const char* interface, uint32_t version )
+{
+  if( strcmp( interface, tizen_policy_interface.name ) == 0 )
+  {
+    uint32_t clientVersion = std::min( version, MAX_TIZEN_CLIENT_VERSION );
+
+    mTizenPolicy = static_cast< tizen_policy* >( wl_registry_bind( registry, name, &tizen_policy_interface, clientVersion ) );
+    if( !mTizenPolicy )
+    {
+      DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl::RegistryGlobalCallback: wl_registry_bind(tizen_policy_interface) is failed.\n" );
+      return;
+    }
+
+    tizen_policy_add_listener( mTizenPolicy, &tizenPolicyListener, data );
+
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl::RegistryGlobalCallback: tizen_policy_add_listener is called.\n" );
+  }
+  else if( strcmp( interface, tizen_display_policy_interface.name ) == 0 )
+  {
+    mTizenDisplayPolicy = static_cast< tizen_display_policy* >( wl_registry_bind( registry, name, &tizen_display_policy_interface, version ) );
+    if( !mTizenDisplayPolicy )
+    {
+      DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl::RegistryGlobalCallback: wl_registry_bind(tizen_display_policy_interface) is failed.\n" );
+      return;
+    }
+
+    tizen_display_policy_add_listener( mTizenDisplayPolicy, &tizenDisplayPolicyListener, data );
+
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl::RegistryGlobalCallback: tizen_display_policy_add_listener is called.\n" );
+  }
+}
+
+void WindowBaseEcoreWl::RegistryGlobalCallbackRemove( void* data, struct wl_registry* registry, uint32_t id )
+{
+  mTizenPolicy = NULL;
+  mTizenDisplayPolicy = NULL;
+}
+
+void WindowBaseEcoreWl::TizenPolicyNotificationChangeDone(void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, int32_t level, uint32_t state )
+{
+  mNotificationLevel = level;
+  mNotificationChangeState = state;
+  mNotificationLevelChangeDone = true;
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl::TizenPolicyNotificationChangeDone: level = %d, state = %d\n", level, state );
+}
+
+void WindowBaseEcoreWl::TizenPolicyScreenModeChangeDone( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, uint32_t mode, uint32_t state )
+{
+  mScreenOffMode = mode;
+  mScreenOffModeChangeState = state;
+  mScreenOffModeChangeDone = true;
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl::TizenPolicyScreenModeChangeDone: mode = %d, state = %d\n", mode, state );
+}
+
+void WindowBaseEcoreWl::DisplayPolicyBrightnessChangeDone( void* data, struct tizen_display_policy *displayPolicy, struct wl_surface* surface, int32_t brightness, uint32_t state )
+{
+  mBrightness = brightness;
+  mBrightnessChangeState = state;
+  mBrightnessChangeDone = true;
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl::DisplayPolicyBrightnessChangeDone: brightness = %d, state = %d\n", brightness, state );
+}
+
+Any WindowBaseEcoreWl::GetNativeWindow()
+{
+  return mEcoreWindow;
+}
+
+int WindowBaseEcoreWl::GetNativeWindowId()
+{
+  return ecore_wl_window_id_get( mEcoreWindow );
+}
+
+EGLNativeWindowType WindowBaseEcoreWl::CreateEglWindow( int width, int height )
+{
+  mEglWindow = wl_egl_window_create( mWlSurface, width, height );
+
+  return static_cast< EGLNativeWindowType >( mEglWindow );
+}
+
+void WindowBaseEcoreWl::DestroyEglWindow()
+{
+  if( mEglWindow != NULL )
+  {
+    wl_egl_window_destroy( mEglWindow );
+    mEglWindow = NULL;
+  }
+}
+
+void WindowBaseEcoreWl::SetEglWindowRotation( int angle )
+{
+  wl_egl_window_rotation rotation;
+
+  switch( angle )
+  {
+    case 0:
+    {
+      rotation = ROTATION_0;
+      break;
+    }
+    case 90:
+    {
+      rotation = ROTATION_270;
+      break;
+    }
+    case 180:
+    {
+      rotation = ROTATION_180;
+      break;
+    }
+    case 270:
+    {
+      rotation = ROTATION_90;
+      break;
+    }
+    default:
+    {
+      rotation = ROTATION_0;
+      break;
+    }
+  }
+
+  wl_egl_window_set_rotation( mEglWindow, rotation );
+}
+
+void WindowBaseEcoreWl::SetEglWindowBufferTransform( int angle )
+{
+  wl_output_transform bufferTransform;
+
+  switch( angle )
+  {
+    case 0:
+    {
+      bufferTransform = WL_OUTPUT_TRANSFORM_NORMAL;
+      break;
+    }
+    case 90:
+    {
+      bufferTransform = WL_OUTPUT_TRANSFORM_90;
+      break;
+    }
+    case 180:
+    {
+      bufferTransform = WL_OUTPUT_TRANSFORM_180;
+      break;
+    }
+    case 270:
+    {
+      bufferTransform = WL_OUTPUT_TRANSFORM_270;
+      break;
+    }
+    default:
+    {
+      bufferTransform = WL_OUTPUT_TRANSFORM_NORMAL;
+      break;
+    }
+  }
+
+  wl_egl_window_set_buffer_transform( mEglWindow, bufferTransform );
+}
+
+void WindowBaseEcoreWl::SetEglWindowTransform( int angle )
+{
+  wl_output_transform windowTransform;
+
+  switch( angle )
+  {
+    case 0:
+    {
+      windowTransform = WL_OUTPUT_TRANSFORM_NORMAL;
+      break;
+    }
+    case 90:
+    {
+      windowTransform = WL_OUTPUT_TRANSFORM_90;
+      break;
+    }
+    case 180:
+    {
+      windowTransform = WL_OUTPUT_TRANSFORM_180;
+      break;
+    }
+    case 270:
+    {
+      windowTransform = WL_OUTPUT_TRANSFORM_270;
+      break;
+    }
+    default:
+    {
+      windowTransform = WL_OUTPUT_TRANSFORM_NORMAL;
+      break;
+    }
+  }
+
+  wl_egl_window_set_window_transform( mEglWindow, windowTransform );
+}
+
+void WindowBaseEcoreWl::ResizeEglWindow( PositionSize positionSize )
+{
+  wl_egl_window_resize( mEglWindow, positionSize.width, positionSize.height, positionSize.x, positionSize.y );
+}
+
+bool WindowBaseEcoreWl::IsEglWindowRotationSupported()
+{
+  // 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 )
+  {
+    return true;
+  }
+
+  return false;
+}
+
+void WindowBaseEcoreWl::Move( PositionSize positionSize )
+{
+  ecore_wl_window_position_set( mEcoreWindow, positionSize.x, positionSize.y );
+}
+
+void WindowBaseEcoreWl::Resize( PositionSize positionSize )
+{
+  ecore_wl_window_update_size( mEcoreWindow, positionSize.width, positionSize.height );
+}
+
+void WindowBaseEcoreWl::MoveResize( PositionSize positionSize )
+{
+  ecore_wl_window_position_set( mEcoreWindow, positionSize.x, positionSize.y );
+  ecore_wl_window_update_size( mEcoreWindow, positionSize.width, positionSize.height );
+}
+
+void WindowBaseEcoreWl::SetClass( const std::string& name, const std::string& className )
+{
+  ecore_wl_window_title_set( mEcoreWindow, name.c_str() );
+  ecore_wl_window_class_name_set( mEcoreWindow, className.c_str() );
+}
+
+void WindowBaseEcoreWl::Raise()
+{
+  // Use ecore_wl_window_activate to prevent the window shown without rendering
+  ecore_wl_window_activate( mEcoreWindow );
+}
+
+void WindowBaseEcoreWl::Lower()
+{
+  ecore_wl_window_lower( mEcoreWindow );
+}
+
+void WindowBaseEcoreWl::Activate()
+{
+  ecore_wl_window_activate( mEcoreWindow );
+}
+
+void WindowBaseEcoreWl::SetAvailableAnlges( const std::vector< int >& angles )
+{
+  int rotations[4] = { 0 };
+  DALI_LOG_RELEASE_INFO( "WindowBaseEcoreWl::SetAvailableAnlges, angle's count: %d\n", angles.size() );
+  for( std::size_t i = 0; i < angles.size(); ++i )
+  {
+    rotations[i] = static_cast< int >( angles[i] );
+    DALI_LOG_RELEASE_INFO( "%d ", rotations[i] );
+  }
+  ecore_wl_window_rotation_available_rotations_set( mEcoreWindow, rotations, angles.size() );
+}
+
+void WindowBaseEcoreWl::SetPreferredAngle( int angle )
+{
+  ecore_wl_window_rotation_preferred_rotation_set( mEcoreWindow, angle );
+}
+
+void WindowBaseEcoreWl::SetAcceptFocus( bool accept )
+{
+  ecore_wl_window_focus_skip_set( mEcoreWindow, !accept );
+}
+
+void WindowBaseEcoreWl::Show()
+{
+  ecore_wl_window_show( mEcoreWindow );
+}
+
+void WindowBaseEcoreWl::Hide()
+{
+  ecore_wl_window_hide( mEcoreWindow );
+}
+
+unsigned int WindowBaseEcoreWl::GetSupportedAuxiliaryHintCount() const
+{
+  return mSupportedAuxiliaryHints.size();
+}
+
+std::string WindowBaseEcoreWl::GetSupportedAuxiliaryHint( unsigned int index ) const
+{
+  if( index >= GetSupportedAuxiliaryHintCount() )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::GetSupportedAuxiliaryHint: Invalid index! [%d]\n", index );
+  }
+
+  return mSupportedAuxiliaryHints[index];
+}
+
+unsigned int WindowBaseEcoreWl::AddAuxiliaryHint( const std::string& hint, const std::string& value )
+{
+  bool supported = false;
+
+  // Check if the hint is suppported
+  for( std::vector< std::string >::iterator iter = mSupportedAuxiliaryHints.begin(); iter != mSupportedAuxiliaryHints.end(); ++iter )
+  {
+    if( *iter == hint )
+    {
+      supported = true;
+      break;
+    }
+  }
+
+  if( !supported )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Concise, "WindowBaseEcoreWl::AddAuxiliaryHint: Not supported auxiliary hint [%s]\n", hint.c_str() );
+    return 0;
+  }
+
+  // Check if the hint is already added
+  for( unsigned int i = 0; i < mAuxiliaryHints.size(); i++ )
+  {
+    if( mAuxiliaryHints[i].first == hint )
+    {
+      // Just change the value
+      mAuxiliaryHints[i].second = value;
+
+      DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::AddAuxiliaryHint: Change! hint = %s, value = %s, id = %d\n", hint.c_str(), value.c_str(), i + 1 );
+
+      return i + 1;   // id is index + 1
+    }
+  }
+
+  // Add the hint
+  mAuxiliaryHints.push_back( std::pair< std::string, std::string >( hint, value ) );
+
+  unsigned int id = mAuxiliaryHints.size();
+
+  ecore_wl_window_aux_hint_add( mEcoreWindow, static_cast< int >( id ), hint.c_str(), value.c_str() );
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::AddAuxiliaryHint: hint = %s, value = %s, id = %d\n", hint.c_str(), value.c_str(), id );
+
+  return id;
+}
+
+bool WindowBaseEcoreWl::RemoveAuxiliaryHint( unsigned int id )
+{
+  if( id == 0 || id > mAuxiliaryHints.size() )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Concise, "WindowBaseEcoreWl::RemoveAuxiliaryHint: Invalid id [%d]\n", id );
+    return false;
+  }
+
+  mAuxiliaryHints[id - 1].second = std::string();
+
+  ecore_wl_window_aux_hint_del( mEcoreWindow, static_cast< int >( id ) );
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::RemoveAuxiliaryHint: id = %d, hint = %s\n", id, mAuxiliaryHints[id - 1].first.c_str() );
+
+  return true;
+}
+
+bool WindowBaseEcoreWl::SetAuxiliaryHintValue( unsigned int id, const std::string& value )
+{
+  if( id == 0 || id > mAuxiliaryHints.size() )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Concise, "WindowBaseEcoreWl::SetAuxiliaryHintValue: Invalid id [%d]\n", id );
+    return false;
+  }
+
+  mAuxiliaryHints[id - 1].second = value;
+
+  ecore_wl_window_aux_hint_change( mEcoreWindow, static_cast< int >( id ), value.c_str() );
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::SetAuxiliaryHintValue: id = %d, hint = %s, value = %s\n", id, mAuxiliaryHints[id - 1].first.c_str(), mAuxiliaryHints[id - 1].second.c_str() );
+
+  return true;
+}
+
+std::string WindowBaseEcoreWl::GetAuxiliaryHintValue( unsigned int id ) const
+{
+  if( id == 0 || id > mAuxiliaryHints.size() )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Concise, "WindowBaseEcoreWl::GetAuxiliaryHintValue: Invalid id [%d]\n", id );
+    return std::string();
+  }
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::GetAuxiliaryHintValue: id = %d, hint = %s, value = %s\n", id, mAuxiliaryHints[id - 1].first.c_str(), mAuxiliaryHints[id - 1].second.c_str() );
+
+  return mAuxiliaryHints[id - 1].second;
+}
+
+unsigned int WindowBaseEcoreWl::GetAuxiliaryHintId( const std::string& hint ) const
+{
+  for( unsigned int i = 0; i < mAuxiliaryHints.size(); i++ )
+  {
+    if( mAuxiliaryHints[i].first == hint )
+    {
+      DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::GetAuxiliaryHintId: hint = %s, id = %d\n", hint.c_str(), i + 1 );
+      return i + 1;
+    }
+  }
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::GetAuxiliaryHintId: Invalid hint! [%s]\n", hint.c_str() );
+
+  return 0;
+}
+
+void WindowBaseEcoreWl::SetInputRegion( const Rect< int >& inputRegion )
+{
+  ecore_wl_window_input_region_set( mEcoreWindow, inputRegion.x, inputRegion.y, inputRegion.width, inputRegion.height );
+}
+
+void WindowBaseEcoreWl::SetType( Dali::Window::Type type )
+{
+  Ecore_Wl_Window_Type windowType;
+
+  switch( type )
+  {
+    case Dali::Window::NORMAL:
+    {
+      windowType = ECORE_WL_WINDOW_TYPE_TOPLEVEL;
+      break;
+    }
+    case Dali::Window::NOTIFICATION:
+    {
+      windowType = ECORE_WL_WINDOW_TYPE_NOTIFICATION;
+      break;
+    }
+    case Dali::Window::UTILITY:
+    {
+      windowType = ECORE_WL_WINDOW_TYPE_UTILITY;
+      break;
+    }
+    case Dali::Window::DIALOG:
+    {
+      windowType = ECORE_WL_WINDOW_TYPE_DIALOG;
+      break;
+    }
+    default:
+    {
+      windowType = ECORE_WL_WINDOW_TYPE_TOPLEVEL;
+      break;
+    }
+  }
+
+  ecore_wl_window_type_set( mEcoreWindow, windowType );
+}
+
+bool WindowBaseEcoreWl::SetNotificationLevel( Dali::Window::NotificationLevel::Type level )
+{
+  while( !mTizenPolicy )
+  {
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+  }
+
+  int notificationLevel;
+
+  switch( level )
+  {
+    case Dali::Window::NotificationLevel::NONE:
+    {
+      notificationLevel = TIZEN_POLICY_LEVEL_NONE;
+      break;
+    }
+    case Dali::Window::NotificationLevel::BASE:
+    {
+      notificationLevel = TIZEN_POLICY_LEVEL_DEFAULT;
+      break;
+    }
+    case Dali::Window::NotificationLevel::MEDIUM:
+    {
+      notificationLevel = TIZEN_POLICY_LEVEL_MEDIUM;
+      break;
+    }
+    case Dali::Window::NotificationLevel::HIGH:
+    {
+      notificationLevel = TIZEN_POLICY_LEVEL_HIGH;
+      break;
+    }
+    case Dali::Window::NotificationLevel::TOP:
+    {
+      notificationLevel = TIZEN_POLICY_LEVEL_TOP;
+      break;
+    }
+    default:
+    {
+      DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::SetNotificationLevel: invalid level [%d]\n", level );
+      notificationLevel = TIZEN_POLICY_LEVEL_DEFAULT;
+      break;
+    }
+  }
+
+  mNotificationLevelChangeDone = false;
+  mNotificationChangeState = TIZEN_POLICY_ERROR_STATE_NONE;
+
+  tizen_policy_set_notification_level( mTizenPolicy, ecore_wl_window_surface_get( mEcoreWindow ), notificationLevel );
+
+  int count = 0;
+
+  while( !mNotificationLevelChangeDone && count < 3 )
+  {
+    ecore_wl_flush();
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+    count++;
+  }
+
+  if( !mNotificationLevelChangeDone )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::SetNotificationLevel: Level change is failed [%d, %d]\n", level, mNotificationChangeState );
+    return false;
+  }
+  else if( mNotificationChangeState == TIZEN_POLICY_ERROR_STATE_PERMISSION_DENIED )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::SetNotificationLevel: Permission denied! [%d]\n", level );
+    return false;
+  }
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::SetNotificationLevel: Level is changed [%d]\n", mNotificationLevel );
+
+  return true;
+}
+
+Dali::Window::NotificationLevel::Type WindowBaseEcoreWl::GetNotificationLevel() const
+{
+  while( !mTizenPolicy )
+  {
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+  }
+
+  int count = 0;
+
+  while( !mNotificationLevelChangeDone && count < 3 )
+  {
+    ecore_wl_flush();
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+    count++;
+  }
+
+  if( !mNotificationLevelChangeDone )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::GetNotificationLevel: Error! [%d]\n", mNotificationChangeState );
+    return Dali::Window::NotificationLevel::NONE;
+  }
+
+  Dali::Window::NotificationLevel::Type level;
+
+  switch( mNotificationLevel )
+  {
+    case TIZEN_POLICY_LEVEL_NONE:
+    {
+      level = Dali::Window::NotificationLevel::NONE;
+      break;
+    }
+    case TIZEN_POLICY_LEVEL_DEFAULT:
+    {
+      level = Dali::Window::NotificationLevel::BASE;
+      break;
+    }
+    case TIZEN_POLICY_LEVEL_MEDIUM:
+    {
+      level = Dali::Window::NotificationLevel::MEDIUM;
+      break;
+    }
+    case TIZEN_POLICY_LEVEL_HIGH:
+    {
+      level = Dali::Window::NotificationLevel::HIGH;
+      break;
+    }
+    case TIZEN_POLICY_LEVEL_TOP:
+    {
+      level = Dali::Window::NotificationLevel::TOP;
+      break;
+    }
+    default:
+    {
+      DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::GetNotificationLevel: invalid level [%d]\n", mNotificationLevel );
+      level = Dali::Window::NotificationLevel::NONE;
+      break;
+    }
+  }
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::GetNotificationLevel: level [%d]\n", mNotificationLevel );
+
+  return level;
+}
+
+void WindowBaseEcoreWl::SetOpaqueState( bool opaque )
+{
+  while( !mTizenPolicy )
+  {
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+  }
+
+  tizen_policy_set_opaque_state( mTizenPolicy, ecore_wl_window_surface_get( mEcoreWindow ), ( opaque ? 1 : 0 ) );
+}
+
+bool WindowBaseEcoreWl::SetScreenOffMode(Dali::Window::ScreenOffMode::Type screenOffMode)
+{
+  while( !mTizenPolicy )
+  {
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+  }
+
+  mScreenOffModeChangeDone = false;
+  mScreenOffModeChangeState = TIZEN_POLICY_ERROR_STATE_NONE;
+
+  unsigned int mode = 0;
+
+  switch( screenOffMode )
+  {
+    case Dali::Window::ScreenOffMode::TIMEOUT:
+    {
+      mode = 0;
+      break;
+    }
+    case Dali::Window::ScreenOffMode::NEVER:
+    {
+      mode = 1;
+      break;
+    }
+  }
+
+  tizen_policy_set_window_screen_mode( mTizenPolicy, ecore_wl_window_surface_get( mEcoreWindow ), mode );
+
+  int count = 0;
+
+  while( !mScreenOffModeChangeDone && count < 3 )
+  {
+    ecore_wl_flush();
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+    count++;
+  }
+
+  if( !mScreenOffModeChangeDone )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::SetScreenOffMode: Screen mode change is failed [%d, %d]\n", screenOffMode, mScreenOffModeChangeState );
+    return false;
+  }
+  else if( mScreenOffModeChangeState == TIZEN_POLICY_ERROR_STATE_PERMISSION_DENIED )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::SetScreenOffMode: Permission denied! [%d]\n", screenOffMode );
+    return false;
+  }
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::SetScreenOffMode: Screen mode is changed [%d]\n", mScreenOffMode );
+
+  return true;
+}
+
+Dali::Window::ScreenOffMode::Type WindowBaseEcoreWl::GetScreenOffMode() const
+{
+  while( !mTizenPolicy )
+  {
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+  }
+
+  int count = 0;
+
+  while( !mScreenOffModeChangeDone && count < 3 )
+  {
+    ecore_wl_flush();
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+    count++;
+  }
+
+  if( !mScreenOffModeChangeDone )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::GetScreenOffMode: Error! [%d]\n", mScreenOffModeChangeState );
+    return Dali::Window::ScreenOffMode::TIMEOUT;
+  }
+
+  Dali::Window::ScreenOffMode::Type screenMode = Dali::Window::ScreenOffMode::TIMEOUT;
+
+  switch( mScreenOffMode )
+  {
+    case 0:
+    {
+      screenMode = Dali::Window::ScreenOffMode::TIMEOUT;
+      break;
+    }
+    case 1:
+    {
+      screenMode = Dali::Window::ScreenOffMode::NEVER;
+      break;
+    }
+  }
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::GetScreenOffMode: screen mode [%d]\n", mScreenOffMode );
+
+  return screenMode;
+}
+
+bool WindowBaseEcoreWl::SetBrightness( int brightness )
+{
+  while( !mTizenDisplayPolicy )
+  {
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+  }
+
+  mBrightnessChangeDone = false;
+  mBrightnessChangeState = TIZEN_POLICY_ERROR_STATE_NONE;
+
+  tizen_display_policy_set_window_brightness( mTizenDisplayPolicy, ecore_wl_window_surface_get( mEcoreWindow ), brightness );
+
+  int count = 0;
+
+  while( !mBrightnessChangeDone && count < 3 )
+  {
+    ecore_wl_flush();
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+    count++;
+  }
+
+  if( !mBrightnessChangeDone )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::SetBrightness: Brightness change is failed [%d, %d]\n", brightness, mBrightnessChangeState );
+    return false;
+  }
+  else if( mBrightnessChangeState == TIZEN_POLICY_ERROR_STATE_PERMISSION_DENIED )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::SetBrightness: Permission denied! [%d]\n", brightness );
+    return false;
+  }
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::SetBrightness: Brightness is changed [%d]\n", mBrightness );
+
+  return true;
+}
+
+int WindowBaseEcoreWl::GetBrightness() const
+{
+  while( !mTizenDisplayPolicy )
+  {
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+  }
+
+  int count = 0;
+
+  while( !mBrightnessChangeDone && count < 3 )
+  {
+    ecore_wl_flush();
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+    count++;
+  }
+
+  if( !mBrightnessChangeDone )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::GetBrightness: Error! [%d]\n", mBrightnessChangeState );
+    return 0;
+  }
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl::GetBrightness: Brightness [%d]\n", mBrightness );
+
+  return mBrightness;
+}
+
+bool WindowBaseEcoreWl::GrabKey( Dali::KEY key, KeyGrab::KeyGrabMode grabMode )
+{
+  Ecore_Wl_Window_Keygrab_Mode mode;
+
+  switch( grabMode )
+  {
+    case KeyGrab::TOPMOST:
+    {
+      mode = ECORE_WL_WINDOW_KEYGRAB_TOPMOST;
+      break;
+    }
+    case KeyGrab::SHARED:
+    {
+      mode = ECORE_WL_WINDOW_KEYGRAB_SHARED;
+      break;
+    }
+    case KeyGrab::OVERRIDE_EXCLUSIVE:
+    {
+      mode = ECORE_WL_WINDOW_KEYGRAB_OVERRIDE_EXCLUSIVE;
+      break;
+    }
+    case KeyGrab::EXCLUSIVE:
+    {
+      mode = ECORE_WL_WINDOW_KEYGRAB_EXCLUSIVE;
+      break;
+    }
+    default:
+    {
+      return false;
+    }
+  }
+
+  return ecore_wl_window_keygrab_set( mEcoreWindow, KeyLookup::GetKeyName( key ), 0, 0, 0, mode );
+}
+
+bool WindowBaseEcoreWl::UngrabKey( Dali::KEY key )
+{
+  return ecore_wl_window_keygrab_unset( mEcoreWindow, KeyLookup::GetKeyName( key ), 0, 0 );
+}
+
+bool WindowBaseEcoreWl::GrabKeyList( const Dali::Vector< Dali::KEY >& key, const Dali::Vector< KeyGrab::KeyGrabMode >& grabMode, Dali::Vector< bool >& result )
+{
+  int keyCount = key.Count();
+  int keyGrabModeCount = grabMode.Count();
+
+  if( keyCount != keyGrabModeCount || keyCount == 0 )
+  {
+    return false;
+  }
+
+  eina_init();
+
+  Eina_List* keyList = NULL;
+  Ecore_Wl_Window_Keygrab_Info* info = new Ecore_Wl_Window_Keygrab_Info[keyCount];
+
+  for( int index = 0; index < keyCount; ++index )
+  {
+    info[index].key = const_cast< char* >( KeyLookup::GetKeyName( key[index] ) );
+
+    switch( grabMode[index] )
+    {
+      case KeyGrab::TOPMOST:
+      {
+        info[index].mode = ECORE_WL_WINDOW_KEYGRAB_TOPMOST;
+        break;
+      }
+      case KeyGrab::SHARED:
+      {
+        info[index].mode = ECORE_WL_WINDOW_KEYGRAB_SHARED;
+        break;
+      }
+      case KeyGrab::OVERRIDE_EXCLUSIVE:
+      {
+        info[index].mode = ECORE_WL_WINDOW_KEYGRAB_OVERRIDE_EXCLUSIVE;
+        break;
+      }
+      case KeyGrab::EXCLUSIVE:
+      {
+        info[index].mode = ECORE_WL_WINDOW_KEYGRAB_EXCLUSIVE;
+        break;
+      }
+      default:
+      {
+        info[index].mode = ECORE_WL_WINDOW_KEYGRAB_UNKNOWN;
+        break;
+      }
+    }
+
+    keyList = eina_list_append( keyList, &info );
+  }
+
+  Eina_List* grabList = ecore_wl_window_keygrab_list_set( mEcoreWindow, keyList );
+
+  result.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 )
+    {
+      int 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 )
+        {
+          result[index] = false;
+        }
+        ++index;
+      }
+    }
+  }
+
+  delete [] info;
+
+  eina_list_free( keyList );
+  eina_list_free( grabList );
+  eina_shutdown();
+
+  return true;
+}
+
+bool WindowBaseEcoreWl::UngrabKeyList( const Dali::Vector< Dali::KEY >& key, Dali::Vector< bool >& result )
+{
+  int keyCount = key.Count();
+  if( keyCount == 0 )
+  {
+    return false;
+  }
+
+  eina_init();
+
+  Eina_List* keyList = NULL;
+  Ecore_Wl_Window_Keygrab_Info* info = new Ecore_Wl_Window_Keygrab_Info[keyCount];
+
+  for( int index = 0; index < keyCount; ++index )
+  {
+    info[index].key = const_cast< char* >( KeyLookup::GetKeyName( key[index] ) );
+    keyList = eina_list_append( keyList, &info );
+  }
+
+  Eina_List* ungrabList = ecore_wl_window_keygrab_list_unset( mEcoreWindow, keyList );
+
+  result.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 )
+    {
+      int index = 0;
+      EINA_LIST_FOREACH( keyList, l, listData )
+      {
+        if( strcmp( static_cast< char* >( data ), static_cast< Ecore_Wl_Window_Keygrab_Info* >( listData )->key ) == 0 )
+        {
+          result[index] = false;
+        }
+        ++index;
+      }
+    }
+  }
+
+  delete [] info;
+
+  eina_list_free( keyList );
+  eina_list_free( ungrabList );
+  eina_shutdown();
+
+  return true;
+}
+
+void WindowBaseEcoreWl::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
+{
+  // calculate DPI
+  float xres, yres;
+
+  // 1 inch = 25.4 millimeters
+  xres = ecore_wl_dpi_get();
+  yres = ecore_wl_dpi_get();
+
+  dpiHorizontal = int( xres + 0.5f );  // rounding
+  dpiVertical   = int( yres + 0.5f );
+}
+
+int WindowBaseEcoreWl::GetScreenRotationAngle()
+{
+  int transform = 0;
+
+  if( ecore_wl_window_ignore_output_transform_get( mEcoreWindow ) )
+  {
+    transform = 0;
+  }
+  else
+  {
+    transform = ecore_wl_output_transform_get( ecore_wl_window_output_find( mEcoreWindow ) );
+  }
+
+  return transform * 90;
+}
+
+void WindowBaseEcoreWl::SetWindowRotationAngle( int degree )
+{
+  ecore_wl_window_rotation_set( mEcoreWindow, degree );
+}
+
+void WindowBaseEcoreWl::WindowRotationCompleted( int degree, int width, int height )
+{
+  ecore_wl_window_rotation_change_done_send( mEcoreWindow );
+}
+
+void WindowBaseEcoreWl::SetTransparency( bool transparent )
+{
+  ecore_wl_window_alpha_set( mEcoreWindow, transparent );
+}
+
+void WindowBaseEcoreWl::InitializeEcoreElDBus()
+{
+#ifdef DALI_ELDBUS_AVAILABLE
+  Eldbus_Object* object;
+  Eldbus_Proxy* manager;
+
+  if( !( mSystemConnection = eldbus_connection_get( ELDBUS_CONNECTION_TYPE_SYSTEM ) ) )
+  {
+    DALI_LOG_ERROR( "Unable to get system bus\n" );
+  }
+
+  object = eldbus_object_get( mSystemConnection, BUS, PATH );
+  if( !object )
+  {
+    DALI_LOG_ERROR( "Getting object failed\n" );
+    return;
+  }
+
+  manager = eldbus_proxy_get( object, INTERFACE );
+  if( !manager )
+  {
+    DALI_LOG_ERROR( "Getting proxy failed\n" );
+    return;
+  }
+
+  if( !eldbus_proxy_signal_handler_add( manager, "GestureDetected", EcoreElDBusAccessibilityNotification, this ) )
+  {
+    DALI_LOG_ERROR( "No signal handler returned\n" );
+  }
+#endif
+}
+
+void WindowBaseEcoreWl::CreateWindow( PositionSize positionSize )
+{
+  mEcoreWindow = ecore_wl_window_new( 0, positionSize.x, positionSize.y, positionSize.width, positionSize.height, ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW );
+
+  if ( mEcoreWindow == 0 )
+  {
+    DALI_ASSERT_ALWAYS( 0 && "Failed to create Wayland window" );
+  }
+}
+
+void WindowBaseEcoreWl::SetParent( WindowBase* parentWinBase )
+{
+  Ecore_Wl_Window* ecoreParent = NULL;
+  if( parentWinBase )
+  {
+    WindowBaseEcoreWl* winBaseEcore = static_cast<WindowBaseEcoreWl*>( parentWinBase );
+    ecoreParent = winBaseEcore->mEcoreWindow;
+  }
+  ecore_wl_window_parent_set( mEcoreWindow, ecoreParent );
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#pragma GCC diagnostic pop
diff --git a/dali/internal/window-system/tizen-wayland/ecore-wl/window-base-ecore-wl.h b/dali/internal/window-system/tizen-wayland/ecore-wl/window-base-ecore-wl.h
new file mode 100644 (file)
index 0000000..5811b5c
--- /dev/null
@@ -0,0 +1,490 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_WINDOW_BASE_ECORE_WL_H
+#define DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_WINDOW_BASE_ECORE_WL_H
+
+/*
+ * Copyright (c) 2018 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 <dali/internal/window-system/common/window-base.h>
+
+// EXTERNAL HEADERS
+#include <Ecore.h>
+#include <Ecore_Wayland.h>
+#include <tizen-extension-client-protocol.h>
+#include <wayland-egl.h>
+
+#ifdef DALI_ELDBUS_AVAILABLE
+#include <Eldbus.h>
+#endif
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class WindowRenderSurface;
+class WindowRenderSurfaceEcoreWl;
+
+/**
+ * WindowBaseEcoreWl class provides an WindowBase Ecore-Wayland implementation.
+ */
+class WindowBaseEcoreWl : public WindowBase
+{
+public:
+
+  /**
+   * @brief Constructor
+   */
+  WindowBaseEcoreWl( PositionSize positionSize, Any surface, bool isTransparent );
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~WindowBaseEcoreWl();
+
+public:
+
+  /**
+   * @brief Called when the window iconify state is changed.
+   */
+  Eina_Bool OnIconifyStateChanged( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the window gains focus.
+   */
+  Eina_Bool OnFocusIn( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the window loses focus.
+   */
+  Eina_Bool OnFocusOut( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the output is transformed.
+   */
+  Eina_Bool OnOutputTransform( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the output transform should be ignored.
+   */
+  Eina_Bool OnIgnoreOutputTransform( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a rotation event is recevied.
+   */
+  void OnRotation( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a touch down is received.
+   */
+  void OnMouseButtonDown( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a touch up is received.
+   */
+  void OnMouseButtonUp( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a touch motion is received.
+   */
+  void OnMouseButtonMove( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a touch is canceled.
+   */
+  void OnMouseButtonCancel( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a mouse wheel is received.
+   */
+  void OnMouseWheel( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a detent rotation event is recevied.
+   */
+  void OnDetentRotation( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a key down is received.
+   */
+  void OnKeyDown( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a key up is received.
+   */
+  void OnKeyUp( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the source window notifies us the content in clipboard is selected.
+   */
+  void OnDataSend( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the source window sends us about the selected content.
+   */
+  void OnDataReceive( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a font name is changed.
+   */
+  void OnFontNameChanged();
+
+  /**
+   * @brief Called when a font size is changed.
+   */
+  void OnFontSizeChanged();
+
+#ifdef DALI_ELDBUS_AVAILABLE
+  /**
+   * @brief Called when Ecore ElDBus accessibility event is received.
+   */
+  void OnEcoreElDBusAccessibilityNotification( void* context, const Eldbus_Message* message );
+#endif
+
+  /**
+   * @brief RegistryGlobalCallback
+   */
+  void RegistryGlobalCallback( void* data, struct wl_registry *registry, uint32_t name, const char* interface, uint32_t version );
+
+  /**
+   * @brief RegistryGlobalCallbackRemove
+   */
+  void RegistryGlobalCallbackRemove( void* data, struct wl_registry* registry, uint32_t id );
+
+  /**
+   * @brief TizenPolicyNotificationChangeDone
+   */
+  void TizenPolicyNotificationChangeDone(void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, int32_t level, uint32_t state );
+
+  /**
+   * @brief TizenPolicyScreenModeChangeDone
+   */
+  void TizenPolicyScreenModeChangeDone( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, uint32_t mode, uint32_t state );
+
+  /**
+   * @brief DisplayPolicyBrightnessChangeDone
+   */
+  void DisplayPolicyBrightnessChangeDone( void* data, struct tizen_display_policy *displayPolicy, struct wl_surface* surface, int32_t brightness, uint32_t state );
+
+public:
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindow()
+   */
+  virtual Any GetNativeWindow() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindowId()
+   */
+  virtual int GetNativeWindowId() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::CreateEglWindow()
+   */
+  virtual EGLNativeWindowType CreateEglWindow( int width, int height ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::DestroyEglWindow()
+   */
+  virtual void DestroyEglWindow() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetEglWindowRotation()
+   */
+  virtual void SetEglWindowRotation( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetEglWindowBufferTransform()
+   */
+  virtual void SetEglWindowBufferTransform( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetEglWindowTransform()
+   */
+  virtual void SetEglWindowTransform( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::ResizeEglWindow()
+   */
+  virtual void ResizeEglWindow( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::IsEglWindowRotationSupported()
+   */
+  virtual bool IsEglWindowRotationSupported() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Move()
+   */
+  virtual void Move( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Resize()
+   */
+  virtual void Resize( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::MoveResize()
+   */
+  virtual void MoveResize( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetClass()
+   */
+  virtual void SetClass( const std::string& name, const std::string& className ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Raise()
+   */
+  virtual void Raise() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Lower()
+   */
+  virtual void Lower() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Activate()
+   */
+  virtual void Activate() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetAvailableAnlges()
+   */
+  virtual void SetAvailableAnlges( const std::vector< int >& angles ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetPreferredAngle()
+   */
+  virtual void SetPreferredAngle( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetAcceptFocus()
+   */
+  virtual void SetAcceptFocus( bool accept ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Show()
+   */
+  virtual void Show() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Hide()
+   */
+  virtual void Hide() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetSupportedAuxiliaryHintCount()
+   */
+  virtual unsigned int GetSupportedAuxiliaryHintCount() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetSupportedAuxiliaryHint()
+   */
+  virtual std::string GetSupportedAuxiliaryHint( unsigned int index ) const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::AddAuxiliaryHint()
+   */
+  virtual unsigned int AddAuxiliaryHint( const std::string& hint, const std::string& value ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::RemoveAuxiliaryHint()
+   */
+  virtual bool RemoveAuxiliaryHint( unsigned int id ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetAuxiliaryHintValue()
+   */
+  virtual bool SetAuxiliaryHintValue( unsigned int id, const std::string& value ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetAuxiliaryHintValue()
+   */
+  virtual std::string GetAuxiliaryHintValue( unsigned int id ) const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetAuxiliaryHintId()
+   */
+  virtual unsigned int GetAuxiliaryHintId( const std::string& hint ) const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetInputRegion()
+   */
+  virtual void SetInputRegion( const Rect< int >& inputRegion ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetType()
+   */
+  virtual void SetType( Dali::Window::Type type ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetNotificationLevel()
+   */
+  virtual bool SetNotificationLevel( Dali::Window::NotificationLevel::Type level ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNotificationLevel()
+   */
+  virtual Dali::Window::NotificationLevel::Type GetNotificationLevel() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetOpaqueState()
+   */
+  virtual void SetOpaqueState( bool opaque ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetScreenOffMode()
+   */
+  virtual bool SetScreenOffMode(Dali::Window::ScreenOffMode::Type screenOffMode) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetScreenOffMode()
+   */
+  virtual Dali::Window::ScreenOffMode::Type GetScreenOffMode() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetBrightness()
+   */
+  virtual bool SetBrightness( int brightness ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetBrightness()
+   */
+  virtual int GetBrightness() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GrabKey()
+   */
+  virtual bool GrabKey( Dali::KEY key, KeyGrab::KeyGrabMode grabMode ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::UngrabKey()
+   */
+  virtual bool UngrabKey( Dali::KEY key ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GrabKeyList()
+   */
+  virtual bool GrabKeyList( const Dali::Vector< Dali::KEY >& key, const Dali::Vector< KeyGrab::KeyGrabMode >& grabMode, Dali::Vector< bool >& result ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::UngrabKeyList()
+   */
+  virtual bool UngrabKeyList( const Dali::Vector< Dali::KEY >& key, Dali::Vector< bool >& result ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetDpi()
+   */
+  virtual void GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetScreenRotationAngle()
+   */
+  virtual int GetScreenRotationAngle() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetWindowRotationAngle()
+   */
+  virtual void SetWindowRotationAngle( int degree ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::WindowRotationCompleted()
+   */
+  virtual void WindowRotationCompleted( int degree, int width, int height ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetTransparency()
+   */
+  virtual void SetTransparency( bool transparent ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetParent()
+   */
+  virtual void SetParent( WindowBase* parentWinBase ) override;
+
+private:
+
+  /**
+   * Second stage initialization
+   */
+  void Initialize( PositionSize positionSize, Any surface, bool isTransparent );
+
+  /**
+   * Initialize Ecore ElDBus
+   */
+  void InitializeEcoreElDBus();
+
+  /**
+   * @brief Create window
+   */
+  void CreateWindow( PositionSize positionSize );
+
+protected:
+
+  // Undefined
+  WindowBaseEcoreWl(const WindowBaseEcoreWl&) = delete;
+
+  // Undefined
+  WindowBaseEcoreWl& operator=(const WindowBaseEcoreWl& rhs) = delete;
+
+private:
+
+  typedef std::vector< std::pair< std::string, std::string > > AuxiliaryHints;
+
+  Dali::Vector< Ecore_Event_Handler* > mEcoreEventHandler;
+
+  Ecore_Wl_Window*                     mEcoreWindow;
+  wl_surface*                          mWlSurface;
+  wl_egl_window*                       mEglWindow;
+  wl_display*                          mDisplay;
+  wl_event_queue*                      mEventQueue;
+  tizen_policy*                        mTizenPolicy;
+  tizen_display_policy*                mTizenDisplayPolicy;
+
+  std::vector< std::string >           mSupportedAuxiliaryHints;
+  AuxiliaryHints                       mAuxiliaryHints;
+
+  int                                  mNotificationLevel;
+  uint32_t                             mNotificationChangeState;
+  bool                                 mNotificationLevelChangeDone;
+
+  int                                  mScreenOffMode;
+  uint32_t                             mScreenOffModeChangeState;
+  bool                                 mScreenOffModeChangeDone;
+
+  int                                  mBrightness;
+  uint32_t                             mBrightnessChangeState;
+  bool                                 mBrightnessChangeDone;
+
+  bool                                 mOwnSurface;
+
+#ifdef DALI_ELDBUS_AVAILABLE
+  Eldbus_Connection*                   mSystemConnection;
+#endif // DALI_ELDBUS_AVAILABLE
+
+};
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_WINDOW_BASE_ECORE_WL_H
diff --git a/dali/internal/window-system/tizen-wayland/ecore-wl/window-factory-ecore-wl.cpp b/dali/internal/window-system/tizen-wayland/ecore-wl/window-factory-ecore-wl.cpp
new file mode 100644 (file)
index 0000000..429de0d
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/tizen-wayland/ecore-wl/window-factory-ecore-wl.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/window-system/tizen-wayland/ecore-wl/window-base-ecore-wl.h>
+#include <dali/internal/window-system/common/display-utils.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+std::unique_ptr< WindowBase > WindowFactoryEcoreWl::CreateWindowBase( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+{
+  return Utils::MakeUnique< WindowBaseEcoreWl >( positionSize, surface, isTransparent );
+}
+
+// this should be created from Window impl
+std::unique_ptr< WindowFactory > GetWindowFactory()
+{
+  // returns Window factory
+  return Utils::MakeUnique< WindowFactoryEcoreWl >();
+}
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
diff --git a/dali/internal/window-system/tizen-wayland/ecore-wl/window-factory-ecore-wl.h b/dali/internal/window-system/tizen-wayland/ecore-wl/window-factory-ecore-wl.h
new file mode 100644 (file)
index 0000000..9f58b99
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_WINDOW_FACTORY_ECORE_WL_H
+#define DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_WINDOW_FACTORY_ECORE_WL_H
+
+/*
+ * Copyright (c) 2018 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/internal/window-system/common/window-factory.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class WindowFactoryEcoreWl : public WindowFactory
+{
+public:
+  std::unique_ptr< WindowBase > CreateWindowBase( Dali::PositionSize positionSize, Any surface, bool isTransparent ) override;
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_WINDOW_FACTORY_ECORE_WL_H
diff --git a/dali/internal/window-system/tizen-wayland/ecore-wl/window-system-ecore-wl.cpp b/dali/internal/window-system/tizen-wayland/ecore-wl/window-system-ecore-wl.cpp
new file mode 100644 (file)
index 0000000..a38aa6e
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018 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 HEADERS
+#include <dali/internal/window-system/common/window-system.h>
+
+// EXTERNAL_HEADERS
+#include <Ecore_Wayland.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace WindowSystem
+{
+
+void Initialize()
+{
+  ecore_wl_init( NULL );
+}
+
+void Shutdown()
+{
+  ecore_wl_shutdown();
+}
+
+void GetScreenSize( int& width, int& height )
+{
+  ecore_wl_screen_size_get( &width, &height );
+}
+
+bool SetKeyboardRepeatInfo( float rate, float delay )
+{
+  return ecore_wl_keyboard_repeat_info_set( static_cast<double>( rate ), static_cast<double>( delay ) );
+}
+
+bool GetKeyboardRepeatInfo( float& rate, float& delay )
+{
+  double rateVal, delayVal;
+  bool ret = ecore_wl_keyboard_repeat_info_get( &rateVal, &delayVal );
+  rate = static_cast<float>( rateVal );
+  delay = static_cast<float>( delayVal );
+
+  return ret;
+}
+
+} // namespace WindowSystem
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#pragma GCC diagnostic pop
diff --git a/dali/internal/window-system/tizen-wayland/ecore-wl2/render-surface-factory-ecore-wl2.cpp b/dali/internal/window-system/tizen-wayland/ecore-wl2/render-surface-factory-ecore-wl2.cpp
new file mode 100644 (file)
index 0000000..e0069a7
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/tizen-wayland/ecore-wl2/render-surface-factory-ecore-wl2.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/window-system/common/window-render-surface.h>
+#include <dali/internal/window-system/tizen-wayland/native-render-surface-ecore-wl.h>
+#include <dali/internal/window-system/common/pixmap-render-surface.h>
+#include <dali/internal/window-system/common/display-utils.h>
+
+// EXTERNAL INCLUDES
+#include <memory>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+std::unique_ptr< WindowRenderSurface > RenderSurfaceFactoryEcoreWl2::CreateWindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+{
+  return Utils::MakeUnique< WindowRenderSurface >( positionSize, surface, isTransparent );
+}
+
+std::unique_ptr< PixmapRenderSurface > RenderSurfaceFactoryEcoreWl2::CreatePixmapRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+{
+  return std::unique_ptr< PixmapRenderSurface >( nullptr );
+}
+
+std::unique_ptr< NativeRenderSurface > RenderSurfaceFactoryEcoreWl2::CreateNativeRenderSurface( Dali::PositionSize positionSize, bool isTransparent )
+{
+  return Utils::MakeUnique< NativeRenderSurfaceEcoreWl >( positionSize, isTransparent );
+}
+
+// this should be created from somewhere
+std::unique_ptr< RenderSurfaceFactory > GetRenderSurfaceFactory()
+{
+  // returns Window factory
+  return Utils::MakeUnique< RenderSurfaceFactoryEcoreWl2 >();
+}
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
diff --git a/dali/internal/window-system/tizen-wayland/ecore-wl2/render-surface-factory-ecore-wl2.h b/dali/internal/window-system/tizen-wayland/ecore-wl2/render-surface-factory-ecore-wl2.h
new file mode 100644 (file)
index 0000000..fbb4eff
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_RENDER_SURFACE_FACTORY_ECORE_WL2_H
+#define DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_RENDER_SURFACE_FACTORY_ECORE_WL2_H
+
+/*
+ * Copyright (c) 2018 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/internal/window-system/common/render-surface-factory.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class RenderSurfaceFactoryEcoreWl2 : public RenderSurfaceFactory
+{
+public:
+  std::unique_ptr< WindowRenderSurface > CreateWindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent = false ) override;
+
+  std::unique_ptr< PixmapRenderSurface > CreatePixmapRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent = false ) override;
+
+  std::unique_ptr< NativeRenderSurface > CreateNativeRenderSurface( Dali::PositionSize positionSize, bool isTransparent = false ) override;
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_RENDER_SURFACE_FACTORY_ECORE_WL2_H
diff --git a/dali/internal/window-system/tizen-wayland/ecore-wl2/window-base-ecore-wl2.cpp b/dali/internal/window-system/tizen-wayland/ecore-wl2/window-base-ecore-wl2.cpp
new file mode 100755 (executable)
index 0000000..89fae58
--- /dev/null
@@ -0,0 +1,2361 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+// Ecore is littered with C style cast
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+
+// CLASS HEADER
+#include <dali/internal/window-system/tizen-wayland/ecore-wl2/window-base-ecore-wl2.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/window-system/common/window-impl.h>
+#include <dali/internal/window-system/common/window-system.h>
+#include <dali/internal/window-system/common/window-render-surface.h>
+#include <dali/internal/input/common/key-impl.h>
+
+// EXTERNAL_HEADERS
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/events/mouse-button.h>
+#include <dali/integration-api/debug.h>
+#include <Ecore_Input.h>
+#include <vconf.h>
+#include <vconf-keys.h>
+#include <wayland-egl-tizen.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gWindowBaseLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_WINDOW_BASE" );
+#endif
+
+const uint32_t MAX_TIZEN_CLIENT_VERSION = 7;
+const unsigned int PRIMARY_TOUCH_BUTTON_ID = 1;
+
+const char* DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME = "db/setting/accessibility/font_name";  // It will be update at vconf-key.h and replaced.
+
+// DBUS accessibility
+const char* BUS = "org.enlightenment.wm-screen-reader";
+const char* INTERFACE = "org.tizen.GestureNavigation";
+const char* PATH = "/org/tizen/GestureNavigation";
+
+struct KeyCodeMap
+{
+  xkb_keysym_t keySym;
+  xkb_keycode_t keyCode;
+  bool isKeyCode;
+};
+
+/**
+ * Get the device name from the provided ecore key event
+ */
+void GetDeviceName( Ecore_Event_Key* keyEvent, std::string& result )
+{
+  const char* ecoreDeviceName = ecore_device_name_get( keyEvent->dev );
+
+  if( ecoreDeviceName )
+  {
+    result = ecoreDeviceName;
+  }
+}
+
+/**
+ * Get the device class from the provided ecore event
+ */
+void GetDeviceClass( Ecore_Device_Class ecoreDeviceClass, Device::Class::Type& deviceClass )
+{
+  switch( ecoreDeviceClass )
+  {
+    case ECORE_DEVICE_CLASS_SEAT:
+    {
+      deviceClass = Device::Class::USER;
+      break;
+    }
+    case ECORE_DEVICE_CLASS_KEYBOARD:
+    {
+      deviceClass = Device::Class::KEYBOARD;
+      break;
+    }
+    case ECORE_DEVICE_CLASS_MOUSE:
+    {
+      deviceClass = Device::Class::MOUSE;
+      break;
+    }
+    case ECORE_DEVICE_CLASS_TOUCH:
+    {
+      deviceClass = Device::Class::TOUCH;
+      break;
+    }
+    case ECORE_DEVICE_CLASS_PEN:
+    {
+      deviceClass = Device::Class::PEN;
+      break;
+    }
+    case ECORE_DEVICE_CLASS_POINTER:
+    {
+      deviceClass = Device::Class::POINTER;
+      break;
+    }
+    case ECORE_DEVICE_CLASS_GAMEPAD:
+    {
+      deviceClass = Device::Class::GAMEPAD;
+      break;
+    }
+    default:
+    {
+      deviceClass = Device::Class::NONE;
+      break;
+    }
+  }
+}
+
+void GetDeviceSubclass( Ecore_Device_Subclass ecoreDeviceSubclass, Device::Subclass::Type& deviceSubclass )
+{
+  switch( ecoreDeviceSubclass )
+  {
+    case ECORE_DEVICE_SUBCLASS_FINGER:
+    {
+      deviceSubclass = Device::Subclass::FINGER;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_FINGERNAIL:
+    {
+      deviceSubclass = Device::Subclass::FINGERNAIL;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_KNUCKLE:
+    {
+      deviceSubclass = Device::Subclass::KNUCKLE;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_PALM:
+    {
+      deviceSubclass = Device::Subclass::PALM;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_HAND_SIZE:
+    {
+      deviceSubclass = Device::Subclass::HAND_SIDE;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_HAND_FLAT:
+    {
+      deviceSubclass = Device::Subclass::HAND_FLAT;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_PEN_TIP:
+    {
+      deviceSubclass = Device::Subclass::PEN_TIP;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_TRACKPAD:
+    {
+      deviceSubclass = Device::Subclass::TRACKPAD;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_TRACKPOINT:
+    {
+      deviceSubclass = Device::Subclass::TRACKPOINT;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_TRACKBALL:
+    {
+      deviceSubclass = Device::Subclass::TRACKBALL;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_REMOCON:
+    {
+      deviceSubclass = Device::Subclass::REMOCON;
+      break;
+    }
+    case ECORE_DEVICE_SUBCLASS_VIRTUAL_KEYBOARD:
+    {
+      deviceSubclass = Device::Subclass::VIRTUAL_KEYBOARD;
+      break;
+    }
+    default:
+    {
+      deviceSubclass = Device::Subclass::NONE;
+      break;
+    }
+  }
+}
+
+
+void FindKeyCode( struct xkb_keymap* keyMap, xkb_keycode_t key, void* data )
+{
+  KeyCodeMap* foundKeyCode = static_cast< KeyCodeMap* >( data );
+  if( foundKeyCode->isKeyCode )
+  {
+    return;
+  }
+
+  xkb_keysym_t keySym = foundKeyCode->keySym;
+  int nsyms = 0;
+  const xkb_keysym_t* symsOut = NULL;
+
+  nsyms = xkb_keymap_key_get_syms_by_level( keyMap, key, 0, 0, &symsOut );
+
+  if( nsyms && symsOut )
+  {
+    if( *symsOut == keySym )
+    {
+      foundKeyCode->keyCode = key;
+      foundKeyCode->isKeyCode = true;
+    }
+  }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Window Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+/// Called when the window iconify state is changed.
+static Eina_Bool EcoreEventWindowIconifyStateChanged( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    return windowBase->OnIconifyStateChanged( data, type, event );
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/// Called when the window gains focus
+static Eina_Bool EcoreEventWindowFocusIn( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    return windowBase->OnFocusIn( data, type, event );
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/// Called when the window loses focus
+static Eina_Bool EcoreEventWindowFocusOut( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    return windowBase->OnFocusOut( data, type, event );
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/// Called when the output is transformed
+static Eina_Bool EcoreEventOutputTransform( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    return windowBase->OnOutputTransform( data, type, event );
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/// Called when the output transform should be ignored
+static Eina_Bool EcoreEventIgnoreOutputTransform( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    return windowBase->OnIgnoreOutputTransform( data, type, event );
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when rotate event is recevied.
+ */
+static Eina_Bool EcoreEventRotate( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    DALI_LOG_RELEASE_INFO( "WindowBaseEcoreWl2::EcoreEventRotate\n" );
+    windowBase->OnRotation( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when configure event is recevied.
+ */
+static Eina_Bool EcoreEventConfigure( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->OnConfiguration( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Touch Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Called when a touch down is received.
+ */
+static Eina_Bool EcoreEventMouseButtonDown( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->OnMouseButtonDown( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when a touch up is received.
+ */
+static Eina_Bool EcoreEventMouseButtonUp( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->OnMouseButtonUp( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when a touch motion is received.
+ */
+static Eina_Bool EcoreEventMouseButtonMove( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->OnMouseButtonMove( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when a touch is canceled.
+ */
+static Eina_Bool EcoreEventMouseButtonCancel( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->OnMouseButtonCancel( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when a mouse wheel is received.
+ */
+static Eina_Bool EcoreEventMouseWheel( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->OnMouseWheel( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when a detent rotation event is recevied.
+ */
+static Eina_Bool EcoreEventDetentRotation( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->OnDetentRotation( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Key Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Called when a key down is received.
+ */
+static Eina_Bool EcoreEventKeyDown( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->OnKeyDown( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when a key up is received.
+ */
+static Eina_Bool EcoreEventKeyUp( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->OnKeyUp( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Selection Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Called when the source window notifies us the content in clipboard is selected.
+ */
+static Eina_Bool EcoreEventDataSend( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->OnDataSend( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+* Called when the source window sends us about the selected content.
+* For example, when item is selected in the clipboard.
+*/
+static Eina_Bool EcoreEventDataReceive( void* data, int type, void* event )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->OnDataReceive( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Effect Start/End Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Called when transition animation of the window's shown/hidden is started by window manager.
+ */
+static Eina_Bool EcoreEventEffectStart(void *data, int type, void *event)
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  Ecore_Wl2_Event_Effect_Start *effectStart = static_cast<Ecore_Wl2_Event_Effect_Start*>( event );
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::EcoreEventEffectStart, effect type[ %d ]\n", effectStart->type );
+  if( windowBase )
+  {
+    if( effectStart->type < 3 ) // only under restack
+    {
+      windowBase->OnTransitionEffectEvent( DevelWindow::EffectState::START, static_cast<DevelWindow::EffectType>( effectStart->type ) );
+    }
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when transition animation of the window's shown/hidden is ended by window manager.
+ */
+static Eina_Bool EcoreEventEffectEnd(void *data, int type, void *event)
+{
+  Ecore_Wl2_Event_Effect_Start *effectEnd = static_cast<Ecore_Wl2_Event_Effect_Start*>( event );
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::EcoreEventEffectEnd, effect type[ %d ]\n", effectEnd->type );
+  if( windowBase )
+  {
+    if( effectEnd->type < 3 ) // only under restack
+    {
+      windowBase->OnTransitionEffectEvent( DevelWindow::EffectState::END, static_cast<DevelWindow::EffectType>( effectEnd->type ) );
+    }
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Keymap Changed Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+static Eina_Bool EcoreEventSeatKeymapChanged(void *data, int type, void *event)
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->KeymapChanged( data, type, event );
+  }
+
+  return ECORE_CALLBACK_RENEW;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Font Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Called when a font name is changed.
+ */
+static void VconfNotifyFontNameChanged( keynode_t* node, void* data )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->OnFontNameChanged();
+  }
+}
+
+/**
+ * Called when a font size is changed.
+ */
+static void VconfNotifyFontSizeChanged( keynode_t* node, void* data )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->OnFontSizeChanged();
+  }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// ElDBus Accessibility Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef DALI_ELDBUS_AVAILABLE
+// Callback for Ecore ElDBus accessibility events.
+static void EcoreElDBusAccessibilityNotification( void* context, const Eldbus_Message* message )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( context );
+  if( windowBase )
+  {
+    windowBase->OnEcoreElDBusAccessibilityNotification( context, message );
+  }
+}
+#endif // DALI_ELDBUS_AVAILABLE
+
+static void RegistryGlobalCallback( void* data, struct wl_registry *registry, uint32_t name, const char* interface, uint32_t version )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->RegistryGlobalCallback( data, registry, name, interface, version );
+  }
+}
+
+static void RegistryGlobalCallbackRemove( void* data, struct wl_registry* registry, uint32_t id )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->RegistryGlobalCallbackRemove( data, registry, id );
+  }
+}
+
+static void TizenPolicyConformant( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, uint32_t isConformant )
+{
+}
+
+static void TizenPolicyConformantArea( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, uint32_t conformantPart, uint32_t state, int32_t x, int32_t y, int32_t w, int32_t h )
+{
+}
+
+static void TizenPolicyNotificationChangeDone(void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, int32_t level, uint32_t state )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->TizenPolicyNotificationChangeDone( data, tizenPolicy, surface, level, state );
+  }
+}
+
+static void TizenPolicyTransientForDone( void* data, struct tizen_policy* tizenPolicy, uint32_t childId )
+{
+}
+
+static void TizenPolicyScreenModeChangeDone( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, uint32_t mode, uint32_t state )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->TizenPolicyScreenModeChangeDone( data, tizenPolicy, surface, mode, state );
+  }
+}
+
+static void TizenPolicyIconifyStateChanged( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, uint32_t iconified, uint32_t force )
+{
+}
+
+static void TizenPolicySupportedAuxiliaryHints( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, struct wl_array* hints, uint32_t numNints )
+{
+}
+
+static void TizenPolicyAllowedAuxiliaryHint( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, int id )
+{
+}
+
+static void TizenPolicyAuxiliaryMessage( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, const char* key, const char* val, struct wl_array* options )
+{
+}
+
+static void TizenPolicyConformantRegion( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, uint32_t conformantPart, uint32_t state, int32_t x, int32_t y, int32_t w, int32_t h, uint32_t serial )
+{
+}
+
+static void DisplayPolicyBrightnessChangeDone( void* data, struct tizen_display_policy *displayPolicy, struct wl_surface* surface, int32_t brightness, uint32_t state )
+{
+  WindowBaseEcoreWl2* windowBase = static_cast< WindowBaseEcoreWl2* >( data );
+  if( windowBase )
+  {
+    windowBase->DisplayPolicyBrightnessChangeDone( data, displayPolicy, surface, brightness, state );
+  }
+}
+
+const struct wl_registry_listener registryListener =
+{
+   RegistryGlobalCallback,
+   RegistryGlobalCallbackRemove
+};
+
+const struct tizen_policy_listener tizenPolicyListener =
+{
+   TizenPolicyConformant,
+   TizenPolicyConformantArea,
+   TizenPolicyNotificationChangeDone,
+   TizenPolicyTransientForDone,
+   TizenPolicyScreenModeChangeDone,
+   TizenPolicyIconifyStateChanged,
+   TizenPolicySupportedAuxiliaryHints,
+   TizenPolicyAllowedAuxiliaryHint,
+   TizenPolicyAuxiliaryMessage,
+   TizenPolicyConformantRegion
+};
+
+const struct tizen_display_policy_listener tizenDisplayPolicyListener =
+{
+  DisplayPolicyBrightnessChangeDone
+};
+
+} // unnamed namespace
+
+WindowBaseEcoreWl2::WindowBaseEcoreWl2( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+: mEcoreEventHandler(),
+  mEcoreWindow( NULL ),
+  mWlSurface( NULL ),
+  mEglWindow( NULL ),
+  mDisplay( NULL ),
+  mEventQueue( NULL ),
+  mTizenPolicy( NULL ),
+  mTizenDisplayPolicy( NULL ),
+  mKeyMap( NULL ),
+  mSupportedAuxiliaryHints(),
+  mAuxiliaryHints(),
+  mNotificationLevel( -1 ),
+  mNotificationChangeState( 0 ),
+  mNotificationLevelChangeDone( true ),
+  mScreenOffMode( 0 ),
+  mScreenOffModeChangeState( 0 ),
+  mScreenOffModeChangeDone( true ),
+  mBrightness( 0 ),
+  mBrightnessChangeState( 0 ),
+  mBrightnessChangeDone( true ),
+  mOwnSurface( false ),
+  mMoveResizeSerial( 0 ),
+  mLastSubmittedMoveResizeSerial( 0 )
+#ifdef DALI_ELDBUS_AVAILABLE
+  , mSystemConnection( NULL )
+#endif
+{
+  Initialize( positionSize, surface, isTransparent );
+}
+
+WindowBaseEcoreWl2::~WindowBaseEcoreWl2()
+{
+#ifdef DALI_ELDBUS_AVAILABLE
+    // Close down ElDBus connections.
+    if( mSystemConnection )
+    {
+      eldbus_connection_unref( mSystemConnection );
+    }
+#endif // DALI_ELDBUS_AVAILABLE
+
+  vconf_ignore_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged );
+  vconf_ignore_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged );
+
+  for( Dali::Vector< Ecore_Event_Handler* >::Iterator iter = mEcoreEventHandler.Begin(), endIter = mEcoreEventHandler.End(); iter != endIter; ++iter )
+  {
+    ecore_event_handler_del( *iter );
+  }
+  mEcoreEventHandler.Clear();
+
+  if( mEventQueue )
+  {
+    wl_event_queue_destroy( mEventQueue );
+  }
+
+  mSupportedAuxiliaryHints.clear();
+  mAuxiliaryHints.clear();
+
+  if( mEglWindow != NULL )
+  {
+    wl_egl_window_destroy( mEglWindow );
+    mEglWindow = NULL;
+  }
+
+  if( mOwnSurface )
+  {
+    ecore_wl2_window_free( mEcoreWindow );
+
+    WindowSystem::Shutdown();
+  }
+}
+
+void WindowBaseEcoreWl2::Initialize( PositionSize positionSize, Any surface, bool isTransparent )
+{
+  if( surface.Empty() == false )
+  {
+    // check we have a valid type
+    DALI_ASSERT_ALWAYS( ( surface.GetType() == typeid (Ecore_Wl2_Window *) ) && "Surface type is invalid" );
+
+    mEcoreWindow = AnyCast< Ecore_Wl2_Window* >( surface );
+  }
+  else
+  {
+    // we own the surface about to created
+    WindowSystem::Initialize();
+
+    mOwnSurface = true;
+    CreateWindow( positionSize );
+  }
+
+  mWlSurface = ecore_wl2_window_surface_get( mEcoreWindow );
+
+  SetTransparency( isTransparent );
+
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL2_EVENT_WINDOW_ICONIFY_STATE_CHANGE, EcoreEventWindowIconifyStateChanged, this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL2_EVENT_FOCUS_IN,                    EcoreEventWindowFocusIn,             this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL2_EVENT_FOCUS_OUT,                   EcoreEventWindowFocusOut,            this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL2_EVENT_OUTPUT_TRANSFORM,            EcoreEventOutputTransform,           this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL2_EVENT_IGNORE_OUTPUT_TRANSFORM,     EcoreEventIgnoreOutputTransform,     this ) );
+
+  // Register Rotate event
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL2_EVENT_WINDOW_ROTATE,               EcoreEventRotate,                    this ) );
+
+  // Register Configure event
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL2_EVENT_WINDOW_CONFIGURE,            EcoreEventConfigure,                 this ) );
+
+  // Register Touch events
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_MOUSE_BUTTON_DOWN,               EcoreEventMouseButtonDown,           this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_MOUSE_BUTTON_UP,                 EcoreEventMouseButtonUp,             this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_MOUSE_MOVE,                      EcoreEventMouseButtonMove,           this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_MOUSE_BUTTON_CANCEL,             EcoreEventMouseButtonCancel,         this ) );
+
+  // Register Mouse wheel events
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_MOUSE_WHEEL,                     EcoreEventMouseWheel,                this ) );
+
+  // Register Detent event
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_DETENT_ROTATE,                   EcoreEventDetentRotation,            this ) );
+
+  // Register Key events
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_KEY_DOWN,                        EcoreEventKeyDown,                   this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_KEY_UP,                          EcoreEventKeyUp,                     this ) );
+
+  // Register Selection event - clipboard selection
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL2_EVENT_DATA_SOURCE_SEND,            EcoreEventDataSend,                  this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL2_EVENT_SELECTION_DATA_READY,        EcoreEventDataReceive,               this ) );
+
+  // Register Effect Start/End event
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL2_EVENT_EFFECT_START,                EcoreEventEffectStart,               this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL2_EVENT_EFFECT_END,                  EcoreEventEffectEnd,                 this ) );
+
+  // Register Vconf notify - font name and size
+  vconf_notify_key_changed( DALI_VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_NAME, VconfNotifyFontNameChanged, this );
+  vconf_notify_key_changed( VCONFKEY_SETAPPL_ACCESSIBILITY_FONT_SIZE, VconfNotifyFontSizeChanged, this );
+
+  InitializeEcoreElDBus();
+
+  Ecore_Wl2_Display* display = ecore_wl2_connected_display_get( NULL );
+  mDisplay = ecore_wl2_display_get( display );
+
+  if( mDisplay )
+  {
+    wl_display* displayWrapper = static_cast< wl_display* >( wl_proxy_create_wrapper( mDisplay ) );
+    if( displayWrapper )
+    {
+      mEventQueue = wl_display_create_queue( mDisplay );
+      if( mEventQueue )
+      {
+        wl_proxy_set_queue( reinterpret_cast< wl_proxy* >( displayWrapper ), mEventQueue );
+
+        wl_registry* registry = wl_display_get_registry( displayWrapper );
+        wl_registry_add_listener( registry, &registryListener, this );
+      }
+
+      wl_proxy_wrapper_destroy( displayWrapper );
+    }
+  }
+
+  Ecore_Wl2_Input* ecoreWlInput = ecore_wl2_input_default_input_get( display );
+
+  if( ecoreWlInput )
+  {
+    mKeyMap = ecore_wl2_input_keymap_get( ecoreWlInput );
+
+    mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_WL2_EVENT_SEAT_KEYMAP_CHANGED, EcoreEventSeatKeymapChanged, this ) );
+  }
+
+  // get auxiliary hint
+  Eina_List* hints = ecore_wl2_window_aux_hints_supported_get( mEcoreWindow );
+  if( hints )
+  {
+    Eina_List* l = NULL;
+    char* hint = NULL;
+
+    for( l = hints, ( hint =  static_cast< char* >( eina_list_data_get(l) ) ); l; l = eina_list_next(l), ( hint = static_cast< char* >( eina_list_data_get(l) ) ) )
+    {
+      mSupportedAuxiliaryHints.push_back( hint );
+
+      DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::Initialize: %s\n", hint );
+    }
+  }
+}
+
+Eina_Bool WindowBaseEcoreWl2::OnIconifyStateChanged( void* data, int type, void* event )
+{
+  Ecore_Wl2_Event_Window_Iconify_State_Change* iconifyChangedEvent( static_cast< Ecore_Wl2_Event_Window_Iconify_State_Change* >( event ) );
+  Eina_Bool handled( ECORE_CALLBACK_PASS_ON );
+
+  if( iconifyChangedEvent->win == static_cast< unsigned int>( ecore_wl2_window_id_get( mEcoreWindow ) ) )
+  {
+    if( iconifyChangedEvent->iconified == EINA_TRUE )
+    {
+      mIconifyChangedSignal.Emit( true );
+    }
+    else
+    {
+      mIconifyChangedSignal.Emit( false );
+    }
+    handled = ECORE_CALLBACK_DONE;
+  }
+
+  return handled;
+}
+
+Eina_Bool WindowBaseEcoreWl2::OnFocusIn( void* data, int type, void* event )
+{
+  Ecore_Wl2_Event_Focus_In* focusInEvent( static_cast< Ecore_Wl2_Event_Focus_In* >( event ) );
+
+  if( focusInEvent->window == static_cast< unsigned int >( ecore_wl2_window_id_get( mEcoreWindow ) ) )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "Window EcoreEventWindowFocusIn\n" );
+
+    mFocusChangedSignal.Emit( true );
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+Eina_Bool WindowBaseEcoreWl2::OnFocusOut( void* data, int type, void* event )
+{
+  Ecore_Wl2_Event_Focus_Out* focusOutEvent( static_cast< Ecore_Wl2_Event_Focus_Out* >( event ) );
+
+  if( focusOutEvent->window == static_cast< unsigned int >( ecore_wl2_window_id_get( mEcoreWindow ) ) )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "Window EcoreEventWindowFocusOut\n" );
+
+    mFocusChangedSignal.Emit( false );
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+Eina_Bool WindowBaseEcoreWl2::OnOutputTransform( void* data, int type, void* event )
+{
+  Ecore_Wl2_Event_Output_Transform* transformEvent( static_cast< Ecore_Wl2_Event_Output_Transform* >( event ) );
+
+  if( transformEvent->output == ecore_wl2_window_output_find( mEcoreWindow ) )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "Window (%p) EcoreEventOutputTransform\n", mEcoreWindow );
+
+    mOutputTransformedSignal.Emit();
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+Eina_Bool WindowBaseEcoreWl2::OnIgnoreOutputTransform( void* data, int type, void* event )
+{
+  Ecore_Wl2_Event_Ignore_Output_Transform* ignoreTransformEvent( static_cast< Ecore_Wl2_Event_Ignore_Output_Transform* >( event ) );
+
+  if( ignoreTransformEvent->win == mEcoreWindow )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "Window (%p) EcoreEventIgnoreOutputTransform\n", mEcoreWindow );
+
+    mOutputTransformedSignal.Emit();
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+void WindowBaseEcoreWl2::OnRotation( void* data, int type, void* event )
+{
+  Ecore_Wl2_Event_Window_Rotation* ev( static_cast< Ecore_Wl2_Event_Window_Rotation* >( event ) );
+
+  if( ev->win == static_cast< unsigned int >( ecore_wl2_window_id_get( mEcoreWindow ) ) )
+  {
+    DALI_LOG_RELEASE_INFO( "WindowBaseEcoreWl2::OnRotation, angle: %d, width: %d, height: %d\n", ev->angle, ev->w, ev->h );
+
+    RotationEvent rotationEvent;
+    rotationEvent.angle = ev->angle;
+    rotationEvent.winResize = 0;
+
+    if( ev->angle == 0 || ev->angle == 180 )
+    {
+      rotationEvent.width = ev->w;
+      rotationEvent.height = ev->h;
+    }
+    else
+    {
+      rotationEvent.width = ev->h;
+      rotationEvent.height = ev->w;
+    }
+
+    mRotationSignal.Emit( rotationEvent );
+  }
+}
+
+void WindowBaseEcoreWl2::OnConfiguration( void* data, int type, void* event )
+{
+  Ecore_Wl2_Event_Window_Configure* ev( static_cast< Ecore_Wl2_Event_Window_Configure* >( event ) );
+
+  if( ev->win == static_cast< unsigned int >( ecore_wl2_window_id_get( mEcoreWindow ) ) )
+  {
+    // Note: To comply with the wayland protocol, Dali should make an ack_configure
+    // by calling ecore_wl2_window_commit
+    ecore_wl2_window_commit(mEcoreWindow, EINA_FALSE);
+  }
+}
+
+void WindowBaseEcoreWl2::OnMouseButtonDown( void* data, int type, void* event )
+{
+  Ecore_Event_Mouse_Button* touchEvent = static_cast< Ecore_Event_Mouse_Button* >( event );
+
+  if( touchEvent->window == static_cast< unsigned int >( ecore_wl2_window_id_get( mEcoreWindow ) ) )
+  {
+    Device::Class::Type deviceClass;
+    Device::Subclass::Type deviceSubclass;
+
+    GetDeviceClass( ecore_device_class_get( touchEvent->dev ), deviceClass );
+    GetDeviceSubclass( ecore_device_subclass_get( touchEvent->dev ), deviceSubclass );
+
+    PointState::Type state ( PointState::DOWN );
+
+    if( deviceClass != Device::Class::Type::MOUSE )
+    {
+      // Check if the buttons field is set and ensure it's the primary touch button.
+      // If this event was triggered by buttons other than the primary button (used for touch), then
+      // just send an interrupted event to Core.
+      if( touchEvent->buttons && (touchEvent->buttons != PRIMARY_TOUCH_BUTTON_ID ) )
+      {
+        state = PointState::INTERRUPTED;
+      }
+    }
+
+    Integration::Point point;
+    point.SetDeviceId( touchEvent->multi.device );
+    point.SetState( state );
+    point.SetScreenPosition( Vector2( touchEvent->x, touchEvent->y ) );
+    point.SetRadius( touchEvent->multi.radius, Vector2( touchEvent->multi.radius_x, touchEvent->multi.radius_y ) );
+    point.SetPressure( touchEvent->multi.pressure );
+    point.SetAngle( Degree( touchEvent->multi.angle ) );
+    point.SetDeviceClass( deviceClass );
+    point.SetDeviceSubclass( deviceSubclass );
+    point.SetMouseButton( static_cast< MouseButton::Type >( touchEvent->buttons) );
+
+    mTouchEventSignal.Emit( point, touchEvent->timestamp );
+  }
+}
+
+void WindowBaseEcoreWl2::OnMouseButtonUp( void* data, int type, void* event )
+{
+  Ecore_Event_Mouse_Button* touchEvent = static_cast< Ecore_Event_Mouse_Button* >( event );
+
+  if( touchEvent->window == static_cast< unsigned int >( ecore_wl2_window_id_get( mEcoreWindow ) ) )
+  {
+    Device::Class::Type deviceClass;
+    Device::Subclass::Type deviceSubclass;
+
+    GetDeviceClass( ecore_device_class_get( touchEvent->dev ), deviceClass );
+    GetDeviceSubclass( ecore_device_subclass_get( touchEvent->dev ), deviceSubclass );
+
+    Integration::Point point;
+    point.SetDeviceId( touchEvent->multi.device );
+    point.SetState( PointState::UP );
+    point.SetScreenPosition( Vector2( touchEvent->x, touchEvent->y ) );
+    point.SetRadius( touchEvent->multi.radius, Vector2( touchEvent->multi.radius_x, touchEvent->multi.radius_y ) );
+    point.SetPressure( touchEvent->multi.pressure );
+    point.SetAngle( Degree( touchEvent->multi.angle ) );
+    point.SetDeviceClass( deviceClass );
+    point.SetDeviceSubclass( deviceSubclass );
+    point.SetMouseButton( static_cast< MouseButton::Type >( touchEvent->buttons) );
+
+    mTouchEventSignal.Emit( point, touchEvent->timestamp );
+  }
+}
+
+void WindowBaseEcoreWl2::OnMouseButtonMove( void* data, int type, void* event )
+{
+  Ecore_Event_Mouse_Move* touchEvent = static_cast< Ecore_Event_Mouse_Move* >( event );
+
+  if( touchEvent->window == static_cast< unsigned int >( ecore_wl2_window_id_get( mEcoreWindow ) ) )
+  {
+    Device::Class::Type deviceClass;
+    Device::Subclass::Type deviceSubclass;
+
+    GetDeviceClass( ecore_device_class_get( touchEvent->dev ), deviceClass );
+    GetDeviceSubclass( ecore_device_subclass_get( touchEvent->dev ), deviceSubclass );
+
+    Integration::Point point;
+    point.SetDeviceId( touchEvent->multi.device );
+    point.SetState( PointState::MOTION );
+    point.SetScreenPosition( Vector2( touchEvent->x, touchEvent->y ) );
+    point.SetRadius( touchEvent->multi.radius, Vector2( touchEvent->multi.radius_x, touchEvent->multi.radius_y ) );
+    point.SetPressure( touchEvent->multi.pressure );
+    point.SetAngle( Degree( touchEvent->multi.angle ) );
+    point.SetDeviceClass( deviceClass );
+    point.SetDeviceSubclass( deviceSubclass );
+
+    mTouchEventSignal.Emit( point, touchEvent->timestamp );
+  }
+}
+
+void WindowBaseEcoreWl2::OnMouseButtonCancel( void* data, int type, void* event )
+{
+  Ecore_Event_Mouse_Button* touchEvent = static_cast< Ecore_Event_Mouse_Button* >( event );
+
+  if( touchEvent->window == static_cast< unsigned int >( ecore_wl2_window_id_get( mEcoreWindow ) ) )
+  {
+    Integration::Point point;
+    point.SetDeviceId( touchEvent->multi.device );
+    point.SetState( PointState::INTERRUPTED );
+    point.SetScreenPosition( Vector2( 0.0f, 0.0f ) );
+
+    mTouchEventSignal.Emit( point, touchEvent->timestamp );
+
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl::OnMouseButtonCancel\n" );
+  }
+}
+
+void WindowBaseEcoreWl2::OnMouseWheel( void* data, int type, void* event )
+{
+  Ecore_Event_Mouse_Wheel* mouseWheelEvent = static_cast< Ecore_Event_Mouse_Wheel* >( event );
+
+  if( mouseWheelEvent->window == static_cast< unsigned int >( ecore_wl2_window_id_get( mEcoreWindow ) ) )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl::OnMouseWheel: direction: %d, modifiers: %d, x: %d, y: %d, z: %d\n", mouseWheelEvent->direction, mouseWheelEvent->modifiers, mouseWheelEvent->x, mouseWheelEvent->y, mouseWheelEvent->z );
+
+    WheelEvent wheelEvent( WheelEvent::MOUSE_WHEEL, mouseWheelEvent->direction, mouseWheelEvent->modifiers, Vector2( mouseWheelEvent->x, mouseWheelEvent->y ), mouseWheelEvent->z, mouseWheelEvent->timestamp );
+
+    mWheelEventSignal.Emit( wheelEvent );
+  }
+}
+
+void WindowBaseEcoreWl2::OnDetentRotation( void* data, int type, void* event )
+{
+  Ecore_Event_Detent_Rotate* detentEvent = static_cast< Ecore_Event_Detent_Rotate* >( event );
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Concise, "WindowBaseEcoreWl::OnDetentRotation\n" );
+
+  int direction = ( detentEvent->direction == ECORE_DETENT_DIRECTION_CLOCKWISE ) ? 1 : -1;
+  int timeStamp = detentEvent->timestamp;
+
+  WheelEvent wheelEvent( WheelEvent::CUSTOM_WHEEL, direction, 0, Vector2( 0.0f, 0.0f ), 0, timeStamp );
+
+  mWheelEventSignal.Emit( wheelEvent );
+}
+
+void WindowBaseEcoreWl2::OnKeyDown( void* data, int type, void* event )
+{
+  Ecore_Event_Key* keyEvent = static_cast< Ecore_Event_Key* >( event );
+
+  if( keyEvent->window == static_cast< unsigned int >( ecore_wl2_window_id_get( mEcoreWindow ) ) )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl::OnKeyDown\n" );
+
+    std::string keyName( keyEvent->keyname );
+    std::string logicalKey( "" );
+    std::string keyString( "" );
+    std::string compose( "" );
+
+    // Ensure key compose string is not NULL as keys like SHIFT or arrow have a null string.
+    if( keyEvent->compose )
+    {
+      compose = keyEvent->compose;
+    }
+
+    // Ensure key symbol is not NULL as keys like SHIFT have a null string.
+    if( keyEvent->key )
+    {
+      logicalKey = keyEvent->key;
+    }
+
+    int keyCode = 0;
+    GetKeyCode( keyName, keyCode ); // Get key code dynamically.
+
+    if( keyCode == 0 )
+    {
+      // Get a specific key code from dali key look up table.
+      keyCode = KeyLookup::GetDaliKeyCode( keyEvent->keyname );
+    }
+
+    keyCode = ( keyCode == -1 ) ? 0 : keyCode;
+    int modifier( keyEvent->modifiers );
+    unsigned long time = keyEvent->timestamp;
+    if( !strncmp( keyEvent->keyname, "Keycode-", 8 ) )
+    {
+      keyCode = atoi( keyEvent->keyname + 8 );
+    }
+
+    // Ensure key event string is not NULL as keys like SHIFT have a null string.
+    if( keyEvent->string )
+    {
+      keyString = keyEvent->string;
+    }
+
+    std::string deviceName;
+    Device::Class::Type deviceClass;
+    Device::Subclass::Type deviceSubclass;
+
+    GetDeviceName( keyEvent, deviceName );
+    GetDeviceClass( ecore_device_class_get( keyEvent->dev ), deviceClass );
+    GetDeviceSubclass( ecore_device_subclass_get( keyEvent->dev ), deviceSubclass );
+
+    Integration::KeyEvent keyEvent( keyName, logicalKey, keyString, keyCode, modifier, time, Integration::KeyEvent::Down, compose, deviceName, deviceClass, deviceSubclass );
+
+     mKeyEventSignal.Emit( keyEvent );
+  }
+}
+
+void WindowBaseEcoreWl2::OnKeyUp( void* data, int type, void* event )
+{
+  Ecore_Event_Key* keyEvent = static_cast< Ecore_Event_Key* >( event );
+
+  if( keyEvent->window == static_cast< unsigned int >( ecore_wl2_window_id_get( mEcoreWindow ) ) )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl::OnKeyUp\n" );
+
+    std::string keyName( keyEvent->keyname );
+    std::string logicalKey( "" );
+    std::string keyString( "" );
+    std::string compose( "" );
+
+    // Ensure key compose string is not NULL as keys like SHIFT or arrow have a null string.
+    if( keyEvent->compose )
+    {
+      compose = keyEvent->compose;
+    }
+
+    // Ensure key symbol is not NULL as keys like SHIFT have a null string.
+    if( keyEvent->key )
+    {
+      logicalKey = keyEvent->key;
+    }
+
+    int keyCode = 0;
+    GetKeyCode( keyName, keyCode ); // Get key code dynamically.
+
+    if( keyCode == 0 )
+    {
+      // Get a specific key code from dali key look up table.
+      keyCode = KeyLookup::GetDaliKeyCode( keyEvent->keyname );
+    }
+
+    keyCode = ( keyCode == -1 ) ? 0 : keyCode;
+    int modifier( keyEvent->modifiers );
+    unsigned long time = keyEvent->timestamp;
+    if( !strncmp( keyEvent->keyname, "Keycode-", 8 ) )
+    {
+      keyCode = atoi( keyEvent->keyname + 8 );
+    }
+
+    // Ensure key event string is not NULL as keys like SHIFT have a null string.
+    if( keyEvent->string )
+    {
+      keyString = keyEvent->string;
+    }
+
+    std::string deviceName;
+    Device::Class::Type deviceClass;
+    Device::Subclass::Type deviceSubclass;
+
+    GetDeviceName( keyEvent, deviceName );
+    GetDeviceClass( ecore_device_class_get( keyEvent->dev ), deviceClass );
+    GetDeviceSubclass( ecore_device_subclass_get( keyEvent->dev ), deviceSubclass );
+
+    Integration::KeyEvent keyEvent( keyName, logicalKey, keyString, keyCode, modifier, time, Integration::KeyEvent::Up, compose, deviceName, deviceClass, deviceSubclass );
+
+     mKeyEventSignal.Emit( keyEvent );
+  }
+}
+
+void WindowBaseEcoreWl2::OnDataSend( void* data, int type, void* event )
+{
+  mSelectionDataSendSignal.Emit( event );
+}
+
+void WindowBaseEcoreWl2::OnDataReceive( void* data, int type, void* event )
+{
+  mSelectionDataReceivedSignal.Emit( event  );
+}
+
+void WindowBaseEcoreWl2::OnFontNameChanged()
+{
+  mStyleChangedSignal.Emit( StyleChange::DEFAULT_FONT_CHANGE );
+}
+
+void WindowBaseEcoreWl2::OnFontSizeChanged()
+{
+  mStyleChangedSignal.Emit( StyleChange::DEFAULT_FONT_SIZE_CHANGE );
+}
+
+void WindowBaseEcoreWl2::OnEcoreElDBusAccessibilityNotification( void* context, const Eldbus_Message* message )
+{
+#ifdef DALI_ELDBUS_AVAILABLE
+  AccessibilityInfo info;
+
+  // The string defines the arg-list's respective types.
+  if( !eldbus_message_arguments_get( message, "iiiiiiu", &info.gestureValue, &info.startX, &info.startY, &info.endX, &info.endY, &info.state, &info.eventTime ) )
+  {
+    DALI_LOG_ERROR( "OnEcoreElDBusAccessibilityNotification: Error getting arguments\n" );
+  }
+
+  mAccessibilitySignal.Emit( info );
+#endif
+}
+
+void WindowBaseEcoreWl2::OnTransitionEffectEvent( DevelWindow::EffectState state, DevelWindow::EffectType type )
+{
+  mTransitionEffectEventSignal.Emit( state, type );
+}
+
+void WindowBaseEcoreWl2::KeymapChanged(void *data, int type, void *event)
+{
+  Ecore_Wl2_Event_Seat_Keymap_Changed *changed = static_cast<Ecore_Wl2_Event_Seat_Keymap_Changed*>( event );
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::KeymapChanged, keymap id[ %d ]\n", changed->id );
+  Ecore_Wl2_Input* ecoreWlInput = ecore_wl2_input_default_input_get( changed->display );
+  if( ecoreWlInput )
+  {
+    mKeyMap = ecore_wl2_input_keymap_get( ecoreWlInput );
+  }
+}
+
+void WindowBaseEcoreWl2::RegistryGlobalCallback( void* data, struct wl_registry *registry, uint32_t name, const char* interface, uint32_t version )
+{
+  if( strcmp( interface, tizen_policy_interface.name ) == 0 )
+  {
+    uint32_t clientVersion = std::min( version, MAX_TIZEN_CLIENT_VERSION );
+
+    mTizenPolicy = static_cast< tizen_policy* >( wl_registry_bind( registry, name, &tizen_policy_interface, clientVersion ) );
+    if( !mTizenPolicy )
+    {
+      DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::RegistryGlobalCallback: wl_registry_bind(tizen_policy_interface) is failed.\n" );
+      return;
+    }
+
+    tizen_policy_add_listener( mTizenPolicy, &tizenPolicyListener, data );
+
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::RegistryGlobalCallback: tizen_policy_add_listener is called.\n" );
+  }
+  else if( strcmp( interface, tizen_display_policy_interface.name ) == 0 )
+  {
+    mTizenDisplayPolicy = static_cast< tizen_display_policy* >( wl_registry_bind( registry, name, &tizen_display_policy_interface, version ) );
+    if( !mTizenDisplayPolicy )
+    {
+      DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::RegistryGlobalCallback: wl_registry_bind(tizen_display_policy_interface) is failed.\n" );
+      return;
+    }
+
+    tizen_display_policy_add_listener( mTizenDisplayPolicy, &tizenDisplayPolicyListener, data );
+
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::RegistryGlobalCallback: tizen_display_policy_add_listener is called.\n" );
+  }
+}
+
+void WindowBaseEcoreWl2::RegistryGlobalCallbackRemove( void* data, struct wl_registry* registry, uint32_t id )
+{
+  mTizenPolicy = NULL;
+  mTizenDisplayPolicy = NULL;
+}
+
+void WindowBaseEcoreWl2::TizenPolicyNotificationChangeDone(void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, int32_t level, uint32_t state )
+{
+  mNotificationLevel = level;
+  mNotificationChangeState = state;
+  mNotificationLevelChangeDone = true;
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::TizenPolicyNotificationChangeDone: level = %d, state = %d\n", level, state );
+}
+
+void WindowBaseEcoreWl2::TizenPolicyScreenModeChangeDone( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, uint32_t mode, uint32_t state )
+{
+  mScreenOffMode = mode;
+  mScreenOffModeChangeState = state;
+  mScreenOffModeChangeDone = true;
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::TizenPolicyScreenModeChangeDone: mode = %d, state = %d\n", mode, state );
+}
+
+void WindowBaseEcoreWl2::DisplayPolicyBrightnessChangeDone( void* data, struct tizen_display_policy *displayPolicy, struct wl_surface* surface, int32_t brightness, uint32_t state )
+{
+  mBrightness = brightness;
+  mBrightnessChangeState = state;
+  mBrightnessChangeDone = true;
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreWl2::DisplayPolicyBrightnessChangeDone: brightness = %d, state = %d\n", brightness, state );
+}
+
+void WindowBaseEcoreWl2::GetKeyCode( std::string keyName, int32_t& keyCode )
+{
+  xkb_keysym_t sym = XKB_KEY_NoSymbol;
+  KeyCodeMap foundKeyCode;
+
+  sym = xkb_keysym_from_name( keyName.c_str(), XKB_KEYSYM_NO_FLAGS );
+  if( sym == XKB_KEY_NoSymbol )
+  {
+    DALI_LOG_ERROR( "Failed to get keysym in WindowBaseEcoreWl2\n" );
+    return;
+  }
+
+  foundKeyCode.keySym = sym;
+  foundKeyCode.isKeyCode = false;
+  xkb_keymap_key_for_each( mKeyMap, FindKeyCode, &foundKeyCode );
+  keyCode = static_cast< int32_t >( foundKeyCode.keyCode );
+}
+
+Any WindowBaseEcoreWl2::GetNativeWindow()
+{
+  return mEcoreWindow;
+}
+
+int WindowBaseEcoreWl2::GetNativeWindowId()
+{
+  return ecore_wl2_window_id_get( mEcoreWindow );
+}
+
+EGLNativeWindowType WindowBaseEcoreWl2::CreateEglWindow( int width, int height )
+{
+  mEglWindow = wl_egl_window_create( mWlSurface, width, height );
+
+  return static_cast< EGLNativeWindowType >( mEglWindow );
+}
+
+void WindowBaseEcoreWl2::DestroyEglWindow()
+{
+  if( mEglWindow != NULL )
+  {
+    wl_egl_window_destroy( mEglWindow );
+    mEglWindow = NULL;
+  }
+}
+
+void WindowBaseEcoreWl2::SetEglWindowRotation( int angle )
+{
+  wl_egl_window_tizen_rotation rotation;
+
+  switch( angle )
+  {
+    case 0:
+    {
+      rotation = WL_EGL_WINDOW_TIZEN_ROTATION_0 ;
+      break;
+    }
+    case 90:
+    {
+      rotation = WL_EGL_WINDOW_TIZEN_ROTATION_270;
+      break;
+    }
+    case 180:
+    {
+      rotation = WL_EGL_WINDOW_TIZEN_ROTATION_180;
+      break;
+    }
+    case 270:
+    {
+      rotation = WL_EGL_WINDOW_TIZEN_ROTATION_90;
+      break;
+    }
+    default:
+    {
+      rotation = WL_EGL_WINDOW_TIZEN_ROTATION_0 ;
+      break;
+    }
+  }
+
+  wl_egl_window_tizen_set_rotation( mEglWindow, rotation );
+}
+
+void WindowBaseEcoreWl2::SetEglWindowBufferTransform( int angle )
+{
+  wl_output_transform bufferTransform;
+
+  switch( angle )
+  {
+    case 0:
+    {
+      bufferTransform = WL_OUTPUT_TRANSFORM_NORMAL;
+      break;
+    }
+    case 90:
+    {
+      bufferTransform = WL_OUTPUT_TRANSFORM_90;
+      break;
+    }
+    case 180:
+    {
+      bufferTransform = WL_OUTPUT_TRANSFORM_180;
+      break;
+    }
+    case 270:
+    {
+      bufferTransform = WL_OUTPUT_TRANSFORM_270;
+      break;
+    }
+    default:
+    {
+      bufferTransform = WL_OUTPUT_TRANSFORM_NORMAL;
+      break;
+    }
+  }
+
+  wl_egl_window_tizen_set_buffer_transform( mEglWindow, bufferTransform );
+}
+
+void WindowBaseEcoreWl2::SetEglWindowTransform( int angle )
+{
+  wl_output_transform windowTransform;
+
+  switch( angle )
+  {
+    case 0:
+    {
+      windowTransform = WL_OUTPUT_TRANSFORM_NORMAL;
+      break;
+    }
+    case 90:
+    {
+      windowTransform = WL_OUTPUT_TRANSFORM_90;
+      break;
+    }
+    case 180:
+    {
+      windowTransform = WL_OUTPUT_TRANSFORM_180;
+      break;
+    }
+    case 270:
+    {
+      windowTransform = WL_OUTPUT_TRANSFORM_270;
+      break;
+    }
+    default:
+    {
+      windowTransform = WL_OUTPUT_TRANSFORM_NORMAL;
+      break;
+    }
+  }
+
+  wl_egl_window_tizen_set_window_transform( mEglWindow, windowTransform );
+}
+
+void WindowBaseEcoreWl2::ResizeEglWindow( PositionSize positionSize )
+{
+  wl_egl_window_resize( mEglWindow, positionSize.width, positionSize.height, positionSize.x, positionSize.y );
+
+  // Note: Both "Resize" and "MoveResize" cases can reach here, but only "MoveResize" needs to submit serial number
+  if( mMoveResizeSerial != mLastSubmittedMoveResizeSerial )
+  {
+    wl_egl_window_tizen_set_window_serial( mEglWindow, mMoveResizeSerial );
+    mLastSubmittedMoveResizeSerial = mMoveResizeSerial;
+  }
+}
+
+bool WindowBaseEcoreWl2::IsEglWindowRotationSupported()
+{
+  // Check capability
+  wl_egl_window_tizen_capability capability = static_cast< wl_egl_window_tizen_capability >( wl_egl_window_tizen_get_capabilities( mEglWindow ) );
+  if( capability == WL_EGL_WINDOW_TIZEN_CAPABILITY_ROTATION_SUPPORTED )
+  {
+    return true;
+  }
+
+  return false;
+}
+
+void WindowBaseEcoreWl2::Move( PositionSize positionSize )
+{
+  ecore_wl2_window_position_set( mEcoreWindow, positionSize.x, positionSize.y );
+}
+
+void WindowBaseEcoreWl2::Resize( PositionSize positionSize )
+{
+  ecore_wl2_window_geometry_set( mEcoreWindow, positionSize.x, positionSize.y, positionSize.width, positionSize.height );
+}
+
+void WindowBaseEcoreWl2::MoveResize( PositionSize positionSize )
+{
+  ecore_wl2_window_sync_geometry_set( mEcoreWindow, ++mMoveResizeSerial, positionSize.x, positionSize.y, positionSize.width, positionSize.height );
+}
+
+void WindowBaseEcoreWl2::SetClass( const std::string& name, const std::string& className )
+{
+  ecore_wl2_window_title_set( mEcoreWindow, name.c_str() );
+  ecore_wl2_window_class_set( mEcoreWindow, className.c_str() );
+}
+
+void WindowBaseEcoreWl2::Raise()
+{
+  // Use ecore_wl2_window_activate to prevent the window shown without rendering
+  ecore_wl2_window_activate( mEcoreWindow );
+}
+
+void WindowBaseEcoreWl2::Lower()
+{
+  ecore_wl2_window_lower( mEcoreWindow );
+}
+
+void WindowBaseEcoreWl2::Activate()
+{
+  ecore_wl2_window_activate( mEcoreWindow );
+}
+
+void WindowBaseEcoreWl2::SetAvailableAnlges( const std::vector< int >& angles )
+{
+  int rotations[4] = { 0 };
+  DALI_LOG_RELEASE_INFO( "WindowBaseEcoreWl2::SetAvailableAnlges, angle's count: %d, angles\n", angles.size() );
+  for( std::size_t i = 0; i < angles.size(); ++i )
+  {
+    rotations[i] = static_cast< int >( angles[i] );
+    DALI_LOG_RELEASE_INFO( "%d ", rotations[i] );
+  }
+  ecore_wl2_window_available_rotations_set( mEcoreWindow, rotations, angles.size() );
+}
+
+void WindowBaseEcoreWl2::SetPreferredAngle( int angle )
+{
+  ecore_wl2_window_preferred_rotation_set( mEcoreWindow, angle );
+}
+
+void WindowBaseEcoreWl2::SetAcceptFocus( bool accept )
+{
+  ecore_wl2_window_focus_skip_set( mEcoreWindow, !accept );
+}
+
+void WindowBaseEcoreWl2::Show()
+{
+  ecore_wl2_window_show( mEcoreWindow );
+}
+
+void WindowBaseEcoreWl2::Hide()
+{
+  ecore_wl2_window_hide( mEcoreWindow );
+}
+
+unsigned int WindowBaseEcoreWl2::GetSupportedAuxiliaryHintCount() const
+{
+  return mSupportedAuxiliaryHints.size();
+}
+
+std::string WindowBaseEcoreWl2::GetSupportedAuxiliaryHint( unsigned int index ) const
+{
+  if( index >= GetSupportedAuxiliaryHintCount() )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::GetSupportedAuxiliaryHint: Invalid index! [%d]\n", index );
+  }
+
+  return mSupportedAuxiliaryHints[index];
+}
+
+unsigned int WindowBaseEcoreWl2::AddAuxiliaryHint( const std::string& hint, const std::string& value )
+{
+  bool supported = false;
+
+  // Check if the hint is suppported
+  for( std::vector< std::string >::iterator iter = mSupportedAuxiliaryHints.begin(); iter != mSupportedAuxiliaryHints.end(); ++iter )
+  {
+    if( *iter == hint )
+    {
+      supported = true;
+      break;
+    }
+  }
+
+  if( !supported )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Concise, "WindowBaseEcoreWl2::AddAuxiliaryHint: Not supported auxiliary hint [%s]\n", hint.c_str() );
+    return 0;
+  }
+
+  // Check if the hint is already added
+  for( unsigned int i = 0; i < mAuxiliaryHints.size(); i++ )
+  {
+    if( mAuxiliaryHints[i].first == hint )
+    {
+      // Just change the value
+      mAuxiliaryHints[i].second = value;
+
+      DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::AddAuxiliaryHint: Change! hint = %s, value = %s, id = %d\n", hint.c_str(), value.c_str(), i + 1 );
+
+      return i + 1;   // id is index + 1
+    }
+  }
+
+  // Add the hint
+  mAuxiliaryHints.push_back( std::pair< std::string, std::string >( hint, value ) );
+
+  unsigned int id = mAuxiliaryHints.size();
+
+  ecore_wl2_window_aux_hint_add( mEcoreWindow, static_cast< int >( id ), hint.c_str(), value.c_str() );
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::AddAuxiliaryHint: hint = %s, value = %s, id = %d\n", hint.c_str(), value.c_str(), id );
+
+  return id;
+}
+
+bool WindowBaseEcoreWl2::RemoveAuxiliaryHint( unsigned int id )
+{
+  if( id == 0 || id > mAuxiliaryHints.size() )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Concise, "WindowBaseEcoreWl2::RemoveAuxiliaryHint: Invalid id [%d]\n", id );
+    return false;
+  }
+
+  mAuxiliaryHints[id - 1].second = std::string();
+
+  ecore_wl2_window_aux_hint_del( mEcoreWindow, static_cast< int >( id ) );
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::RemoveAuxiliaryHint: id = %d, hint = %s\n", id, mAuxiliaryHints[id - 1].first.c_str() );
+
+  return true;
+}
+
+bool WindowBaseEcoreWl2::SetAuxiliaryHintValue( unsigned int id, const std::string& value )
+{
+  if( id == 0 || id > mAuxiliaryHints.size() )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Concise, "WindowBaseEcoreWl2::SetAuxiliaryHintValue: Invalid id [%d]\n", id );
+    return false;
+  }
+
+  mAuxiliaryHints[id - 1].second = value;
+
+  ecore_wl2_window_aux_hint_change( mEcoreWindow, static_cast< int >( id ), value.c_str() );
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::SetAuxiliaryHintValue: id = %d, hint = %s, value = %s\n", id, mAuxiliaryHints[id - 1].first.c_str(), mAuxiliaryHints[id - 1].second.c_str() );
+
+  return true;
+}
+
+std::string WindowBaseEcoreWl2::GetAuxiliaryHintValue( unsigned int id ) const
+{
+  if( id == 0 || id > mAuxiliaryHints.size() )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Concise, "WindowBaseEcoreWl2::GetAuxiliaryHintValue: Invalid id [%d]\n", id );
+    return std::string();
+  }
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::GetAuxiliaryHintValue: id = %d, hint = %s, value = %s\n", id, mAuxiliaryHints[id - 1].first.c_str(), mAuxiliaryHints[id - 1].second.c_str() );
+
+  return mAuxiliaryHints[id - 1].second;
+}
+
+unsigned int WindowBaseEcoreWl2::GetAuxiliaryHintId( const std::string& hint ) const
+{
+  for( unsigned int i = 0; i < mAuxiliaryHints.size(); i++ )
+  {
+    if( mAuxiliaryHints[i].first == hint )
+    {
+      DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::GetAuxiliaryHintId: hint = %s, id = %d\n", hint.c_str(), i + 1 );
+      return i + 1;
+    }
+  }
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::GetAuxiliaryHintId: Invalid hint! [%s]\n", hint.c_str() );
+
+  return 0;
+}
+
+void WindowBaseEcoreWl2::SetInputRegion( const Rect< int >& inputRegion )
+{
+  ecore_wl2_window_input_region_set( mEcoreWindow, inputRegion.x, inputRegion.y, inputRegion.width, inputRegion.height );
+}
+
+void WindowBaseEcoreWl2::SetType( Dali::Window::Type type )
+{
+  Ecore_Wl2_Window_Type windowType;
+
+  switch( type )
+  {
+    case Dali::Window::NORMAL:
+    {
+      windowType = ECORE_WL2_WINDOW_TYPE_TOPLEVEL;
+      break;
+    }
+    case Dali::Window::NOTIFICATION:
+    {
+      windowType = ECORE_WL2_WINDOW_TYPE_NOTIFICATION;
+      break;
+    }
+    case Dali::Window::UTILITY:
+    {
+      windowType = ECORE_WL2_WINDOW_TYPE_UTILITY;
+      break;
+    }
+    case Dali::Window::DIALOG:
+    {
+      windowType = ECORE_WL2_WINDOW_TYPE_DIALOG;
+      break;
+    }
+    default:
+    {
+      windowType = ECORE_WL2_WINDOW_TYPE_TOPLEVEL;
+      break;
+    }
+  }
+
+  ecore_wl2_window_type_set( mEcoreWindow, windowType );
+}
+
+bool WindowBaseEcoreWl2::SetNotificationLevel( Dali::Window::NotificationLevel::Type level )
+{
+  while( !mTizenPolicy )
+  {
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+  }
+
+  int notificationLevel;
+
+  switch( level )
+  {
+    case Dali::Window::NotificationLevel::NONE:
+    {
+      notificationLevel = TIZEN_POLICY_LEVEL_NONE;
+      break;
+    }
+    case Dali::Window::NotificationLevel::BASE:
+    {
+      notificationLevel = TIZEN_POLICY_LEVEL_DEFAULT;
+      break;
+    }
+    case Dali::Window::NotificationLevel::MEDIUM:
+    {
+      notificationLevel = TIZEN_POLICY_LEVEL_MEDIUM;
+      break;
+    }
+    case Dali::Window::NotificationLevel::HIGH:
+    {
+      notificationLevel = TIZEN_POLICY_LEVEL_HIGH;
+      break;
+    }
+    case Dali::Window::NotificationLevel::TOP:
+    {
+      notificationLevel = TIZEN_POLICY_LEVEL_TOP;
+      break;
+    }
+    default:
+    {
+      DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::SetNotificationLevel: invalid level [%d]\n", level );
+      notificationLevel = TIZEN_POLICY_LEVEL_DEFAULT;
+      break;
+    }
+  }
+
+  mNotificationLevelChangeDone = false;
+  mNotificationChangeState = TIZEN_POLICY_ERROR_STATE_NONE;
+
+  tizen_policy_set_notification_level( mTizenPolicy, ecore_wl2_window_surface_get( mEcoreWindow ), notificationLevel );
+
+  int count = 0;
+
+  while( !mNotificationLevelChangeDone && count < 3 )
+  {
+    ecore_wl2_display_flush( ecore_wl2_connected_display_get( NULL ) );
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+    count++;
+  }
+
+  if( !mNotificationLevelChangeDone )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::SetNotificationLevel: Level change is failed [%d, %d]\n", level, mNotificationChangeState );
+    return false;
+  }
+  else if( mNotificationChangeState == TIZEN_POLICY_ERROR_STATE_PERMISSION_DENIED )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::SetNotificationLevel: Permission denied! [%d]\n", level );
+    return false;
+  }
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::SetNotificationLevel: Level is changed [%d]\n", mNotificationLevel );
+
+  return true;
+}
+
+Dali::Window::NotificationLevel::Type WindowBaseEcoreWl2::GetNotificationLevel() const
+{
+  while( !mTizenPolicy )
+  {
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+  }
+
+  int count = 0;
+
+  while( !mNotificationLevelChangeDone && count < 3 )
+  {
+    ecore_wl2_display_flush( ecore_wl2_connected_display_get( NULL ) );
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+    count++;
+  }
+
+  if( !mNotificationLevelChangeDone )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::GetNotificationLevel: Error! [%d]\n", mNotificationChangeState );
+    return Dali::Window::NotificationLevel::NONE;
+  }
+
+  Dali::Window::NotificationLevel::Type level;
+
+  switch( mNotificationLevel )
+  {
+    case TIZEN_POLICY_LEVEL_NONE:
+    {
+      level = Dali::Window::NotificationLevel::NONE;
+      break;
+    }
+    case TIZEN_POLICY_LEVEL_DEFAULT:
+    {
+      level = Dali::Window::NotificationLevel::BASE;
+      break;
+    }
+    case TIZEN_POLICY_LEVEL_MEDIUM:
+    {
+      level = Dali::Window::NotificationLevel::MEDIUM;
+      break;
+    }
+    case TIZEN_POLICY_LEVEL_HIGH:
+    {
+      level = Dali::Window::NotificationLevel::HIGH;
+      break;
+    }
+    case TIZEN_POLICY_LEVEL_TOP:
+    {
+      level = Dali::Window::NotificationLevel::TOP;
+      break;
+    }
+    default:
+    {
+      DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::GetNotificationLevel: invalid level [%d]\n", mNotificationLevel );
+      level = Dali::Window::NotificationLevel::NONE;
+      break;
+    }
+  }
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::GetNotificationLevel: level [%d]\n", mNotificationLevel );
+
+  return level;
+}
+
+void WindowBaseEcoreWl2::SetOpaqueState( bool opaque )
+{
+  while( !mTizenPolicy )
+  {
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+  }
+
+  tizen_policy_set_opaque_state( mTizenPolicy, ecore_wl2_window_surface_get( mEcoreWindow ), ( opaque ? 1 : 0 ) );
+}
+
+bool WindowBaseEcoreWl2::SetScreenOffMode(Dali::Window::ScreenOffMode::Type screenOffMode)
+{
+  while( !mTizenPolicy )
+  {
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+  }
+
+  mScreenOffModeChangeDone = false;
+  mScreenOffModeChangeState = TIZEN_POLICY_ERROR_STATE_NONE;
+
+  unsigned int mode = 0;
+
+  switch( screenOffMode )
+  {
+    case Dali::Window::ScreenOffMode::TIMEOUT:
+    {
+      mode = 0;
+      break;
+    }
+    case Dali::Window::ScreenOffMode::NEVER:
+    {
+      mode = 1;
+      break;
+    }
+  }
+
+  tizen_policy_set_window_screen_mode( mTizenPolicy, ecore_wl2_window_surface_get( mEcoreWindow ), mode );
+
+  int count = 0;
+
+  while( !mScreenOffModeChangeDone && count < 3 )
+  {
+    ecore_wl2_display_flush( ecore_wl2_connected_display_get( NULL ) );
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+    count++;
+  }
+
+  if( !mScreenOffModeChangeDone )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::SetScreenOffMode: Screen mode change is failed [%d, %d]\n", screenOffMode, mScreenOffModeChangeState );
+    return false;
+  }
+  else if( mScreenOffModeChangeState == TIZEN_POLICY_ERROR_STATE_PERMISSION_DENIED )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::SetScreenOffMode: Permission denied! [%d]\n", screenOffMode );
+    return false;
+  }
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::SetScreenOffMode: Screen mode is changed [%d]\n", mScreenOffMode );
+
+  return true;
+}
+
+Dali::Window::ScreenOffMode::Type WindowBaseEcoreWl2::GetScreenOffMode() const
+{
+  while( !mTizenPolicy )
+  {
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+  }
+
+  int count = 0;
+
+  while( !mScreenOffModeChangeDone && count < 3 )
+  {
+    ecore_wl2_display_flush( ecore_wl2_connected_display_get( NULL ) );
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+    count++;
+  }
+
+  if( !mScreenOffModeChangeDone )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::GetScreenOffMode: Error! [%d]\n", mScreenOffModeChangeState );
+    return Dali::Window::ScreenOffMode::TIMEOUT;
+  }
+
+  Dali::Window::ScreenOffMode::Type screenMode = Dali::Window::ScreenOffMode::TIMEOUT;
+
+  switch( mScreenOffMode )
+  {
+    case 0:
+    {
+      screenMode = Dali::Window::ScreenOffMode::TIMEOUT;
+      break;
+    }
+    case 1:
+    {
+      screenMode = Dali::Window::ScreenOffMode::NEVER;
+      break;
+    }
+  }
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::GetScreenOffMode: screen mode [%d]\n", mScreenOffMode );
+
+  return screenMode;
+}
+
+bool WindowBaseEcoreWl2::SetBrightness( int brightness )
+{
+  while( !mTizenDisplayPolicy )
+  {
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+  }
+
+  mBrightnessChangeDone = false;
+  mBrightnessChangeState = TIZEN_POLICY_ERROR_STATE_NONE;
+
+  tizen_display_policy_set_window_brightness( mTizenDisplayPolicy, ecore_wl2_window_surface_get( mEcoreWindow ), brightness );
+
+  int count = 0;
+
+  while( !mBrightnessChangeDone && count < 3 )
+  {
+    ecore_wl2_display_flush( ecore_wl2_connected_display_get( NULL ) );
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+    count++;
+  }
+
+  if( !mBrightnessChangeDone )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::SetBrightness: Brightness change is failed [%d, %d]\n", brightness, mBrightnessChangeState );
+    return false;
+  }
+  else if( mBrightnessChangeState == TIZEN_POLICY_ERROR_STATE_PERMISSION_DENIED )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::SetBrightness: Permission denied! [%d]\n", brightness );
+    return false;
+  }
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::SetBrightness: Brightness is changed [%d]\n", mBrightness );
+
+  return true;
+}
+
+int WindowBaseEcoreWl2::GetBrightness() const
+{
+  while( !mTizenDisplayPolicy )
+  {
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+  }
+
+  int count = 0;
+
+  while( !mBrightnessChangeDone && count < 3 )
+  {
+    ecore_wl2_display_flush( ecore_wl2_connected_display_get( NULL ) );
+    wl_display_dispatch_queue( mDisplay, mEventQueue );
+    count++;
+  }
+
+  if( !mBrightnessChangeDone )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::GetBrightness: Error! [%d]\n", mBrightnessChangeState );
+    return 0;
+  }
+
+  DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Verbose, "WindowBaseEcoreWl2::GetBrightness: Brightness [%d]\n", mBrightness );
+
+  return mBrightness;
+}
+
+bool WindowBaseEcoreWl2::GrabKey( Dali::KEY key, KeyGrab::KeyGrabMode grabMode )
+{
+  Ecore_Wl2_Window_Keygrab_Mode mode;
+
+  switch( grabMode )
+  {
+    case KeyGrab::TOPMOST:
+    {
+      mode = ECORE_WL2_WINDOW_KEYGRAB_TOPMOST;
+      break;
+    }
+    case KeyGrab::SHARED:
+    {
+      mode = ECORE_WL2_WINDOW_KEYGRAB_SHARED;
+      break;
+    }
+    case KeyGrab::OVERRIDE_EXCLUSIVE:
+    {
+      mode = ECORE_WL2_WINDOW_KEYGRAB_OVERRIDE_EXCLUSIVE;
+      break;
+    }
+    case KeyGrab::EXCLUSIVE:
+    {
+      mode = ECORE_WL2_WINDOW_KEYGRAB_EXCLUSIVE;
+      break;
+    }
+    default:
+    {
+      return false;
+    }
+  }
+
+  return ecore_wl2_window_keygrab_set( mEcoreWindow, KeyLookup::GetKeyName( key ), 0, 0, 0, mode );
+}
+
+bool WindowBaseEcoreWl2::UngrabKey( Dali::KEY key )
+{
+  return ecore_wl2_window_keygrab_unset( mEcoreWindow, KeyLookup::GetKeyName( key ), 0, 0 );
+}
+
+bool WindowBaseEcoreWl2::GrabKeyList( const Dali::Vector< Dali::KEY >& key, const Dali::Vector< KeyGrab::KeyGrabMode >& grabMode, Dali::Vector< bool >& result )
+{
+  int keyCount = key.Count();
+  int keyGrabModeCount = grabMode.Count();
+
+  if( keyCount != keyGrabModeCount || keyCount == 0 )
+  {
+    return false;
+  }
+
+  eina_init();
+
+  Eina_List* keyList = NULL;
+  Ecore_Wl2_Window_Keygrab_Info* info = new Ecore_Wl2_Window_Keygrab_Info[keyCount];
+
+  for( int index = 0; index < keyCount; ++index )
+  {
+    info[index].key = const_cast< char* >( KeyLookup::GetKeyName( key[index] ) );
+
+    switch( grabMode[index] )
+    {
+      case KeyGrab::TOPMOST:
+      {
+        info[index].mode = ECORE_WL2_WINDOW_KEYGRAB_TOPMOST;
+        break;
+      }
+      case KeyGrab::SHARED:
+      {
+        info[index].mode = ECORE_WL2_WINDOW_KEYGRAB_SHARED;
+        break;
+      }
+      case KeyGrab::OVERRIDE_EXCLUSIVE:
+      {
+        info[index].mode = ECORE_WL2_WINDOW_KEYGRAB_OVERRIDE_EXCLUSIVE;
+        break;
+      }
+      case KeyGrab::EXCLUSIVE:
+      {
+        info[index].mode = ECORE_WL2_WINDOW_KEYGRAB_EXCLUSIVE;
+        break;
+      }
+      default:
+      {
+        info[index].mode = ECORE_WL2_WINDOW_KEYGRAB_UNKNOWN;
+        break;
+      }
+    }
+
+    keyList = eina_list_append( keyList, &info );
+  }
+
+  Eina_List* grabList = ecore_wl2_window_keygrab_list_set( mEcoreWindow, keyList );
+
+  result.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 )
+    {
+      int index = 0;
+      EINA_LIST_FOREACH( keyList, l, listData )
+      {
+        if( static_cast< Ecore_Wl2_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_Wl2_Window_Keygrab_Info* >( listData )->key ) == 0 )
+        {
+          result[index] = false;
+        }
+        ++index;
+      }
+    }
+  }
+
+  delete [] info;
+
+  eina_list_free( keyList );
+  eina_list_free( grabList );
+  eina_shutdown();
+
+  return true;
+}
+
+bool WindowBaseEcoreWl2::UngrabKeyList( const Dali::Vector< Dali::KEY >& key, Dali::Vector< bool >& result )
+{
+  int keyCount = key.Count();
+  if( keyCount == 0 )
+  {
+    return false;
+  }
+
+  eina_init();
+
+  Eina_List* keyList = NULL;
+  Ecore_Wl2_Window_Keygrab_Info* info = new Ecore_Wl2_Window_Keygrab_Info[keyCount];
+
+  for( int index = 0; index < keyCount; ++index )
+  {
+    info[index].key = const_cast< char* >( KeyLookup::GetKeyName( key[index] ) );
+    keyList = eina_list_append( keyList, &info );
+  }
+
+  Eina_List* ungrabList = ecore_wl2_window_keygrab_list_unset( mEcoreWindow, keyList );
+
+  result.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 )
+    {
+      int index = 0;
+      EINA_LIST_FOREACH( keyList, l, listData )
+      {
+        if( strcmp( static_cast< char* >( data ), static_cast< Ecore_Wl2_Window_Keygrab_Info* >( listData )->key ) == 0 )
+        {
+          result[index] = false;
+        }
+        ++index;
+      }
+    }
+  }
+
+  delete [] info;
+
+  eina_list_free( keyList );
+  eina_list_free( ungrabList );
+  eina_shutdown();
+
+  return true;
+}
+
+void WindowBaseEcoreWl2::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
+{
+  // calculate DPI
+  float xres, yres;
+
+  Ecore_Wl2_Output* output = ecore_wl2_window_output_find( mEcoreWindow );
+
+  // 1 inch = 25.4 millimeters
+  xres = ecore_wl2_output_dpi_get( output );
+  yres = ecore_wl2_output_dpi_get( output );
+
+  dpiHorizontal = int( xres + 0.5f );  // rounding
+  dpiVertical   = int( yres + 0.5f );
+}
+
+int WindowBaseEcoreWl2::GetScreenRotationAngle()
+{
+  int transform = 0;
+
+  if( ecore_wl2_window_ignore_output_transform_get( mEcoreWindow ) )
+  {
+    transform = 0;
+  }
+  else
+  {
+    transform = ecore_wl2_output_transform_get( ecore_wl2_window_output_find( mEcoreWindow ) );
+  }
+
+  return transform * 90;
+}
+
+void WindowBaseEcoreWl2::SetWindowRotationAngle( int degree )
+{
+  ecore_wl2_window_rotation_set( mEcoreWindow, degree );
+}
+
+void WindowBaseEcoreWl2::WindowRotationCompleted( int degree, int width, int height )
+{
+  ecore_wl2_window_rotation_change_done_send( mEcoreWindow, degree, width, height );
+}
+
+void WindowBaseEcoreWl2::SetTransparency( bool transparent )
+{
+  ecore_wl2_window_alpha_set( mEcoreWindow, transparent );
+}
+
+void WindowBaseEcoreWl2::InitializeEcoreElDBus()
+{
+#ifdef DALI_ELDBUS_AVAILABLE
+  Eldbus_Object* object;
+  Eldbus_Proxy* manager;
+
+  if( !( mSystemConnection = eldbus_connection_get( ELDBUS_CONNECTION_TYPE_SYSTEM ) ) )
+  {
+    DALI_LOG_ERROR( "Unable to get system bus\n" );
+  }
+
+  object = eldbus_object_get( mSystemConnection, BUS, PATH );
+  if( !object )
+  {
+    DALI_LOG_ERROR( "Getting object failed\n" );
+    return;
+  }
+
+  manager = eldbus_proxy_get( object, INTERFACE );
+  if( !manager )
+  {
+    DALI_LOG_ERROR( "Getting proxy failed\n" );
+    return;
+  }
+
+  if( !eldbus_proxy_signal_handler_add( manager, "GestureDetected", EcoreElDBusAccessibilityNotification, this ) )
+  {
+    DALI_LOG_ERROR( "No signal handler returned\n" );
+  }
+#endif
+}
+
+void WindowBaseEcoreWl2::CreateWindow( PositionSize positionSize )
+{
+  Ecore_Wl2_Display* display = ecore_wl2_display_connect( NULL );
+  if( !display )
+  {
+    DALI_ASSERT_ALWAYS( 0 && "Failed to get display" );
+  }
+
+  mEcoreWindow = ecore_wl2_window_new( display, NULL, positionSize.x, positionSize.y, positionSize.width, positionSize.height );
+
+  if ( mEcoreWindow == 0 )
+  {
+    DALI_ASSERT_ALWAYS( 0 && "Failed to create Wayland window" );
+  }
+
+  // Set default type
+  ecore_wl2_window_type_set( mEcoreWindow, ECORE_WL2_WINDOW_TYPE_TOPLEVEL );
+}
+
+void WindowBaseEcoreWl2::SetParent( WindowBase* parentWinBase )
+{
+  Ecore_Wl2_Window* ecoreParent = NULL;
+  if( parentWinBase )
+  {
+    WindowBaseEcoreWl2* winBaseEcore2 = static_cast<WindowBaseEcoreWl2*>( parentWinBase );
+    ecoreParent = winBaseEcore2->mEcoreWindow;
+  }
+  ecore_wl2_window_parent_set( mEcoreWindow, ecoreParent );
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#pragma GCC diagnostic pop
diff --git a/dali/internal/window-system/tizen-wayland/ecore-wl2/window-base-ecore-wl2.h b/dali/internal/window-system/tizen-wayland/ecore-wl2/window-base-ecore-wl2.h
new file mode 100644 (file)
index 0000000..c7a7240
--- /dev/null
@@ -0,0 +1,515 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_WINDOW_BASE_ECORE_WL2_H
+#define DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_WINDOW_BASE_ECORE_WL2_H
+
+/*
+ * Copyright (c) 2018 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 <dali/internal/window-system/common/window-base.h>
+
+// EXTERNAL HEADERS
+#include <Ecore.h>
+#include <Ecore_Wl2.h>
+#include <tizen-extension-client-protocol.h>
+#include <wayland-egl.h>
+#include <xkbcommon/xkbcommon.h>
+
+#ifdef DALI_ELDBUS_AVAILABLE
+#include <Eldbus.h>
+#endif
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class WindowRenderSurface;
+class WindowRenderSurfaceEcoreWl2;
+
+/**
+ * WindowBaseEcoreWl2 class provides an WindowBase Ecore-Wayland2 implementation.
+ */
+class WindowBaseEcoreWl2 : public WindowBase
+{
+public:
+
+  /**
+   * @brief Constructor
+   */
+  WindowBaseEcoreWl2( PositionSize positionSize, Any surface, bool isTransparent );
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~WindowBaseEcoreWl2();
+
+public:
+
+  /**
+   * @brief Called when the window iconify state is changed.
+   */
+  Eina_Bool OnIconifyStateChanged( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the window gains focus.
+   */
+  Eina_Bool OnFocusIn( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the window loses focus.
+   */
+  Eina_Bool OnFocusOut( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the output is transformed.
+   */
+  Eina_Bool OnOutputTransform( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the output transform should be ignored.
+   */
+  Eina_Bool OnIgnoreOutputTransform( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a rotation event is recevied.
+   */
+  void OnRotation( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a configure event is recevied.
+   */
+  void OnConfiguration( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a touch down is received.
+   */
+  void OnMouseButtonDown( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a touch up is received.
+   */
+  void OnMouseButtonUp( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a touch motion is received.
+   */
+  void OnMouseButtonMove( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a touch is canceled.
+   */
+  void OnMouseButtonCancel( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a mouse wheel is received.
+   */
+  void OnMouseWheel( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a detent rotation event is recevied.
+   */
+  void OnDetentRotation( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a key down is received.
+   */
+  void OnKeyDown( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a key up is received.
+   */
+  void OnKeyUp( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the source window notifies us the content in clipboard is selected.
+   */
+  void OnDataSend( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the source window sends us about the selected content.
+   */
+  void OnDataReceive( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a font name is changed.
+   */
+  void OnFontNameChanged();
+
+  /**
+   * @brief Called when a font size is changed.
+   */
+  void OnFontSizeChanged();
+
+  /**
+   * @brief Called when a transition effect-start/end event is received.
+   */
+  void OnTransitionEffectEvent( DevelWindow::EffectState state, DevelWindow::EffectType type );
+
+#ifdef DALI_ELDBUS_AVAILABLE
+  /**
+   * @brief Called when Ecore ElDBus accessibility event is received.
+   */
+  void OnEcoreElDBusAccessibilityNotification( void* context, const Eldbus_Message* message );
+#endif
+
+  /**
+   * @brief Called when a keymap is changed.
+   */
+  void KeymapChanged(void *data, int type, void *event);
+
+  /**
+   * @brief RegistryGlobalCallback
+   */
+  void RegistryGlobalCallback( void* data, struct wl_registry *registry, uint32_t name, const char* interface, uint32_t version );
+
+  /**
+   * @brief RegistryGlobalCallbackRemove
+   */
+  void RegistryGlobalCallbackRemove( void* data, struct wl_registry* registry, uint32_t id );
+
+  /**
+   * @brief TizenPolicyNotificationChangeDone
+   */
+  void TizenPolicyNotificationChangeDone(void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, int32_t level, uint32_t state );
+
+  /**
+   * @brief TizenPolicyScreenModeChangeDone
+   */
+  void TizenPolicyScreenModeChangeDone( void* data, struct tizen_policy* tizenPolicy, struct wl_surface* surface, uint32_t mode, uint32_t state );
+
+  /**
+   * @brief DisplayPolicyBrightnessChangeDone
+   */
+  void DisplayPolicyBrightnessChangeDone( void* data, struct tizen_display_policy *displayPolicy, struct wl_surface* surface, int32_t brightness, uint32_t state );
+
+
+  /**
+   * @brief Gets the key code by keyName.
+   */
+  void GetKeyCode( std::string keyName, int32_t& keyCode );
+
+public:
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindow()
+   */
+  virtual Any GetNativeWindow() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindowId()
+   */
+  virtual int GetNativeWindowId() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::CreateEglWindow()
+   */
+  virtual EGLNativeWindowType CreateEglWindow( int width, int height ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::DestroyEglWindow()
+   */
+  virtual void DestroyEglWindow() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetEglWindowRotation()
+   */
+  virtual void SetEglWindowRotation( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetEglWindowBufferTransform()
+   */
+  virtual void SetEglWindowBufferTransform( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetEglWindowTransform()
+   */
+  virtual void SetEglWindowTransform( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::ResizeEglWindow()
+   */
+  virtual void ResizeEglWindow( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::IsEglWindowRotationSupported()
+   */
+  virtual bool IsEglWindowRotationSupported() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Move()
+   */
+  virtual void Move( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Resize()
+   */
+  virtual void Resize( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::MoveResize()
+   */
+  virtual void MoveResize( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetClass()
+   */
+  virtual void SetClass( const std::string& name, const std::string& className ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Raise()
+   */
+  virtual void Raise() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Lower()
+   */
+  virtual void Lower() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Activate()
+   */
+  virtual void Activate() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetAvailableAnlges()
+   */
+  virtual void SetAvailableAnlges( const std::vector< int >& angles ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetPreferredAngle()
+   */
+  virtual void SetPreferredAngle( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetAcceptFocus()
+   */
+  virtual void SetAcceptFocus( bool accept ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Show()
+   */
+  virtual void Show() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Hide()
+   */
+  virtual void Hide() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetSupportedAuxiliaryHintCount()
+   */
+  virtual unsigned int GetSupportedAuxiliaryHintCount() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetSupportedAuxiliaryHint()
+   */
+  virtual std::string GetSupportedAuxiliaryHint( unsigned int index ) const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::AddAuxiliaryHint()
+   */
+  virtual unsigned int AddAuxiliaryHint( const std::string& hint, const std::string& value ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::RemoveAuxiliaryHint()
+   */
+  virtual bool RemoveAuxiliaryHint( unsigned int id ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetAuxiliaryHintValue()
+   */
+  virtual bool SetAuxiliaryHintValue( unsigned int id, const std::string& value ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetAuxiliaryHintValue()
+   */
+  virtual std::string GetAuxiliaryHintValue( unsigned int id ) const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetAuxiliaryHintId()
+   */
+  virtual unsigned int GetAuxiliaryHintId( const std::string& hint ) const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetInputRegion()
+   */
+  virtual void SetInputRegion( const Rect< int >& inputRegion ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetType()
+   */
+  virtual void SetType( Dali::Window::Type type ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetNotificationLevel()
+   */
+  virtual bool SetNotificationLevel( Dali::Window::NotificationLevel::Type level ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNotificationLevel()
+   */
+  virtual Dali::Window::NotificationLevel::Type GetNotificationLevel() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetOpaqueState()
+   */
+  virtual void SetOpaqueState( bool opaque ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetScreenOffMode()
+   */
+  virtual bool SetScreenOffMode(Dali::Window::ScreenOffMode::Type screenOffMode) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetScreenOffMode()
+   */
+  virtual Dali::Window::ScreenOffMode::Type GetScreenOffMode() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetBrightness()
+   */
+  virtual bool SetBrightness( int brightness ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetBrightness()
+   */
+  virtual int GetBrightness() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GrabKey()
+   */
+  virtual bool GrabKey( Dali::KEY key, KeyGrab::KeyGrabMode grabMode ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::UngrabKey()
+   */
+  virtual bool UngrabKey( Dali::KEY key ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GrabKeyList()
+   */
+  virtual bool GrabKeyList( const Dali::Vector< Dali::KEY >& key, const Dali::Vector< KeyGrab::KeyGrabMode >& grabMode, Dali::Vector< bool >& result ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::UngrabKeyList()
+   */
+  virtual bool UngrabKeyList( const Dali::Vector< Dali::KEY >& key, Dali::Vector< bool >& result ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetDpi()
+   */
+  virtual void GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetScreenRotationAngle()
+   */
+  virtual int GetScreenRotationAngle() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetWindowRotationAngle()
+   */
+  virtual void SetWindowRotationAngle( int degree ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::WindowRotationCompleted()
+   */
+  virtual void WindowRotationCompleted( int degree, int width, int height ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetTransparency()
+   */
+  virtual void SetTransparency( bool transparent ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetParent()
+   */
+  virtual void SetParent( WindowBase* parentWinBase ) override;
+
+private:
+
+  /**
+   * Second stage initialization
+   */
+  void Initialize( PositionSize positionSize, Any surface, bool isTransparent );
+
+  /**
+   * Initialize Ecore ElDBus
+   */
+  void InitializeEcoreElDBus();
+
+  /**
+   * @brief Create window
+   */
+  void CreateWindow( PositionSize positionSize );
+
+protected:
+
+  // Undefined
+  WindowBaseEcoreWl2(const WindowBaseEcoreWl2&) = delete;
+
+  // Undefined
+  WindowBaseEcoreWl2& operator=(const WindowBaseEcoreWl2& rhs) = delete;
+
+private:
+
+  typedef std::vector< std::pair< std::string, std::string > > AuxiliaryHints;
+
+  Dali::Vector< Ecore_Event_Handler* > mEcoreEventHandler;
+
+  Ecore_Wl2_Window*                    mEcoreWindow;
+  wl_surface*                          mWlSurface;
+  wl_egl_window*                       mEglWindow;
+  wl_display*                          mDisplay;
+  wl_event_queue*                      mEventQueue;
+  tizen_policy*                        mTizenPolicy;
+  tizen_display_policy*                mTizenDisplayPolicy;
+  xkb_keymap*                          mKeyMap;
+
+  std::vector< std::string >           mSupportedAuxiliaryHints;
+  AuxiliaryHints                       mAuxiliaryHints;
+
+  int                                  mNotificationLevel;
+  uint32_t                             mNotificationChangeState;
+  bool                                 mNotificationLevelChangeDone;
+
+  int                                  mScreenOffMode;
+  uint32_t                             mScreenOffModeChangeState;
+  bool                                 mScreenOffModeChangeDone;
+
+  int                                  mBrightness;
+  uint32_t                             mBrightnessChangeState;
+  bool                                 mBrightnessChangeDone;
+
+  bool                                 mOwnSurface;
+
+  volatile uint32_t                    mMoveResizeSerial;
+  uint32_t                             mLastSubmittedMoveResizeSerial;
+
+#ifdef DALI_ELDBUS_AVAILABLE
+  Eldbus_Connection*                   mSystemConnection;
+#endif // DALI_ELDBUS_AVAILABLE
+};
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_WINDOW_BASE_ECORE_WL2_H
diff --git a/dali/internal/window-system/tizen-wayland/ecore-wl2/window-factory-ecore-wl2.cpp b/dali/internal/window-system/tizen-wayland/ecore-wl2/window-factory-ecore-wl2.cpp
new file mode 100644 (file)
index 0000000..ab72e47
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/tizen-wayland/ecore-wl2/window-factory-ecore-wl2.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/window-system/tizen-wayland/ecore-wl2/window-base-ecore-wl2.h>
+#include <dali/internal/window-system/common/display-utils.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+std::unique_ptr< WindowBase > WindowFactoryEcoreWl2::CreateWindowBase( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+{
+  return Utils::MakeUnique< WindowBaseEcoreWl2 >( positionSize, surface, isTransparent );
+}
+
+// this should be created from Window impl
+std::unique_ptr< WindowFactory > GetWindowFactory()
+{
+  // returns Window factory
+  return Utils::MakeUnique< WindowFactoryEcoreWl2 >();
+}
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
diff --git a/dali/internal/window-system/tizen-wayland/ecore-wl2/window-factory-ecore-wl2.h b/dali/internal/window-system/tizen-wayland/ecore-wl2/window-factory-ecore-wl2.h
new file mode 100644 (file)
index 0000000..f979c2c
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_WINDOW_FACTORY_ECORE_WL2_H
+#define DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_WINDOW_FACTORY_ECORE_WL2_H
+
+/*
+ * Copyright (c) 2018 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/internal/window-system/common/window-factory.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class WindowFactoryEcoreWl2 : public WindowFactory
+{
+public:
+  std::unique_ptr< WindowBase > CreateWindowBase( Dali::PositionSize positionSize, Any surface, bool isTransparent ) override;
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_WINDOW_FACTORY_ECORE_WL2_H
diff --git a/dali/internal/window-system/tizen-wayland/ecore-wl2/window-system-ecore-wl2.cpp b/dali/internal/window-system/tizen-wayland/ecore-wl2/window-system-ecore-wl2.cpp
new file mode 100644 (file)
index 0000000..4974602
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018 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 HEADERS
+#include <dali/internal/window-system/common/window-system.h>
+#include <dali/devel-api/adaptor-framework/keyboard.h>
+
+// EXTERNAL_HEADERS
+#include <Ecore_Wl2.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace WindowSystem
+{
+
+void Initialize()
+{
+  ecore_wl2_init();
+}
+
+void Shutdown()
+{
+  ecore_wl2_shutdown();
+}
+
+void GetScreenSize( int& width, int& height )
+{
+  Ecore_Wl2_Display* display = ecore_wl2_display_connect( NULL );
+  if( display )
+  {
+    ecore_wl2_display_screen_size_get( display, &width, &height );
+    DALI_ASSERT_ALWAYS((width>0) && "screen width is 0");
+    DALI_ASSERT_ALWAYS((height>0) && "screen height is 0");
+  }
+}
+
+bool SetKeyboardRepeatInfo( float rate, float delay )
+{
+  Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get( ecore_wl2_connected_display_get( NULL ) );
+  return ecore_wl2_input_keyboard_repeat_set( input, static_cast<double>( rate ), static_cast<double>( delay ) );
+}
+
+bool GetKeyboardRepeatInfo( float& rate, float& delay )
+{
+  Ecore_Wl2_Input* input = ecore_wl2_input_default_input_get( ecore_wl2_connected_display_get( NULL ) );
+  double rateVal, delayVal;
+  bool ret = ecore_wl2_input_keyboard_repeat_get( input, &rateVal, &delayVal );
+  rate = static_cast<float>( rateVal );
+  delay = static_cast<float>( delayVal );
+
+  return ret;
+}
+
+} // namespace WindowSystem
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#pragma GCC diagnostic pop
diff --git a/dali/internal/window-system/tizen-wayland/native-render-surface-ecore-wl.cpp b/dali/internal/window-system/tizen-wayland/native-render-surface-ecore-wl.cpp
new file mode 100644 (file)
index 0000000..3ef4f68
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/tizen-wayland/native-render-surface-ecore-wl.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/integration-api/debug.h>
+
+#ifdef ECORE_WAYLAND2
+#include <Ecore_Wl2.h>
+#else
+#include <Ecore_Wayland.h>
+#endif
+
+#include <tbm_bufmgr.h>
+#include <tbm_surface_internal.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/thread-synchronization-interface.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/adaptor/common/adaptor-internal-services.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+#include <dali/internal/graphics/gles/egl-implementation.h>
+#include <dali/internal/system/common/trigger-event.h>
+#include <dali/internal/window-system/common/display-connection.h>
+#include <dali/internal/window-system/common/window-system.h>
+
+namespace Dali
+{
+
+namespace
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gNativeSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_NATIVE_RENDER_SURFACE");
+#endif
+
+} // unnamed namespace
+
+NativeRenderSurfaceEcoreWl::NativeRenderSurfaceEcoreWl( Dali::PositionSize positionSize, bool isTransparent )
+: mPosition( positionSize ),
+  mRenderNotification( NULL ),
+  mGraphics( NULL ),
+  mEGL( nullptr ),
+  mEGLSurface( nullptr ),
+  mEGLContext( nullptr ),
+  mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
+  mTbmFormat( isTransparent ? TBM_FORMAT_ARGB8888 : TBM_FORMAT_RGB888 ),
+  mOwnSurface( false ),
+  mDrawableCompleted( false ),
+  mTbmQueue( NULL ),
+  mConsumeSurface( NULL ),
+  mThreadSynchronization( NULL )
+{
+  Dali::Internal::Adaptor::WindowSystem::Initialize();
+
+  CreateNativeRenderable();
+  setenv( "EGL_PLATFORM", "tbm", 1 );
+}
+
+NativeRenderSurfaceEcoreWl::~NativeRenderSurfaceEcoreWl()
+{
+  if ( mEGLSurface )
+  {
+    DestroySurface();
+  }
+
+  // release the surface if we own one
+  if( mOwnSurface )
+  {
+    ReleaseDrawable();
+
+    if( mTbmQueue )
+    {
+      tbm_surface_queue_destroy( mTbmQueue );
+    }
+
+    DALI_LOG_INFO( gNativeSurfaceLogFilter, Debug::General, "Own tbm surface queue destroy\n" );
+  }
+
+  Dali::Internal::Adaptor::WindowSystem::Shutdown();
+}
+
+Any NativeRenderSurfaceEcoreWl::GetDrawable()
+{
+  return mConsumeSurface;
+}
+
+void NativeRenderSurfaceEcoreWl::SetRenderNotification( TriggerEventInterface* renderNotification )
+{
+  mRenderNotification = renderNotification;
+}
+
+void NativeRenderSurfaceEcoreWl::WaitUntilSurfaceReplaced()
+{
+  ConditionalWait::ScopedLock lock( mTbmSurfaceCondition );
+  while( !mDrawableCompleted )
+  {
+    mTbmSurfaceCondition.Wait( lock );
+  }
+
+  mDrawableCompleted = false;
+}
+
+PositionSize NativeRenderSurfaceEcoreWl::GetPositionSize() const
+{
+  return mPosition;
+}
+
+void NativeRenderSurfaceEcoreWl::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
+{
+  // calculate DPI
+  float xres, yres;
+
+  // 1 inch = 25.4 millimeters
+#ifdef ECORE_WAYLAND2
+  // TODO: Application should set dpi value in wayland2
+  xres = 96;
+  yres = 96;
+#else
+  xres = ecore_wl_dpi_get();
+  yres = ecore_wl_dpi_get();
+#endif
+
+  dpiHorizontal = int( xres + 0.5f );  // rounding
+  dpiVertical   = int( yres + 0.5f );
+}
+
+void NativeRenderSurfaceEcoreWl::InitializeGraphics()
+{
+  DALI_LOG_TRACE_METHOD( gNativeSurfaceLogFilter );
+  unsetenv( "EGL_PLATFORM" );
+
+  mGraphics = &mAdaptor->GetGraphicsInterface();
+  auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
+
+  mEGL = &eglGraphics->GetEglInterface();
+
+  if ( mEGLContext == NULL )
+  {
+    // Create the OpenGL context for this window
+    Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
+    eglImpl.CreateWindowContext( mEGLContext );
+
+    // Create the OpenGL surface
+    CreateSurface();
+  }
+}
+
+void NativeRenderSurfaceEcoreWl::CreateSurface()
+{
+  DALI_LOG_TRACE_METHOD( gNativeSurfaceLogFilter );
+
+  auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
+  Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+
+  mEGLSurface = eglImpl.CreateSurfaceWindow( reinterpret_cast< EGLNativeWindowType >( mTbmQueue ), mColorDepth );
+}
+
+void NativeRenderSurfaceEcoreWl::DestroySurface()
+{
+  DALI_LOG_TRACE_METHOD( gNativeSurfaceLogFilter );
+
+  auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
+  Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+
+  eglImpl.DestroySurface( mEGLSurface );
+}
+
+bool NativeRenderSurfaceEcoreWl::ReplaceGraphicsSurface()
+{
+  DALI_LOG_TRACE_METHOD( gNativeSurfaceLogFilter );
+
+  if( !mTbmQueue )
+  {
+    return false;
+  }
+
+  auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
+  Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+
+  return eglImpl.ReplaceSurfaceWindow( reinterpret_cast< EGLNativeWindowType >( mTbmQueue ), mEGLSurface, mEGLContext );
+}
+
+void NativeRenderSurfaceEcoreWl::MoveResize( Dali::PositionSize positionSize )
+{
+  tbm_surface_queue_error_e error = TBM_SURFACE_QUEUE_ERROR_NONE;
+
+  error = tbm_surface_queue_reset( mTbmQueue, positionSize.width, positionSize.height, mTbmFormat );
+
+  if( error != TBM_SURFACE_QUEUE_ERROR_NONE )
+  {
+    DALI_LOG_ERROR( "Failed to resize tbm_surface_queue" );
+  }
+
+  mPosition = positionSize;
+}
+
+void NativeRenderSurfaceEcoreWl::StartRender()
+{
+}
+
+bool NativeRenderSurfaceEcoreWl::PreRender( bool )
+{
+  // nothing to do for pixmaps
+  return true;
+}
+
+void NativeRenderSurfaceEcoreWl::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface )
+{
+  auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
+  if ( eglGraphics )
+  {
+    Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+
+    eglImpl.SwapBuffers( mEGLSurface );
+  }
+
+  if( mThreadSynchronization )
+  {
+    mThreadSynchronization->PostRenderStarted();
+  }
+
+  if( tbm_surface_queue_can_acquire( mTbmQueue, 1 ) )
+  {
+    if( tbm_surface_queue_acquire( mTbmQueue, &mConsumeSurface ) != TBM_SURFACE_QUEUE_ERROR_NONE )
+    {
+      DALI_LOG_ERROR( "Failed to acquire a tbm_surface\n" );
+      return;
+    }
+  }
+
+  tbm_surface_internal_ref( mConsumeSurface );
+
+  if( replacingSurface )
+  {
+    ConditionalWait::ScopedLock lock( mTbmSurfaceCondition );
+    mDrawableCompleted = true;
+    mTbmSurfaceCondition.Notify( lock );
+  }
+
+ // create damage for client applications which wish to know the update timing
+  if( !replacingSurface && mRenderNotification )
+  {
+    // use notification trigger
+    // Tell the event-thread to render the tbm_surface
+    mRenderNotification->Trigger();
+  }
+
+  if( mThreadSynchronization )
+  {
+    // wait until the event-thread completed to use the tbm_surface
+    mThreadSynchronization->PostRenderWaitForCompletion();
+  }
+
+  // release the consumed surface after post render was completed
+  ReleaseDrawable();
+}
+
+void NativeRenderSurfaceEcoreWl::StopRender()
+{
+  ReleaseLock();
+}
+
+void NativeRenderSurfaceEcoreWl::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
+{
+  mThreadSynchronization = &threadSynchronization;
+}
+
+Dali::RenderSurfaceInterface::Type NativeRenderSurfaceEcoreWl::GetSurfaceType()
+{
+  return Dali::RenderSurfaceInterface::NATIVE_RENDER_SURFACE;
+}
+
+void NativeRenderSurfaceEcoreWl::MakeContextCurrent()
+{
+  if ( mEGL != nullptr )
+  {
+    mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
+  }
+}
+
+Integration::DepthBufferAvailable NativeRenderSurfaceEcoreWl::GetDepthBufferRequired()
+{
+  return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
+}
+
+Integration::StencilBufferAvailable NativeRenderSurfaceEcoreWl::GetStencilBufferRequired()
+{
+  return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
+}
+
+void NativeRenderSurfaceEcoreWl::ReleaseLock()
+{
+  if( mThreadSynchronization )
+  {
+    mThreadSynchronization->PostRenderComplete();
+  }
+}
+
+void NativeRenderSurfaceEcoreWl::CreateNativeRenderable()
+{
+  // check we're creating one with a valid size
+  DALI_ASSERT_ALWAYS( mPosition.width > 0 && mPosition.height > 0 && "tbm_surface size is invalid" );
+
+  mTbmQueue = tbm_surface_queue_create( 3, mPosition.width, mPosition.height, mTbmFormat, TBM_BO_DEFAULT );
+
+  if( mTbmQueue )
+  {
+    mOwnSurface = true;
+  }
+  else
+  {
+    mOwnSurface = false;
+  }
+}
+
+void NativeRenderSurfaceEcoreWl::ReleaseDrawable()
+{
+  if( mConsumeSurface )
+  {
+    tbm_surface_internal_unref( mConsumeSurface );
+
+    if( tbm_surface_internal_is_valid( mConsumeSurface ) )
+    {
+      tbm_surface_queue_release( mTbmQueue, mConsumeSurface );
+    }
+    mConsumeSurface = NULL;
+  }
+}
+
+} // namespace Dali
diff --git a/dali/internal/window-system/tizen-wayland/native-render-surface-ecore-wl.h b/dali/internal/window-system/tizen-wayland/native-render-surface-ecore-wl.h
new file mode 100644 (file)
index 0000000..e3a33ba
--- /dev/null
@@ -0,0 +1,195 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_NATIVE_SURFACE_ECORE_WL_H
+#define DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_NATIVE_SURFACE_ECORE_WL_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <tbm_surface.h>
+#include <tbm_surface_queue.h>
+#include <dali/devel-api/threading/conditional-wait.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/integration-api/adaptor-framework/egl-interface.h>
+#include <dali/integration-api/adaptor-framework/native-render-surface.h>
+#include <dali/internal/graphics/common/graphics-interface.h>
+
+namespace Dali
+{
+
+class DisplayConnection;
+class EglInterface;
+
+/**
+ * Ecore Wayland Native implementation of render surface.
+ */
+class NativeRenderSurfaceEcoreWl : public Dali::NativeRenderSurface
+{
+public:
+
+  /**
+    * Uses an Wayland surface to render to.
+    * @param [in] positionSize the position and size of the surface
+    * @param [in] isTransparent if it is true, surface has 32 bit color depth, otherwise, 24 bit
+    */
+  NativeRenderSurfaceEcoreWl( Dali::PositionSize positionSize, bool isTransparent = false );
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~NativeRenderSurfaceEcoreWl();
+
+public: // from WindowRenderSurface
+
+  /**
+   * @copydoc Dali::NativeRenderSurface::GetSurface()
+   */
+  virtual Any GetDrawable() override;
+
+  /**
+   * @copydoc Dali::NativeRenderSurface::SetRenderNotification()
+   */
+  virtual void SetRenderNotification( TriggerEventInterface* renderNotification ) override;
+
+  /**
+   * @copydoc Dali::NativeRenderSurface::WaitUntilSurfaceReplaced()
+   */
+  virtual void WaitUntilSurfaceReplaced() override;
+
+public: // from Dali::RenderSurfaceInterface
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::GetPositionSize()
+   */
+  virtual PositionSize GetPositionSize() const override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::GetDpi()
+   */
+  virtual void GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical ) override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::InitializeGraphics()
+   */
+  virtual void InitializeGraphics() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::CreateSurface()
+   */
+  virtual void CreateSurface() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::DestroySurface()
+   */
+  virtual void DestroySurface() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::ReplaceGraphicsSurface()
+   */
+  virtual bool ReplaceGraphicsSurface() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::MoveResize()
+   */
+  virtual void MoveResize( Dali::PositionSize positionSize) override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::StartRender()
+   */
+  virtual void StartRender() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::PreRender()
+   */
+  virtual bool PreRender( bool resizingSurface ) override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::PostRender()
+   */
+  virtual void PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface );
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::StopRender()
+   */
+  virtual void StopRender() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::SetThreadSynchronization
+   */
+  virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::GetSurfaceType()
+   */
+  virtual Dali::RenderSurfaceInterface::Type GetSurfaceType() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::MakeContextCurrent()
+   */
+  virtual void MakeContextCurrent() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::GetDepthBufferRequired()
+   */
+  virtual Integration::DepthBufferAvailable GetDepthBufferRequired() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::GetStencilBufferRequired()
+   */
+  virtual Integration::StencilBufferAvailable GetStencilBufferRequired() override;
+
+private:
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::ReleaseLock()
+   */
+  virtual void ReleaseLock() override;
+
+  /**
+   * @copydoc Dali::NativeRenderSurface::CreateNativeRenderable()
+   */
+  virtual void CreateNativeRenderable() override;
+
+  /**
+   * @copydoc Dali::NativeRenderSurface::ReleaseDrawable()
+   */
+  virtual void ReleaseDrawable() override;
+
+private: // Data
+
+  PositionSize                           mPosition;
+  TriggerEventInterface*                 mRenderNotification;
+  Internal::Adaptor::GraphicsInterface*  mGraphics;                  ///< The graphics interface
+  EglInterface*                          mEGL;
+  EGLSurface                             mEGLSurface;
+  EGLContext                             mEGLContext;
+  ColorDepth                             mColorDepth;
+  tbm_format                             mTbmFormat;
+  bool                                   mOwnSurface;
+  bool                                   mDrawableCompleted;
+
+  tbm_surface_queue_h                    mTbmQueue;
+  tbm_surface_h                          mConsumeSurface;
+  ThreadSynchronizationInterface*        mThreadSynchronization;     ///< A pointer to the thread-synchronization
+  ConditionalWait                        mTbmSurfaceCondition;
+
+};
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_TIZENWAYLAND_NATIVE_SURFACE_ECORE_WL_H
diff --git a/dali/internal/window-system/ubuntu-x11/display-connection-factory-x.cpp b/dali/internal/window-system/ubuntu-x11/display-connection-factory-x.cpp
new file mode 100644 (file)
index 0000000..bf544f6
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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/internal/window-system/ubuntu-x11/display-connection-factory-x.h>
+#include <dali/internal/window-system/ubuntu-x11/display-connection-impl-x.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+std::unique_ptr<Dali::Internal::Adaptor::DisplayConnection> DisplayConnectionFactoryX::CreateDisplayConnection()
+{
+  return Utils::MakeUnique<DisplayConnectionX11>();
+}
+
+// this should be created from somewhere
+std::unique_ptr<DisplayConnectionFactory> GetDisplayConnectionFactory()
+{
+  // returns X display factory
+  return Utils::MakeUnique<DisplayConnectionFactoryX>();
+}
+
+}
+}
+}
diff --git a/dali/internal/window-system/ubuntu-x11/display-connection-factory-x.h b/dali/internal/window-system/ubuntu-x11/display-connection-factory-x.h
new file mode 100644 (file)
index 0000000..3e8e576
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_ECOREX_DISPLAY_CONNECTION_FACTORY_ECORE_X_H
+#define DALI_INTERNAL_WINDOWSYSTEM_ECOREX_DISPLAY_CONNECTION_FACTORY_ECORE_X_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/internal/window-system/common/display-connection-factory.h>
+#include <dali/internal/window-system/common/display-utils.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class DisplayConnectionFactoryX : public DisplayConnectionFactory
+{
+public:
+  std::unique_ptr<Dali::Internal::Adaptor::DisplayConnection> CreateDisplayConnection() override;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_ECOREX_DISPLAY_CONNECTION_FACTORY_ECORE_X_H
diff --git a/dali/internal/window-system/ubuntu-x11/display-connection-impl-x.cpp b/dali/internal/window-system/ubuntu-x11/display-connection-impl-x.cpp
new file mode 100644 (file)
index 0000000..78c3fc0
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/ubuntu-x11/display-connection-impl-x.h>
+
+// EXTERNAL_HEADERS
+#include <dali/internal/system/linux/dali-ecore-x.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/window-system/ubuntu-x11/pixmap-render-surface-ecore-x.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+DisplayConnection* DisplayConnectionX11::New()
+{
+  //DisplayConnection* pDisplayConnection(new DisplayConnection());
+
+  //return pDisplayConnection;
+  return nullptr;
+}
+
+DisplayConnectionX11::DisplayConnectionX11()
+: mGraphics( nullptr ),
+  mDisplay( nullptr )
+{
+}
+
+DisplayConnectionX11::~DisplayConnectionX11()
+{
+  if(mDisplay)
+  {
+    XCloseDisplay(mDisplay);
+  }
+}
+
+Any DisplayConnectionX11::GetDisplay()
+{
+  return Any(mDisplay);
+}
+
+void DisplayConnectionX11::ConsumeEvents()
+{
+  // check events so that we can flush the queue and avoid any potential memory leaks in X
+  // looping if events remain
+  int events(0);
+  do
+  {
+    // Check if there are any events in the queue
+    events = XEventsQueued(mDisplay, QueuedAfterFlush);
+
+    if (events > 0)
+    {
+      // Just flush event to prevent memory leak from event queue as the events get built up in
+      // memory but are only deleted when we retrieve them
+      XEvent ev;
+      XNextEvent(mDisplay, &ev);
+    }
+  }
+  while (events > 0);
+}
+
+bool DisplayConnectionX11::InitializeGraphics()
+{
+  auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+  EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+
+  if (!eglImpl.InitializeGles(reinterpret_cast<EGLNativeDisplayType>(mDisplay)))
+  {
+    DALI_LOG_ERROR("Failed to initialize GLES.\n");
+    return false;
+  }
+
+  return true;
+}
+
+void DisplayConnectionX11::SetSurfaceType( Dali::RenderSurfaceInterface::Type type )
+{
+  if( type == Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE )
+  {
+    // Because of DDK issue, we need to use separated x display instead of ecore default display
+    mDisplay = XOpenDisplay(0);
+  }
+}
+
+void DisplayConnectionX11::SetGraphicsInterface( GraphicsInterface& graphics )
+{
+  mGraphics = &graphics;
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/window-system/ubuntu-x11/display-connection-impl-x.h b/dali/internal/window-system/ubuntu-x11/display-connection-impl-x.h
new file mode 100644 (file)
index 0000000..64ffb76
--- /dev/null
@@ -0,0 +1,122 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_ECOREX_DISPLAY_CONNECTION_IMPL_ECORE_X_H
+#define DALI_INTERNAL_WINDOWSYSTEM_ECOREX_DISPLAY_CONNECTION_IMPL_ECORE_X_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/window-system/common/display-connection-impl.h>
+#include <dali/internal/window-system/ubuntu-x11/ecore-x-types.h>
+
+namespace Dali
+{
+
+class DisplayConnection;
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+
+class Impl
+{
+public:
+
+  XDisplay*  mDisplay;        ///< X-display for rendering
+};
+
+
+/**
+ * DisplayConnection implementation
+ */
+class DisplayConnectionX11 : public Dali::Internal::Adaptor::DisplayConnection
+{
+public:
+
+  /**
+   * @brief Default constructor
+   */
+  DisplayConnectionX11();
+
+  /**
+   * @brief Create an initialized DisplayConnection.
+   *
+   * @return A handle to a newly allocated DisplayConnection resource.
+   */
+  static DisplayConnection* New();
+
+public:
+
+  /**
+   * @copydoc Dali::DisplayConnection::GetDisplay
+   */
+  Any GetDisplay();
+
+  /**
+   * @copydoc Dali::DisplayConnection::ConsumeEvents
+   */
+  void ConsumeEvents();
+
+  /**
+   * @copydoc Dali::DisplayConnection::InitializeGraphics
+   */
+  bool InitializeGraphics();
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::DisplayConnection::SetSurfaceType
+   */
+  void SetSurfaceType( Dali::RenderSurfaceInterface::Type type );
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::DisplayConnection::SetGraphicsInterface
+   */
+  void SetGraphicsInterface( GraphicsInterface& graphics );
+
+public:
+
+  /**
+   * Destructor
+   */
+  virtual ~DisplayConnectionX11();
+
+protected:
+
+  // Undefined
+  DisplayConnectionX11(const DisplayConnectionX11&) = delete;
+
+  // Undefined
+  DisplayConnectionX11& operator=(const DisplayConnectionX11& rhs) = delete;
+
+private:
+
+  GraphicsInterface* mGraphics; ///< The graphics interface
+
+public:
+
+  XDisplay*  mDisplay;        ///< X-display for rendering
+
+};
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_ECOREX_DISPLAY_CONNECTION_IMPL_ECORE_X_H
diff --git a/dali/internal/window-system/ubuntu-x11/ecore-x-types.h b/dali/internal/window-system/ubuntu-x11/ecore-x-types.h
new file mode 100644 (file)
index 0000000..e5bc6c9
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef DALI_X11_TYPES_H
+#define DALI_X11_TYPES_H
+
+/*
+ * Copyright (c) 2019 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 <X11/Xlib.h>
+
+namespace Dali
+{
+
+typedef ::Pixmap XPixmap;
+typedef ::Window XWindow;
+typedef ::Display XDisplay;
+typedef ::Screen XScreen;
+
+} // namespace Dali
+
+#endif /* DALI_X11_TYPES_H */
diff --git a/dali/internal/window-system/ubuntu-x11/pixmap-render-surface-ecore-x.cpp b/dali/internal/window-system/ubuntu-x11/pixmap-render-surface-ecore-x.cpp
new file mode 100644 (file)
index 0000000..2e93140
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/ubuntu-x11/pixmap-render-surface-ecore-x.h>
+
+// EXTERNAL INCLUDES
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/extensions/Xfixes.h> // for damage notify
+#include <X11/extensions/Xdamage.h> // for damage notify
+#include <dali/integration-api/gl-abstraction.h>
+#include <dali/integration-api/debug.h>
+#include <dali/devel-api/threading/mutex.h>
+
+// INTERNAL INCLUDES
+#include <dali/integration-api/adaptor-framework/thread-synchronization-interface.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+#include <dali/internal/adaptor/common/adaptor-internal-services.h>
+#include <dali/internal/graphics/gles/egl-graphics.h>
+#include <dali/internal/system/common/trigger-event.h>
+#include <dali/internal/window-system/common/display-connection.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gPixmapRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_PIXMAP_RENDER_SURFACE_ECORE_X");
+#endif
+
+namespace
+{
+static const int INITIAL_PRODUCE_BUFFER_INDEX = 0;
+static const int INITIAL_CONSUME_BUFFER_INDEX = 1;
+}
+
+PixmapRenderSurfaceEcoreX::PixmapRenderSurfaceEcoreX( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+: mGraphics( nullptr ),
+  mDisplayConnection( nullptr ),
+  mPosition( positionSize ),
+  mRenderNotification( NULL ),
+  mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
+  mOwnSurface( false ),
+  mProduceBufferIndex( INITIAL_PRODUCE_BUFFER_INDEX ),
+  mConsumeBufferIndex( INITIAL_CONSUME_BUFFER_INDEX ),
+  mX11Pixmaps(),
+  mEglSurfaces(),
+  mThreadSynchronization( nullptr ),
+  mPixmapCondition()
+{
+  for( int i = 0; i != BUFFER_COUNT; ++i )
+  {
+    mX11Pixmaps[i] = 0;
+    mEglSurfaces[i] = 0;
+  }
+
+  Initialize( surface );
+}
+
+PixmapRenderSurfaceEcoreX::~PixmapRenderSurfaceEcoreX()
+{
+  DestroySurface();
+
+  // release the surface if we own one
+  if( mOwnSurface )
+  {
+    for (int i = 0; i < BUFFER_COUNT; ++i)
+    {
+      Ecore_X_Pixmap pixmap = mX11Pixmaps[i];
+
+      // if we did create the pixmap, delete the pixmap
+      DALI_LOG_INFO( gPixmapRenderSurfaceLogFilter, Debug::General, "Own pixmap (%x) freed\n", pixmap );
+      ecore_x_pixmap_free( pixmap );
+    }
+  }
+}
+
+void PixmapRenderSurfaceEcoreX::Initialize( Any surface )
+{
+  // see if there is a surface in Any surface
+  unsigned int surfaceId  = GetSurfaceId( surface );
+
+  // if the surface is empty, create a new one.
+  if ( surfaceId == 0 )
+  {
+    // we own the surface about to created
+    mOwnSurface = true;
+    CreateRenderable();
+  }
+  else
+  {
+    // XLib should already be initialized so no point in calling XInitThreads
+    UseExistingRenderable( surfaceId );
+  }
+}
+
+Any PixmapRenderSurfaceEcoreX::GetSurface()
+{
+  Ecore_X_Pixmap pixmap = 0;
+  {
+    ConditionalWait::ScopedLock lock( mPixmapCondition );
+    pixmap = mX11Pixmaps[mProduceBufferIndex];
+  }
+
+  return Any( pixmap );
+}
+
+void PixmapRenderSurfaceEcoreX::SetRenderNotification(TriggerEventInterface* renderNotification)
+{
+  mRenderNotification = renderNotification;
+}
+
+PositionSize PixmapRenderSurfaceEcoreX::GetPositionSize() const
+{
+  return mPosition;
+}
+
+void PixmapRenderSurfaceEcoreX::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
+{
+  // calculate DPI
+  float xres, yres;
+
+  // 1 inch = 25.4 millimeters
+  xres = ecore_x_dpi_get();
+  yres = ecore_x_dpi_get();
+
+  dpiHorizontal = int( xres + 0.5f );  // rounding
+  dpiVertical   = int( yres + 0.5f );
+}
+
+void PixmapRenderSurfaceEcoreX::InitializeGraphics()
+{
+  mGraphics = &mAdaptor->GetGraphicsInterface();
+  mDisplayConnection = &mAdaptor->GetDisplayConnectionInterface();
+
+
+  auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+  Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+  eglImpl.ChooseConfig(false, mColorDepth);
+}
+
+void PixmapRenderSurfaceEcoreX::CreateSurface()
+{
+  DALI_LOG_TRACE_METHOD( gPixmapRenderSurfaceLogFilter );
+
+  auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+  Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+
+  for (int i = 0; i < BUFFER_COUNT; ++i)
+  {
+    // create the EGL surface
+    // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
+    XPixmap pixmap = static_cast<XPixmap>( mX11Pixmaps[i] );
+    mEglSurfaces[i] = eglImpl.CreateSurfacePixmap( EGLNativePixmapType( pixmap ), mColorDepth ); // reinterpret_cast does not compile
+  }
+}
+
+void PixmapRenderSurfaceEcoreX::DestroySurface()
+{
+  DALI_LOG_TRACE_METHOD( gPixmapRenderSurfaceLogFilter );
+
+  auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+
+  Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+
+  for (int i = 0; i < BUFFER_COUNT; ++i)
+  {
+    // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
+    XPixmap pixmap = static_cast<XPixmap>( mX11Pixmaps[i] );
+    eglImpl.MakeCurrent( EGLNativePixmapType( pixmap ), mEglSurfaces[i] );
+    eglImpl.DestroySurface( mEglSurfaces[i] );
+  }
+}
+
+bool PixmapRenderSurfaceEcoreX::ReplaceGraphicsSurface()
+{
+  DALI_LOG_TRACE_METHOD( gPixmapRenderSurfaceLogFilter );
+
+  bool contextLost = false;
+
+  auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+
+  Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+
+  for (int i = 0; i < BUFFER_COUNT; ++i)
+  {
+    // a new surface for the new pixmap
+    // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
+    XPixmap pixmap = static_cast<XPixmap>( mX11Pixmaps[i] );
+    contextLost = eglImpl.ReplaceSurfacePixmap( EGLNativePixmapType( pixmap ), mEglSurfaces[i] ); // reinterpret_cast does not compile
+  }
+
+  // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
+  XPixmap pixmap = static_cast<XPixmap>( mX11Pixmaps[mProduceBufferIndex] );
+  eglImpl.MakeCurrent( EGLNativePixmapType( pixmap ), mEglSurfaces[mProduceBufferIndex] );
+
+  return contextLost;
+}
+
+void PixmapRenderSurfaceEcoreX::StartRender()
+{
+}
+
+bool PixmapRenderSurfaceEcoreX::PreRender( bool )
+{
+  // Nothing to do for pixmaps
+  return true;
+}
+
+void PixmapRenderSurfaceEcoreX::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface )
+{
+  auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
+
+  // flush gl instruction queue
+  Integration::GlAbstraction& glAbstraction = eglGraphics->GetGlAbstraction();
+  glAbstraction.Flush();
+
+  if( mThreadSynchronization )
+  {
+    mThreadSynchronization->PostRenderStarted();
+  }
+
+  {
+    ConditionalWait::ScopedLock lock( mPixmapCondition );
+    mConsumeBufferIndex = __sync_fetch_and_xor( &mProduceBufferIndex, 1 ); // Swap buffer indexes.
+
+    Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
+
+    // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
+    XPixmap pixmap = static_cast<XPixmap>( mX11Pixmaps[mProduceBufferIndex] );
+    eglImpl.MakeCurrent( EGLNativePixmapType( pixmap ), mEglSurfaces[mProduceBufferIndex] );
+  }
+
+  // create damage for client applications which wish to know the update timing
+  if( mRenderNotification )
+  {
+    // use notification trigger
+    // Tell the event-thread to render the pixmap
+    mRenderNotification->Trigger();
+  }
+  else
+  {
+    // as a fallback, send damage event.
+    Ecore_X_Drawable drawable = Ecore_X_Drawable( mX11Pixmaps[mProduceBufferIndex] );
+
+    if( drawable )
+    {
+      XRectangle rect;
+      XserverRegion region;
+
+      rect.x = 0;
+      rect.y = 0;
+      rect.width = mPosition.width;
+      rect.height = mPosition.height;
+
+      XDisplay* display = AnyCast<XDisplay*>(mDisplayConnection->GetDisplay());
+
+      // make a fixes region as updated area
+      region = XFixesCreateRegion( display, &rect, 1 );
+      // add damage event to updated drawable
+      Drawable xdrawable( drawable ); // ecore type is unsigned int whereas in 64bit linux Drawable is long unsigned int
+      XDamageAdd( display, xdrawable, region );
+      XFixesDestroyRegion( display, region );
+
+      XFlush( display );
+    }
+  }
+
+  if( mThreadSynchronization )
+  {
+    mThreadSynchronization->PostRenderWaitForCompletion();
+  }
+}
+
+void PixmapRenderSurfaceEcoreX::StopRender()
+{
+  ReleaseLock();
+}
+
+void PixmapRenderSurfaceEcoreX::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
+{
+  mThreadSynchronization = &threadSynchronization;
+}
+
+void PixmapRenderSurfaceEcoreX::ReleaseLock()
+{
+  if( mThreadSynchronization )
+  {
+    mThreadSynchronization->PostRenderComplete();
+  }
+}
+
+Dali::RenderSurfaceInterface::Type PixmapRenderSurfaceEcoreX::GetSurfaceType()
+{
+  return Dali::RenderSurfaceInterface::PIXMAP_RENDER_SURFACE;
+}
+
+void PixmapRenderSurfaceEcoreX::MakeContextCurrent()
+{
+}
+
+void PixmapRenderSurfaceEcoreX::CreateRenderable()
+{
+  // check we're creating one with a valid size
+  DALI_ASSERT_ALWAYS( mPosition.width > 0 && mPosition.height > 0 && "Pixmap size is invalid" );
+
+  for (int i = 0; i < BUFFER_COUNT; ++i)
+  {
+    // create the pixmap
+    mX11Pixmaps[i] = ecore_x_pixmap_new(0, mPosition.width, mPosition.height, mColorDepth);
+
+    // clear the pixmap
+    unsigned int foreground;
+    Ecore_X_GC gc;
+    foreground = 0;
+    gc = ecore_x_gc_new( mX11Pixmaps[i],
+                         ECORE_X_GC_VALUE_MASK_FOREGROUND,
+                         &foreground );
+
+    DALI_ASSERT_ALWAYS( gc && "CreateRenderable(): failed to get gc" );
+
+    ecore_x_drawable_rectangle_fill( mX11Pixmaps[i], gc, 0, 0, mPosition.width, mPosition.height );
+
+    DALI_ASSERT_ALWAYS( mX11Pixmaps[i] && "Failed to create X pixmap" );
+
+    // we SHOULD guarantee the xpixmap/x11 window was created in x server.
+    ecore_x_sync();
+
+    ecore_x_gc_free(gc);
+  }
+}
+
+void PixmapRenderSurfaceEcoreX::UseExistingRenderable( unsigned int surfaceId )
+{
+}
+
+unsigned int PixmapRenderSurfaceEcoreX::GetSurfaceId( Any surface ) const
+{
+  unsigned int surfaceId = 0;
+
+  if ( surface.Empty() == false )
+  {
+    // check we have a valid type
+    DALI_ASSERT_ALWAYS( ( (surface.GetType() == typeid (XWindow) ) ||
+                          (surface.GetType() == typeid (Ecore_X_Window) ) )
+                        && "Surface type is invalid" );
+
+    if ( surface.GetType() == typeid (Ecore_X_Window) )
+    {
+      surfaceId = AnyCast<Ecore_X_Window>( surface );
+    }
+    else
+    {
+      surfaceId = AnyCast<XWindow>( surface );
+    }
+  }
+  return surfaceId;
+}
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
diff --git a/dali/internal/window-system/ubuntu-x11/pixmap-render-surface-ecore-x.h b/dali/internal/window-system/ubuntu-x11/pixmap-render-surface-ecore-x.h
new file mode 100644 (file)
index 0000000..034fee6
--- /dev/null
@@ -0,0 +1,199 @@
+#ifndef DALI_ECORE_X_PIXMAP_RENDER_SURFACE_H
+#define DALI_ECORE_X_PIXMAP_RENDER_SURFACE_H
+
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/devel-api/threading/conditional-wait.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/integration-api/adaptor-framework/egl-interface.h>
+#include <dali/internal/graphics/common/graphics-interface.h>
+#include <dali/internal/graphics/gles/egl-implementation.h>
+#include <dali/internal/system/linux/dali-ecore-x.h>
+#include <dali/internal/window-system/common/pixmap-render-surface.h>
+#include <dali/internal/window-system/ubuntu-x11/ecore-x-types.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * Ecore X11 Pixmap implementation of render surface.
+ */
+class PixmapRenderSurfaceEcoreX : public PixmapRenderSurface
+{
+public:
+
+  /**
+    * Uses an X11 surface to render to.
+    * @param [in] positionSize the position and size of the surface
+    * @param [in] surface can be a X-window or X-pixmap (type must be unsigned int).
+    * @param [in] isTransparent if it is true, surface has 32 bit color depth, otherwise, 24 bit
+    */
+  PixmapRenderSurfaceEcoreX( Dali::PositionSize positionSize, Any surface, bool isTransparent = false );
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~PixmapRenderSurfaceEcoreX();
+
+public: // from WindowRenderSurface
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::PixmapRenderSurface::GetSurface()
+   */
+  virtual Any GetSurface() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::PixmapRenderSurface::SetRenderNotification()
+   */
+  virtual void SetRenderNotification( TriggerEventInterface* renderNotification ) override;
+
+public: // from Dali::RenderSurfaceInterface
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::GetPositionSize()
+   */
+  virtual PositionSize GetPositionSize() const override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::GetDpi()
+   */
+  virtual void GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical ) override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::InitializeGraphics()
+   */
+  virtual void InitializeGraphics() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::CreateSurface()
+   */
+  virtual void CreateSurface() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::DestroySurface()
+   */
+  virtual void DestroySurface() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::ReplaceGraphicsSurface()
+   */
+  virtual bool ReplaceGraphicsSurface() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::MoveResize()
+   */
+  virtual void MoveResize( Dali::PositionSize positionSize) override {}
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::StartRender()
+   */
+  virtual void StartRender() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::PreRender()
+   */
+  virtual bool PreRender( bool resizingSurface ) override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::PostRender()
+   */
+  virtual void PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface ) override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::StopRender()
+   */
+  virtual void StopRender() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::SetThreadSynchronization
+   */
+  virtual void SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization ) override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::GetSurfaceType()
+   */
+  virtual Dali::RenderSurfaceInterface::Type GetSurfaceType() override;
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::MakeContextCurrent()
+   */
+  virtual void MakeContextCurrent() override;
+
+private: // from PixmapRenderSurface
+
+  /**
+   * @copydoc Dali::RenderSurfaceInterface::ReleaseLock()
+   */
+  virtual void ReleaseLock() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::PixmapRenderSurface::Initialize()
+   */
+  virtual void Initialize( Any surface ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::PixmapRenderSurface::Initialize()
+   */
+  virtual void CreateRenderable() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::PixmapRenderSurface::Initialize()
+   */
+  virtual void UseExistingRenderable( unsigned int surfaceId ) override;
+
+private:
+
+  /**
+   * Get the surface id if the surface parameter is not empty
+   * @param surface Any containing a surface id, or can be empty
+   * @return surface id, or zero if surface is empty
+   */
+  unsigned int GetSurfaceId( Any surface ) const;
+
+private: // Data
+
+  static const int BUFFER_COUNT = 2;
+  GraphicsInterface*              mGraphics;               ///< Graphics interface
+  Dali::DisplayConnection*        mDisplayConnection;      ///< Display connection
+  PositionSize                    mPosition;               ///< Position
+  TriggerEventInterface*          mRenderNotification;     ///< Render notification trigger
+  ColorDepth                      mColorDepth;             ///< Color depth of surface (32 bit or 24 bit)
+  bool                            mOwnSurface;             ///< Whether we own the surface (responsible for deleting it)
+
+  int                             mProduceBufferIndex;
+  int                             mConsumeBufferIndex;
+  XPixmap                         mX11Pixmaps[BUFFER_COUNT];  ///< X-Pixmap
+  EGLSurface                      mEglSurfaces[BUFFER_COUNT];
+  ThreadSynchronizationInterface* mThreadSynchronization;     ///< A pointer to the thread-synchronization
+  ConditionalWait                 mPixmapCondition;           ///< condition to share pixmap
+};
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
+
+#endif // DALI_ECORE_X_PIXMAP_RENDER_SURFACE_H
diff --git a/dali/internal/window-system/ubuntu-x11/render-surface-factory-ecore-x.cpp b/dali/internal/window-system/ubuntu-x11/render-surface-factory-ecore-x.cpp
new file mode 100644 (file)
index 0000000..b8b1f7e
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/ubuntu-x11/render-surface-factory-ecore-x.h>
+
+// EXTERNAL HEADERS
+#include <memory>
+
+// INTERNAL HEADERS
+#include <dali/integration-api/adaptor-framework/native-render-surface.h>
+#include <dali/internal/window-system/common/display-utils.h>
+#include <dali/internal/window-system/common/window-render-surface.h>
+#include <dali/internal/window-system/ubuntu-x11/pixmap-render-surface-ecore-x.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+std::unique_ptr< WindowRenderSurface > RenderSurfaceFactoryEcoreX::CreateWindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+{
+  return Utils::MakeUnique< WindowRenderSurface >( positionSize, surface, isTransparent );
+}
+
+std::unique_ptr< PixmapRenderSurface > RenderSurfaceFactoryEcoreX::CreatePixmapRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+{
+  return Utils::MakeUnique< PixmapRenderSurfaceEcoreX >( positionSize, surface, isTransparent );
+}
+
+std::unique_ptr< NativeRenderSurface > RenderSurfaceFactoryEcoreX::CreateNativeRenderSurface( Dali::PositionSize positionSize, bool isTransparent )
+{
+  return std::unique_ptr< NativeRenderSurface >( nullptr );
+}
+
+// this should be created from somewhere
+std::unique_ptr< RenderSurfaceFactory > GetRenderSurfaceFactory()
+{
+  // returns Window factory
+  return Utils::MakeUnique< RenderSurfaceFactoryEcoreX >();
+}
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
diff --git a/dali/internal/window-system/ubuntu-x11/render-surface-factory-ecore-x.h b/dali/internal/window-system/ubuntu-x11/render-surface-factory-ecore-x.h
new file mode 100644 (file)
index 0000000..47086a6
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_ECOREX_RENDER_SURFACE_FACTORY_ECORE_X_H
+#define DALI_INTERNAL_WINDOWSYSTEM_ECOREX_RENDER_SURFACE_FACTORY_ECORE_X_H
+
+/*
+ * Copyright (c) 2018 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/internal/window-system/common/render-surface-factory.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class RenderSurfaceFactoryEcoreX : public RenderSurfaceFactory
+{
+public:
+  std::unique_ptr< WindowRenderSurface > CreateWindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent = false ) override;
+
+  std::unique_ptr< PixmapRenderSurface > CreatePixmapRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent = false ) override;
+
+  std::unique_ptr< NativeRenderSurface > CreateNativeRenderSurface( Dali::PositionSize positionSize, bool isTransparent = false ) override;
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_ECOREX_RENDER_SURFACE_FACTORY_ECORE_X_H
diff --git a/dali/internal/window-system/ubuntu-x11/window-base-ecore-x.cpp b/dali/internal/window-system/ubuntu-x11/window-base-ecore-x.cpp
new file mode 100755 (executable)
index 0000000..ab67b43
--- /dev/null
@@ -0,0 +1,916 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/ubuntu-x11/window-base-ecore-x.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/window-system/common/window-impl.h>
+#include <dali/internal/window-system/common/window-system.h>
+#include <dali/internal/window-system/common/window-render-surface.h>
+#include <dali/internal/window-system/ubuntu-x11/ecore-x-types.h>
+
+// EXTERNAL_HEADERS
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/events/mouse-button.h>
+#include <dali/integration-api/debug.h>
+#include <dali/internal/input/ubuntu-x11/dali-ecore-input.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+const std::string DEFAULT_DEVICE_NAME = "";
+const Device::Class::Type DEFAULT_DEVICE_CLASS = Device::Class::NONE;
+const Device::Subclass::Type DEFAULT_DEVICE_SUBCLASS = Device::Subclass::NONE;
+
+const unsigned int PRIMARY_TOUCH_BUTTON_ID( 1 );
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gWindowBaseLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_WINDOW_BASE" );
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Window Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+static Eina_Bool EcoreEventWindowPropertyChanged( void* data, int type, void* event )
+{
+  WindowBaseEcoreX* windowBase = static_cast< WindowBaseEcoreX* >( data );
+  if( windowBase )
+  {
+    return windowBase->OnWindowPropertyChanged( data, type, event );
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when the window receives a delete request
+ */
+static Eina_Bool EcoreEventWindowDeleteRequest( void* data, int type, void* event )
+{
+  WindowBaseEcoreX* windowBase = static_cast< WindowBaseEcoreX* >( data );
+  if( windowBase )
+  {
+    windowBase->OnDeleteRequest();
+  }
+  return ECORE_CALLBACK_DONE;
+}
+
+/**
+ * Called when the window gains focus.
+ */
+static Eina_Bool EcoreEventWindowFocusIn( void* data, int type, void* event )
+{
+  WindowBaseEcoreX* windowBase = static_cast< WindowBaseEcoreX* >( data );
+  if( windowBase )
+  {
+    windowBase->OnFocusIn( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when the window loses focus.
+ */
+static Eina_Bool EcoreEventWindowFocusOut( void* data, int type, void* event )
+{
+  WindowBaseEcoreX* windowBase = static_cast< WindowBaseEcoreX* >( data );
+  if( windowBase )
+  {
+    windowBase->OnFocusOut( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when the window is damaged.
+ */
+static Eina_Bool EcoreEventWindowDamaged( void* data, int type, void* event )
+{
+  WindowBaseEcoreX* windowBase = static_cast< WindowBaseEcoreX* >( data );
+  if( windowBase )
+  {
+    windowBase->OnWindowDamaged( data, type, event );
+  }
+
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Selection Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Called when the source window notifies us the content in clipboard is selected.
+ */
+static Eina_Bool EcoreEventSelectionClear( void* data, int type, void* event )
+{
+  WindowBaseEcoreX* windowBase = static_cast< WindowBaseEcoreX* >( data );
+  if( windowBase )
+  {
+    windowBase->OnSelectionClear( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when the source window sends us about the selected content.
+ * For example, when dragged items are dragged INTO our window or when items are selected in the clipboard.
+ */
+static Eina_Bool EcoreEventSelectionNotify( void* data, int type, void* event )
+{
+  WindowBaseEcoreX* windowBase = static_cast< WindowBaseEcoreX* >( data );
+  if( windowBase )
+  {
+    windowBase->OnSelectionNotify( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Touch Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Called when a touch down is received.
+ */
+static Eina_Bool EcoreEventMouseButtonDown( void* data, int type, void* event )
+{
+  WindowBaseEcoreX* windowBase = static_cast< WindowBaseEcoreX* >( data );
+  if( windowBase )
+  {
+    windowBase->OnMouseButtonDown( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when a touch up is received.
+ */
+static Eina_Bool EcoreEventMouseButtonUp( void* data, int type, void* event )
+{
+  WindowBaseEcoreX* windowBase = static_cast< WindowBaseEcoreX* >( data );
+  if( windowBase )
+  {
+    windowBase->OnMouseButtonUp( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when a touch motion is received.
+ */
+static Eina_Bool EcoreEventMouseButtonMove( void* data, int type, void* event )
+{
+  WindowBaseEcoreX* windowBase = static_cast< WindowBaseEcoreX* >( data );
+  if( windowBase )
+  {
+    windowBase->OnMouseButtonMove( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Wheel Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Called when a mouse wheel is received.
+ */
+static Eina_Bool EcoreEventMouseWheel( void* data, int type, void* event )
+{
+  WindowBaseEcoreX* windowBase = static_cast< WindowBaseEcoreX* >( data );
+  if( windowBase )
+  {
+    windowBase->OnMouseWheel( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+// Key Callbacks
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Called when a key down is received.
+ */
+static Eina_Bool EcoreEventKeyDown( void* data, int type, void* event )
+{
+  WindowBaseEcoreX* windowBase = static_cast< WindowBaseEcoreX* >( data );
+  if( windowBase )
+  {
+    windowBase->OnKeyDown( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+/**
+ * Called when a key up is received.
+ */
+static Eina_Bool EcoreEventKeyUp( void* data, int type, void* event )
+{
+  WindowBaseEcoreX* windowBase = static_cast< WindowBaseEcoreX* >( data );
+  if( windowBase )
+  {
+    windowBase->OnKeyUp( data, type, event );
+  }
+  return ECORE_CALLBACK_PASS_ON;
+}
+
+} // unnamed namespace
+
+WindowBaseEcoreX::WindowBaseEcoreX( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+: mEcoreEventHandler(),
+  mEcoreWindow( 0 ),
+  mOwnSurface( false ),
+  mIsTransparent( false ), // Should only be set to true once we actually create a transparent window regardless of what isTransparent is.
+  mRotationAppSet( false )
+{
+  Initialize( positionSize, surface, isTransparent );
+}
+
+WindowBaseEcoreX::~WindowBaseEcoreX()
+{
+  for( Dali::Vector< Ecore_Event_Handler* >::Iterator iter = mEcoreEventHandler.Begin(), endIter = mEcoreEventHandler.End(); iter != endIter; ++iter )
+  {
+    ecore_event_handler_del( *iter );
+  }
+  mEcoreEventHandler.Clear();
+
+  if( mOwnSurface )
+  {
+    ecore_x_window_free( mEcoreWindow );
+
+    WindowSystem::Shutdown();
+  }
+}
+
+void WindowBaseEcoreX::Initialize( PositionSize positionSize, Any surface, bool isTransparent )
+{
+  // see if there is a surface in Any surface
+  unsigned int surfaceId = GetSurfaceId( surface );
+
+  // if the surface is empty, create a new one.
+  if( surfaceId == 0 )
+  {
+    WindowSystem::Initialize();
+
+    // we own the surface about to created
+    mOwnSurface = true;
+    CreateWindow( positionSize, isTransparent );
+  }
+  else
+  {
+    // XLib should already be initialized so no point in calling XInitThreads
+    mEcoreWindow = static_cast< Ecore_X_Window >( surfaceId );
+  }
+
+  // set up etc properties to match with ecore-evas
+  char *id = NULL;
+  if( ( id = getenv("DESKTOP_STARTUP_ID") ) )
+  {
+    ecore_x_netwm_startup_id_set( mEcoreWindow, id );
+  }
+
+  ecore_x_icccm_hints_set( mEcoreWindow,
+                           1,                                // accepts_focus
+                           ECORE_X_WINDOW_STATE_HINT_NORMAL, // initial_state
+                           0,                                // icon_pixmap
+                           0,                                // icon_mask
+                           0,                                // icon_window
+                           0,                                // window_group
+                           0 );                              // is_urgent
+
+  // we SHOULD guarantee the x11 window was created in x server.
+  ecore_x_sync();
+
+  ecore_x_input_multi_select( mEcoreWindow );
+
+  // This ensures that we catch the window close (or delete) request
+  ecore_x_icccm_protocol_set( mEcoreWindow, ECORE_X_WM_PROTOCOL_DELETE_REQUEST, EINA_TRUE );
+
+  // Enable Drag & Drop
+  ecore_x_dnd_aware_set( mEcoreWindow, EINA_TRUE );
+
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_X_EVENT_WINDOW_PROPERTY,       EcoreEventWindowPropertyChanged, this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_X_EVENT_WINDOW_DELETE_REQUEST, EcoreEventWindowDeleteRequest,   this ) );
+
+  // Register window focus events
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_X_EVENT_WINDOW_FOCUS_IN,       EcoreEventWindowFocusIn,   this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_X_EVENT_WINDOW_FOCUS_OUT,      EcoreEventWindowFocusOut,  this ) );
+
+  // Register Window damage events
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_X_EVENT_WINDOW_DAMAGE,         EcoreEventWindowDamaged,   this ) );
+
+  // Register Touch events
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_MOUSE_BUTTON_DOWN,       EcoreEventMouseButtonDown, this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_MOUSE_BUTTON_UP,         EcoreEventMouseButtonUp,   this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_MOUSE_MOVE,              EcoreEventMouseButtonMove, this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_MOUSE_OUT,               EcoreEventMouseButtonUp,   this ) ); // process mouse out event like up event
+
+  // Register Mouse wheel events
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_MOUSE_WHEEL,             EcoreEventMouseWheel,      this ) );
+
+  // Register Key events
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_KEY_DOWN,                EcoreEventKeyDown,         this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_EVENT_KEY_UP,                  EcoreEventKeyUp,           this ) );
+
+  // Register Selection event
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_X_EVENT_SELECTION_CLEAR,       EcoreEventSelectionClear,  this ) );
+  mEcoreEventHandler.PushBack( ecore_event_handler_add( ECORE_X_EVENT_SELECTION_NOTIFY,      EcoreEventSelectionNotify, this ) );
+}
+
+Eina_Bool WindowBaseEcoreX::OnWindowPropertyChanged( void* data, int type, void* event )
+{
+  Ecore_X_Event_Window_Property* propertyChangedEvent = static_cast< Ecore_X_Event_Window_Property* >( event );
+  Eina_Bool handled( ECORE_CALLBACK_PASS_ON );
+
+  if( propertyChangedEvent->win == mEcoreWindow )
+  {
+    Ecore_X_Window_State_Hint state( ecore_x_icccm_state_get( propertyChangedEvent->win ) );
+
+    switch( state )
+    {
+      case ECORE_X_WINDOW_STATE_HINT_WITHDRAWN:
+      {
+        // Window was hidden.
+        mIconifyChangedSignal.Emit( true );
+        handled = ECORE_CALLBACK_DONE;
+        break;
+      }
+      case ECORE_X_WINDOW_STATE_HINT_ICONIC:
+      {
+        // Window was iconified (minimised).
+        mIconifyChangedSignal.Emit( true );
+        handled = ECORE_CALLBACK_DONE;
+        break;
+      }
+      case ECORE_X_WINDOW_STATE_HINT_NORMAL:
+      {
+        // Window was shown.
+        mIconifyChangedSignal.Emit( false );
+        handled = ECORE_CALLBACK_DONE;
+        break;
+      }
+      default:
+      {
+        // Ignore
+        break;
+      }
+    }
+  }
+
+  return handled;
+}
+
+void WindowBaseEcoreX::OnDeleteRequest()
+{
+  mDeleteRequestSignal.Emit();
+}
+
+void WindowBaseEcoreX::OnFocusIn( void* data, int type, void* event )
+{
+  Ecore_X_Event_Window_Focus_In* focusInEvent = static_cast< Ecore_X_Event_Window_Focus_In* >( event );
+
+  if( focusInEvent->win == mEcoreWindow )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "Window EcoreEventWindowFocusIn\n" );
+
+    mFocusChangedSignal.Emit( true );
+  }
+}
+
+void WindowBaseEcoreX::OnFocusOut( void* data, int type, void* event )
+{
+  Ecore_X_Event_Window_Focus_Out* focusOutEvent = static_cast< Ecore_X_Event_Window_Focus_Out* >( event );
+
+  // If the window loses focus then hide the keyboard.
+  if( focusOutEvent->win == mEcoreWindow )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "Window EcoreEventWindowFocusOut\n" );
+
+    mFocusChangedSignal.Emit( false );
+  }
+}
+
+void WindowBaseEcoreX::OnWindowDamaged( void* data, int type, void* event )
+{
+  Ecore_X_Event_Window_Damage* windowDamagedEvent = static_cast< Ecore_X_Event_Window_Damage* >( event );
+
+  if( windowDamagedEvent->win == mEcoreWindow )
+  {
+    DamageArea area;
+    area.x = windowDamagedEvent->x;
+    area.y = windowDamagedEvent->y;
+    area.width = windowDamagedEvent->w;
+    area.height = windowDamagedEvent->h;
+
+    mWindowDamagedSignal.Emit( area );
+  }
+}
+
+void WindowBaseEcoreX::OnMouseButtonDown( void* data, int type, void* event )
+{
+  Ecore_Event_Mouse_Button* touchEvent = static_cast< Ecore_Event_Mouse_Button* >( event );
+
+  if( touchEvent->window == mEcoreWindow )
+  {
+    PointState::Type state ( PointState::DOWN );
+
+    Integration::Point point;
+    point.SetDeviceId( touchEvent->multi.device );
+    point.SetState( state );
+    point.SetScreenPosition( Vector2( touchEvent->x, touchEvent->y ) );
+    point.SetRadius( touchEvent->multi.radius, Vector2( touchEvent->multi.radius_x, touchEvent->multi.radius_y ) );
+    point.SetPressure( touchEvent->multi.pressure );
+    point.SetAngle( Degree( touchEvent->multi.angle ) );
+    if( touchEvent->buttons)
+    {
+      point.SetMouseButton( static_cast< MouseButton::Type >( touchEvent->buttons) );
+    }
+
+    mTouchEventSignal.Emit( point, touchEvent->timestamp );
+  }
+}
+
+void WindowBaseEcoreX::OnMouseButtonUp( void* data, int type, void* event )
+{
+  Ecore_Event_Mouse_Button* touchEvent = static_cast< Ecore_Event_Mouse_Button* >( event );
+
+  if( touchEvent->window == mEcoreWindow )
+  {
+    Integration::Point point;
+    point.SetDeviceId( touchEvent->multi.device );
+    point.SetState( PointState::UP );
+    point.SetScreenPosition( Vector2( touchEvent->x, touchEvent->y ) );
+    point.SetRadius( touchEvent->multi.radius, Vector2( touchEvent->multi.radius_x, touchEvent->multi.radius_y ) );
+    point.SetPressure( touchEvent->multi.pressure );
+    point.SetAngle( Degree( static_cast<float>( touchEvent->multi.angle ) ) );
+    if( touchEvent->buttons)
+    {
+      point.SetMouseButton( static_cast< MouseButton::Type >( touchEvent->buttons) );
+    }
+
+    mTouchEventSignal.Emit( point, touchEvent->timestamp );
+  }
+}
+
+void WindowBaseEcoreX::OnMouseButtonMove( void* data, int type, void* event )
+{
+  Ecore_Event_Mouse_Move* touchEvent = static_cast< Ecore_Event_Mouse_Move* >( event );
+
+  if( touchEvent->window == mEcoreWindow )
+  {
+    Integration::Point point;
+    point.SetDeviceId( touchEvent->multi.device );
+    point.SetState( PointState::MOTION );
+    point.SetScreenPosition( Vector2( static_cast<float>( touchEvent->x ), static_cast<float>( touchEvent->y ) ) );
+    point.SetRadius( static_cast<float>( touchEvent->multi.radius ), Vector2( static_cast<float>( touchEvent->multi.radius_x ), static_cast<float>( touchEvent->multi.radius_y ) ) );
+    point.SetPressure( static_cast<float>( touchEvent->multi.pressure ) );
+    point.SetAngle( Degree( static_cast<float>( touchEvent->multi.angle ) ) );
+
+    mTouchEventSignal.Emit( point, touchEvent->timestamp );
+  }
+}
+
+void WindowBaseEcoreX::OnMouseWheel( void* data, int type, void* event )
+{
+  Ecore_Event_Mouse_Wheel* mouseWheelEvent = static_cast< Ecore_Event_Mouse_Wheel* >( event );
+
+  if( mouseWheelEvent->window == mEcoreWindow )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreX::OnMouseWheel: direction: %d, modifiers: %d, x: %d, y: %d, z: %d\n", mouseWheelEvent->direction, mouseWheelEvent->modifiers, mouseWheelEvent->x, mouseWheelEvent->y, mouseWheelEvent->z );
+
+    WheelEvent wheelEvent( WheelEvent::MOUSE_WHEEL, mouseWheelEvent->direction, mouseWheelEvent->modifiers, Vector2( static_cast<float>( mouseWheelEvent->x ), static_cast<float>( mouseWheelEvent->y ) ), mouseWheelEvent->z, mouseWheelEvent->timestamp );
+
+    mWheelEventSignal.Emit( wheelEvent );
+  }
+}
+
+void WindowBaseEcoreX::OnKeyDown( void* data, int type, void* event )
+{
+  Ecore_Event_Key* keyEvent = static_cast< Ecore_Event_Key* >( event );
+
+  if( keyEvent->window == mEcoreWindow )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseEcoreX::OnKeyDown\n" );
+
+    std::string keyName( keyEvent->keyname );
+    std::string logicalKey( "" );
+    std::string keyString( "" );
+    std::string compose( "" );
+
+    // Ensure key compose string is not NULL as keys like SHIFT or arrow have a null string.
+    if( keyEvent->compose )
+    {
+      compose = keyEvent->compose;
+    }
+
+    // Ensure key symbol is not NULL as keys like SHIFT have a null string.
+    if( keyEvent->key )
+    {
+      logicalKey = keyEvent->key;
+    }
+
+    int keyCode = ecore_x_keysym_keycode_get( keyEvent->keyname );
+    int modifier( keyEvent->modifiers );
+    unsigned long time = keyEvent->timestamp;
+
+    // Ensure key event string is not NULL as keys like SHIFT have a null string.
+    if( keyEvent->string )
+    {
+      keyString = keyEvent->string;
+    }
+
+    Integration::KeyEvent keyEvent( keyName, logicalKey, keyString, keyCode, modifier, time, Integration::KeyEvent::Down, compose, DEFAULT_DEVICE_NAME, DEFAULT_DEVICE_CLASS, DEFAULT_DEVICE_SUBCLASS );
+
+    mKeyEventSignal.Emit( keyEvent );
+  }
+}
+
+void WindowBaseEcoreX::OnKeyUp( void* data, int type, void* event )
+{
+  Ecore_Event_Key* keyEvent = static_cast< Ecore_Event_Key* >( event );
+
+  if ( keyEvent->window == mEcoreWindow )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, " WindowBaseEcoreX::OnKeyUp\n" );
+
+    std::string keyName( keyEvent->keyname );
+    std::string logicalKey( "" );
+    std::string keyString( "" );
+    std::string compose( "" );
+
+    // Ensure key compose string is not NULL as keys like SHIFT or arrow have a null string.
+    if( keyEvent->compose )
+    {
+      compose = keyEvent->compose;
+    }
+    // Ensure key symbol is not NULL as keys like SHIFT have a null string.
+    if( keyEvent->key )
+    {
+      logicalKey = keyEvent->key;
+    }
+
+    int keyCode = ecore_x_keysym_keycode_get( keyEvent->keyname );
+    int modifier( keyEvent->modifiers );
+    unsigned long time( keyEvent->timestamp );
+
+    // Ensure key event string is not NULL as keys like SHIFT have a null string.
+    if( keyEvent->string )
+    {
+      keyString = keyEvent->string;
+    }
+
+    Integration::KeyEvent keyEvent( keyName, logicalKey, keyString, keyCode, modifier, time, Integration::KeyEvent::Up, compose, DEFAULT_DEVICE_NAME, DEFAULT_DEVICE_CLASS, DEFAULT_DEVICE_SUBCLASS );
+
+    mKeyEventSignal.Emit( keyEvent );
+  }
+}
+
+void WindowBaseEcoreX::OnSelectionClear( void* data, int type, void* event )
+{
+  Ecore_X_Event_Selection_Clear* selectionClearEvent = static_cast< Ecore_X_Event_Selection_Clear* >( event );
+
+  if( selectionClearEvent->win == mEcoreWindow )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Concise, " WindowBaseEcoreX::OnSelectionClear\n" );
+
+    if( selectionClearEvent->selection == ECORE_X_SELECTION_SECONDARY )
+    {
+      // Request to get the content from Ecore.
+      ecore_x_selection_secondary_request( selectionClearEvent->win, ECORE_X_SELECTION_TARGET_TEXT );
+    }
+  }
+}
+
+void WindowBaseEcoreX::OnSelectionNotify( void* data, int type, void* event )
+{
+  Ecore_X_Event_Selection_Notify* selectionNotifyEvent = static_cast< Ecore_X_Event_Selection_Notify* >( event );
+
+  if( selectionNotifyEvent->win == mEcoreWindow )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::Concise, " WindowBaseEcoreX::OnSelectionNotify\n" );
+
+    Ecore_X_Selection_Data* selectionData = static_cast< Ecore_X_Selection_Data* >( selectionNotifyEvent->data );
+    if( selectionData->data )
+    {
+      if( selectionNotifyEvent->selection == ECORE_X_SELECTION_SECONDARY )
+      {
+        mSelectionDataReceivedSignal.Emit( event  );
+      }
+    }
+  }
+}
+
+Any WindowBaseEcoreX::GetNativeWindow()
+{
+  return mEcoreWindow;
+}
+
+int WindowBaseEcoreX::GetNativeWindowId()
+{
+  return mEcoreWindow;
+}
+
+EGLNativeWindowType WindowBaseEcoreX::CreateEglWindow( int width, int height )
+{
+  // need to create X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
+  XWindow window( mEcoreWindow );
+  return reinterpret_cast< EGLNativeWindowType >( window );
+}
+
+void WindowBaseEcoreX::DestroyEglWindow()
+{
+}
+
+void WindowBaseEcoreX::SetEglWindowRotation( int angle )
+{
+}
+
+void WindowBaseEcoreX::SetEglWindowBufferTransform( int angle )
+{
+}
+
+void WindowBaseEcoreX::SetEglWindowTransform( int angle )
+{
+}
+
+void WindowBaseEcoreX::ResizeEglWindow( PositionSize positionSize )
+{
+}
+
+bool WindowBaseEcoreX::IsEglWindowRotationSupported()
+{
+  return false;
+}
+
+void WindowBaseEcoreX::Move( PositionSize positionSize )
+{
+  ecore_x_window_move( mEcoreWindow, positionSize.x, positionSize.y );
+}
+
+void WindowBaseEcoreX::Resize( PositionSize positionSize )
+{
+  ecore_x_window_resize( mEcoreWindow, positionSize.width, positionSize.height );
+}
+
+void WindowBaseEcoreX::MoveResize( PositionSize positionSize )
+{
+  ecore_x_window_move_resize( mEcoreWindow, positionSize.x, positionSize.y, positionSize.width, positionSize.height );
+}
+
+void WindowBaseEcoreX::SetClass( const std::string& name, const std::string& className )
+{
+  ecore_x_icccm_title_set( mEcoreWindow, name.c_str() );
+  ecore_x_netwm_name_set( mEcoreWindow, name.c_str() );
+  ecore_x_icccm_name_class_set( mEcoreWindow, name.c_str(), className.c_str() );
+}
+
+void WindowBaseEcoreX::Raise()
+{
+  ecore_x_window_raise( mEcoreWindow );
+}
+
+void WindowBaseEcoreX::Lower()
+{
+  ecore_x_window_lower( mEcoreWindow );
+}
+
+void WindowBaseEcoreX::Activate()
+{
+  ecore_x_netwm_client_active_request( ecore_x_window_root_get( mEcoreWindow ), mEcoreWindow, 1 /* request type, 1:application, 2:pager */, 0 );
+}
+
+void WindowBaseEcoreX::SetAvailableAnlges( const std::vector< int >& angles )
+{
+}
+
+void WindowBaseEcoreX::SetPreferredAngle( int angle )
+{
+}
+
+void WindowBaseEcoreX::SetAcceptFocus( bool accept )
+{
+}
+
+void WindowBaseEcoreX::Show()
+{
+  ecore_x_window_show( mEcoreWindow );
+}
+
+void WindowBaseEcoreX::Hide()
+{
+  ecore_x_window_hide( mEcoreWindow );
+}
+
+unsigned int WindowBaseEcoreX::GetSupportedAuxiliaryHintCount() const
+{
+  return 0;
+}
+
+std::string WindowBaseEcoreX::GetSupportedAuxiliaryHint( unsigned int index ) const
+{
+  return std::string();
+}
+
+unsigned int WindowBaseEcoreX::AddAuxiliaryHint( const std::string& hint, const std::string& value )
+{
+  return 0;
+}
+
+bool WindowBaseEcoreX::RemoveAuxiliaryHint( unsigned int id )
+{
+  return false;
+}
+
+bool WindowBaseEcoreX::SetAuxiliaryHintValue( unsigned int id, const std::string& value )
+{
+  return false;
+}
+
+std::string WindowBaseEcoreX::GetAuxiliaryHintValue( unsigned int id ) const
+{
+  return std::string();
+}
+
+unsigned int WindowBaseEcoreX::GetAuxiliaryHintId( const std::string& hint ) const
+{
+  return 0;
+}
+
+void WindowBaseEcoreX::SetInputRegion( const Rect< int >& inputRegion )
+{
+}
+
+void WindowBaseEcoreX::SetType( Dali::Window::Type type )
+{
+}
+
+bool WindowBaseEcoreX::SetNotificationLevel( Dali::Window::NotificationLevel::Type level )
+{
+  return false;
+}
+
+Dali::Window::NotificationLevel::Type WindowBaseEcoreX::GetNotificationLevel() const
+{
+  return Dali::Window::NotificationLevel::NONE;
+}
+
+void WindowBaseEcoreX::SetOpaqueState( bool opaque )
+{
+}
+
+bool WindowBaseEcoreX::SetScreenOffMode(Dali::Window::ScreenOffMode::Type screenOffMode)
+{
+  return false;
+}
+
+Dali::Window::ScreenOffMode::Type WindowBaseEcoreX::GetScreenOffMode() const
+{
+  return Dali::Window::ScreenOffMode::TIMEOUT;
+}
+
+bool WindowBaseEcoreX::SetBrightness( int brightness )
+{
+  return false;
+}
+
+int WindowBaseEcoreX::GetBrightness() const
+{
+  return 0;
+}
+
+bool WindowBaseEcoreX::GrabKey( Dali::KEY key, KeyGrab::KeyGrabMode grabMode )
+{
+  return false;
+}
+
+bool WindowBaseEcoreX::UngrabKey( Dali::KEY key )
+{
+  return false;
+}
+
+bool WindowBaseEcoreX::GrabKeyList( const Dali::Vector< Dali::KEY >& key, const Dali::Vector< KeyGrab::KeyGrabMode >& grabMode, Dali::Vector< bool >& result )
+{
+  return false;
+}
+
+bool WindowBaseEcoreX::UngrabKeyList( const Dali::Vector< Dali::KEY >& key, Dali::Vector< bool >& result )
+{
+  return false;
+}
+
+void WindowBaseEcoreX::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
+{
+  // 1 inch = 25.4 millimeters
+  // ecore does not account for differing DPI in the x and y axes, so only get for x is available
+
+  dpiHorizontal = ecore_x_dpi_get();
+  dpiVertical   = ecore_x_dpi_get();
+}
+
+int WindowBaseEcoreX::GetScreenRotationAngle()
+{
+  return 0;
+}
+
+void WindowBaseEcoreX::SetWindowRotationAngle( int degree )
+{
+}
+
+void WindowBaseEcoreX::WindowRotationCompleted( int degree, int width, int height )
+{
+}
+
+void WindowBaseEcoreX::SetTransparency( bool transparent )
+{
+}
+
+unsigned int WindowBaseEcoreX::GetSurfaceId( Any surface ) const
+{
+  unsigned int surfaceId = 0;
+
+  if ( surface.Empty() == false )
+  {
+    // check we have a valid type
+    DALI_ASSERT_ALWAYS( ( (surface.GetType() == typeid (XWindow) ) || (surface.GetType() == typeid (Ecore_X_Window) ) )
+                        && "Surface type is invalid" );
+
+    if ( surface.GetType() == typeid (Ecore_X_Window) )
+    {
+      surfaceId = AnyCast< Ecore_X_Window >( surface );
+    }
+    else
+    {
+      surfaceId = static_cast<unsigned int>( AnyCast< XWindow >( surface ) );
+    }
+  }
+  return surfaceId;
+}
+
+void WindowBaseEcoreX::CreateWindow( PositionSize positionSize, bool isTransparent )
+{
+ if( isTransparent )
+ {
+   // create 32 bit window
+   mEcoreWindow = ecore_x_window_argb_new( 0, positionSize.x, positionSize.y, positionSize.width, positionSize.height );
+   mIsTransparent = true;
+ }
+ else
+ {
+   // create 24 bit window
+   mEcoreWindow = ecore_x_window_new( 0, positionSize.x, positionSize.y, positionSize.width, positionSize.height );
+ }
+
+ if ( mEcoreWindow == 0 )
+ {
+   DALI_ASSERT_ALWAYS( 0 && "Failed to create X window" );
+ }
+}
+
+void WindowBaseEcoreX::SetParent( WindowBase* parentWinBase )
+{
+  Ecore_X_Window ecoreParent = 0;
+  if( parentWinBase )
+  {
+    WindowBaseEcoreX* winBaseEcoreX = static_cast<WindowBaseEcoreX*>( parentWinBase );
+    ecoreParent = winBaseEcoreX->mEcoreWindow;
+    ecore_x_icccm_transient_for_set( mEcoreWindow, ecoreParent );
+  }
+  else
+  {
+    ecoreParent = 0;
+    ecore_x_icccm_transient_for_unset( mEcoreWindow );
+  }
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/window-system/ubuntu-x11/window-base-ecore-x.h b/dali/internal/window-system/ubuntu-x11/window-base-ecore-x.h
new file mode 100644 (file)
index 0000000..8ab7080
--- /dev/null
@@ -0,0 +1,398 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_ECOREX_WINDOW_BASE_ECORE_X_H
+#define DALI_INTERNAL_WINDOWSYSTEM_ECOREX_WINDOW_BASE_ECORE_X_H
+
+/*
+ * Copyright (c) 2019 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 <dali/internal/window-system/common/window-base.h>
+
+// EXTERNAL HEADERS
+#include <dali/internal/system/linux/dali-ecore.h>
+#include <dali/internal/system/linux/dali-ecore-x.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+/**
+ * WindowBaseEcoreX class provides an WindowBase EcoreX implementation.
+ */
+class WindowBaseEcoreX : public WindowBase
+{
+public:
+
+  /**
+   * @brief Constructor
+   */
+  WindowBaseEcoreX( PositionSize positionSize, Any surface, bool isTransparent );
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~WindowBaseEcoreX();
+
+public:
+
+  /**
+   * @brief Called when the window property is changed.
+   */
+  Eina_Bool OnWindowPropertyChanged( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the window receives a delete request
+   */
+  void OnDeleteRequest();
+
+  /**
+   * @brief Called when the window gains focus.
+   */
+  void OnFocusIn( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the window loses focus.
+   */
+  void OnFocusOut( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the window is damaged.
+   */
+  void OnWindowDamaged( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a touch down is received.
+   */
+  void OnMouseButtonDown( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a touch up is received.
+   */
+  void OnMouseButtonUp( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a touch motion is received.
+   */
+  void OnMouseButtonMove( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a mouse wheel is received.
+   */
+  void OnMouseWheel( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a key down is received.
+   */
+  void OnKeyDown( void* data, int type, void* event );
+
+  /**
+   * @brief Called when a key up is received.
+   */
+  void OnKeyUp( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the source window notifies us the content in clipboard is selected.
+   */
+  void OnSelectionClear( void* data, int type, void* event );
+
+  /**
+   * @brief Called when the source window sends us about the selected content.
+   */
+  void OnSelectionNotify( void* data, int type, void* event );
+
+public:
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindow()
+   */
+  virtual Any GetNativeWindow() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindowId()
+   */
+  virtual int GetNativeWindowId() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::CreateEglWindow()
+   */
+  virtual EGLNativeWindowType CreateEglWindow( int width, int height ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::DestroyEglWindow()
+   */
+  virtual void DestroyEglWindow() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetEglWindowRotation()
+   */
+  virtual void SetEglWindowRotation( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetEglWindowBufferTransform()
+   */
+  virtual void SetEglWindowBufferTransform( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetEglWindowTransform()
+   */
+  virtual void SetEglWindowTransform( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::ResizeEglWindow()
+   */
+  virtual void ResizeEglWindow( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::IsEglWindowRotationSupported()
+   */
+  virtual bool IsEglWindowRotationSupported() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Move()
+   */
+  virtual void Move( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Resize()
+   */
+  virtual void Resize( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::MoveResize()
+   */
+  virtual void MoveResize( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetClass()
+   */
+  virtual void SetClass( const std::string& name, const std::string& className ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Raise()
+   */
+  virtual void Raise() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Lower()
+   */
+  virtual void Lower() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Activate()
+   */
+  virtual void Activate() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetAvailableAnlges()
+   */
+  virtual void SetAvailableAnlges( const std::vector< int >& angles ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetPreferredAngle()
+   */
+  virtual void SetPreferredAngle( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetAcceptFocus()
+   */
+  virtual void SetAcceptFocus( bool accept ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Show()
+   */
+  virtual void Show() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Hide()
+   */
+  virtual void Hide() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetSupportedAuxiliaryHintCount()
+   */
+  virtual unsigned int GetSupportedAuxiliaryHintCount() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetSupportedAuxiliaryHint()
+   */
+  virtual std::string GetSupportedAuxiliaryHint( unsigned int index ) const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::AddAuxiliaryHint()
+   */
+  virtual unsigned int AddAuxiliaryHint( const std::string& hint, const std::string& value ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::RemoveAuxiliaryHint()
+   */
+  virtual bool RemoveAuxiliaryHint( unsigned int id ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetAuxiliaryHintValue()
+   */
+  virtual bool SetAuxiliaryHintValue( unsigned int id, const std::string& value ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetAuxiliaryHintValue()
+   */
+  virtual std::string GetAuxiliaryHintValue( unsigned int id ) const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetAuxiliaryHintId()
+   */
+  virtual unsigned int GetAuxiliaryHintId( const std::string& hint ) const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetInputRegion()
+   */
+  virtual void SetInputRegion( const Rect< int >& inputRegion ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetType()
+   */
+  virtual void SetType( Dali::Window::Type type ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetNotificationLevel()
+   */
+  virtual bool SetNotificationLevel( Dali::Window::NotificationLevel::Type level ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNotificationLevel()
+   */
+  virtual Dali::Window::NotificationLevel::Type GetNotificationLevel() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetOpaqueState()
+   */
+  virtual void SetOpaqueState( bool opaque ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetScreenOffMode()
+   */
+  virtual bool SetScreenOffMode(Dali::Window::ScreenOffMode::Type screenOffMode) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetScreenOffMode()
+   */
+  virtual Dali::Window::ScreenOffMode::Type GetScreenOffMode() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetBrightness()
+   */
+  virtual bool SetBrightness( int brightness ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetBrightness()
+   */
+  virtual int GetBrightness() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GrabKey()
+   */
+  virtual bool GrabKey( Dali::KEY key, KeyGrab::KeyGrabMode grabMode ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::UngrabKey()
+   */
+  virtual bool UngrabKey( Dali::KEY key ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GrabKeyList()
+   */
+  virtual bool GrabKeyList( const Dali::Vector< Dali::KEY >& key, const Dali::Vector< KeyGrab::KeyGrabMode >& grabMode, Dali::Vector< bool >& result ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::UngrabKeyList()
+   */
+  virtual bool UngrabKeyList( const Dali::Vector< Dali::KEY >& key, Dali::Vector< bool >& result ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetDpi()
+   */
+  virtual void GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetScreenRotationAngle()
+   */
+  virtual int GetScreenRotationAngle() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetWindowRotationAngle()
+   */
+  virtual void SetWindowRotationAngle( int degree ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::WindowRotationCompleted()
+   */
+  virtual void WindowRotationCompleted( int degree, int width, int height ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetTransparency()
+   */
+  virtual void SetTransparency( bool transparent ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetParent()
+   */
+  virtual void SetParent( WindowBase* parentWinBase ) override;
+
+private:
+
+  /**
+   * Second stage initialization
+   */
+  void Initialize( PositionSize positionSize, Any surface, bool isTransparent );
+
+  /**
+   * @brief Get the surface id if the surface parameter is not empty
+   * @param surface Any containing a surface id, or can be empty
+   * @return surface id, or zero if surface is empty
+   */
+  unsigned int GetSurfaceId( Any surface ) const;
+
+  /**
+   * @brief Create window
+   */
+  void CreateWindow( PositionSize positionSize, bool isTransparent );
+
+protected:
+
+  // Undefined
+  WindowBaseEcoreX(const WindowBaseEcoreX&) = delete;
+
+  // Undefined
+  WindowBaseEcoreX& operator=(const WindowBaseEcoreX& rhs) = delete;
+
+private:
+
+  Dali::Vector< Ecore_Event_Handler* > mEcoreEventHandler;
+  Ecore_X_Window                       mEcoreWindow;        ///< Native window handle
+  bool                                 mOwnSurface:1;       ///< Whether we own the surface (responsible for deleting it)
+  bool                                 mIsTransparent;      ///< Whether the window is transparent (32 bit or 24 bit)
+  bool                                 mRotationAppSet:1;
+};
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_ECOREX_WINDOW_BASE_ECORE_X_H
diff --git a/dali/internal/window-system/ubuntu-x11/window-factory-ecore-x.cpp b/dali/internal/window-system/ubuntu-x11/window-factory-ecore-x.cpp
new file mode 100644 (file)
index 0000000..83e0f11
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/ubuntu-x11/window-factory-ecore-x.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/window-system/ubuntu-x11/window-base-ecore-x.h>
+#include <dali/internal/window-system/common/display-utils.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+std::unique_ptr< WindowBase > WindowFactoryEcoreX::CreateWindowBase( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+{
+  return Utils::MakeUnique< WindowBaseEcoreX >( positionSize, surface, isTransparent );
+}
+
+// this should be created from Window impl
+std::unique_ptr< WindowFactory > GetWindowFactory()
+{
+  // returns Window factory
+  return Utils::MakeUnique< WindowFactoryEcoreX >();
+}
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
diff --git a/dali/internal/window-system/ubuntu-x11/window-factory-ecore-x.h b/dali/internal/window-system/ubuntu-x11/window-factory-ecore-x.h
new file mode 100644 (file)
index 0000000..55cd0f8
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_ECOREX_WINDOW_FACTORY_ECORE_X_H
+#define DALI_INTERNAL_WINDOWSYSTEM_ECOREX_WINDOW_FACTORY_ECORE_X_H
+
+/*
+ * Copyright (c) 2018 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/internal/window-system/common/window-factory.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class WindowFactoryEcoreX : public WindowFactory
+{
+public:
+  std::unique_ptr< WindowBase > CreateWindowBase( Dali::PositionSize positionSize, Any surface, bool isTransparent ) override;
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_ECOREX_WINDOW_FACTORY_ECORE_X_H
diff --git a/dali/internal/window-system/ubuntu-x11/window-interface-ecore-x.cpp b/dali/internal/window-system/ubuntu-x11/window-interface-ecore-x.cpp
new file mode 100644 (file)
index 0000000..1b22155
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * 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 <dali/internal/window-system/ubuntu-x11/window-interface-ecore-x.h>
+
+// EXTERNAL INCLUDES
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/window-system/ubuntu-x11/ecore-x-types.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace ECore
+{
+
+namespace WindowInterface
+{
+// CONSTANTS
+const char* const CBHM_WINDOW = "CBHM_XWIN";
+
+Ecore_X_Window GetWindow()
+{
+  Ecore_X_Atom xAtomCbhm = ecore_x_atom_get( CBHM_WINDOW );
+
+  Ecore_X_Window xCbhmWin = 0;
+  unsigned char *buf = NULL;
+  int num = 0;
+// XA_WINDOW is a macro with C cast
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+  int ret = ecore_x_window_prop_property_get( 0, xAtomCbhm, XA_WINDOW, 0, &buf, &num );
+#pragma GCC diagnostic pop
+
+  if ( ret && num )
+  {
+    memcpy( &xCbhmWin, buf, sizeof( Ecore_X_Window ) );
+  }
+  if ( buf )
+  {
+    free( buf );
+  }
+
+  return xCbhmWin;
+}
+
+std::string GetWindowProperty( Ecore_X_Atom property, Ecore_X_Atom *xDataType, unsigned int num  )
+{
+   std::string data("");
+
+   if ( !property )
+   {
+      return data;
+   }
+
+   ecore_x_sync();
+
+   long unsigned int numRet = 0, bytes = 0;
+   int ret = 0, sizeRet;
+   unsigned int i;
+   unsigned char *propRet;
+   Ecore_X_Atom typeRet;
+
+   // X11 Function to get window property
+   ret = XGetWindowProperty( static_cast<Display*>(ecore_x_display_get()), // Display* X Server Connection
+                             GetWindow(),                                  // Window  window in question
+                             property,                                     // Atom  name of property
+                             num,                                          // long offset where required data is stored
+                             LONG_MAX,                                     // long length of data to retrieve
+                             False,                                        // Bool flag to delete data
+                             ecore_x_window_prop_any_type(),               // Atom atom id associated to property type
+                             reinterpret_cast< Atom * >( &typeRet ),       // Atom actual_type_return, atom id property type
+                             &sizeRet,                                     // int* format of property
+                             &numRet,                                      // unsigned long*  number of items being returned in prop_return
+                             &bytes,                                       // unsigned long* remaining bytes if partial retrieval
+                             &propRet );                                   // unsigned char** return data
+   if ( ret != Success )
+   {
+     return data;
+   }
+
+   if ( !numRet )
+   {
+      XFree( propRet );
+      return data;
+   }
+
+   numRet--; // As propRet in XGetWindowProperty gets an extra 0 added for compatibility reasons.
+
+   switch ( sizeRet ) // Format returned by XGetWindowProperty int, short, long
+   {
+   case 8:
+   {
+     for ( i = 0; i < numRet; i++ )
+     {
+       data += propRet[i];
+     }
+   }
+   break;
+
+   case 16:
+   {
+     for ( i = 0; i < numRet; i++ )
+     {
+       data += ( propRet )[i];
+     }
+   }
+   break;
+
+   case 32:
+   {
+     for ( i = 0; i < numRet; i++ )
+     {
+       data += ( propRet )[i];
+     }
+   }
+   break;
+   }
+
+   XFree( propRet );
+
+   if ( xDataType )
+   {
+     *xDataType = typeRet;
+   }
+
+   return data;
+  }
+
+void SendXEvent(Ecore_X_Display* display, Ecore_X_Window window, bool propagate,
+    long int eventMask, Ecore_X_Atom messageType, int messageFormat, const char *msg )
+{
+  XClientMessageEvent message;
+  memset(&message, 0, sizeof( message ) );
+  message.type = ClientMessage;
+  message.display = static_cast<Display*>( display );
+  message.message_type = messageType;
+  message.format = messageFormat;
+  message.window = window;
+  snprintf(message.data.b, 20, "%s", msg);
+
+  XSendEvent( static_cast<Display*>( display ), window, propagate, eventMask, reinterpret_cast< XEvent* >( &message ) );
+}
+
+
+} // namespace WindowInterface
+
+
+} // namespace ECore
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
diff --git a/dali/internal/window-system/ubuntu-x11/window-interface-ecore-x.h b/dali/internal/window-system/ubuntu-x11/window-interface-ecore-x.h
new file mode 100644 (file)
index 0000000..b9e0b3b
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef DALI_INTERNAL_ECORE_X_RENDER_SURFACE_H
+#define DALI_INTERNAL_ECORE_X_RENDER_SURFACE_H
+
+/*
+ * Copyright (c) 2019 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/internal/system/linux/dali-ecore-x.h>
+#include <X11/Xlib.h>
+
+// INTERNAL INCLUDES
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace ECore
+{
+
+namespace WindowInterface
+{
+/**
+ * X11 Window interface, to separate X11 calls within adaptor.
+ */
+
+/**
+ * Gets the Ecore X Window
+ * @return window
+ */
+ Ecore_X_Window GetWindow();
+
+ /**
+  * Gets a specified X window property
+  * @param[in] property the required property id
+  * @param[in] xDataType the type
+  * @param[in] num the offset / index of the property
+  * @return string the property value
+  */
+ std::string GetWindowProperty( Ecore_X_Atom property, Ecore_X_Atom *xDataType, unsigned int num  );
+
+ /**
+  * Send an X Event
+  * @param[in] display target display
+  * @param[in] window target window
+  * @param[in] propagate to propagate to other windows
+  * @parma[in] eventMask event mask
+  * @param[in] messageType Ecore_X_Atom message type
+  * @param[in] messageFormat format of message
+  * @param[in] msg message to send
+  */
+ void SendXEvent(Ecore_X_Display* display, Ecore_X_Window window, bool propagate,
+                 long int eventMask, Ecore_X_Atom messageType, int messageFormat, const char *msg );
+
+} // namespace WindowInterface
+
+
+} // namespace ECore
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_ECORE_X_RENDER_SURFACE_H
diff --git a/dali/internal/window-system/ubuntu-x11/window-system-ecore-x.cpp b/dali/internal/window-system/ubuntu-x11/window-system-ecore-x.cpp
new file mode 100644 (file)
index 0000000..20b141c
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2019 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 HEADERS
+#include <dali/internal/window-system/common/window-system.h>
+#include <dali/devel-api/adaptor-framework/keyboard.h>
+
+// EXTERNAL_HEADERS
+#include <dali/internal/system/linux/dali-ecore-x.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace WindowSystem
+{
+
+void Initialize()
+{
+  ecore_x_init( NULL );
+}
+
+void Shutdown()
+{
+  ecore_x_shutdown();
+}
+
+void GetScreenSize( int& width, int& height )
+{
+  ecore_x_screen_size_get( ecore_x_default_screen_get(), &width, &height );
+}
+
+bool SetKeyboardRepeatInfo( float rate, float delay )
+{
+  return false;
+}
+
+bool GetKeyboardRepeatInfo( float& rate, float& delay )
+{
+  return false;
+}
+
+} // namespace WindowSystem
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+#pragma GCC diagnostic pop
diff --git a/dali/internal/window-system/windows/display-connection-factory-win.cpp b/dali/internal/window-system/windows/display-connection-factory-win.cpp
new file mode 100755 (executable)
index 0000000..8a93649
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 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 <dali/internal/window-system/windows/display-connection-factory-win.h>
+#include <dali/internal/window-system/windows/display-connection-impl-win.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+
+
+std::unique_ptr<Dali::Internal::Adaptor::DisplayConnection> DisplayConnectionFactoryWin::CreateDisplayConnection()
+{
+  return Utils::MakeUnique<DisplayConnectionWin>();
+}
+
+// this should be created from somewhere
+std::unique_ptr<DisplayConnectionFactory> GetDisplayConnectionFactory()
+{
+  // returns windows display factory
+  return Utils::MakeUnique<DisplayConnectionFactoryWin>();
+}
+
+}
+}
+}
\ No newline at end of file
diff --git a/dali/internal/window-system/windows/display-connection-factory-win.h b/dali/internal/window-system/windows/display-connection-factory-win.h
new file mode 100755 (executable)
index 0000000..72b73ab
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_WIN_DISPLAY_CONNECTION_FACTORY_WIN_H
+#define DALI_INTERNAL_WINDOWSYSTEM_WIN_DISPLAY_CONNECTION_FACTORY_WIN_H
+
+/*
+ * Copyright (c) 2018 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/internal/window-system/common/display-connection-factory.h>
+#include <dali/internal/window-system/common/display-utils.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class DisplayConnectionFactoryWin : public DisplayConnectionFactory
+{
+public:
+  std::unique_ptr<Dali::Internal::Adaptor::DisplayConnection> CreateDisplayConnection() override;
+};
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_WIN_DISPLAY_CONNECTION_FACTORY_WIN_H
diff --git a/dali/internal/window-system/windows/display-connection-impl-win.cpp b/dali/internal/window-system/windows/display-connection-impl-win.cpp
new file mode 100755 (executable)
index 0000000..59babb4
--- /dev/null
@@ -0,0 +1,105 @@
+/*\r
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+ // CLASS HEADER\r
+#include <dali/internal/window-system/windows/display-connection-impl-win.h>\r
+\r
+// EXTERNAL INCLUDES\r
+#include <dali/integration-api/debug.h>\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali/internal/graphics/gles/egl-graphics.h>\r
+\r
+namespace Dali\r
+{\r
+\r
+namespace Internal\r
+{\r
+\r
+namespace Adaptor\r
+{\r
+\r
+DisplayConnection* DisplayConnectionWin::New()\r
+{\r
+  DisplayConnection* pDisplayConnection(new DisplayConnectionWin());\r
+\r
+  return pDisplayConnection;\r
+}\r
+\r
+DisplayConnectionWin::DisplayConnectionWin()\r
+: mDisplay(NULL)\r
+{\r
+}\r
+\r
+DisplayConnectionWin::~DisplayConnectionWin()\r
+{\r
+}\r
+\r
+Any DisplayConnectionWin::GetDisplay()\r
+{\r
+  return Any(mDisplay);\r
+}\r
+\r
+void DisplayConnectionWin::ConsumeEvents()\r
+{\r
+}\r
+\r
+bool DisplayConnectionWin::InitializeEgl(EglInterface& egl)\r
+{\r
+  EglImplementation& eglImpl = static_cast<EglImplementation&>( egl );\r
+\r
+  if( !eglImpl.InitializeGles( reinterpret_cast<EGLNativeDisplayType>( mDisplay ) ) )\r
+  {\r
+    DALI_LOG_ERROR( "Failed to initialize GLES.\n" );\r
+    return false;\r
+  }\r
+\r
+  return true;\r
+}\r
+\r
+bool DisplayConnectionWin::InitializeGraphics()\r
+{\r
+  auto eglGraphics = static_cast<EglGraphics *>( mGraphics );\r
+  EglImplementation& eglImpl = eglGraphics->GetEglImplementation();\r
+\r
+  if( !eglImpl.InitializeGles( reinterpret_cast<EGLNativeDisplayType>( mDisplay ) ) )\r
+  {\r
+    DALI_LOG_ERROR( "Failed to initialize GLES.\n" );\r
+    return false;\r
+  }\r
+\r
+  return true;\r
+}\r
+\r
+void DisplayConnectionWin::SetSurfaceType( Dali::RenderSurfaceInterface::Type type )\r
+{\r
+  if( type == Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE )\r
+  {\r
+     mDisplay = GetDC( GetForegroundWindow() );\r
+  }\r
+}\r
+\r
+void DisplayConnectionWin::SetGraphicsInterface( GraphicsInterface& graphics )\r
+{\r
+  mGraphics = &graphics;\r
+}\r
+\r
+} // namespace Adaptor\r
+\r
+} // namespace Internal\r
+\r
+} // namespace Dali\r
diff --git a/dali/internal/window-system/windows/display-connection-impl-win.h b/dali/internal/window-system/windows/display-connection-impl-win.h
new file mode 100755 (executable)
index 0000000..636419e
--- /dev/null
@@ -0,0 +1,116 @@
+#ifndef DALI_INTERNAL_WIN_DIPLAY_CONNECTION_H\r
+#define DALI_INTERNAL_WIN_DIPLAY_CONNECTION_H\r
+\r
+/*\r
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali/internal/window-system/common/display-connection-impl.h>\r
+#include <dali/public-api/object/base-object.h>\r
+#include <dali/internal/graphics/gles/egl-implementation.h>\r
+\r
+namespace Dali\r
+{\r
+\r
+class RenderSurface;\r
+class DisplayConnection;\r
+\r
+namespace Internal\r
+{\r
+\r
+namespace Adaptor\r
+{\r
+\r
+/**\r
+ * DisplayConnection implementation\r
+ */\r
+class DisplayConnectionWin : public Dali::Internal::Adaptor::DisplayConnection\r
+{\r
+public:\r
+\r
+  /**\r
+   * @brief Default constructor\r
+   */\r
+  DisplayConnectionWin();\r
+\r
+  /**\r
+   * @brief Create an initialized DisplayConnection.\r
+   *\r
+   * @return A handle to a newly allocated DisplayConnection resource.\r
+   */\r
+  static DisplayConnection* New();\r
+\r
+public:\r
+\r
+  /**\r
+   * @copydoc Dali::DisplayConnection::GetDisplay\r
+   */\r
+  Any GetDisplay();\r
+\r
+  /**\r
+   * @copydoc Dali::DisplayConnection::ConsumeEvents\r
+   */\r
+  void ConsumeEvents();\r
+\r
+  /**\r
+   * @copydoc Dali::DisplayConnection::InitializeEgl\r
+   */\r
+  bool InitializeEgl(EglInterface& egl);\r
+\r
+  /**\r
+  * @copydoc Dali::DisplayConnection::InitializeGraphics\r
+  */\r
+  bool InitializeGraphics();\r
+\r
+  /**\r
+  * @copydoc Dali::Internal::Adaptor::DisplayConnection::SetSurfaceType\r
+  */\r
+  void SetSurfaceType( Dali::RenderSurfaceInterface::Type type );\r
+\r
+  /**\r
+  * @copydoc Dali::Internal::Adaptor::DisplayConnection::SetGraphicsInterface\r
+  */\r
+  void SetGraphicsInterface( GraphicsInterface& graphics );\r
+\r
+public:\r
+\r
+  /**\r
+   * Destructor\r
+   */\r
+  virtual ~DisplayConnectionWin();\r
+\r
+private:\r
+\r
+  // Undefined\r
+  DisplayConnectionWin(const DisplayConnectionWin&) = delete;\r
+\r
+  // Undefined\r
+  DisplayConnectionWin& operator=(const DisplayConnectionWin& rhs) = delete;\r
+\r
+private:\r
+\r
+  GraphicsInterface *mGraphics; ///< The graphics interface\r
+  HDC mDisplay;\r
+};\r
+\r
+} // namespace Adaptor\r
+\r
+} // namespace internal\r
+\r
+} // namespace Dali\r
+\r
+#endif // DALI_INTERNAL_WIN_DIPLAY_CONNECTION_H\r
diff --git a/dali/internal/window-system/windows/event-system-win.h b/dali/internal/window-system/windows/event-system-win.h
new file mode 100755 (executable)
index 0000000..ddd7c6c
--- /dev/null
@@ -0,0 +1,107 @@
+#ifndef _WINDOWEVENTSYSTEM_H_\r
+#define _WINDOWEVENTSYSTEM_H_\r
+\r
+/*\r
+* Copyright (c) 2018 Samsung Electronics Co., Ltd.\r
+*\r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+* you may not use this file except in compliance with the License.\r
+* You may obtain a copy of the License at\r
+*\r
+* http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+*\r
+*/\r
+#define DEVICE_MOUSE                    0\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali/internal/window-system/windows/platform-implement-win.h>\r
+\r
+namespace Dali\r
+{\r
+\r
+namespace Internal\r
+{\r
+\r
+namespace Adaptor\r
+{\r
+\r
+struct _Event_Mouse_Button\r
+{\r
+  WinWindowHandle     window; /**< The main window where event happened */\r
+\r
+  uint32_t            timestamp; /**< Time when the event occurred */\r
+\r
+  int32_t             x; /**< x coordinate relative to window where event happened */\r
+  int32_t             y; /**< y coordinate relative to window where event happened */\r
+\r
+  struct\r
+  {\r
+    int32_t       device; /**< 0 if normal mouse, 1+ for other mouse-devices (eg multi-touch - other fingers) */\r
+    double        radius, radius_x, radius_y; /**< radius of press point - radius_x and y if its an ellipse (radius is the average of the 2) */\r
+    double        pressure; /**< pressure - 1.0 == normal, > 1.0 == more, 0.0 == none */\r
+    double        angle; /**< angle relative to perpendicular (0.0 == perpendicular), in degrees */\r
+    double        x, y; /**< same as x, y, but with sub-pixel precision, if available */\r
+    struct\r
+    {\r
+      double     x, y;\r
+    } root; /**< same as root.x, root.y, but with sub-pixel precision, if available */\r
+  } multi;\r
+};\r
+\r
+/**\r
+* @struct _Event_Mouse_Wheel\r
+* Contains information about an Windows mouse wheel event.\r
+*/\r
+struct _Event_Mouse_Wheel\r
+{\r
+  WinWindowHandle     window; /**< The main window where event happened */\r
+  WinWindowHandle     root_window; /**< The root window where event happened */\r
+  WinWindowHandle     event_window; /**< The child window where event happened */\r
+\r
+  uint32_t            timestamp; /**< Time when the event occurred */\r
+  uint32_t            modifiers; /**< The combination of modifiers key (SHIFT,CTRL,ALT,..)*/\r
+\r
+  int32_t              direction; /**< Orientation of the wheel (horizontal/vertical) */\r
+  int32_t              z; /**< Value of the wheel event (+1/-1) */\r
+\r
+  int32_t              x; /**< x coordinate relative to window where event happened */\r
+  int32_t              y; /**< y coordinate relative to window where event happened */\r
+  struct\r
+  {\r
+       int32_t           x;\r
+       int32_t           y;\r
+  } root; /**< Coordinates relative to root window */\r
+};\r
+\r
+typedef struct _Event_Mouse_Button Event_Mouse_Button;\r
+typedef struct _Event_Mouse_Wheel  Event_Mouse_Wheel;\r
+\r
+struct TWinEventInfo\r
+{\r
+  TWinEventInfo( uint64_t hWnd, uint32_t uMsg, uint64_t wParam, uint64_t lParam)\r
+  {\r
+    this->mWindow = (WinWindowHandle)hWnd;\r
+    this->uMsg = uMsg;\r
+    this->wParam = wParam;\r
+    this->lParam = lParam;\r
+  }\r
+\r
+  WinWindowHandle mWindow;\r
+  uint32_t uMsg;\r
+  uint64_t wParam;\r
+  uint64_t lParam;\r
+};\r
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali\r
+\r
+#endif\r
diff --git a/dali/internal/window-system/windows/platform-implement-win.cpp b/dali/internal/window-system/windows/platform-implement-win.cpp
new file mode 100755 (executable)
index 0000000..13932b5
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+* Copyright (c) 2018 Samsung Electronics Co., Ltd.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*
+*/
+
+// CLASS HEADER
+#include <dali/internal/window-system/windows/platform-implement-win.h>
+
+// EXTERNAL INCLUDES
+#include <map>
+#include <windows.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/window-system/windows/event-system-win.h>
+
+namespace
+{
+static constexpr float INCH = 25.4;
+}
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace WindowsPlatformImplementation
+{
+
+LRESULT CALLBACK WinProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+  WindowImpl::ProcWinMessage( reinterpret_cast<uint64_t>( hWnd ), uMsg, wParam, lParam );
+
+  LRESULT ret = DefWindowProc( hWnd, uMsg, wParam, lParam );
+  return ret;
+}
+
+std::map<uint64_t, WindowImpl*> mHWndToListener;
+
+WindowImpl::WindowImpl()
+{
+  colorDepth = -1;
+  mHWnd = 0;
+  mHdc = 0;
+  listener = NULL;
+  windowStyle = WS_OVERLAPPED;
+}
+
+WindowImpl::~WindowImpl()
+{
+  mHWndToListener.erase( mHWnd );
+}
+
+void WindowImpl::ProcWinMessage( uint64_t hWnd, uint32_t uMsg, uint64_t wParam, uint64_t lParam )
+{
+  std::map<uint64_t, WindowImpl*>::iterator x = mHWndToListener.find( hWnd );
+
+  if( mHWndToListener.end() != x )
+  {
+    CallbackBase* listener = x->second->listener;
+
+    if( NULL != listener )
+    {
+      TWinEventInfo eventInfo( hWnd, uMsg, wParam, lParam );
+      CallbackBase::Execute( *listener, &eventInfo );
+    }
+  }
+}
+
+void WindowImpl::GetDPI( float &xDpi, float &yDpi )
+{
+  HDC hdcScreen = GetDC( reinterpret_cast<HWND>( mHWnd ) );
+
+  int32_t iX = GetDeviceCaps( hdcScreen, HORZRES );    // pixel
+  int32_t iY = GetDeviceCaps( hdcScreen, VERTRES );    // pixel
+  int32_t iPhsX = GetDeviceCaps( hdcScreen, HORZSIZE );    // mm
+  int32_t iPhsY = GetDeviceCaps( hdcScreen, VERTSIZE );    // mm
+
+  xDpi = static_cast<float>( iX ) / static_cast<float>( iPhsX ) * INCH;
+  yDpi = static_cast<float>( iY ) / static_cast<float>( iPhsY ) * INCH;
+}
+
+int WindowImpl::GetColorDepth()
+{
+  DALI_ASSERT_DEBUG( colorDepth >= 0 && "HWND hasn't been created, no color depth" );
+  return colorDepth;
+}
+
+uint64_t WindowImpl::CreateHwnd(
+  _In_opt_ const char *lpClassName,
+  _In_opt_ const char *lpWindowName,
+  _In_ int X,
+  _In_ int Y,
+  _In_ int nWidth,
+  _In_ int nHeight,
+  _In_opt_ uint64_t parent )
+{
+  WNDCLASS cs = { 0 };
+  cs.cbClsExtra = 0;
+  cs.cbWndExtra = 0;
+  cs.hbrBackground = (HBRUSH)( COLOR_WINDOW + 2 );
+  cs.hCursor = NULL;
+  cs.hIcon = NULL;
+  cs.hInstance = GetModuleHandle( NULL );
+  cs.lpfnWndProc = (WNDPROC)WinProc;
+  cs.lpszClassName = lpClassName;
+  cs.lpszMenuName = NULL;
+  cs.style = CS_VREDRAW | CS_HREDRAW;
+  RegisterClass( &cs );
+
+  HWND hWnd = CreateWindow( lpClassName, lpWindowName, windowStyle, X, Y, nWidth + 2 * GetEdgeWidth(), nHeight + 2 * GetEdgeHeight(), NULL, NULL, cs.hInstance, NULL );
+  ::ShowWindow( hWnd, SW_SHOW );
+
+  SetHWND( reinterpret_cast<uint64_t>(hWnd) );
+
+  return mHWnd;
+}
+
+void WindowImpl::SetListener( CallbackBase *callback )
+{
+  listener = callback;
+}
+
+bool WindowImpl::PostWinMessage(
+  _In_ uint32_t Msg,
+  _In_ uint32_t wParam,
+  _In_ uint64_t lParam )
+{
+  return (bool)PostMessage( reinterpret_cast<HWND>( mHWnd ), Msg, wParam, lParam );
+}
+
+int32_t WindowImpl::GetEdgeWidth()
+{
+  switch( windowStyle )
+  {
+  case WS_OVERLAPPED:
+  {
+    return 8;
+  }
+  default:
+  {
+    return 0;
+  }
+  }
+}
+
+int32_t WindowImpl::GetEdgeHeight()
+{
+  switch( windowStyle )
+  {
+  case WS_OVERLAPPED:
+  {
+    return 18;
+  }
+  default:
+  {
+    return 0;
+  }
+  }
+}
+
+void WindowImpl::SetHWND( uint64_t inHWnd )
+{
+  if (mHWnd != inHWnd)
+  {
+    mHWnd = inHWnd;
+    mHdc = reinterpret_cast<uint64_t>(GetDC(reinterpret_cast<HWND>(mHWnd)));
+    colorDepth = GetDeviceCaps(reinterpret_cast<HDC>(mHdc), BITSPIXEL) * GetDeviceCaps(reinterpret_cast<HDC>(mHdc), PLANES);
+
+    std::map<uint64_t, WindowImpl*>::iterator x = mHWndToListener.find(mHWnd);
+
+    if (mHWndToListener.end() == x)
+    {
+      mHWndToListener.insert(std::make_pair(mHWnd, this));
+    }
+    else
+    {
+      x->second = this;
+    }
+  }
+}
+
+void WindowImpl::SetWinProc()
+{
+  // Sets the WinProc function.
+  LONG_PTR ret = SetWindowLongPtr((HWND)mHWnd,
+                                  GWLP_WNDPROC,
+                                  reinterpret_cast<LONG_PTR>(&WinProc));
+
+  if (0 == ret)
+  {
+    DWORD error = GetLastError();
+    return;
+  }
+
+  HMODULE module = GetModuleHandle(nullptr);
+  ret = SetWindowLongPtr((HWND)mHWnd,
+                         GWLP_HINSTANCE,
+                         reinterpret_cast<LONG_PTR>(&module));
+}
+
+bool PostWinThreadMessage(
+  _In_ uint32_t Msg,
+  _In_ uint32_t wParam,
+  _In_ uint64_t lParam,
+  _In_ uint64_t threadID/* = -1*/ )
+{
+  if( -1 == threadID )
+  {
+    threadID = GetCurrentThreadId();
+  }
+
+  return (bool)PostThreadMessage( threadID, Msg, wParam, lParam );
+}
+
+struct TTimerCallbackInfo
+{
+  void *data;
+  timerCallback callback;
+  HWND hWnd;
+};
+
+void CALLBACK TimerProc(HWND hWnd, UINT nMsg, UINT_PTR nTimerid, DWORD dwTime)
+{
+  TTimerCallbackInfo *info = (TTimerCallbackInfo*)nTimerid;
+  info->callback( info->data );
+}
+
+int SetTimer(int interval, timerCallback callback, void *data)
+{
+  TTimerCallbackInfo *callbackInfo = new TTimerCallbackInfo;
+  callbackInfo->data = data;
+  callbackInfo->callback = callback;
+  callbackInfo->hWnd = ::GetActiveWindow();
+
+  UINT_PTR timerID = (UINT_PTR)callbackInfo;
+  ::SetTimer( callbackInfo->hWnd, timerID, interval, TimerProc );
+
+  return timerID;
+}
+
+void KillTimer(int id)
+{
+  TTimerCallbackInfo *info = (TTimerCallbackInfo*)id;
+  ::KillTimer( info->hWnd, id );
+  delete info;
+}
+
+const char* GetKeyName( int keyCode )
+{
+  switch( keyCode )
+  {
+    case VK_BACK:
+    {
+      return "Backspace";
+    }
+    case VK_TAB:
+    {
+      return "Tab";
+    }
+    case VK_RETURN:
+    {
+      return "Return";
+    }
+    case VK_ESCAPE:
+    {
+      return "Escape";
+    }
+    case VK_SPACE:
+    {
+      return "Space";
+    }
+    case VK_LEFT:
+    {
+      return "Left";
+    }
+    case VK_UP:
+    {
+      return "Up";
+    }
+    case VK_RIGHT:
+    {
+      return "Right";
+    }
+    case VK_DOWN:
+    {
+      return "Down";
+    }
+    case 48:
+    {
+      return "0";
+    }
+    case 49:
+    {
+      return "1";
+    }
+    case 50:
+    {
+      return "2";
+    }
+    case 51:
+    {
+      return "3";
+    }
+    case 52:
+    {
+      return "4";
+    }
+    case 53:
+    {
+      return "5";
+    }
+    case 54:
+    {
+      return "6";
+    }
+    case 55:
+    {
+      return "7";
+    }
+    case 56:
+    {
+      return "8";
+    }
+    case 57:
+    {
+      return "9";
+    }
+    default:
+    {
+      break;
+    }
+  }
+
+  return "";
+}
+
+static LARGE_INTEGER cpuFrequency;
+static LARGE_INTEGER *pCpuFrequency = NULL;
+
+uint64_t GetCurrentThreadId()
+{
+  return ::GetCurrentThreadId();
+}
+
+void GetNanoseconds( uint64_t& timeInNanoseconds )
+{
+  if( NULL == pCpuFrequency )
+  {
+    pCpuFrequency = &cpuFrequency;
+    QueryPerformanceFrequency( pCpuFrequency );
+  }
+
+  LARGE_INTEGER curTime;
+  QueryPerformanceCounter( &curTime );
+
+  timeInNanoseconds = static_cast<double>(curTime.QuadPart) / static_cast<double>(pCpuFrequency->QuadPart) * 1000000000;
+}
+
+unsigned int GetCurrentMilliSeconds( void )
+{
+  if( NULL == pCpuFrequency )
+  {
+    pCpuFrequency = &cpuFrequency;
+    QueryPerformanceFrequency( pCpuFrequency );
+  }
+
+  LARGE_INTEGER curTime;
+  QueryPerformanceCounter( &curTime );
+
+  return curTime.QuadPart * 1000 / pCpuFrequency->QuadPart;
+}
+
+} // namespace WindowsPlatformImplement
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
diff --git a/dali/internal/window-system/windows/platform-implement-win.h b/dali/internal/window-system/windows/platform-implement-win.h
new file mode 100755 (executable)
index 0000000..7f1fe0a
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef PLATFORM_IMPLEMENT_WIN_INCLUDE\r
+#define PLATFORM_IMPLEMENT_WIN_INCLUDE\r
+\r
+/*\r
+* Copyright (c) 2018 Samsung Electronics Co., Ltd.\r
+*\r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+* you may not use this file except in compliance with the License.\r
+* You may obtain a copy of the License at\r
+*\r
+* http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+*\r
+*/\r
+\r
+// EXTERNAL_HEADERS\r
+#include <stdint.h>\r
+#include <dali/public-api/signals/callback.h>\r
+\r
+typedef uint64_t   WinWindowHandle;\r
+typedef uint64_t   WinPixmap;\r
+\r
+namespace Dali\r
+{\r
+\r
+namespace Internal\r
+{\r
+\r
+namespace Adaptor\r
+{\r
+\r
+namespace WindowsPlatformImplementation\r
+{\r
+\r
+bool PostWinThreadMessage(\r
+    _In_ uint32_t Msg,\r
+    _In_ uint32_t wParam,\r
+    _In_ uint64_t lParam,\r
+    _In_ uint64_t threadID = -1 );\r
+\r
+using timerCallback = bool(*)(void *data);\r
+\r
+int SetTimer(int interval, timerCallback callback, void *data);\r
+\r
+void KillTimer(int id);\r
+\r
+const char* GetKeyName( int keyCode );\r
+\r
+uint64_t GetCurrentThreadId();\r
+\r
+void GetNanoseconds( uint64_t& timeInNanoseconds );\r
+\r
+unsigned int GetCurrentMilliSeconds( void );\r
+\r
+class WindowImpl\r
+{\r
+public:\r
+  WindowImpl();\r
+\r
+  virtual ~WindowImpl();\r
+\r
+  static void ProcWinMessage( uint64_t hWnd, uint32_t uMsg, uint64_t wParam, uint64_t lParam );\r
+\r
+  void GetDPI( float &xDpi, float &yDpi );\r
+\r
+  int GetColorDepth();\r
+\r
+  uint64_t CreateHwnd(\r
+    _In_opt_ const char *lpClassName,\r
+    _In_opt_ const char *lpWindowName,\r
+    _In_ int X,\r
+    _In_ int Y,\r
+    _In_ int nWidth,\r
+    _In_ int nHeight,\r
+    _In_opt_ uint64_t parent );\r
+\r
+  void SetListener( CallbackBase *callback );\r
+\r
+  bool PostWinMessage(\r
+    _In_ uint32_t Msg,\r
+    _In_ uint32_t wParam,\r
+    _In_ uint64_t lParam );\r
+\r
+  int32_t GetEdgeWidth();\r
+\r
+  int32_t GetEdgeHeight();\r
+\r
+  void SetHWND(uint64_t inHWnd);\r
+  void SetWinProc();\r
+\r
+protected:\r
+\r
+private:\r
+\r
+  unsigned long windowStyle;\r
+\r
+  int colorDepth;\r
+  uint64_t mHWnd;\r
+  uint64_t mHdc;\r
+\r
+  CallbackBase *listener;\r
+};\r
+\r
+} // namespace WindowsPlatformImplement\r
+\r
+} // namespace Adaptor\r
+\r
+} // namespace internal\r
+\r
+} // namespace Dali\r
+\r
+#endif // WIN32_WINDOWS_SYSTEM_INCLUDE\r
diff --git a/dali/internal/window-system/windows/render-surface-factory-win.cpp b/dali/internal/window-system/windows/render-surface-factory-win.cpp
new file mode 100755 (executable)
index 0000000..efb6714
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/windows/render-surface-factory-win.h>
+
+// EXTERNAL HEADERS
+#include <dali/integration-api/debug.h>
+
+// INTERNAL HEADERS
+#include <dali/integration-api/adaptor-framework/native-render-surface.h>
+#include <dali/internal/window-system/common/display-utils.h>
+#include <dali/internal/window-system/common/pixmap-render-surface.h>
+#include <dali/internal/window-system/common/window-render-surface.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+std::unique_ptr< WindowRenderSurface > RenderSurfaceFactoryWin::CreateWindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+{
+  return Utils::MakeUnique< WindowRenderSurface >( positionSize, surface, isTransparent );
+}
+
+std::unique_ptr< PixmapRenderSurface > RenderSurfaceFactoryWin::CreatePixmapRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+{
+  DALI_LOG_ERROR("Pixmap isn't been supported in Windows");
+  return nullptr;
+}
+
+std::unique_ptr< NativeRenderSurface > RenderSurfaceFactoryWin::CreateNativeRenderSurface( Dali::PositionSize positionSize, bool isTransparent )
+{
+  return std::unique_ptr< NativeRenderSurface >( nullptr );
+}
+
+// this should be created from somewhere
+std::unique_ptr< RenderSurfaceFactory > GetRenderSurfaceFactory()
+{
+  // returns Window factory
+  return Utils::MakeUnique< RenderSurfaceFactoryWin >();
+}
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
diff --git a/dali/internal/window-system/windows/render-surface-factory-win.h b/dali/internal/window-system/windows/render-surface-factory-win.h
new file mode 100755 (executable)
index 0000000..fd05c74
--- /dev/null
@@ -0,0 +1,44 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_WIN_RENDER_SURFACE_FACTORY_WIN_H
+#define DALI_INTERNAL_WINDOWSYSTEM_WIN_RENDER_SURFACE_FACTORY_WIN_H
+
+/*
+ * Copyright (c) 2018 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/internal/window-system/common/render-surface-factory.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class RenderSurfaceFactoryWin : public RenderSurfaceFactory
+{
+public:
+  std::unique_ptr< WindowRenderSurface > CreateWindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent = false ) override;
+
+  std::unique_ptr< PixmapRenderSurface > CreatePixmapRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent = false ) override;
+
+  std::unique_ptr< NativeRenderSurface > CreateNativeRenderSurface( Dali::PositionSize positionSize, bool isTransparent = false ) override;
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_WIN_RENDER_SURFACE_FACTORY_WIN_H
diff --git a/dali/internal/window-system/windows/window-base-win.cpp b/dali/internal/window-system/windows/window-base-win.cpp
new file mode 100755 (executable)
index 0000000..c968bea
--- /dev/null
@@ -0,0 +1,575 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/windows/window-base-win.h>
+
+// EXTERNAL_HEADERS
+#include <dali/public-api/object/any.h>
+#include <dali/integration-api/debug.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/window-system/common/window-impl.h>
+#include <dali/internal/window-system/common/window-render-surface.h>
+#include <dali/internal/window-system/common/window-system.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace
+{
+
+const Device::Class::Type DEFAULT_DEVICE_CLASS = Device::Class::NONE;
+const Device::Subclass::Type DEFAULT_DEVICE_SUBCLASS = Device::Subclass::NONE;
+
+const unsigned int PRIMARY_TOUCH_BUTTON_ID( 1 );
+
+#if defined(DEBUG_ENABLED)
+Debug::Filter* gWindowBaseLogFilter = Debug::Filter::New( Debug::NoLogging, false, "LOG_WINDOW_BASE" );
+#endif
+
+} // unnamed namespace
+
+WindowBaseWin::WindowBaseWin( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+: mWin32Window( 0 ),
+  mOwnSurface( false ),
+  mIsTransparent( false ), // Should only be set to true once we actually create a transparent window regardless of what isTransparent is.
+  mRotationAppSet( false )
+{
+  Initialize( positionSize, surface, isTransparent );
+}
+
+WindowBaseWin::~WindowBaseWin()
+{
+  mWindowImpl.PostWinMessage( WM_CLOSE, 0, 0 );
+}
+
+void WindowBaseWin::Initialize( PositionSize positionSize, Any surface, bool isTransparent )
+{
+  // see if there is a surface in Any surface
+  unsigned int surfaceId = GetSurfaceId( surface );
+
+  // if the surface is empty, create a new one.
+  if( surfaceId == 0 )
+  {
+    // we own the surface about to created
+    mOwnSurface = true;
+    CreateWinWindow( positionSize, isTransparent );
+  }
+  else
+  {
+    SetWinWindow( surfaceId );
+  }
+
+  mWindowImpl.SetListener( MakeCallback( this, &WindowBaseWin::EventEntry ) );
+}
+
+void WindowBaseWin::OnDeleteRequest()
+{
+  mDeleteRequestSignal.Emit();
+}
+
+void WindowBaseWin::OnFocusIn( int type, TWinEventInfo *event )
+{
+}
+
+void WindowBaseWin::OnFocusOut( int type, TWinEventInfo *event )
+{
+}
+
+void WindowBaseWin::OnWindowDamaged( int type, TWinEventInfo *event )
+{
+  Event_Mouse_Button* windowDamagedEvent( (Event_Mouse_Button*)event );
+
+  if( windowDamagedEvent->window == mWin32Window )
+  {
+    DamageArea area;
+    area.x = 0;
+    area.y = 0;
+    WindowSystem::GetScreenSize( area.width, area.height );
+
+    mWindowDamagedSignal.Emit( area );
+  }
+}
+
+void WindowBaseWin::OnMouseButtonDown( int type, TWinEventInfo *event )
+{
+  Event_Mouse_Button touchEvent = *((Event_Mouse_Button*)event);
+  touchEvent.timestamp = GetTickCount();
+  touchEvent.x = LOWORD( event->lParam );
+  touchEvent.y = HIWORD( event->lParam );
+  touchEvent.multi.device = DEVICE_MOUSE;
+
+  if( touchEvent.window == mWin32Window )
+  {
+    PointState::Type state ( PointState::DOWN );
+
+    Integration::Point point;
+    point.SetDeviceId( touchEvent.multi.device );
+    point.SetState( state );
+    point.SetScreenPosition( Vector2( touchEvent.x, touchEvent.y + mWindowImpl.GetEdgeHeight() ) );
+    point.SetRadius( touchEvent.multi.radius, Vector2( touchEvent.multi.radius_x, touchEvent.multi.radius_y ) );
+    point.SetPressure( touchEvent.multi.pressure );
+    point.SetAngle( Degree( touchEvent.multi.angle ) );
+
+    mTouchEventSignal.Emit( point, touchEvent.timestamp );
+  }
+}
+
+void WindowBaseWin::OnMouseButtonUp( int type, TWinEventInfo *event )
+{
+  Event_Mouse_Button touchEvent = *( (Event_Mouse_Button*)event );
+  touchEvent.timestamp = GetTickCount();
+  touchEvent.x = LOWORD( event->lParam );
+  touchEvent.y = HIWORD( event->lParam );
+  touchEvent.multi.device = DEVICE_MOUSE;
+
+  if( touchEvent.window == mWin32Window )
+  {
+    PointState::Type state( PointState::UP );
+
+    Integration::Point point;
+    point.SetDeviceId( touchEvent.multi.device );
+    point.SetState( state );
+    point.SetScreenPosition( Vector2( touchEvent.x, touchEvent.y + mWindowImpl.GetEdgeHeight() ) );
+    point.SetRadius( touchEvent.multi.radius, Vector2( touchEvent.multi.radius_x, touchEvent.multi.radius_y ) );
+    point.SetPressure( touchEvent.multi.pressure );
+    point.SetAngle( Degree( touchEvent.multi.angle ) );
+
+    mTouchEventSignal.Emit( point, touchEvent.timestamp );
+  }
+}
+
+void WindowBaseWin::OnMouseButtonMove( int type, TWinEventInfo *event )
+{
+  Event_Mouse_Button touchEvent = *((Event_Mouse_Button*)event);
+  touchEvent.timestamp = GetTickCount();
+  touchEvent.x = LOWORD( event->lParam );
+  touchEvent.y = HIWORD( event->lParam );
+  touchEvent.multi.device = DEVICE_MOUSE;
+
+  if( touchEvent.window == mWin32Window )
+  {
+    PointState::Type state( PointState::MOTION );
+
+    Integration::Point point;
+    point.SetDeviceId( touchEvent.multi.device );
+    point.SetState( state );
+    point.SetScreenPosition( Vector2( touchEvent.x, touchEvent.y + mWindowImpl.GetEdgeHeight() ) );
+    point.SetRadius( touchEvent.multi.radius, Vector2( touchEvent.multi.radius_x, touchEvent.multi.radius_y ) );
+    point.SetPressure( touchEvent.multi.pressure );
+    point.SetAngle( Degree( touchEvent.multi.angle ) );
+
+    mTouchEventSignal.Emit( point, touchEvent.timestamp );
+  }
+}
+
+void WindowBaseWin::OnMouseWheel( int type, TWinEventInfo *event )
+{
+  Event_Mouse_Wheel mouseWheelEvent = *((Event_Mouse_Wheel*)( event ));
+
+  if( mouseWheelEvent.window == mWin32Window )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseWin::OnMouseWheel: direction: %d, modifiers: %d, x: %d, y: %d, z: %d\n", mouseWheelEvent.direction, mouseWheelEvent.modifiers, mouseWheelEvent.x, mouseWheelEvent.y, mouseWheelEvent.z );
+
+    WheelEvent wheelEvent( WheelEvent::MOUSE_WHEEL, mouseWheelEvent.direction, mouseWheelEvent.modifiers, Vector2( mouseWheelEvent.x, mouseWheelEvent.y ), mouseWheelEvent.z, mouseWheelEvent.timestamp );
+
+    mWheelEventSignal.Emit( wheelEvent );
+  }
+}
+
+void WindowBaseWin::OnKeyDown( int type, TWinEventInfo *event )
+{
+  if( event->mWindow == mWin32Window )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseWin::OnKeyDown\n" );
+
+    int keyCode = event->wParam;
+    std::string keyName( WindowsPlatformImplementation::GetKeyName( keyCode ) );
+    std::string keyString;
+    std::string emptyString;
+
+    int modifier( 0 );
+    unsigned long time( 0 );
+
+    // Ensure key event string is not NULL as keys like SHIFT have a null string.
+    keyString.push_back( event->wParam );
+
+    Integration::KeyEvent keyEvent( keyName, emptyString, keyString, keyCode, modifier, time, Integration::KeyEvent::Down, emptyString, emptyString, DEFAULT_DEVICE_CLASS, DEFAULT_DEVICE_SUBCLASS );
+
+    mKeyEventSignal.Emit( keyEvent );
+  }
+}
+
+void WindowBaseWin::OnKeyUp( int type, TWinEventInfo *event )
+{
+  if( event->mWindow == mWin32Window )
+  {
+    DALI_LOG_INFO( gWindowBaseLogFilter, Debug::General, "WindowBaseWin::OnKeyDown\n" );
+
+    int keyCode = event->wParam;
+    std::string keyName( WindowsPlatformImplementation::GetKeyName( keyCode ) );
+    std::string keyString;
+    std::string emptyString;
+
+    int modifier( 0 );
+    unsigned long time( 0 );
+
+    // Ensure key event string is not NULL as keys like SHIFT have a null string.
+    keyString.push_back( event->wParam );
+
+    Integration::KeyEvent keyEvent( keyName, emptyString, keyString, keyCode, modifier, time, Integration::KeyEvent::Up, emptyString, emptyString, DEFAULT_DEVICE_CLASS, DEFAULT_DEVICE_SUBCLASS );
+
+    mKeyEventSignal.Emit( keyEvent );
+  }
+}
+
+Any WindowBaseWin::GetNativeWindow()
+{
+  return mWin32Window;
+}
+
+int WindowBaseWin::GetNativeWindowId()
+{
+  return mWin32Window;
+}
+
+EGLNativeWindowType WindowBaseWin::CreateEglWindow( int width, int height )
+{
+  return reinterpret_cast< EGLNativeWindowType >( mWin32Window );
+}
+
+void WindowBaseWin::DestroyEglWindow()
+{
+}
+
+void WindowBaseWin::SetEglWindowRotation( int angle )
+{
+}
+
+void WindowBaseWin::SetEglWindowBufferTransform( int angle )
+{
+}
+
+void WindowBaseWin::SetEglWindowTransform( int angle )
+{
+}
+
+void WindowBaseWin::ResizeEglWindow( PositionSize positionSize )
+{
+}
+
+bool WindowBaseWin::IsEglWindowRotationSupported()
+{
+  return false;
+}
+
+void WindowBaseWin::Move( PositionSize positionSize )
+{
+}
+
+void WindowBaseWin::Resize( PositionSize positionSize )
+{
+  ::SetWindowPos( (HWND)mWin32Window, NULL, positionSize.x, positionSize.y, positionSize.width, positionSize.height, SWP_SHOWWINDOW );
+}
+
+void WindowBaseWin::MoveResize( PositionSize positionSize )
+{
+}
+
+void WindowBaseWin::SetClass( const std::string& name, const std::string& className )
+{
+}
+
+void WindowBaseWin::Raise()
+{
+}
+
+void WindowBaseWin::Lower()
+{
+}
+
+void WindowBaseWin::Activate()
+{
+}
+
+void WindowBaseWin::SetAvailableAnlges( const std::vector< int >& angles )
+{
+}
+
+void WindowBaseWin::SetPreferredAngle( int angle )
+{
+}
+
+void WindowBaseWin::SetAcceptFocus( bool accept )
+{
+}
+
+void WindowBaseWin::Show()
+{
+}
+
+void WindowBaseWin::Hide()
+{
+}
+
+unsigned int WindowBaseWin::GetSupportedAuxiliaryHintCount() const
+{
+  return 0;
+}
+
+std::string WindowBaseWin::GetSupportedAuxiliaryHint( unsigned int index ) const
+{
+  return std::string();
+}
+
+unsigned int WindowBaseWin::AddAuxiliaryHint( const std::string& hint, const std::string& value )
+{
+  return 0;
+}
+
+bool WindowBaseWin::RemoveAuxiliaryHint( unsigned int id )
+{
+  return false;
+}
+
+bool WindowBaseWin::SetAuxiliaryHintValue( unsigned int id, const std::string& value )
+{
+  return false;
+}
+
+std::string WindowBaseWin::GetAuxiliaryHintValue( unsigned int id ) const
+{
+  return std::string();
+}
+
+unsigned int WindowBaseWin::GetAuxiliaryHintId( const std::string& hint ) const
+{
+  return 0;
+}
+
+void WindowBaseWin::SetInputRegion( const Rect< int >& inputRegion )
+{
+}
+
+void WindowBaseWin::SetType( Dali::Window::Type type )
+{
+}
+
+bool WindowBaseWin::SetNotificationLevel( Dali::Window::NotificationLevel::Type level )
+{
+  return false;
+}
+
+Dali::Window::NotificationLevel::Type WindowBaseWin::GetNotificationLevel() const
+{
+  return Dali::Window::NotificationLevel::NONE;
+}
+
+void WindowBaseWin::SetOpaqueState( bool opaque )
+{
+}
+
+bool WindowBaseWin::SetScreenOffMode(Dali::Window::ScreenOffMode::Type screenOffMode)
+{
+  return false;
+}
+
+Dali::Window::ScreenOffMode::Type WindowBaseWin::GetScreenOffMode() const
+{
+  return Dali::Window::ScreenOffMode::TIMEOUT;
+}
+
+bool WindowBaseWin::SetBrightness( int brightness )
+{
+  return false;
+}
+
+int WindowBaseWin::GetBrightness() const
+{
+  return 0;
+}
+
+bool WindowBaseWin::GrabKey( Dali::KEY key, KeyGrab::KeyGrabMode grabMode )
+{
+  return false;
+}
+
+bool WindowBaseWin::UngrabKey( Dali::KEY key )
+{
+  return false;
+}
+
+bool WindowBaseWin::GrabKeyList( const Dali::Vector< Dali::KEY >& key, const Dali::Vector< KeyGrab::KeyGrabMode >& grabMode, Dali::Vector< bool >& result )
+{
+  return false;
+}
+
+bool WindowBaseWin::UngrabKeyList( const Dali::Vector< Dali::KEY >& key, Dali::Vector< bool >& result )
+{
+  return false;
+}
+
+void WindowBaseWin::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
+{
+  // calculate DPI
+  float xres, yres;
+
+  //// 1 inch = 25.4 millimeters
+  mWindowImpl.GetDPI( xres, yres );
+
+  xres *= 1.5f;
+  yres *= 1.5f;
+
+  dpiHorizontal = static_cast<int>( xres + 0.5f );  // rounding
+  dpiVertical = static_cast<int>( yres + 0.5f );
+}
+
+int WindowBaseWin::GetScreenRotationAngle()
+{
+  return 0;
+}
+
+void WindowBaseWin::SetWindowRotationAngle( int degree )
+{
+}
+
+void WindowBaseWin::WindowRotationCompleted( int degree, int width, int height )
+{
+}
+
+void WindowBaseWin::SetTransparency( bool transparent )
+{
+}
+
+unsigned int WindowBaseWin::GetSurfaceId( Any surface ) const
+{
+  unsigned int surfaceId = 0;
+
+  if ( surface.Empty() == false )
+  {
+    // check we have a valid type
+    DALI_ASSERT_ALWAYS( (surface.GetType() == typeid ( WinWindowHandle ) )
+                        && "Surface type is invalid" );
+
+    surfaceId = AnyCast< WinWindowHandle >( surface );
+  }
+  return surfaceId;
+}
+
+void WindowBaseWin::CreateWinWindow( PositionSize positionSize, bool isTransparent )
+{
+  long hWnd = mWindowImpl.CreateHwnd( "Demo", "Demo", positionSize.x, positionSize.y, positionSize.width, positionSize.height, NULL );
+
+  mWin32Window = static_cast<WinWindowHandle>(hWnd);
+
+  DALI_ASSERT_ALWAYS( mWin32Window != 0 && "There is no Windows window" );
+}
+
+void WindowBaseWin::SetWinWindow( unsigned int surfaceId )
+{
+  HWND hWnd = (HWND)surfaceId;
+
+  mWin32Window = static_cast<WinWindowHandle>(surfaceId);
+
+  mWindowImpl.SetHWND( reinterpret_cast<uint64_t>(hWnd));
+
+  mWindowImpl.SetWinProc();
+}
+
+void WindowBaseWin::EventEntry( TWinEventInfo *event )
+{
+  unsigned int uMsg = event->uMsg;
+
+  switch( uMsg )
+  {
+  case WM_SETFOCUS:
+  {
+    OnFocusIn( uMsg, event );
+    break;
+  }
+
+  case WM_KILLFOCUS:
+  {
+    OnFocusOut( uMsg, event );
+    break;
+  }
+
+  case WM_PAINT:
+  {
+    OnWindowDamaged( uMsg, event );
+    break;
+  }
+
+  case WM_LBUTTONDOWN:
+  {
+    OnMouseButtonDown( uMsg, event );
+    break;
+  }
+
+  case WM_LBUTTONUP:
+  {
+    OnMouseButtonUp( uMsg, event );
+    break;
+  }
+
+  case WM_MOUSEMOVE:
+  {
+    OnMouseButtonMove( uMsg, event );
+    break;
+  }
+
+  case WM_MOUSEWHEEL:
+  {
+    OnMouseWheel( uMsg, event );
+    break;
+  }
+
+  case WM_KEYDOWN:
+  {
+    OnKeyDown( uMsg, event );
+    break;
+  }
+
+  case WM_KEYUP:
+  {
+    OnKeyUp( uMsg, event );
+    break;
+  }
+
+  default:
+    break;
+  }
+}
+
+void WindowBaseWin::SetParent( WindowBase* parentWinBase )
+{
+
+}
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
diff --git a/dali/internal/window-system/windows/window-base-win.h b/dali/internal/window-system/windows/window-base-win.h
new file mode 100755 (executable)
index 0000000..c0a17dc
--- /dev/null
@@ -0,0 +1,394 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_WINDOW_BASE_WIN_H
+#define DALI_INTERNAL_WINDOWSYSTEM_WINDOW_BASE_WIN_H
+
+/*
+ * Copyright (c) 2018 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 <dali/internal/window-system/common/window-base.h>
+#include <dali/internal/window-system/windows/platform-implement-win.h>
+#include <dali/internal/window-system/windows/event-system-win.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class Window;
+class WindowRenderSurface;
+class WindowRenderSurfaceWin;
+
+/**
+ * WindowBaseWin class provides an WindowBase Win32 implementation.
+ */
+class WindowBaseWin : public WindowBase
+{
+public:
+
+  /**
+   * @brief Constructor
+   */
+  WindowBaseWin( PositionSize positionSize, Any surface, bool isTransparent );
+
+  /**
+   * @brief Destructor
+   */
+  virtual ~WindowBaseWin();
+
+public:
+
+  /**
+   * Called when the window receives a delete request
+   */
+  void OnDeleteRequest();
+
+  /**
+   * @brief Called when the window gains focus.
+   */
+  void OnFocusIn( int type, TWinEventInfo *event );
+
+  /**
+   * @brief Called when the window loses focus.
+   */
+  void OnFocusOut( int type, TWinEventInfo *event );
+
+  /**
+   * @brief Called when the window is damaged.
+   */
+  void OnWindowDamaged( int type, TWinEventInfo *event );
+
+  /**
+   * @brief Called when a touch down is received.
+   */
+  void OnMouseButtonDown( int type, TWinEventInfo *event );
+
+  /**
+   * @brief Called when a touch up is received.
+   */
+  void OnMouseButtonUp( int type, TWinEventInfo *event );
+
+  /**
+   * @brief Called when a touch motion is received.
+   */
+  void OnMouseButtonMove( int type, TWinEventInfo *event );
+
+  /**
+   * @brief Called when a mouse wheel is received.
+   */
+  void OnMouseWheel( int type, TWinEventInfo *event );
+
+  /**
+   * @brief Called when a key down is received.
+   */
+  void OnKeyDown( int type, TWinEventInfo *event );
+
+  /**
+   * @brief Called when a key up is received.
+   */
+  void OnKeyUp( int type, TWinEventInfo *event );
+
+
+public:
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindow()
+   */
+  virtual Any GetNativeWindow() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNativeWindowId()
+   */
+  virtual int GetNativeWindowId() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::CreateEglWindow()
+   */
+  virtual EGLNativeWindowType CreateEglWindow( int width, int height ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::DestroyEglWindow()
+   */
+  virtual void DestroyEglWindow() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetEglWindowRotation()
+   */
+  virtual void SetEglWindowRotation( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetEglWindowBufferTransform()
+   */
+  virtual void SetEglWindowBufferTransform( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetEglWindowTransform()
+   */
+  virtual void SetEglWindowTransform( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::ResizeEglWindow()
+   */
+  virtual void ResizeEglWindow( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::IsEglWindowRotationSupported()
+   */
+  virtual bool IsEglWindowRotationSupported() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Move()
+   */
+  virtual void Move( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Resize()
+   */
+  virtual void Resize( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::MoveResize()
+   */
+  virtual void MoveResize( PositionSize positionSize ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetClass()
+   */
+  virtual void SetClass( const std::string& name, const std::string& className ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Raise()
+   */
+  virtual void Raise() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Lower()
+   */
+  virtual void Lower() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Activate()
+   */
+  virtual void Activate() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetAvailableAnlges()
+   */
+  virtual void SetAvailableAnlges( const std::vector< int >& angles ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetPreferredAngle()
+   */
+  virtual void SetPreferredAngle( int angle ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetAcceptFocus()
+   */
+  virtual void SetAcceptFocus( bool accept ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Show()
+   */
+  virtual void Show() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::Hide()
+   */
+  virtual void Hide() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetSupportedAuxiliaryHintCount()
+   */
+  virtual unsigned int GetSupportedAuxiliaryHintCount() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetSupportedAuxiliaryHint()
+   */
+  virtual std::string GetSupportedAuxiliaryHint( unsigned int index ) const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::AddAuxiliaryHint()
+   */
+  virtual unsigned int AddAuxiliaryHint( const std::string& hint, const std::string& value ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::RemoveAuxiliaryHint()
+   */
+  virtual bool RemoveAuxiliaryHint( unsigned int id ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetAuxiliaryHintValue()
+   */
+  virtual bool SetAuxiliaryHintValue( unsigned int id, const std::string& value ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetAuxiliaryHintValue()
+   */
+  virtual std::string GetAuxiliaryHintValue( unsigned int id ) const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetAuxiliaryHintId()
+   */
+  virtual unsigned int GetAuxiliaryHintId( const std::string& hint ) const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetInputRegion()
+   */
+  virtual void SetInputRegion( const Rect< int >& inputRegion ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetType()
+   */
+  virtual void SetType( Dali::Window::Type type ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetNotificationLevel()
+   */
+  virtual bool SetNotificationLevel( Dali::Window::NotificationLevel::Type level ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetNotificationLevel()
+   */
+  virtual Dali::Window::NotificationLevel::Type GetNotificationLevel() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetOpaqueState()
+   */
+  virtual void SetOpaqueState( bool opaque ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetScreenOffMode()
+   */
+  virtual bool SetScreenOffMode(Dali::Window::ScreenOffMode::Type screenOffMode) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetScreenOffMode()
+   */
+  virtual Dali::Window::ScreenOffMode::Type GetScreenOffMode() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetBrightness()
+   */
+  virtual bool SetBrightness( int brightness ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetBrightness()
+   */
+  virtual int GetBrightness() const override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GrabKey()
+   */
+  virtual bool GrabKey( Dali::KEY key, KeyGrab::KeyGrabMode grabMode ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::UngrabKey()
+   */
+  virtual bool UngrabKey( Dali::KEY key ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GrabKeyList()
+   */
+  virtual bool GrabKeyList( const Dali::Vector< Dali::KEY >& key, const Dali::Vector< KeyGrab::KeyGrabMode >& grabMode, Dali::Vector< bool >& result ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::UngrabKeyList()
+   */
+  virtual bool UngrabKeyList( const Dali::Vector< Dali::KEY >& key, Dali::Vector< bool >& result ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetDpi()
+   */
+  virtual void GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::GetScreenRotationAngle()
+   */
+  virtual int GetScreenRotationAngle() override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetWindowRotationAngle()
+   */
+  virtual void SetWindowRotationAngle( int degree ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::WindowRotationCompleted()
+   */
+  virtual void WindowRotationCompleted( int degree, int width, int height ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetTransparency()
+   */
+  virtual void SetTransparency( bool transparent ) override;
+
+  /**
+   * @copydoc Dali::Internal::Adaptor::WindowBase::SetParent()
+   */
+  virtual void SetParent( WindowBase* parentWinBase ) override;
+
+private:
+
+  /**
+   * Second stage initialization
+   */
+  void Initialize( PositionSize positionSize, Any surface, bool isTransparent );
+
+  /**
+   * @brief Get the surface id if the surface parameter is not empty
+   * @param surface Any containing a surface id, or can be empty
+   * @return surface id, or zero if surface is empty
+   */
+  unsigned int GetSurfaceId( Any surface ) const;
+
+  /**
+   * @brief Create window
+   */
+  void CreateWinWindow( PositionSize positionSize, bool isTransparent );
+
+  /**
+   * @brief Sets up an already created window.
+   */
+  void SetWinWindow( unsigned int surfaceId );
+
+private:
+
+  // Undefined
+  WindowBaseWin(const WindowBaseWin&) = delete;
+
+  // Undefined
+  WindowBaseWin& operator=(const WindowBaseWin& rhs) = delete;
+
+private:
+  void EventEntry( TWinEventInfo *event );
+
+private:
+  WinWindowHandle                      mWin32Window;        ///< Native window handle
+  bool                                 mOwnSurface:1;       ///< Whether we own the surface (responsible for deleting it)
+  bool                                 mIsTransparent:1;    ///< Whether the window is transparent (32 bit or 24 bit)
+  bool                                 mRotationAppSet:1;
+
+  WindowsPlatformImplementation::WindowImpl mWindowImpl;
+};
+
+} // namespace Adaptor
+
+} // namespace internal
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_WINDOW_BASE_WIN_H
diff --git a/dali/internal/window-system/windows/window-factory-win.cpp b/dali/internal/window-system/windows/window-factory-win.cpp
new file mode 100755 (executable)
index 0000000..4be2aaa
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/window-system/windows/window-factory-win.h>
+
+// INTERNAL HEADERS
+#include <dali/internal/window-system/windows/window-base-win.h>
+#include <dali/internal/window-system/common/display-utils.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+std::unique_ptr< WindowBase > WindowFactoryWin::CreateWindowBase( Dali::PositionSize positionSize, Any surface, bool isTransparent )
+{
+  return Utils::MakeUnique< WindowBaseWin >( positionSize, surface, isTransparent );
+}
+
+// this should be created from Window impl
+std::unique_ptr< WindowFactory > GetWindowFactory()
+{
+  // returns Window factory
+  return Utils::MakeUnique< WindowFactoryWin >();
+}
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
diff --git a/dali/internal/window-system/windows/window-factory-win.h b/dali/internal/window-system/windows/window-factory-win.h
new file mode 100755 (executable)
index 0000000..9b1b8de
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef DALI_INTERNAL_WINDOWSYSTEM_WINDOW_FACTORY_WIN_H
+#define DALI_INTERNAL_WINDOWSYSTEM_WINDOW_FACTORY_WIN_H
+
+/*
+ * Copyright (c) 2018 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/internal/window-system/common/window-factory.h>
+
+namespace Dali
+{
+namespace Internal
+{
+namespace Adaptor
+{
+
+class WindowFactoryWin : public WindowFactory
+{
+public:
+  std::unique_ptr< WindowBase > CreateWindowBase( Dali::PositionSize positionSize, Any surface, bool isTransparent ) override;
+};
+
+} // namespace Adaptor
+} // namespace Internal
+} // namespace Dali
+
+#endif // DALI_INTERNAL_WINDOWSYSTEM_WINDOW_FACTORY_WIN_H
diff --git a/dali/internal/window-system/windows/window-system-win.cpp b/dali/internal/window-system/windows/window-system-win.cpp
new file mode 100755 (executable)
index 0000000..1fcbc68
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 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 HEADERS
+#include <dali/internal/window-system/common/window-system.h>
+
+// EXTERNAL HEADERS
+#include <Windows.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+namespace WindowSystem
+{
+
+void Initialize()
+{
+}
+
+void GetScreenSize( int& width, int& height )
+{
+  width = GetSystemMetrics( SM_CXSCREEN );
+  height = GetSystemMetrics( SM_CYSCREEN );
+}
+
+bool SetKeyboardRepeatInfo( float rate, float delay )
+{
+  return false;
+}
+
+bool GetKeyboardRepeatInfo( float& rate, float& delay )
+{
+  return false;
+}
+
+} // namespace WindowSystem
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+} // namespace Dali
+
diff --git a/dali/public-api/adaptor-framework/application-configuration.h b/dali/public-api/adaptor-framework/application-configuration.h
new file mode 100644 (file)
index 0000000..0e23ff1
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef DALI_APPLICATION_CONFIGURATION_H
+#define DALI_APPLICATION_CONFIGURATION_H
+
+/*
+ * Copyright (c) 2019 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.
+ */
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+/**
+ * @brief Enumeration for Application configuration.
+ * @SINCE_1_0.0
+ */
+namespace Configuration
+{
+
+/**
+ * @brief Enumeration for application context loss policy.
+ * @SINCE_1_0.0
+ */
+enum ContextLoss
+{
+  APPLICATION_HANDLES_CONTEXT_LOSS,  ///< Application will tear down and recreate UI on context loss and context regained signals. Dali doesn't need to retain data. @SINCE_1_0.0
+  APPLICATION_DOES_NOT_HANDLE_CONTEXT_LOSS, ///< Application expects Dali to retain data ( increased memory footprint ) @SINCE_1_0.0
+};
+
+} // Configuration
+
+/**
+ * @}
+ */
+
+} // namespace Dali
+
+#endif // DALI_APPLICATION_CONFIGURATION_H
diff --git a/dali/public-api/adaptor-framework/application.cpp b/dali/public-api/adaptor-framework/application.cpp
new file mode 100644 (file)
index 0000000..8aa2318
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * 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 <dali/public-api/adaptor-framework/application.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/adaptor/common/application-impl.h>
+
+namespace Dali
+{
+
+Application Application::New()
+{
+  return New( NULL, NULL );
+}
+
+Application Application::New( int* argc, char **argv[] )
+{
+  Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::GetPreInitializedApplication();
+  if( internal )
+  {
+    // pre-initialized application
+    internal->SetCommandLineOptions( argc, argv );
+    if( argc && ( *argc > 0 ) )
+    {
+      internal->GetWindow().SetClass( (*argv)[0], "" );
+    }
+
+    return Application( internal.Get() );
+  }
+  else
+  {
+    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::GetPreInitializedApplication();
+  if( internal )
+  {
+    // pre-initialized application
+    internal->SetCommandLineOptions( argc, argv );
+    if( argc && ( *argc > 0 ) )
+    {
+      internal->GetWindow().SetClass( (*argv)[0], "" );
+    }
+    internal->SetStyleSheet( stylesheet );
+
+    return Application( internal.Get() );
+  }
+  else
+  {
+    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::GetPreInitializedApplication();
+  if( internal )
+  {
+    // pre-initialized application
+    internal->SetCommandLineOptions( argc, argv );
+    if( argc && ( *argc > 0 ) )
+    {
+      internal->GetWindow().SetClass( (*argv)[0], "" );
+    }
+    internal->SetStyleSheet( stylesheet );
+
+    internal->GetWindow().SetTransparency( ( windowMode == Application::OPAQUE ? false : true ) );
+
+    return Application( internal.Get() );
+  }
+  else
+  {
+    internal = Internal::Adaptor::Application::New( argc, argv, stylesheet, windowMode, PositionSize(),
+      Internal::Adaptor::Framework::NORMAL);
+    return Application(internal.Get());
+  }
+}
+
+Application Application::New( int* argc, char **argv[], const std::string& stylesheet, Application::WINDOW_MODE windowMode, PositionSize positionSize )
+{
+  Internal::Adaptor::ApplicationPtr internal = Internal::Adaptor::Application::GetPreInitializedApplication();
+  if( internal )
+  {
+    // pre-initialized application
+    internal->SetCommandLineOptions( argc, argv );
+    if( argc && ( *argc > 0 ) )
+    {
+      internal->GetWindow().SetClass( (*argv)[0], "" );
+    }
+    internal->SetStyleSheet( stylesheet );
+
+    internal->GetWindow().SetTransparency( ( windowMode == Application::OPAQUE ? false : true ) );
+    internal->GetWindow().SetSize( Window::WindowSize( positionSize.width, positionSize.height ) );
+    internal->GetWindow().SetPosition( Window::WindowPosition( positionSize.x, positionSize.y ) );
+
+    return Application( internal.Get() );
+  }
+  else
+  {
+    internal = Internal::Adaptor::Application::New( argc, argv, stylesheet, windowMode, positionSize, Internal::Adaptor::Framework::NORMAL );
+    return Application( internal.Get() );
+  }
+}
+
+Application::~Application()
+{
+}
+
+Application::Application()
+{
+}
+
+Application::Application(const Application& application)
+: BaseHandle(application)
+{
+}
+
+Application& Application::operator=(const Application& application)
+{
+  if( *this != application )
+  {
+    BaseHandle::operator=( application );
+  }
+  return *this;
+}
+
+void Application::MainLoop()
+{
+  Internal::Adaptor::GetImplementation(*this).MainLoop(Configuration::APPLICATION_HANDLES_CONTEXT_LOSS);
+}
+
+void Application::MainLoop(Configuration::ContextLoss configuration)
+{
+  Internal::Adaptor::GetImplementation(*this).MainLoop(configuration);
+}
+
+void Application::Lower()
+{
+  Internal::Adaptor::GetImplementation(*this).Lower();
+}
+
+void Application::Quit()
+{
+  Internal::Adaptor::GetImplementation(*this).Quit();
+}
+
+bool Application::AddIdle( CallbackBase* callback )
+{
+  return Internal::Adaptor::GetImplementation(*this).AddIdle( callback, false );
+}
+
+Window Application::GetWindow()
+{
+  return Internal::Adaptor::GetImplementation(*this).GetWindow();
+}
+
+void Application::ReplaceWindow(PositionSize windowPosition, const std::string& name)
+{
+  DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: ReplaceWindow is deprecated and will be removed from next release.\n" );
+
+  Internal::Adaptor::GetImplementation(*this).ReplaceWindow(windowPosition, name);
+}
+
+std::string Application::GetResourcePath()
+{
+  return Internal::Adaptor::Application::GetResourcePath();
+}
+
+std::string Application::GetRegion() const
+{
+  return Internal::Adaptor::GetImplementation(*this).GetRegion();
+}
+
+std::string Application::GetLanguage() const
+{
+  return Internal::Adaptor::GetImplementation(*this).GetLanguage();
+}
+
+void Application::SetViewMode( ViewMode viewMode )
+{
+  Internal::Adaptor::GetImplementation(*this).SetViewMode( viewMode );
+}
+
+ViewMode Application::GetViewMode() const
+{
+  return Internal::Adaptor::GetImplementation(*this).GetViewMode();
+}
+
+void Application::SetStereoBase( float stereoBase )
+{
+  Internal::Adaptor::GetImplementation(*this).SetStereoBase( stereoBase );
+}
+
+float Application::GetStereoBase() const
+{
+  return Internal::Adaptor::GetImplementation(*this).GetStereoBase();
+}
+
+Application::AppSignalType& Application::InitSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).InitSignal();
+}
+
+Application::AppSignalType& Application::TerminateSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).TerminateSignal();
+}
+
+Application::AppSignalType& Application::PauseSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).PauseSignal();
+}
+
+Application::AppSignalType& Application::ResumeSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).ResumeSignal();
+}
+
+Application::AppSignalType& Application::ResetSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).ResetSignal();
+}
+
+Application::AppSignalType& Application::ResizeSignal()
+{
+  DALI_LOG_WARNING_NOFN( "DEPRECATION WARNING: ResizeSignal() is deprecated and will be removed from next release. Use Window::ResizedSignal() instead.\n" );
+
+  return Internal::Adaptor::GetImplementation(*this).ResizeSignal();
+}
+
+Application::AppControlSignalType & Application::AppControlSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).AppControlSignal();
+}
+
+Application::AppSignalType& Application::LanguageChangedSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).LanguageChangedSignal();
+}
+
+Application::AppSignalType& Application::RegionChangedSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).RegionChangedSignal();
+}
+
+Application::AppSignalType& Application::BatteryLowSignal()
+{
+  DALI_LOG_WARNING_NOFN( "DEPRECATION WARNING: BatteryLowSignal() is deprecated and will be removed from next release. Use Application::LowBatterySignal() instead.\n" );
+  return Internal::Adaptor::GetImplementation(*this).BatteryLowSignal();
+}
+
+Application::AppSignalType& Application::MemoryLowSignal()
+{
+  DALI_LOG_WARNING_NOFN( "DEPRECATION WARNING: MemoryLowSignal() is deprecated and will be removed from next release. Use Application::LowMemorySignal() instead.\n" );
+  return Internal::Adaptor::GetImplementation(*this).MemoryLowSignal();
+}
+
+Application::LowBatterySignalType& Application::LowBatterySignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).LowBatterySignal();
+}
+
+Application::LowMemorySignalType& Application::LowMemorySignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).LowMemorySignal();
+}
+
+Application::Application(Internal::Adaptor::Application* application)
+: BaseHandle(application)
+{
+}
+
+
+} // namespace Dali
diff --git a/dali/public-api/adaptor-framework/application.h b/dali/public-api/adaptor-framework/application.h
new file mode 100644 (file)
index 0000000..38dec63
--- /dev/null
@@ -0,0 +1,477 @@
+#ifndef DALI_APPLICATION_H
+#define DALI_APPLICATION_H
+
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/view-mode.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/signals/callback.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/application-configuration.h>
+#include <dali/public-api/adaptor-framework/device-status.h>
+#include <dali/public-api/adaptor-framework/window.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class Application;
+}
+}
+/**
+ * @brief An Application class object should be created by every application
+ * that wishes to use Dali.
+ *
+ * It provides a means for initializing the
+ * resources required by the Dali::Core.
+ *
+ * The Application class emits several signals which the user can
+ * connect to.  The user should not create any Dali objects in the main
+ * function and instead should connect to the Init signal of the
+ * Application and create the Dali objects in the connected callback.
+ *
+ * Applications should follow the example below:
+ *
+ * @code
+ * class ExampleController: public ConnectionTracker
+ * {
+ * 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);
+ *   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
+ *  -w|--width          Stage Width
+ *  -h|--height         Stage Height
+ *  -d|--dpi            Emulated DPI
+ *     --help           Help
+ * @endcode
+ *
+ * When the above options are found, they are stripped from argv, and argc is updated appropriately.
+ * @SINCE_1_0.0
+ */
+class DALI_ADAPTOR_API Application : public BaseHandle
+{
+public:
+
+  typedef Signal< void (DeviceStatus::Battery::Status) > LowBatterySignalType; ///< Application device signal type @SINCE_1_2.62
+  typedef Signal< void (DeviceStatus::Memory::Status) > LowMemorySignalType;   ///< Application device signal type @SINCE_1_2.62
+  typedef Signal< void (Application&) > AppSignalType;  ///< Application lifecycle signal and system signal callback type @SINCE_1_0.0
+  typedef Signal< void (Application&, void *) > AppControlSignalType; ///< Application control signal callback type @SINCE_1_0.0
+
+  /**
+   * @brief Enumeration for deciding whether a Dali application window is opaque or transparent.
+   * @SINCE_1_0.0
+   */
+  enum WINDOW_MODE
+  {
+    OPAQUE = 0,       ///< The window will be opaque @SINCE_1_0.0
+    TRANSPARENT = 1   ///< The window transparency will match the alpha value set in Dali::Stage::SetBackgroundcolor() @SINCE_1_0.0
+  };
+
+public:
+
+  /**
+   * @brief This is the constructor for applications without an argument list.
+   * @SINCE_1_0.0
+   * @PRIVLEVEL_PUBLIC
+   * @PRIVILEGE_DISPLAY
+   * @return A handle to the Application
+   */
+  static Application New();
+
+  /**
+   * @brief This is the constructor for applications.
+   *
+   * @SINCE_1_0.0
+   * @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
+   * @return A handle to the Application
+   */
+  static Application New( int* argc, char **argv[] );
+
+  /**
+   * @brief This is the constructor for applications with a name.
+   *
+   * @SINCE_1_0.0
+   * @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
+   * @return A handle to the Application
+   * @note If the stylesheet is not specified, then the library's default stylesheet will not be overridden.
+   */
+  static Application New( int* argc, char **argv[], const std::string& stylesheet );
+
+  /**
+   * @brief This is the constructor for applications with a name.
+   *
+   * @SINCE_1_0.0
+   * @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
+   * @return A handle to the Application
+   * @note If the stylesheet is not specified, then the library's default stylesheet will not be overridden.
+   */
+  static Application New( int* argc, char **argv[], const std::string& stylesheet, WINDOW_MODE windowMode );
+
+  /**
+   * @brief This is the constructor for applications.
+   *
+   * @SINCE_1_2.60
+   * @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.
+   */
+  static Application New( int* argc, char **argv[], const std::string& stylesheet, Application::WINDOW_MODE windowMode, PositionSize positionSize );
+
+  /**
+   * @brief Constructs an empty handle.
+   * @SINCE_1_0.0
+   */
+  Application();
+
+  /**
+   * @brief Copy Constructor.
+   * @SINCE_1_0.0
+   * @param[in] application Handle to an object
+   */
+  Application( const Application& application );
+
+  /**
+   * @brief Assignment operator.
+   * @SINCE_1_0.0
+   * @param[in] application Handle to an object
+   * @return A reference to this
+   */
+  Application& operator=( const Application& application );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~Application();
+
+public:
+  /**
+   * @brief This starts the application.
+   *
+   * Choosing this form of main loop indicates that the default
+   * application configuration of APPLICATION_HANDLES_CONTEXT_LOSS is used. On platforms where
+   * context loss can occur, the application is responsible for tearing down and re-loading UI.
+   * The application should listen to Stage::ContextLostSignal and Stage::ContextRegainedSignal.
+   * @SINCE_1_0.0
+   */
+  void MainLoop();
+
+  /**
+   * @brief This starts the application, and allows the app to choose a different configuration.
+   *
+   * If the application plans on using the ReplaceSurface or ReplaceWindow API, then this will
+   * trigger context loss & regain.
+   * The application should listen to Stage::ContextLostSignal and Stage::ContextRegainedSignal.
+   * @SINCE_1_0.0
+   * @param[in] configuration The context loss configuration
+   */
+  void MainLoop(Configuration::ContextLoss configuration);
+
+  /**
+   * @brief This lowers the application to bottom without actually quitting it.
+   * @SINCE_1_0.0
+   */
+  void Lower();
+
+  /**
+   * @brief This quits the application.  Tizen applications should use Lower to improve re-start performance unless they need to Quit completely.
+   * @SINCE_1_0.0
+   */
+  void Quit();
+
+  /**
+   * @brief Ensures that the function passed in is called from the main loop when it is idle.
+   * @SINCE_1_0.0
+   * @param[in] callback The function to call
+   * @return @c true if added successfully, @c false otherwise
+   *
+   * @note Function must be called from main event thread only
+   *
+   * A callback of the following type may be used:
+   * @code
+   *   void MyFunction();
+   * @endcode
+   * This callback will be deleted once it is called.
+   *
+   * @note Ownership of the callback is passed onto this class.
+   */
+  bool AddIdle( CallbackBase* callback );
+
+  /**
+   * @brief Retrieves the main window used by the Application class.
+   *
+   * The application writer can use the window to change indicator and orientation
+   * properties.
+   * @SINCE_1_0.0
+   * @return A handle to the window
+   */
+  Window GetWindow();
+
+  /**
+   * @DEPRECATED_1_4.12
+   * @brief Replaces the current window.
+   *
+   * This will force context loss.
+   * If you plan on using this API in your application, then you should configure
+   * it to prevent discard behavior when handling the Init signal.
+   * @SINCE_1_0.0
+   * @param[in] windowPosition The position and size parameters of the new window
+   * @param[in] name The name of the new window
+   */
+  void ReplaceWindow(PositionSize windowPosition, const std::string& name)  DALI_DEPRECATED_API;
+
+  /**
+   * @brief Get path application resources are stored at
+   *
+   * @SINCE_1_2.2
+   * @return the full path of the resources
+   */
+  static std::string GetResourcePath();
+
+  /**
+   * @brief This is used to get region information from device.
+   *
+   * @SINCE_1_2.62
+   * @return Region information
+   */
+  std::string GetRegion() const;
+
+  /**
+   * @brief This is used to get language information from device.
+   *
+   * @SINCE_1_2.62
+   * @return Language information
+   */
+  std::string GetLanguage() const;
+
+public: // Stereoscopy
+
+  /**
+   * @DEPRECATED_1_3_51
+   * @brief Sets the viewing mode for the application.
+   * @SINCE_1_0.0
+   * @param[in] viewMode The new viewing mode
+   */
+  void SetViewMode( ViewMode viewMode );
+
+  /**
+   * @DEPRECATED_1_3_51
+   * @brief Gets the current viewing mode.
+   * @SINCE_1_0.0
+   * @return The current viewing mode
+   */
+  ViewMode GetViewMode() const;
+
+  /**
+   * @DEPRECATED_1_3_51
+   * @brief Sets the stereo base (eye separation) for Stereoscopic 3D.
+   *
+   * The stereo base is the distance in millimetres between the eyes. Typical values are
+   * between 50mm and 70mm. The default value is 65mm.
+   * @SINCE_1_0.0
+   * @param[in] stereoBase The stereo base (eye separation) for Stereoscopic 3D
+   */
+  void SetStereoBase( float stereoBase );
+
+  /**
+   * @DEPRECATED_1_3_51
+   * @brief Gets the stereo base (eye separation) for Stereoscopic 3D.
+   *
+   * @SINCE_1_0.0
+   * @return The stereo base (eye separation) for Stereoscopic 3D
+   */
+  float GetStereoBase() const;
+
+public:  // Signals
+
+  /**
+   * @brief The user should connect to this signal to determine when they should initialize
+   * their application.
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AppSignalType& InitSignal();
+
+  /**
+   * @brief The user should connect to this signal to determine when they should terminate
+   * their application.
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AppSignalType& TerminateSignal();
+
+  /**
+   * @brief The user should connect to this signal if they need to perform any special
+   * activities when the application is about to be paused.
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AppSignalType& PauseSignal();
+
+  /**
+   * @brief The user should connect to this signal if they need to perform any special
+   * activities when the application has resumed.
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AppSignalType& ResumeSignal();
+
+  /**
+   * @brief This signal is sent when the system requires the user to reinitialize itself.
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AppSignalType& ResetSignal();
+
+  /**
+   * @DEPRECATED_1_2.62 Use Window::ResizedSignal() instead.
+   * @brief This signal is emitted when the window application rendering on is resized.
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AppSignalType& ResizeSignal() DALI_DEPRECATED_API;
+
+  /**
+  * @brief This signal is emitted when another application sends a launch request to the application.
+  *
+  * When the application is launched, this signal is emitted after the main loop of the application starts up.
+  * The passed parameter describes the launch request and contains the information about why the application is launched.
+  * @SINCE_1_0.0
+  * @return The signal to connect to
+  */
+  AppControlSignalType& AppControlSignal();
+
+  /**
+   * @brief This signal is emitted when the language is changed on the device.
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  AppSignalType& LanguageChangedSignal();
+
+  /**
+  * @brief This signal is emitted when the region of the device is changed.
+  * @SINCE_1_0.0
+  * @return The signal to connect to
+  */
+  AppSignalType& RegionChangedSignal();
+
+  /**
+  * @DEPRECATED_1_2.62 Use LowBatterySignal() instead.
+  * @brief This signal is emitted when the battery level of the device is low.
+  * @SINCE_1_0.0
+  * @return The signal to connect to
+  */
+  AppSignalType& BatteryLowSignal() DALI_DEPRECATED_API;
+
+  /**
+  * @DEPRECATED_1_2.62 Use LowMemorySignal() instead.
+  * @brief This signal is emitted when the memory level of the device is low.
+  * @SINCE_1_0.0
+  * @return The signal to connect to
+  */
+  AppSignalType& MemoryLowSignal() DALI_DEPRECATED_API;
+
+  /**
+   * @brief This signal is emitted when the battery level of the device is low.
+   * @SINCE_1_2.62
+   * @return The signal to connect to
+   */
+  LowBatterySignalType& LowBatterySignal();
+
+  /**
+   * @brief This signal is emitted when the memory level of the device is low.
+   * @SINCE_1_2.62
+   * @return The signal to connect to
+   */
+  LowMemorySignalType& LowMemorySignal();
+
+public: // Not intended for application developers
+  /// @cond internal
+  /**
+   * @brief Internal constructor.
+   * @SINCE_1_0.0
+   */
+  explicit DALI_INTERNAL Application(Internal::Adaptor::Application* application);
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // DALI_APPLICATION_H
diff --git a/dali/public-api/adaptor-framework/device-status.h b/dali/public-api/adaptor-framework/device-status.h
new file mode 100644 (file)
index 0000000..57f9ed5
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef DALI_DEVICE_STATUS_H
+#define DALI_DEVICE_STATUS_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace DeviceStatus
+{
+/**
+ * @brief Struct for battery of the device.
+ * @SINCE_1_2.62
+ */
+struct Battery
+{
+  /**
+   * @brief Enumeration for battery status.
+   * @SINCE_1_2.62
+   */
+  enum Status
+  {
+    NORMAL,         ///< Battery is over 5% @SINCE_1_2.62
+    CRITICALLY_LOW, ///< Battery is under 5% @SINCE_1_2.62
+    POWER_OFF       ///< Battery is under 1% @SINCE_1_2.62
+  };
+};
+
+/**
+ * @brief Struct for memory of the device.
+ * @SINCE_1_2.62
+ */
+struct Memory
+{
+  /**
+   * @brief Enumeration for memory status.
+   * @SINCE_1_2.62
+   */
+  enum Status
+  {
+    NORMAL,        ///< Normal Status @SINCE_1_2.62
+    LOW,           ///< Memory is low but not critical @SINCE_1_2.62
+    CRITICALLY_LOW ///< Memory is critically low @SINCE_1_2.62
+  };
+};
+
+}// namespace DeviceStatus
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // DALI_DEVICE_STATUS_H
diff --git a/dali/public-api/adaptor-framework/input-method.h b/dali/public-api/adaptor-framework/input-method.h
new file mode 100644 (file)
index 0000000..9b838c1
--- /dev/null
@@ -0,0 +1,275 @@
+#ifndef DALI_INPUT_MEHTOD_H
+#define DALI_INPUT_MEHTOD_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+/**
+ * @brief Enumeration for input method.
+ * @SINCE_1_0.0
+ */
+namespace InputMethod
+{
+
+/**
+ * @brief Enumeration for settings that can be changed in the system Input Method.
+ *
+ * Key types of map to change virtual keyboard settings in INPUT_METHOD_SETTINGS property.
+ * @SINCE_1_3.20
+ */
+namespace Category
+{
+
+/**
+* @brief Enumeration for Category type.
+*
+* @SINCE_1_3.20
+*/
+enum Type
+{
+  PANEL_LAYOUT,        ///< Set Keyboard layout @SINCE_1_3.20
+  BUTTON_ACTION,       ///< Set Button Action @SINCE_1_3.20
+  AUTO_CAPITALIZE,     ///< Set Auto capitalize of input @SINCE_1_3.20
+  VARIATION            ///< Set variation @SINCE_1_3.20
+};
+
+} // namespace Category
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/////////////////////////// The enumerations below is to set each type of Category. ///////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * @brief Sets Input panel (virtual keyboard) layout types.
+ *
+ * @SINCE_1_3.20
+ */
+namespace PanelLayout
+{
+
+/**
+* @brief Enumeration for PanelLayout type.
+*
+* @SINCE_1_3.20
+*/
+enum Type
+{
+  NORMAL,          ///< Default layout @SINCE_1_3.20
+  NUMBER,          ///< Number layout @SINCE_1_3.20
+  EMAIL,           ///< Email layout @SINCE_1_3.20
+  URL,             ///< URL layout @SINCE_1_3.20
+  PHONENUMBER,     ///< Phone Number layout @SINCE_1_3.20
+  IP,              ///< IP layout @SINCE_1_3.20
+  MONTH,           ///< Month layout @SINCE_1_3.20
+  NUMBER_ONLY,     ///< Number Only layout @SINCE_1_3.20
+  HEX,             ///< Hexadecimal layout @SINCE_1_3.20
+  TERMINAL,        ///< Command-line terminal layout including ESC, Alt, Ctrl key, so on (no auto-correct, no auto-capitalization) @SINCE_1_3.20
+  PASSWORD,        ///< Like normal, but no auto-correct, no auto-capitalization etc @SINCE_1_3.20
+  DATE_TIME,       ///< Date and time layout @SINCE_1_3.20
+  EMOTICON         ///< Emoticon layout @SINCE_1_3.20
+};
+
+} // namespace PanelLayout
+
+/**
+ * @brief Enumeration for specifying what the Input Method "action" button functionality is set to.
+ *
+ * The 'Action' button is traditionally the [RETURN] or [DONE] button.
+ * Not all these actions are supported by all systems.
+ * Setting a custom label will still require one of these actions to be set.
+ * @SINCE_1_3.20
+ */
+namespace ButtonAction
+{
+
+/**
+* @brief Enumeration for ButtonAction type.
+*
+* @SINCE_1_3.20
+*/
+enum Type
+{
+  DEFAULT,       ///< Default action @SINCE_1_3.20
+  DONE,          ///< Done @SINCE_1_3.20
+  GO,            ///< Go action @SINCE_1_3.20
+  JOIN,          ///< Join action @SINCE_1_3.20
+  LOGIN,         ///< Login action @SINCE_1_3.20
+  NEXT,          ///< Next action @SINCE_1_3.20
+  PREVIOUS,      ///< Previous action @SINCE_1_3.20
+  SEARCH,        ///< Search action @SINCE_1_3.20
+  SEND,          ///< Send action @SINCE_1_3.20
+  SIGNIN,        ///< Sign in action @SINCE_1_3.20
+  UNSPECIFIED,   ///< Unspecified action @SINCE_1_3.20
+  NONE           ///< Nothing to do @SINCE_1_3.20
+};
+
+} // namespace ButtonAction
+
+
+/**
+ * @brief Sets Autocapitalization Types.
+ *
+ * @SINCE_1_3.20
+ */
+namespace AutoCapital
+{
+
+/**
+* @brief Enumeration for AutoCapital type.
+*
+* @SINCE_1_3.20
+*/
+enum Type
+{
+  NONE,         ///< No auto-capitalization when typing @SINCE_1_3.20
+  WORD,         ///< Autocapitalize each word typed @SINCE_1_3.20
+  SENTENCE,     ///< Autocapitalize the start of each sentence @SINCE_1_3.20
+  ALL_CHARACTER ///< Autocapitalize all letters @SINCE_1_3.20
+};
+
+} // namespace AutoCapital
+
+
+/////////////////////////// VARIATION based on PANEL_LAYOUT //////////////////////////////////
+
+/**
+ * @brief Available variation for Normal layout.
+ *
+ * @SINCE_1_3.20
+ */
+namespace NormalLayout
+{
+
+/**
+* @brief Enumeration for NormalLayout Variation type.
+*
+* @SINCE_1_3.20
+*/
+enum Type
+{
+  NORMAL,                 ///< The plain normal layout @SINCE_1_3.20
+  WITH_FILENAME,          ///< Filename layout. Symbols such as '/' should be disabled @SINCE_1_3.20
+  WITH_PERSON_NAME        ///< The name of a person @SINCE_1_3.20
+};
+
+} // namespace NormalLayout
+
+/**
+ * @brief Available variation for Number only layout.
+ *
+ * @SINCE_1_3.20
+ */
+namespace NumberOnlyLayout
+{
+
+/**
+* @brief Enumeration for NumberOnlyLayout Variation type.
+*
+* @SINCE_1_3.20
+*/
+enum Type
+{
+  NORMAL,                 ///< The plain normal number layout @SINCE_1_3.20
+  WITH_SIGNED,            ///< The number layout to allow a positive or negative sign at the start @SINCE_1_3.20
+  WITH_DECIMAL,           ///< The number layout to allow decimal point to provide fractional value @SINCE_1_3.20
+  WITH_SIGNED_AND_DECIMAL ///< The number layout to allow decimal point and negative sign @SINCE_1_3.20
+};
+
+} // namespace NumberOnlyLayout
+
+/**
+ * @brief Available variation for Password layout.
+ *
+ * @SINCE_1_3.20
+ */
+namespace PasswordLayout
+{
+
+/**
+* @brief Enumeration for PasswordLayout Variation type.
+*
+* @SINCE_1_3.20
+*/
+enum Type
+{
+  NORMAL,               ///< The normal password layout @SINCE_1_3.20
+  WITH_NUMBER_ONLY      ///< The password layout to allow only number @SINCE_1_3.20
+};
+
+} // namespace PasswordLayout
+
+
+/**
+ * @DEPRECATED_1_3.20 Use ButtonAction instead.
+ * @brief Enumeration for specifying what the Input Method "action" button functionality is set to.
+ *
+ * The 'Action' button is traditionally the [RETURN] or [DONE] button.
+ *
+ * Not all these actions are supported by all systems.
+ *
+ * Setting a custom label will still require one of these actions to be set.
+ * @SINCE_1_0.0
+ */
+enum ActionButton
+{
+  ACTION_DEFAULT,       ///< Default action @SINCE_1_0.0
+  ACTION_DONE,          ///< Done @SINCE_1_0.0
+  ACTION_GO,            ///< Go action @SINCE_1_0.0
+  ACTION_JOIN,          ///< Join action @SINCE_1_0.0
+  ACTION_LOGIN,         ///< Login action @SINCE_1_0.0
+  ACTION_NEXT,          ///< Next action @SINCE_1_0.0
+  ACTION_PREVIOUS,      ///< Previous action @SINCE_1_0.0
+  ACTION_SEARCH,        ///< Search action @SINCE_1_0.0
+  ACTION_SEND,          ///< Send action @SINCE_1_0.0
+  ACTION_SIGNIN,        ///< Sign in action @SINCE_1_0.0
+  ACTION_UNSPECIFIED,   ///< Unspecified action @SINCE_1_0.0
+  ACTION_NONE           ///< Nothing to do @SINCE_1_0.0
+};
+
+/**
+ * @DEPRECATED_1_3.20 Use Category instead.
+ * @brief Enumeration for settings that can be changed in the system Input Method.
+ *
+ * Not all these settings are supported by all systems.
+ * @SINCE_1_0.0
+ */
+enum Settings
+{
+  ACTION_BUTTON,          ///< ActionButton. Apply the one of the ActionButton functions to the action button (return button). @SINCE_1_0.0
+  AUTO_CAPITALISE,        ///< boolean.      Capitalize the first letter of each sentence automatically. @SINCE_1_0.0
+  AUTO_COMPLETE,          ///< boolean.      Suggest words based on the current input. @SINCE_1_0.0
+  AUTO_CORRECT            ///< boolean.      Automatically correct commonly misspelt words. @SINCE_1_0.0
+};
+
+} // namespace InputMethod
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // DALI_INPUT_MEHTOD_H
diff --git a/dali/public-api/adaptor-framework/key-grab.h b/dali/public-api/adaptor-framework/key-grab.h
new file mode 100755 (executable)
index 0000000..e01a0c4
--- /dev/null
@@ -0,0 +1,161 @@
+#ifndef DALI_KEY_GRAB_H
+#define DALI_KEY_GRAB_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/dali-adaptor-common.h>
+#include <dali/public-api/common/dali-vector.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/key.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+class Window;
+
+/**
+ * @brief Key grab functions.
+ * @SINCE_1_0.0
+ */
+namespace KeyGrab
+{
+
+/**
+ * @brief Grabs the key specified by @a key for @a window only when @a window is the topmost window.
+ *
+ * This function can be used for following example scenarios:
+ * - Mobile - Using volume up/down as zoom up/down in camera apps.
+ *
+ * @SINCE_1_0.0
+ * @param[in] window The window to set
+ * @param[in] daliKey The key code to grab (defined in key.h)
+ * @return true if the grab succeeds
+ */
+DALI_ADAPTOR_API bool GrabKeyTopmost( Window window, Dali::KEY daliKey );
+
+/**
+ * @brief Ungrabs the key specified by @a key for @a window.
+ *
+ * @SINCE_1_0.0
+ * @param[in] window The window to set
+ * @param[in] daliKey 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_ADAPTOR_API bool UngrabKeyTopmost( Window window, Dali::KEY daliKey );
+
+/**
+ * @brief Enumeration for key grab mode for platform-level APIs.
+ * @SINCE_1_0.0
+ */
+enum KeyGrabMode
+{
+  TOPMOST = 0,             ///< Grab a key only when on the top of the grabbing-window stack mode. @SINCE_1_0.0
+  SHARED,                  ///< Grab a key together with the other client window(s) mode. @SINCE_1_0.0
+  OVERRIDE_EXCLUSIVE,      ///< Grab a key exclusively regardless of the grabbing-window's position on the window stack with the possibility of overriding the grab by the other client window mode. @SINCE_1_0.0
+  EXCLUSIVE                ///< Grab a key exclusively regardless of the grabbing-window's position on the window stack mode. @SINCE_1_0.0
+};
+
+/**
+ * @PLATFORM
+ * @brief Grabs the key specified by @a key for @a window in @a grabMode.
+ *
+ * @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 foreground 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_0.0
+ * @PRIVLEVEL_PLATFORM
+ * @PRIVILEGE_KEYGRAB
+ * @param[in] window The window to set
+ * @param[in] daliKey The key code to grab (defined in key.h)
+ * @param[in] grabMode The grab mode for the key
+ * @return true if the grab succeeds
+ */
+DALI_ADAPTOR_API bool GrabKey( Window window, Dali::KEY daliKey, KeyGrabMode grabMode );
+
+/**
+ * @PLATFORM
+ * @brief Ungrabs the key specified by @a key for @a window.
+ *
+ * @SINCE_1_0.0
+ * @PRIVLEVEL_PLATFORM
+ * @PRIVILEGE_KEYGRAB
+ * @param[in] window The window to set
+ * @param[in] daliKey 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_ADAPTOR_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 Dali::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 foreground 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_ADAPTOR_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_ADAPTOR_API bool UngrabKeyList( Window window, const Dali::Vector<Dali::KEY>& daliKeyVector, Dali::Vector<bool>& returnVector);
+
+
+} // namespace KeyGrab
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // DALI_KEY_GRAB_H
diff --git a/dali/public-api/adaptor-framework/key.cpp b/dali/public-api/adaptor-framework/key.cpp
new file mode 100644 (file)
index 0000000..25e5a6a
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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 <dali/public-api/adaptor-framework/key.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/input/common/key-impl.h>
+
+namespace Dali
+{
+
+bool IsKey( const KeyEvent& keyEvent, KEY daliKey)
+{
+  return Internal::Adaptor::KeyLookup::IsKey( keyEvent, daliKey );
+}
+
+}
diff --git a/dali/public-api/adaptor-framework/key.h b/dali/public-api/adaptor-framework/key.h
new file mode 100755 (executable)
index 0000000..634e428
--- /dev/null
@@ -0,0 +1,100 @@
+#ifndef DALI_KEYCODE_H
+#define DALI_KEYCODE_H
+
+/*
+ * Copyright (c) 2019 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/events/key-event.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+/**
+ * @brief Enumeration for mapping keyboard and mouse button event keycodes to platform specific codes.
+ * @SINCE_1_0.0
+ */
+
+enum KEY
+{
+  DALI_KEY_INVALID          = -1,       ///< Invalid key value @SINCE_1_0.0
+  DALI_KEY_ESCAPE           = 9,        ///< Escape key @SINCE_1_0.0
+  DALI_KEY_BACKSPACE        = 22,       ///< Backspace key @SINCE_1_0.0
+  DALI_KEY_SHIFT_LEFT       = 50,       ///< Shift Left key @SINCE_1_0.0
+  DALI_KEY_SHIFT_RIGHT      = 62,       ///< Shift Right key @SINCE_1_0.0
+  DALI_KEY_CURSOR_UP        = 111,      ///< Cursor up key @SINCE_1_0.0
+  DALI_KEY_CURSOR_LEFT      = 113,      ///< Cursor left key @SINCE_1_0.0
+  DALI_KEY_CURSOR_RIGHT     = 114,      ///< Cursor right key @SINCE_1_0.0
+  DALI_KEY_CURSOR_DOWN      = 116,      ///< Cursor down key @SINCE_1_0.0
+  DALI_KEY_BACK             = 166,      ///< Back key @SINCE_1_0.0
+  DALI_KEY_CAMERA           = 167,      ///< Camera key @SINCE_1_0.0
+  DALI_KEY_CONFIG           = 168,      ///< Config key @SINCE_1_0.0
+  DALI_KEY_POWER            = 169,      ///< Power key @SINCE_1_0.0
+  DALI_KEY_PAUSE            = 170,      ///< Pause key @SINCE_1_0.0
+  DALI_KEY_CANCEL           = 171,      ///< Cancel key @SINCE_1_0.0
+  DALI_KEY_PLAY_CD          = 172,      ///< Play CD key @SINCE_1_0.0
+  DALI_KEY_STOP_CD          = 173,      ///< Stop CD key @SINCE_1_0.0
+  DALI_KEY_PAUSE_CD         = 174,      ///< Pause CD key @SINCE_1_0.0
+  DALI_KEY_NEXT_SONG        = 175,      ///< Next song key @SINCE_1_0.0
+  DALI_KEY_PREVIOUS_SONG    = 176,      ///< Previous song key @SINCE_1_0.0
+  DALI_KEY_REWIND           = 177,      ///< Rewind key @SINCE_1_0.0
+  DALI_KEY_FASTFORWARD      = 178,      ///< Fastforward key @SINCE_1_0.0
+  DALI_KEY_MEDIA            = 179,      ///< Media key @SINCE_1_0.0
+  DALI_KEY_PLAY_PAUSE       = 180,      ///< Play pause key @SINCE_1_0.0
+  DALI_KEY_MUTE             = 181,      ///< Mute key @SINCE_1_0.0
+  DALI_KEY_MENU             = 182,      ///< Menu key @SINCE_1_0.0
+  DALI_KEY_HOME             = 183,      ///< Home key @SINCE_1_0.0
+  DALI_KEY_HOMEPAGE         = 187,      ///< Homepage key @SINCE_1_0.0
+  DALI_KEY_WEBPAGE          = 188,      ///< Webpage key @SINCE_1_0.0
+  DALI_KEY_MAIL             = 189,      ///< Mail key @SINCE_1_0.0
+  DALI_KEY_SCREENSAVER      = 190,      ///< Screensaver key @SINCE_1_0.0
+  DALI_KEY_BRIGHTNESS_UP    = 191,      ///< Brightness up key @SINCE_1_0.0
+  DALI_KEY_BRIGHTNESS_DOWN  = 192,      ///< Brightness down key @SINCE_1_0.0
+  DALI_KEY_SOFT_KBD         = 193,      ///< Soft KBD key @SINCE_1_0.0
+  DALI_KEY_QUICK_PANEL      = 194,      ///< Quick panel key @SINCE_1_0.0
+  DALI_KEY_TASK_SWITCH      = 195,      ///< Task switch key @SINCE_1_0.0
+  DALI_KEY_APPS             = 196,      ///< Apps key @SINCE_1_0.0
+  DALI_KEY_SEARCH           = 197,      ///< Search key @SINCE_1_0.0
+  DALI_KEY_VOICE            = 198,      ///< Voice key @SINCE_1_0.0
+  DALI_KEY_LANGUAGE         = 199,      ///< Language key @SINCE_1_0.0
+  DALI_KEY_VOLUME_UP        = 200,      ///< Volume up key @SINCE_1_0.0
+  DALI_KEY_VOLUME_DOWN      = 201       ///< Volume down key @SINCE_1_0.0
+};
+
+/**
+ * @brief Checks if a key event is for a specific DALI KEY.
+ *
+ * @SINCE_1_0.0
+ * @param keyEvent reference to a keyEvent structure
+ * @param daliKey Dali key enum
+ * @return @c true if the key is matched, @c false if not
+ */
+DALI_ADAPTOR_API bool IsKey( const Dali::KeyEvent& keyEvent, Dali::KEY daliKey);
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // DALI_KEYCODE_H
diff --git a/dali/public-api/adaptor-framework/native-image-source.cpp b/dali/public-api/adaptor-framework/native-image-source.cpp
new file mode 100755 (executable)
index 0000000..9672c60
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/public-api/adaptor-framework/native-image-source.h>
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/object/any.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/imaging/common/native-image-source-impl.h>
+#include <dali/internal/imaging/common/native-image-source-factory.h>
+
+namespace Dali
+{
+
+NativeImageSourcePtr NativeImageSource::New( unsigned int width, unsigned int height, ColorDepth depth )
+{
+  Any empty;
+  NativeImageSourcePtr image = new NativeImageSource( width, height, depth, empty );
+  return image;
+}
+
+Any NativeImageSource::GetNativeImageSource()
+{
+  return mImpl->GetNativeImageSource();
+}
+
+NativeImageSourcePtr NativeImageSource::New( Any nativeImageSource )
+{
+  NativeImageSourcePtr image = new NativeImageSource(0, 0, COLOR_DEPTH_DEFAULT, nativeImageSource);
+  return image;
+}
+
+bool NativeImageSource::GetPixels( std::vector<unsigned char> &pixbuf, unsigned int &width, unsigned int &height, Pixel::Format& pixelFormat ) const
+{
+  return mImpl->GetPixels( pixbuf, width, height, pixelFormat );
+}
+
+bool NativeImageSource::EncodeToFile(const std::string& filename) const
+{
+  return mImpl->EncodeToFile(filename);
+}
+
+void NativeImageSource::SetSource( Any source )
+{
+  mImpl->SetSource( source );
+}
+
+bool NativeImageSource::IsColorDepthSupported( ColorDepth colorDepth )
+{
+  return mImpl->IsColorDepthSupported( colorDepth );
+}
+
+bool NativeImageSource::GlExtensionCreate()
+{
+  return mImpl->GlExtensionCreate();
+}
+
+void NativeImageSource::GlExtensionDestroy()
+{
+  mImpl->GlExtensionDestroy();
+}
+
+unsigned int NativeImageSource::TargetTexture()
+{
+  return mImpl->TargetTexture();
+}
+
+void NativeImageSource::PrepareTexture()
+{
+  mImpl->PrepareTexture();
+}
+
+unsigned int NativeImageSource::GetWidth() const
+{
+  return mImpl->GetWidth();
+}
+
+unsigned int NativeImageSource::GetHeight() const
+{
+  return mImpl->GetHeight();
+}
+
+bool NativeImageSource::RequiresBlending() const
+{
+  return mImpl->RequiresBlending();
+}
+
+NativeImageInterface::Extension* NativeImageSource::GetExtension()
+{
+  return mImpl->GetNativeImageInterfaceExtension();
+}
+
+NativeImageSource::NativeImageSource( unsigned int width, unsigned int height, ColorDepth depth, Any nativeImageSource )
+{
+  auto factory = Dali::Internal::Adaptor::GetNativeImageSourceFactory();
+  mImpl = factory->CreateNativeImageSource( width, height, depth, nativeImageSource ).release();
+}
+
+NativeImageSource::~NativeImageSource()
+{
+  delete mImpl;
+}
+
+} // namespace Dali
diff --git a/dali/public-api/adaptor-framework/native-image-source.h b/dali/public-api/adaptor-framework/native-image-source.h
new file mode 100755 (executable)
index 0000000..597f063
--- /dev/null
@@ -0,0 +1,251 @@
+#ifndef DALI_NATIVE_IMAGE_SOURCE_H
+#define DALI_NATIVE_IMAGE_SOURCE_H
+
+/*
+ * Copyright (c) 2019 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/vector-wrapper.h>
+#include <dali/public-api/images/native-image-interface.h>
+#include <dali/public-api/images/pixel.h>
+#include <dali/public-api/object/any.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class NativeImageSource;
+}
+}
+
+class NativeImageSource;
+/**
+ * @brief Pointer to Dali::NativeImageSource.
+ * @SINCE_1_0.0
+ */
+typedef Dali::IntrusivePtr<Dali::NativeImageSource> NativeImageSourcePtr;
+
+/**
+ * @brief Used for displaying native images.
+ *
+ * NativeImageSource can be created internally or
+ * externally by native image source.
+ * NativeImage is a platform specific way of providing pixel data to the GPU for rendering,
+ * for example via an EGL image.
+ *
+ * @SINCE_1_1.4
+ * @see NativeImage
+ */
+class DALI_ADAPTOR_API NativeImageSource : public NativeImageInterface
+{
+public:
+
+   /**
+    * @brief Enumeration for the instance when creating a native image, the color depth has to be specified.
+    * @SINCE_1_0.0
+    */
+   enum ColorDepth
+   {
+     COLOR_DEPTH_DEFAULT,     ///< Uses the current screen default depth (recommended) @SINCE_1_0.0
+     COLOR_DEPTH_8,           ///< 8 bits per pixel @SINCE_1_0.0
+     COLOR_DEPTH_16,          ///< 16 bits per pixel @SINCE_1_0.0
+     COLOR_DEPTH_24,          ///< 24 bits per pixel @SINCE_1_0.0
+     COLOR_DEPTH_32           ///< 32 bits per pixel @SINCE_1_0.0
+   };
+
+  /**
+   * @brief Creates a new NativeImageSource.
+   *
+   * Depending on hardware, the width and height may have to be a power of two.
+   * @SINCE_1_0.0
+   * @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
+   */
+  static NativeImageSourcePtr New( unsigned int width, unsigned int height, ColorDepth depth );
+
+  /**
+   * @brief Creates a new NativeImageSource from an existing native image source.
+   *
+   * @SINCE_1_0.0
+   * @param[in] nativeImageSource NativeImageSource must be a any handle with native image source
+   * @return A smart-pointer to a newly allocated image
+   * @see NativeImageInterface
+   */
+  static NativeImageSourcePtr New( Any nativeImageSource );
+
+  /**
+   * @brief Retrieves the internal native image.
+   *
+   * @SINCE_1_0.0
+   * @return Any object containing the internal native image source
+   */
+  Any GetNativeImageSource();
+
+  /**
+   * @brief Gets a copy of the pixels used by NativeImageSource.
+   *
+   * This is only supported for 24 bit RGB and 32 bit RGBA internal formats
+   * (COLOR_DEPTH_24 and COLOR_DEPTH_32).
+   * @SINCE_1_0.0
+   * @param[out] pixbuf A vector to store the pixels in
+   * @param[out] width The width of image
+   * @param[out] height The height of image
+   * @param[out] pixelFormat pixel format used by image
+   * @return     @c true if the pixels were gotten, and @c false otherwise
+   */
+  bool GetPixels( std::vector<unsigned char>& pixbuf, unsigned int& width, unsigned int& height, Pixel::Format& pixelFormat ) const;
+
+  /**
+   * @brief Converts the current pixel contents to either a JPEG or PNG format
+   * and write that to the filesystem.
+   *
+   * @SINCE_1_0.0
+   * @param[in] filename Identify the filesystem location at which to write the encoded image.
+   *                     The extension determines the encoding used.
+   *                     The two valid encoding are (".jpeg"|".jpg") and ".png".
+   * @return    @c true if the pixels were written, and @c false otherwise
+   */
+  bool EncodeToFile(const std::string& filename) const;
+
+  /**
+   * @brief Sets an existing source.
+   *
+   * @SINCE_1_1.19
+   * @param[in] source Any handle with the source
+   */
+  void SetSource( Any source );
+
+  /**
+   * @brief Checks if the specified color depth is supported.
+   *
+   * @SINCE_1_1.34
+   * @param[in] colorDepth The color depth to check
+   * @return @c true if colorDepth is supported, @c false otherwise
+   */
+  bool IsColorDepthSupported( ColorDepth colorDepth );
+
+private:   // native image
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionCreate()
+   */
+  virtual bool GlExtensionCreate();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GlExtensionDestroy()
+   */
+  virtual void GlExtensionDestroy();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::TargetTexture()
+   */
+  virtual unsigned int TargetTexture();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::PrepareTexture()
+   */
+  virtual void PrepareTexture();
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetWidth()
+   */
+  virtual unsigned int GetWidth() const;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetHeight()
+   */
+  virtual unsigned int GetHeight() const;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::RequiresBlending()
+   */
+  virtual bool RequiresBlending() const;
+
+  /**
+   * @copydoc Dali::NativeImageInterface::GetExtension()
+   */
+  NativeImageInterface::Extension* GetExtension();
+
+private:
+
+  /// @cond internal
+  /**
+   * @brief Private constructor.
+   * @SINCE_1_0.0
+   * @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: native image source or is empty
+   */
+  DALI_INTERNAL NativeImageSource( unsigned int width, unsigned int height, ColorDepth depth, Any nativeImageSource );
+
+  /**
+   * @brief A reference counted object may only be deleted by calling Unreference().
+   *
+   * The implementation should destroy the NativeImage resources.
+   * @SINCE_1_0.0
+   */
+  DALI_INTERNAL virtual ~NativeImageSource();
+
+  /**
+   * @brief Undefined copy constructor.
+   *
+   * This avoids accidental calls to a default copy constructor.
+   * @SINCE_1_0.0
+   * @param[in] nativeImageSource A reference to the object to copy
+   */
+  DALI_INTERNAL NativeImageSource( const NativeImageSource& nativeImageSource );
+
+  /**
+   * @brief Undefined assignment operator.
+   *
+   * This avoids accidental calls to a default assignment operator.
+   * @SINCE_1_0.0
+   * @param[in] rhs A reference to the object to copy
+   */
+  DALI_INTERNAL NativeImageSource& operator=(const NativeImageSource& rhs);
+  /// @endcond
+
+private:
+
+  /// @cond internal
+  Internal::Adaptor::NativeImageSource* mImpl; ///< Implementation pointer
+  friend class Internal::Adaptor::NativeImageSource;
+
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // DALI_NATIVE_IMAGE_SOURCE_H
diff --git a/dali/public-api/adaptor-framework/style-change.h b/dali/public-api/adaptor-framework/style-change.h
new file mode 100644 (file)
index 0000000..bd36c9a
--- /dev/null
@@ -0,0 +1,59 @@
+#ifndef DALI_STYLE_CHANGE_H
+#define DALI_STYLE_CHANGE_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+/**
+ * @brief Enumeration for style change information.
+ * @SINCE_1_0.0
+ */
+namespace StyleChange
+{
+
+/**
+ * @brief Enumeration for StyleChange type.
+ * @SINCE_1_0.0
+ */
+enum Type
+{
+  DEFAULT_FONT_CHANGE,      ///< Denotes that the default font has changed. @SINCE_1_0.0
+  DEFAULT_FONT_SIZE_CHANGE, ///< Denotes that the default font size has changed. @SINCE_1_0.0
+  THEME_CHANGE              ///< Denotes that the theme has changed. @SINCE_1_0.0
+};
+
+} // namespace StyleChange
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // DALI_STYLE_CHANGE_H
diff --git a/dali/public-api/adaptor-framework/timer.cpp b/dali/public-api/adaptor-framework/timer.cpp
new file mode 100644 (file)
index 0000000..ba98792
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/public-api/adaptor-framework/timer.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/internal/system/common/timer-impl.h>
+
+namespace Dali
+{
+
+Timer::Timer()
+{
+}
+
+Timer Timer::New( unsigned int milliSec )
+{
+  Internal::Adaptor::TimerPtr internal = Internal::Adaptor::Timer::New( milliSec );
+  return Timer(internal.Get());
+}
+
+Timer::Timer( const Timer& timer )
+: BaseHandle(timer)
+{
+}
+
+Timer& Timer::operator=( const Timer& timer )
+{
+  // check self assignment
+  if( *this != timer )
+  {
+    BaseHandle::operator=(timer);
+  }
+  return *this;
+}
+
+Timer::~Timer()
+{
+}
+
+Timer Timer::DownCast( BaseHandle handle )
+{
+  return Timer( dynamic_cast<Internal::Adaptor::Timer*>( handle.GetObjectPtr() ) );
+}
+
+void Timer::Start()
+{
+  Internal::Adaptor::GetImplementation(*this).Start();
+}
+
+void Timer::Stop()
+{
+  Internal::Adaptor::GetImplementation(*this).Stop();
+}
+
+void Timer::Pause()
+{
+  Internal::Adaptor::GetImplementation(*this).Pause();
+}
+
+void Timer::Resume()
+{
+  Internal::Adaptor::GetImplementation(*this).Resume();
+}
+
+void Timer::SetInterval( unsigned int interval )
+{
+  Internal::Adaptor::GetImplementation(*this).SetInterval( interval, true );
+}
+
+void Timer::SetInterval( unsigned int interval, bool restart )
+{
+  Internal::Adaptor::GetImplementation(*this).SetInterval( interval, restart );
+}
+
+unsigned int Timer::GetInterval() const
+{
+  return Internal::Adaptor::GetImplementation(*this).GetInterval();
+}
+
+bool Timer::IsRunning() const
+{
+  return Internal::Adaptor::GetImplementation(*this).IsRunning();
+}
+
+Timer::TimerSignalType& Timer::TickSignal()
+{
+  return Internal::Adaptor::GetImplementation(*this).TickSignal();
+}
+
+Timer::Timer(Internal::Adaptor::Timer* timer)
+: BaseHandle(timer)
+{
+}
+
+
+} // namespace Dali
diff --git a/dali/public-api/adaptor-framework/timer.h b/dali/public-api/adaptor-framework/timer.h
new file mode 100755 (executable)
index 0000000..edaf556
--- /dev/null
@@ -0,0 +1,202 @@
+#ifndef DALI_TIMER_H
+#define DALI_TIMER_H
+
+/*
+ * Copyright (c) 2019 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/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class Timer;
+}
+}
+
+/**
+ * @brief Mechanism to issue simple periodic or one-shot events.
+ *
+ * Timer is provided for application developers to be able to issue
+ * simple periodic or one-shot events.  Please note that timer
+ * callback functions should return as soon as possible, because they
+ * block the next SignalTick.  Please note that timer signals are not
+ * in sync with Dali's render timer.
+ *
+ * This class is a handle class so it can be stack allocated and used
+ * as a member.
+ * @SINCE_1_0.0
+ */
+class DALI_ADAPTOR_API Timer : public BaseHandle
+{
+public: // Signal typedefs
+
+  typedef Signal< bool () > TimerSignalType; ///< Timer finished signal callback type @SINCE_1_0.0
+
+public: // API
+
+  /**
+   * @brief Constructor, creates an uninitialized timer.
+   *
+   * Call New to fully construct a timer.
+   * @SINCE_1_0.0
+   */
+  Timer();
+
+  /**
+   * @brief Creates a tick Timer that emits periodic signal.
+   *
+   * @SINCE_1_0.0
+   * @param[in] milliSec Interval in milliseconds
+   * @return A new timer
+   */
+  static Timer New( unsigned int milliSec );
+
+  /**
+   * @brief Copy constructor.
+   *
+   * @SINCE_1_0.0
+   * @param[in] timer The handle to copy. The copied handle will point at the same implementation
+   */
+  Timer( const Timer& timer );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @SINCE_1_0.0
+   * @param[in] timer The handle to copy. This handle will point at the same implementation
+   * as the copied handle
+   * @return Reference to this timer handle
+   */
+  Timer& operator=( const Timer& timer );
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~Timer();
+
+  /**
+   * @brief Downcasts a handle to Timer handle.
+   *
+   * If handle points to a Timer object, the downcast produces a valid handle.
+   * If not, the returned handle is left uninitialized.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle to An object
+   * @return handle to a Timer object or an uninitialized handle
+   */
+  static Timer DownCast( BaseHandle handle );
+
+  /**
+   * @brief Starts timer.
+   *
+   * In case a Timer is already running, its time is reset and timer is restarted.
+   * @SINCE_1_0.0
+   */
+  void Start();
+
+  /**
+   * @brief Stops timer.
+   * @SINCE_1_0.0
+   */
+  void Stop();
+
+  /**
+   * @brief Pauses timer.
+   * @SINCE_1_3.41
+   */
+  void Pause();
+
+  /**
+   * @brief Resumes timer.
+   * @SINCE_1_3.41
+   */
+  void Resume();
+
+  /**
+   * @brief Sets a new interval on the timer and starts the timer.
+   *
+   * Cancels the previous timer.
+   * @SINCE_1_0.0
+   * @param[in] milliSec Interval in milliseconds
+   */
+  void SetInterval( unsigned int milliSec );
+
+  /**
+   * @brief Sets a new interval on the timer with option to restart the timer.
+   *
+   * Cancels the previous timer.
+   * @SINCE_1_3.41
+   * @param[in] milliSec Interval in milliseconds
+   * @param[in] restart Flag to set enabled to restart or not.
+   */
+  void SetInterval( unsigned int milliSec, bool restart );
+
+  /**
+   * @brief Gets the interval of timer.
+   *
+   * @SINCE_1_0.0
+   * @return Interval in milliseconds
+   */
+  unsigned int GetInterval() const;
+
+  /**
+   * @brief Tells whether timer is running.
+   * @SINCE_1_0.0
+   * @return Whether Timer is started or not
+   */
+  bool IsRunning() const;
+
+public: // Signals
+
+  /**
+   * @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 and if true, it will continue.
+   * This return value is ignored for one-shot events, which will always stop after the first execution.
+   * @return The signal to Connect() with
+   * @SINCE_1_0.0
+   */
+  TimerSignalType& TickSignal();
+
+public: // Not intended for application developers
+  explicit DALI_INTERNAL Timer(Internal::Adaptor::Timer* timer);
+};
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // DALI_TIMER_H
diff --git a/dali/public-api/adaptor-framework/tts-player.cpp b/dali/public-api/adaptor-framework/tts-player.cpp
new file mode 100644 (file)
index 0000000..db222bc
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * 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 <dali/public-api/adaptor-framework/tts-player.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/accessibility/common/tts-player-impl.h>
+#include <dali/internal/adaptor/common/adaptor-impl.h>
+
+namespace Dali
+{
+
+TtsPlayer::TtsPlayer()
+{
+}
+
+TtsPlayer TtsPlayer::Get(Dali::TtsPlayer::Mode mode)
+{
+  TtsPlayer ttsPlayer;
+
+  if ( Adaptor::IsAvailable() )
+  {
+    ttsPlayer = Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).GetTtsPlayer(mode);
+  }
+
+  return ttsPlayer;
+}
+
+TtsPlayer::~TtsPlayer()
+{
+}
+
+TtsPlayer::TtsPlayer(const TtsPlayer& handle)
+: BaseHandle(handle)
+{
+}
+
+TtsPlayer& TtsPlayer::operator=(const TtsPlayer& rhs)
+{
+  BaseHandle::operator=(rhs);
+  return *this;
+}
+
+void TtsPlayer::Play(const std::string& text)
+{
+  GetImplementation(*this).Play(text);
+}
+
+void TtsPlayer::Stop()
+{
+  GetImplementation(*this).Stop();
+}
+
+void TtsPlayer::Pause()
+{
+  GetImplementation(*this).Pause();
+}
+
+void TtsPlayer::Resume()
+{
+  GetImplementation(*this).Resume();
+}
+
+TtsPlayer::State TtsPlayer::GetState()
+{
+  return GetImplementation(*this).GetState();
+}
+
+TtsPlayer::StateChangedSignalType& TtsPlayer::StateChangedSignal()
+{
+  return GetImplementation(*this).StateChangedSignal();
+}
+
+TtsPlayer::TtsPlayer( Internal::Adaptor::TtsPlayer* player )
+: BaseHandle( player )
+{
+}
+
+} // namespace Dali
diff --git a/dali/public-api/adaptor-framework/tts-player.h b/dali/public-api/adaptor-framework/tts-player.h
new file mode 100755 (executable)
index 0000000..55cef69
--- /dev/null
@@ -0,0 +1,190 @@
+#ifndef DALI_TTS_PLAYER_H
+#define DALI_TTS_PLAYER_H
+
+/*
+ * Copyright (c) 2019 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/object/base-handle.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class TtsPlayer;
+}
+}
+
+/**
+ * @brief The Text-to-speech (TTS) Player.
+ * @SINCE_1_0.0
+ */
+class DALI_ADAPTOR_API TtsPlayer : public BaseHandle
+{
+public: // ENUMs
+
+  /**
+   * @brief Enumeration for the instance of TTS mode.
+   * @SINCE_1_0.0
+   */
+  enum Mode
+  {
+    DEFAULT = 0,  ///< Default mode for normal application @SINCE_1_0.0
+    NOTIFICATION, ///< Notification mode, such as playing utterance is started or completed @SINCE_1_0.0
+    SCREEN_READER, ///< Screen reader mode. To help visually impaired users interact with their devices, screen reader reads text or graphic elements on the screen using the TTS engine. @SINCE_1_0.0
+    MODE_NUM
+  };
+
+  /**
+   * @brief Enumeration for the instance of TTS state.
+   * @SINCE_1_0.0
+   */
+  enum State
+  {
+    UNAVAILABLE = 0,    ///< Player is not available @SINCE_1_0.0
+    READY,              ///< Player is ready to play @SINCE_1_0.0
+    PLAYING,            ///< Player is playing @SINCE_1_0.0
+    PAUSED              ///< Player is paused @SINCE_1_0.0
+  };
+
+public: // Typedefs
+
+  /**
+   * @brief Type of signal emitted when the TTS state changes.
+   * @SINCE_1_0.0
+   */
+  typedef Signal< void ( const Dali::TtsPlayer::State, const Dali::TtsPlayer::State ) > StateChangedSignalType;
+
+public: // API
+
+  /**
+   * @brief Creates an uninitialized handle.
+   *
+   * This can be initialized by calling TtsPlayer::Get().
+   * @SINCE_1_0.0
+   */
+  TtsPlayer();
+
+  /**
+   * @brief Gets the singleton of the TtsPlayer for the given mode.
+   *
+   * @SINCE_1_0.0
+   * @param mode The mode of tts-player
+   * @return A handle of the Ttsplayer for the given mode
+   */
+  static TtsPlayer Get(Dali::TtsPlayer::Mode mode = Dali::TtsPlayer::DEFAULT);
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~TtsPlayer();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @SINCE_1_0.0
+   * @param [in] handle A reference to the copied handle
+   */
+  TtsPlayer(const TtsPlayer& handle);
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @SINCE_1_0.0
+   * @param [in] rhs A reference to the copied handle
+   * @return A reference to this
+   */
+  TtsPlayer& operator=(const TtsPlayer& rhs);
+
+  /**
+   * @brief Starts playing the audio data synthesized from the specified text.
+   *
+   * @SINCE_1_0.0
+   * @param[in] text The text to play
+   * @pre The TtsPlayer needs to be initialized.
+   */
+  void Play(const std::string& text);
+
+  /**
+   * @brief Stops playing the utterance.
+   * @SINCE_1_0.0
+   * @pre The TtsPlayer needs to be initialized.
+   */
+  void Stop();
+
+  /**
+   * @brief Pauses the currently playing utterance.
+   * @SINCE_1_0.0
+   * @pre The TtsPlayer needs to be initialized.
+   */
+  void Pause();
+
+  /**
+   * @brief Resumes the previously paused utterance.
+   * @SINCE_1_0.0
+   * @pre The TtsPlayer needs to be initialized.
+   */
+  void Resume();
+
+  /**
+   * @brief Gets the current state of the player.
+   * @SINCE_1_0.0
+   * @return The current TTS state
+   * @pre The TtsPlayer needs to be initialized.
+   */
+  State GetState();
+
+  /**
+   * @brief Allows connection TTS state change signal.
+   * @SINCE_1_0.0
+   * @return A reference to the signal for connection
+   * @note Only supported by some adaptor types.
+   */
+  Dali::TtsPlayer::StateChangedSignalType& StateChangedSignal();
+
+public: // Not intended for application developers
+
+  /// @cond internal
+  /**
+   * @brief This constructor is used by TtsPlayer::Get().
+   * @SINCE_1_0.0
+   * @param[in] ttsPlayer A pointer to the TTS player
+   */
+  explicit DALI_INTERNAL TtsPlayer( Internal::Adaptor::TtsPlayer* ttsPlayer );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // DALI_TTS_PLAYER_H
diff --git a/dali/public-api/adaptor-framework/widget-application.cpp b/dali/public-api/adaptor-framework/widget-application.cpp
new file mode 100644 (file)
index 0000000..430912d
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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 <dali/public-api/adaptor-framework/widget-application.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/widget-application-impl.h>
+
+namespace Dali
+{
+
+WidgetApplication WidgetApplication::New( int* argc, char **argv[], const std::string& stylesheet )
+{
+  Internal::Adaptor::WidgetApplicationPtr internal = Internal::Adaptor::WidgetApplication::New( argc, argv, stylesheet);
+  return WidgetApplication(internal.Get());
+}
+
+WidgetApplication::~WidgetApplication()
+{
+}
+
+WidgetApplication::WidgetApplication()
+{
+}
+
+WidgetApplication::WidgetApplication(const WidgetApplication& widgetApplication)
+: Application(widgetApplication)
+{
+}
+
+WidgetApplication& WidgetApplication::operator=(const WidgetApplication& widgetApplication)
+{
+  if( *this != widgetApplication )
+  {
+    BaseHandle::operator=( widgetApplication );
+  }
+  return *this;
+}
+
+void WidgetApplication::RegisterWidgetCreatingFunction( const std::string& widgetName, CreateWidgetFunction createFunction )
+{
+  Internal::Adaptor::GetImplementation(*this).RegisterWidgetCreatingFunction( widgetName, createFunction );
+}
+
+WidgetApplication::WidgetApplication(Internal::Adaptor::WidgetApplication* widgetApplication)
+: Application(widgetApplication)
+{
+}
+
+} // namespace Dali
diff --git a/dali/public-api/adaptor-framework/widget-application.h b/dali/public-api/adaptor-framework/widget-application.h
new file mode 100644 (file)
index 0000000..cf71d05
--- /dev/null
@@ -0,0 +1,179 @@
+#ifndef DALI_WIDGET_APPLICATION_H
+#define DALI_WIDGET_APPLICATION_H
+
+/*
+ * Copyright (c) 2018 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 <dali/public-api/adaptor-framework/application.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace Internal DALI_INTERNAL
+{
+
+namespace Adaptor
+{
+class WidgetApplication;
+}
+
+}
+
+class Widget;
+
+/**
+ * @brief An WidgetApplication class object should be created by every widget application
+ * that wishes to use Dali.
+ *
+ * It provides a means for initializing the
+ * resources required by the Dali::Core.
+ *
+ * The WidgetApplication class emits several signals which the user can
+ * connect to.  The user should not create any Dali objects in the main
+ * function and instead should connect to the Init signal of the
+ * WidgetApplication and create the Dali Widget object in the connected callback.
+ *
+ * WidgetApplications should follow the example below:
+ *
+ * @code
+ *
+ * //Widget header which
+ * #include <my-widget.h>
+ *
+ * class ExampleController: public ConnectionTracker
+ * {
+ * public:
+ *   ExampleController( Application& application )
+ *   : mWidgetApplication( application )
+ *   {
+ *     mApplication.InitSignal().Connect( this, &ExampleController::Create );
+ *   }
+ *
+ *   static Widget CreateWidgetFunction(const std::string& widgetName)
+ *   {
+ *     MyWidget widget = MyWidget::New();
+ *     return widget;
+ *   }
+ *
+ *   void Create( Application& application )
+ *   {
+ *     mApplication.RegisterWidgetCreatingFunction( "myWidget", &ExampleController::CreateWidgetFunction );
+ *   }
+ *
+ * private:
+ *   WidgetApplication& mWidgetApplication;
+ * };
+ *
+ * int main (int argc, char **argv)
+ * {
+ *   WidgetApplication app = WidgetApplication::New(&argc, &argv);
+ *   ExampleController example( app );
+ *   app.MainLoop();
+ * }
+ * @endcode
+ *
+ * If required, you can also connect class member functions to a signal:
+ *
+ * @code
+ * MyWidgetApplication app;
+ * app.ResumeSignal().Connect(&app, &MyWidgetApplication::Resume);
+ * @endcode
+ *
+ * @SINCE_1_3_5
+ */
+class DALI_ADAPTOR_API WidgetApplication : public Application
+{
+public:
+
+  /**
+   * @brief This is the typedef for Widget creator.
+   * @SINCE_1_3_5
+   */
+  typedef Widget(*CreateWidgetFunction)(const std::string&);
+
+public:
+
+  /**
+   * @brief This is the constructor for WidgetApplications with a name.
+   *
+   * @SINCE_1_3_5
+   * @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
+   * @return A handle to the WidgetApplication
+   * @note If the stylesheet is not specified, then the library's default stylesheet will not be overridden.
+   */
+  static WidgetApplication New( int* argc, char **argv[], const std::string& stylesheet );
+
+  /**
+   * @brief The default constructor.
+   * @SINCE_1_3_5
+   */
+  WidgetApplication();
+
+  /**
+   * @brief Copy Constructor.
+   *
+   * @SINCE_1_3_5
+   * @param[in] widgetApplication Handle to an object
+   */
+  WidgetApplication( const WidgetApplication& widgetApplication );
+
+  /**
+   * @brief Assignment operator.
+   *
+   * @SINCE_1_3_5
+   * @param[in] widgetApplication Handle to an object
+   * @return A reference to this
+   */
+  WidgetApplication& operator=( const WidgetApplication& widgetApplication );
+
+ /**
+   * @brief Destructor
+   * @SINCE_1_3_5
+   */
+  ~WidgetApplication();
+
+  /**
+   * @brief Register create function for widget.
+   *
+   * @SINCE_1_3_5
+   * @param[in] widgetName  Name of widget
+   * @param[in] createFunction     Function pointer for widget creation.
+   */
+  void RegisterWidgetCreatingFunction( const std::string& widgetName, CreateWidgetFunction createFunction );
+
+public: // Not intended for application developers
+  /// @cond internal
+  /**
+   * @brief Internal constructor.
+   */
+  explicit DALI_INTERNAL WidgetApplication(Internal::Adaptor::WidgetApplication* widgetApplication);
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // DALI_WIDGET_APPLICATION_H
diff --git a/dali/public-api/adaptor-framework/widget-impl.cpp b/dali/public-api/adaptor-framework/widget-impl.cpp
new file mode 100644 (file)
index 0000000..7d67815
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * 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 "widget-impl.h"
+
+// INTERNAL INCLUDES
+#include <dali/internal/system/common/widget-controller.h>
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+WidgetPtr Widget::New()
+{
+  return new Widget();
+}
+
+Widget::Widget()
+: mImpl( nullptr )
+{
+}
+
+Widget::~Widget()
+{
+  if( mImpl != nullptr )
+  {
+    delete mImpl;
+  }
+}
+
+void Widget::OnCreate( const std::string& contentInfo, Dali::Window window )
+{
+}
+
+void Widget::OnTerminate( const std::string& contentInfo, Dali::Widget::Termination type )
+{
+}
+
+void Widget::OnPause()
+{
+}
+
+void Widget::OnResume()
+{
+}
+
+void Widget::OnResize( Dali::Window window )
+{
+}
+
+void Widget::OnUpdate( const std::string& contentInfo, int force )
+{
+}
+
+void Widget::SignalConnected( SlotObserver* slotObserver, CallbackBase* callback )
+{
+  mImpl->SignalConnected( slotObserver, callback );
+}
+
+void Widget::SignalDisconnected( SlotObserver* slotObserver, CallbackBase* callback )
+{
+  mImpl->SignalDisconnected( slotObserver, callback );
+}
+
+void Widget::SetContentInfo( const std::string& contentInfo )
+{
+  if( mImpl != nullptr )
+  {
+    mImpl->SetContentInfo( contentInfo );
+  }
+}
+
+void Widget::SetImpl( Impl* impl )
+{
+  mImpl = impl;
+}
+
+Internal::Adaptor::Widget& GetImplementation(Dali::Widget& widget)
+{
+  DALI_ASSERT_ALWAYS(widget && "widget handle is empty");
+
+  BaseObject& handle = widget.GetBaseObject();
+
+  return static_cast<Internal::Adaptor::Widget&>(handle);
+}
+
+const Internal::Adaptor::Widget& GetImplementation(const Dali::Widget& widget)
+{
+  const BaseObject& handle = widget.GetBaseObject();
+
+  return static_cast<const Internal::Adaptor::Widget&>(handle);
+}
+
+} // Adaptor
+
+} // Internal
+
+} // Dali
diff --git a/dali/public-api/adaptor-framework/widget-impl.h b/dali/public-api/adaptor-framework/widget-impl.h
new file mode 100644 (file)
index 0000000..75b61da
--- /dev/null
@@ -0,0 +1,199 @@
+#ifndef DALI_INTERNAL_WIDGET_H
+#define DALI_INTERNAL_WIDGET_H
+
+/*
+ * Copyright (c) 2018 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/object/base-object.h>
+#include <dali/public-api/signals/connection-tracker-interface.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/widget.h>
+#include <dali/public-api/adaptor-framework/window.h>
+
+namespace Dali
+{
+
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+
+class Widget;
+typedef IntrusivePtr<Widget> WidgetPtr;
+
+/**
+ * @brief This is the internal base class of custom widget.
+ *
+ * It will provides several widget instance lifecycle virtual functions
+ * which the user can override.
+ *
+ * User should override OnCreate function and create scene for custom widget.
+ *
+ * Plus, Implements ConnectionTrackerInterface so that signals (typically connected to member functions) will
+ * be disconnected automatically when the control is destroyed.
+ *
+ * @SINCE_1_3_5
+ */
+class DALI_ADAPTOR_API Widget : public BaseObject, public ConnectionTrackerInterface
+{
+public:
+
+  /**
+   * @brief Creates a new WidgetImpl instance.
+   *
+   * @SINCE_1_3_5
+   * @return A handle to the WidgetImpl instance
+   */
+  static WidgetPtr New();
+
+  /**
+   * @brief The user should override this function to determine when they create widget.
+   *
+   * @SINCE_1_3_5
+   * @param[in] contentInfo Information from WidgetView for creating. It contains previous status of widget which is sent by SetContentInfo before.
+   * @param[in] window Window handle for widget
+   */
+  virtual void OnCreate( const std::string& contentInfo, Dali::Window window );
+
+  /**
+   * @brief The user should override this function to determine when they terminate widget.
+   *
+   * @SINCE_1_3_5
+   * @param[in] contentInfo Data from WidgetView for deleting
+   * @param[in] type Termination type. When user delete widget view, termination type is PERMANENT.
+   */
+  virtual void OnTerminate( const std::string& contentInfo, Dali::Widget::Termination type );
+
+  /**
+   * @brief The user should override this function to determine when they pause widget.
+   * @SINCE_1_3_5
+   */
+  virtual void OnPause();
+
+  /**
+   * @brief The user should override this function to determine when they resume widget.
+   * @SINCE_1_3_5
+   */
+  virtual void OnResume();
+
+  /**
+   * @brief The user should override this function to determine when they resize widget.
+   *
+   * @SINCE_1_3_5
+   * @param[in] window Window handle for widget
+   */
+  virtual void OnResize( Dali::Window window );
+
+  /**
+   * @brief The user should override this function to determine when they update widget.
+   *
+   * @SINCE_1_3_5
+   * @param[in] contentInfo Data from WidgetView for updating
+   * @param[in] force Although the widget is paused, if it is true, the widget can be updated
+   */
+  virtual void OnUpdate( const std::string& contentInfo, int force );
+
+  // From ConnectionTrackerInterface
+
+  /**
+   * @copydoc ConnectionTrackerInterface::SignalConnected
+   */
+  virtual void SignalConnected( SlotObserver* slotObserver, CallbackBase* callback );
+
+  /**
+   * @copydoc ConnectionTrackerInterface::SignalDisconnected
+   */
+  virtual void SignalDisconnected( SlotObserver* slotObserver, CallbackBase* callback );
+
+  /**
+   * @brief Set content info to WidgetView.
+   *
+   * @SINCE_1_3_5
+   * @param[in] contentInfo Content info is kind of context information which contains current status of widget.
+   */
+  void SetContentInfo( const std::string& contentInfo );
+
+protected:
+
+  /**
+   * @brief WidgetImpl constructor
+   */
+  Widget();
+
+  /**
+   * @brief Virtual destructor
+   */
+  virtual ~Widget();
+
+  /// @cond internal
+public:
+  class Impl; // Class declaration is public so we can internally add devel API's to the WidgetImpl
+
+  /**
+   * Set pointer of WidgetImpl Internal.
+   * @SINCE_1_3_5
+   */
+  void SetImpl( Impl* impl );
+
+private:
+  Impl* mImpl;
+
+  // Undefined
+  DALI_INTERNAL Widget(const Widget&);
+  DALI_INTERNAL Widget& operator=(Widget&);
+  /// @endcond
+
+};
+
+/**
+ * @brief Gets implementation from the handle.
+ *
+ * @SINCE_1_3_5
+ * @param handle
+ * @return Implementation
+ * @pre handle is initialized and points to a widget
+ */
+DALI_ADAPTOR_API Internal::Adaptor::Widget& GetImplementation( Dali::Widget& widget );
+
+/**
+ * @brief Gets implementation from the handle.
+ *
+ * @SINCE_1_3_5
+ * @param handle
+ * @return Implementation
+ * @pre Handle is initialized and points to a widget.
+ */
+DALI_ADAPTOR_API const Internal::Adaptor::Widget& GetImplementation( const Dali::Widget& widget );
+
+} // namespace Adaptor
+
+} // namespace Internal
+
+/**
+ * @}
+ */
+
+} // namespace Dali
+#endif // DALI_INTERNAL_WIDGET_H
diff --git a/dali/public-api/adaptor-framework/widget.cpp b/dali/public-api/adaptor-framework/widget.cpp
new file mode 100644 (file)
index 0000000..bc8d070
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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 <dali/public-api/adaptor-framework/widget.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/adaptor-framework/widget-impl.h>
+
+namespace Dali
+{
+
+Widget Widget::New()
+{
+  Internal::Adaptor::WidgetPtr internal = Internal::Adaptor::Widget::New();
+  return Widget(internal.Get());
+}
+
+Widget::~Widget()
+{
+}
+
+Widget::Widget()
+{
+}
+
+Widget::Widget(const Widget& widget)
+: BaseHandle(widget)
+{
+}
+
+Widget& Widget::operator=(const Widget& widget)
+{
+  if( *this != widget )
+  {
+    BaseHandle::operator=( widget );
+  }
+  return *this;
+}
+
+Widget::Widget(Internal::Adaptor::Widget* widget)
+: BaseHandle(widget)
+{
+}
+
+} // namespace Dali
diff --git a/dali/public-api/adaptor-framework/widget.h b/dali/public-api/adaptor-framework/widget.h
new file mode 100755 (executable)
index 0000000..9332298
--- /dev/null
@@ -0,0 +1,112 @@
+#ifndef DALI_WIDGET_H
+#define DALI_WIDGET_H
+
+/*
+ * Copyright (c) 2018 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/object/base-handle.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+  /**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace Internal
+{
+
+namespace Adaptor
+{
+class Widget;
+}
+
+}
+
+
+/**
+ * @brief Widget class is the base class for custom widget.
+ *
+ * To make own Widget, user should inherit this class and its impl class.
+ *
+ * @SINCE_1_3_5
+ */
+class DALI_ADAPTOR_API Widget : public BaseHandle
+{
+public:
+
+  /**
+   * @brief Enumeration class for termination type of widget instance.
+   * @SINCE_1_3_5
+   */
+  enum class Termination
+  {
+    PERMANENT, //< User deleted this widget from the viewer @SINCE_1_3_5
+    TEMPORARY, //< Widget is deleted because of other reasons (e.g. widget process is terminated temporarily by the system) @SINCE_1_3_5
+  };
+
+public:
+
+  /**
+   * @brief This is the constructor for Widget.
+   * @SINCE_1_3_5
+   * @return A handle to the Widget
+   */
+  static Widget New();
+
+  /**
+   * @brief The default constructor.
+   * @SINCE_1_3_5
+   */
+  Widget();
+
+  /**
+   * @brief Copy Constructor.
+   * @SINCE_1_3_5
+   * @param[in] widget Handle to an object
+   */
+  Widget( const Widget& widget );
+
+  /**
+   * @brief Assignment operator.
+   * @SINCE_1_3_5
+   * @param[in] widget Handle to an object
+   * @return A reference to this
+   */
+  Widget& operator=( const Widget& widget );
+
+  /**
+   * @brief Destructor
+   * @SINCE_1_3_5
+   */
+  ~Widget();
+
+public: // Not intended for application developers
+  explicit Widget(Internal::Adaptor::Widget* widget);
+};
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // DALI_WIDGET_H
diff --git a/dali/public-api/adaptor-framework/window.cpp b/dali/public-api/adaptor-framework/window.cpp
new file mode 100644 (file)
index 0000000..9d8c830
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/public-api/adaptor-framework/window.h>
+
+// EXTERNAL INCLUDES
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/actors/actor.h>
+#include <dali/internal/window-system/common/window-impl.h>
+#include <dali/internal/window-system/common/orientation-impl.h>
+
+namespace Dali
+{
+
+class DALI_INTERNAL DragAndDropDetector : public BaseHandle {}; // Empty class only required to compile Deprecated API GetDragAndDropDetector
+
+Window Window::New(PositionSize posSize, const std::string& name, bool isTransparent)
+{
+  return Dali::Window::New(posSize, name, "", isTransparent);
+}
+
+Window Window::New(PositionSize posSize, const std::string& name, const std::string& className, bool isTransparent)
+{
+  Window newWindow;
+
+  const bool isAdaptorAvailable = Dali::Adaptor::IsAvailable();
+  bool isNewWindowAllowed = true;
+
+  if (isAdaptorAvailable)
+  {
+    Dali::Adaptor& adaptor = Internal::Adaptor::Adaptor::Get();
+    isNewWindowAllowed = Internal::Adaptor::Adaptor::GetImplementation(adaptor).IsMultipleWindowSupported();
+  }
+
+  if (isNewWindowAllowed)
+  {
+    Internal::Adaptor::Window* window = Internal::Adaptor::Window::New(posSize, name, className, isTransparent);
+
+    Integration::SceneHolder sceneHolder = Integration::SceneHolder(window);
+
+    if (isAdaptorAvailable)
+    {
+      Dali::Adaptor& adaptor = Internal::Adaptor::Adaptor::Get();
+      Internal::Adaptor::Adaptor::GetImplementation(adaptor).AddWindow(sceneHolder, name, className, isTransparent);
+    }
+    newWindow = Window(window);
+  }
+  else
+  {
+    DALI_LOG_ERROR("This device can't support multiple windows.\n");
+  }
+
+  return newWindow;
+}
+
+Window::Window()
+{
+}
+
+Window::~Window()
+{
+}
+
+Window::Window(const Window& handle)
+: BaseHandle(handle)
+{
+}
+
+Window& Window::operator=(const Window& rhs)
+{
+  BaseHandle::operator=(rhs);
+  return *this;
+}
+
+void Window::Add( Dali::Actor actor )
+{
+  GetImplementation( *this ).Add( actor );
+}
+
+void Window::Remove( Dali::Actor actor )
+{
+  GetImplementation( *this ).Remove( actor );
+}
+
+void Window::SetBackgroundColor( const Vector4& color )
+{
+  GetImplementation( *this ).SetBackgroundColor( color );
+}
+
+Vector4 Window::GetBackgroundColor() const
+{
+  return GetImplementation( *this ).GetBackgroundColor();
+}
+
+Layer Window::GetRootLayer() const
+{
+  return GetImplementation( *this ).GetRootLayer();
+}
+
+uint32_t Window::GetLayerCount() const
+{
+  return GetImplementation( *this ).GetLayerCount();
+}
+
+Layer Window::GetLayer( uint32_t depth ) const
+{
+  return GetImplementation( *this ).GetLayer( depth );
+}
+
+void Window::ShowIndicator( IndicatorVisibleMode visibleMode )
+{
+  DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: ShowIndicator is deprecated and will be removed from next release.\n" );
+
+  GetImplementation(*this).ShowIndicator( visibleMode );
+}
+
+Window::IndicatorSignalType& Window::IndicatorVisibilityChangedSignal()
+{
+  DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: IndicatorVisibilityChangedSignal is deprecated and will be removed from next release.\n" );
+
+  return GetImplementation(*this).IndicatorVisibilityChangedSignal();
+}
+
+void Window::SetIndicatorBgOpacity( IndicatorBgOpacity opacity )
+{
+  DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: SetIndicatorBgOpacity is deprecated and will be removed from next release.\n" );
+
+  GetImplementation(*this).SetIndicatorBgOpacity( opacity );
+}
+
+void Window::RotateIndicator( WindowOrientation orientation )
+{
+  DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: RotateIndicator is deprecated and will be removed from next release.\n" );
+
+  GetImplementation(*this).RotateIndicator( orientation );
+}
+
+void Window::SetClass( std::string name, std::string klass )
+{
+  GetImplementation(*this).SetClass( name, klass );
+}
+
+void Window::Raise()
+{
+  GetImplementation(*this).Raise();
+}
+
+void Window::Lower()
+{
+  GetImplementation(*this).Lower();
+}
+
+void Window::Activate()
+{
+  GetImplementation(*this).Activate();
+}
+
+void Window::AddAvailableOrientation( WindowOrientation orientation )
+{
+  GetImplementation(*this).AddAvailableOrientation( orientation );
+}
+
+void Window::RemoveAvailableOrientation( WindowOrientation orientation )
+{
+  GetImplementation(*this).RemoveAvailableOrientation( orientation );
+}
+
+void Window::SetPreferredOrientation( WindowOrientation orientation )
+{
+  GetImplementation(*this).SetPreferredOrientation( orientation );
+}
+
+Dali::Window::WindowOrientation Window::GetPreferredOrientation()
+{
+  return GetImplementation(*this).GetPreferredOrientation();
+}
+
+DragAndDropDetector Window::GetDragAndDropDetector() const
+{
+  DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: GetDragAndDropDetector is deprecated and will be removed from the next release.\n" );
+  DALI_ASSERT_ALWAYS( &GetImplementation( *this ) == GetObjectPtr() && "Empty Handle" );
+  return Dali::DragAndDropDetector();
+}
+
+Any Window::GetNativeHandle() const
+{
+  return GetImplementation(*this).GetNativeHandle();
+}
+
+Window::FocusSignalType& Window::FocusChangedSignal()
+{
+  DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: FocusChangedSignal is deprecated and will be removed from next release.\n" );
+  return GetImplementation(*this).FocusChangedSignal();
+}
+
+Window::FocusChangeSignalType& Window::FocusChangeSignal()
+{
+  return GetImplementation(*this).FocusChangeSignal();
+}
+
+void Window::SetAcceptFocus( bool accept )
+{
+  GetImplementation(*this).SetAcceptFocus( accept );
+}
+
+bool Window::IsFocusAcceptable() const
+{
+  return GetImplementation(*this).IsFocusAcceptable();
+}
+
+void Window::Show()
+{
+  GetImplementation(*this).Show();
+}
+
+void Window::Hide()
+{
+  GetImplementation(*this).Hide();
+}
+
+bool Window::IsVisible() const
+{
+  return GetImplementation(*this).IsVisible();
+}
+
+unsigned int Window::GetSupportedAuxiliaryHintCount() const
+{
+  return GetImplementation(*this).GetSupportedAuxiliaryHintCount();
+}
+
+std::string Window::GetSupportedAuxiliaryHint( unsigned int index ) const
+{
+  return GetImplementation(*this).GetSupportedAuxiliaryHint( index );
+}
+
+unsigned int Window::AddAuxiliaryHint( const std::string& hint, const std::string& value )
+{
+  return GetImplementation(*this).AddAuxiliaryHint( hint, value );
+}
+
+bool Window::RemoveAuxiliaryHint( unsigned int id )
+{
+  return GetImplementation(*this).RemoveAuxiliaryHint( id );
+}
+
+bool Window::SetAuxiliaryHintValue( unsigned int id, const std::string& value )
+{
+  return GetImplementation(*this).SetAuxiliaryHintValue( id, value );
+}
+
+std::string Window::GetAuxiliaryHintValue( unsigned int id ) const
+{
+  return GetImplementation(*this).GetAuxiliaryHintValue( id );
+}
+
+unsigned int Window::GetAuxiliaryHintId( const std::string& hint ) const
+{
+  return GetImplementation(*this).GetAuxiliaryHintId( hint );
+}
+
+void Window::SetInputRegion( const Rect< int >& inputRegion )
+{
+  return GetImplementation(*this).SetInputRegion( inputRegion );
+}
+
+void Window::SetType( Window::Type type )
+{
+  GetImplementation(*this).SetType( type );
+}
+
+Window::Type Window::GetType() const
+{
+  return GetImplementation(*this).GetType();
+}
+
+bool Window::SetNotificationLevel( Window::NotificationLevel::Type level )
+{
+  return GetImplementation(*this).SetNotificationLevel( level );
+}
+
+Window::NotificationLevel::Type Window::GetNotificationLevel() const
+{
+  return GetImplementation(*this).GetNotificationLevel();
+}
+
+void Window::SetOpaqueState( bool opaque )
+{
+  GetImplementation(*this).SetOpaqueState( opaque );
+}
+
+bool Window::IsOpaqueState() const
+{
+  return GetImplementation(*this).IsOpaqueState();
+}
+
+bool Window::SetScreenOffMode(Window::ScreenOffMode::Type screenMode)
+{
+  return GetImplementation(*this).SetScreenOffMode(screenMode);
+}
+
+Window::ScreenOffMode::Type Window::GetScreenOffMode() const
+{
+  return GetImplementation(*this).GetScreenOffMode();
+}
+
+bool Window::SetBrightness( int brightness )
+{
+  return GetImplementation(*this).SetBrightness( brightness );
+}
+
+int Window::GetBrightness() const
+{
+  return GetImplementation(*this).GetBrightness();
+}
+
+Window::ResizedSignalType& Window::ResizedSignal()
+{
+  DALI_LOG_WARNING_NOFN("DEPRECATION WARNING: ResizedSignal is deprecated and will be removed from next release.\n" );
+  return GetImplementation(*this).ResizedSignal();
+}
+
+Window::ResizeSignalType& Window::ResizeSignal()
+{
+  return GetImplementation(*this).ResizeSignal();
+}
+
+void Window::SetSize( Window::WindowSize size )
+{
+  GetImplementation(*this).SetSize( size );
+}
+
+Window::WindowSize Window::GetSize() const
+{
+  return GetImplementation(*this).GetSize();
+}
+
+void Window::SetPosition( Window::WindowPosition position )
+{
+  GetImplementation(*this).SetPosition( position );
+}
+
+Window::WindowPosition Window::GetPosition() const
+{
+  return GetImplementation(*this).GetPosition();
+}
+
+void Window::SetTransparency( bool transparent )
+{
+  GetImplementation(*this).SetTransparency( transparent );
+}
+
+Window::Window( Internal::Adaptor::Window* window )
+: BaseHandle( window )
+{
+}
+
+} // namespace Dali
diff --git a/dali/public-api/adaptor-framework/window.h b/dali/public-api/adaptor-framework/window.h
new file mode 100755 (executable)
index 0000000..c127f61
--- /dev/null
@@ -0,0 +1,724 @@
+#ifndef DALI_WINDOW_H
+#define DALI_WINDOW_H
+
+/*
+ * Copyright (c) 2019 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/math/rect.h>
+#include <dali/public-api/math/uint-16-pair.h>
+#include <dali/public-api/math/vector2.h>
+#include <dali/public-api/math/vector4.h>
+#include <dali/public-api/object/base-handle.h>
+#include <dali/public-api/object/any.h>
+#include <dali/public-api/signals/dali-signal.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+#undef OPAQUE
+#undef TRANSPARENT
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+typedef Dali::Rect<int> PositionSize;
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class Window;
+}
+}
+
+class DragAndDropDetector;
+class Orientation;
+class Actor;
+class Layer;
+
+/**
+ * @brief The window class is used internally for drawing.
+ *
+ * A Window has an orientation and indicator properties.
+ * You can get a valid Window handle by calling Dali::Application::GetWindow().
+ * @SINCE_1_0.0
+ */
+class DALI_ADAPTOR_API Window : public BaseHandle
+{
+public:
+
+  typedef Uint16Pair WindowSize;          ///< Window size type @SINCE_1_2.60
+  typedef Uint16Pair WindowPosition;      ///< Window position type @SINCE_1_2.60
+
+  typedef Signal< void (bool) > IndicatorSignalType;  ///< @DEPRECATED_1_4.9 @brief Indicator state signal type @SINCE_1_0.0
+  typedef Signal< void (bool) > FocusSignalType;         ///< @DEPRECATED_1_4.35 @brief Window focus signal type @SINCE_1_2.60
+  typedef Signal< void (WindowSize) > ResizedSignalType; ///< @DEPRECATED_1_4.35 @brief Window resized signal type @SINCE_1_2.60
+  typedef Signal< void (Window,bool) > FocusChangeSignalType;         ///< Window focus signal type @SINCE_1_4.35
+  typedef Signal< void (Window,WindowSize) > ResizeSignalType; ///< Window resized signal type @SINCE_1_4.35
+public:
+
+  // Enumerations
+
+  /**
+   * @brief Enumeration for orientation of the window is the way in which a rectangular page is oriented for normal viewing.
+   *
+   * This Enumeration is used the available orientation APIs and the preferred orientation.
+   *
+   * @SINCE_1_0.0
+   */
+  enum WindowOrientation
+  {
+    PORTRAIT = 0,  ///< Portrait orientation. The height of the display area is greater than the width. @SINCE_1_0.0
+    LANDSCAPE = 90,  ///< Landscape orientation. A wide view area is needed. @SINCE_1_0.0
+    PORTRAIT_INVERSE = 180,  ///< Portrait inverse orientation @SINCE_1_0.0
+    LANDSCAPE_INVERSE = 270,  ///< Landscape inverse orientation @SINCE_1_0.0
+    NO_ORIENTATION_PREFERENCE = -1 ///< No orientation. It is used to initialize or unset the preferred orientation.  @SINCE_1_4.51
+  };
+
+  /**
+   * @DEPRECATED_1_4.9
+   * @brief Enumeration for opacity of the indicator.
+   * @SINCE_1_0.0
+   */
+  enum IndicatorBgOpacity
+  {
+    OPAQUE = 100, ///< @DEPRECATED_1_4.9 @brief Fully opaque indicator Bg @SINCE_1_0.0
+    TRANSLUCENT = 50, ///< @DEPRECATED_1_4.9 @brief Semi translucent indicator Bg @SINCE_1_0.0
+    TRANSPARENT = 0 ///< @DEPRECATED_1_4.9 @brief Fully transparent indicator Bg @SINCE_1_0.0
+  };
+
+  /**
+   * @DEPRECATED_1_4.9
+   * @brief Enumeration for visible mode of the indicator.
+   * @SINCE_1_0.0
+   */
+  enum IndicatorVisibleMode
+  {
+    INVISIBLE = 0, ///< @DEPRECATED_1_4.9 @brief Hide indicator @SINCE_1_0.0
+    VISIBLE = 1, ///< @DEPRECATED_1_4.9 @brief Show indicator @SINCE_1_0.0
+    AUTO = 2 ///< @DEPRECATED_1_4.9 @brief Hide in default, will show when necessary @SINCE_1_0.0
+  };
+
+  /**
+   * @brief An enum of Window types.
+   * @SINCE_1_2.60
+   */
+  enum Type
+  {
+    NORMAL,           ///< A default window type. Indicates a normal, top-level window. Almost every window will be created with this type. @SINCE_1_2.60
+    NOTIFICATION,     ///< A notification window, like a warning about battery life or a new E-Mail received. @SINCE_1_2.60
+    UTILITY,          ///< A persistent utility window, like a toolbox or palette. @SINCE_1_2.60
+    DIALOG            ///< Used for simple dialog windows. @SINCE_1_2.60
+  };
+
+  /**
+   * @brief An enum of screen mode.
+   * @SINCE_1_2.60
+   */
+  struct NotificationLevel
+  {
+    /**
+     * @brief An enum of screen mode.
+     * @SINCE_1_2.60
+     */
+    enum Type
+    {
+      NONE   = -1,    ///< No notification level. Default level. This value makes the notification window place in the layer of the normal window. @SINCE_1_2.60
+      BASE   = 10,    ///< Base notification level. @SINCE_1_2.60
+      MEDIUM = 20,    ///< Higher notification level than base. @SINCE_1_2.60
+      HIGH   = 30,    ///< Higher notification level than medium. @SINCE_1_2.60
+      TOP    = 40     ///< The highest notification level. @SINCE_1_2.60
+    };
+  };
+
+  /**
+   * @brief An enum of screen mode.
+   * @SINCE_1_2.60
+   */
+  struct ScreenOffMode
+  {
+    /**
+     * @brief An enum of screen mode.
+     * @SINCE_1_2.60
+     */
+    enum Type
+    {
+      TIMEOUT,              ///< The mode which turns the screen off after a timeout. @SINCE_1_2.60
+      NEVER,                ///< The mode which keeps the screen turned on. @SINCE_1_2.60
+    };
+
+    static constexpr Type DEFAULT { TIMEOUT }; ///< The default mode. @SINCE_1_2.60
+  };
+
+  // Methods
+
+  /**
+   * @brief Creates an initialized handle to a new Window.
+   * @SINCE_1_0.0
+   * @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
+   * @note This creates an extra window in addition to the default main window
+   */
+  static Window New(PositionSize windowPosition, const std::string& name, bool isTransparent = false);
+
+  /**
+   * @brief Creates an initialized handle to a new Window.
+   * @SINCE_1_0.0
+   * @param[in] windowPosition 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
+   * @note This creates an extra window in addition to the default main window
+   * @return A new Window
+   */
+  static Window New(PositionSize windowPosition, const std::string& name, const std::string& className, bool isTransparent = false);
+
+  /**
+   * @brief Creates an uninitialized handle.
+   *
+   * This can be initialized using Dali::Application::GetWindow() or
+   * Dali::Window::New().
+   * @SINCE_1_0.0
+   */
+  Window();
+
+  /**
+   * @brief Destructor.
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_0.0
+   */
+  ~Window();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @SINCE_1_0.0
+   * @param[in] handle A reference to the copied handle
+   */
+  Window(const Window& handle);
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @SINCE_1_0.0
+   * @param[in] rhs A reference to the copied handle
+   * @return A reference to this
+   */
+  Window& operator=(const Window& rhs);
+
+  /**
+   * @brief Adds a child Actor to the Window.
+   *
+   * The child will be referenced.
+   *
+   * @SINCE_1_4.19
+   * @param[in] actor The child
+   * @pre The actor has been initialized.
+   * @pre The actor does not have a parent.
+   */
+  void Add( Actor actor );
+
+  /**
+   * @brief Removes a child Actor from the Window.
+   *
+   * The child will be unreferenced.
+   *
+   * @SINCE_1_4.19
+   * @param[in] actor The child
+   * @pre The actor has been added to the stage.
+   */
+  void Remove( Actor actor );
+
+  /**
+   * @brief Sets the background color of the Window.
+   *
+   * @SINCE_1_4.19
+   * @param[in] color The new background color
+   */
+  void SetBackgroundColor( const Vector4& color );
+
+  /**
+   * @brief Gets the background color of the Window.
+   *
+   * @SINCE_1_4.19
+   * @return The background color
+   */
+  Vector4 GetBackgroundColor() const;
+
+  /**
+   * @brief Returns the root Layer of the Window.
+   *
+   * @SINCE_1_4.19
+   * @return The root layer
+   */
+  Layer GetRootLayer() const;
+
+  /**
+   * @brief Queries the number of on-scene layers in the Window.
+   *
+   * Note that a default layer is always provided (count >= 1).
+   *
+   * @SINCE_1_4.19
+   * @return The number of layers
+   */
+  uint32_t GetLayerCount() const;
+
+  /**
+   * @brief Retrieves the layer at a specified depth in the Window.
+   *
+   * @SINCE_1_4.19
+   * @param[in] depth The depth
+   * @return The layer found at the given depth
+   * @pre Depth is less than layer count; see GetLayerCount().
+   */
+  Layer GetLayer( uint32_t depth ) const;
+
+  /**
+   * @DEPRECATED_1_4.9
+   * @brief This sets whether the indicator bar should be shown or not.
+   * @SINCE_1_0.0
+   * @param[in] visibleMode Visible mode for indicator bar, VISIBLE in default
+   */
+  void ShowIndicator( IndicatorVisibleMode visibleMode ) DALI_DEPRECATED_API;
+
+  /**
+   * @DEPRECATED_1_4.9
+   * @brief This sets the opacity mode of indicator bar.
+   * @SINCE_1_0.0
+   * @param[in] opacity The opacity mode
+   */
+  void SetIndicatorBgOpacity( IndicatorBgOpacity opacity ) DALI_DEPRECATED_API;
+
+  /**
+   * @DEPRECATED_1_4.9
+   * @brief This sets the orientation of indicator bar.
+   *
+   * It does not implicitly show the indicator if it is currently hidden.
+   * @SINCE_1_0.0
+   * @param[in] orientation The orientation
+   */
+  void RotateIndicator(WindowOrientation orientation) DALI_DEPRECATED_API;
+
+  /**
+   * @brief Sets the window name and class string.
+   * @SINCE_1_0.0
+   * @param[in] name The name of the window
+   * @param[in] klass The class of the window
+   */
+  void SetClass(std::string name, std::string klass);
+
+  /**
+   * @brief Raises window to the top of Window stack.
+   * @SINCE_1_0.0
+   */
+  void Raise();
+
+  /**
+   * @brief Lowers window to the bottom of Window stack.
+   * @SINCE_1_0.0
+   */
+  void Lower();
+
+  /**
+   * @brief Activates window to the top of Window stack even it is iconified.
+   * @SINCE_1_0.0
+   */
+  void Activate();
+
+  /**
+   * @brief Adds an orientation to the list of available orientations.
+   * @SINCE_1_0.0
+   * @param[in] orientation The available orientation to add
+   */
+  void AddAvailableOrientation( WindowOrientation orientation );
+
+  /**
+   * @brief Removes an orientation from the list of available orientations.
+   * @SINCE_1_0.0
+   * @param[in] orientation The available orientation to remove
+   */
+  void RemoveAvailableOrientation( WindowOrientation orientation );
+
+  /**
+   * @brief Sets a preferred orientation.
+   * @SINCE_1_0.0
+   * @param[in] orientation The preferred orientation
+   * @pre Orientation is in the list of available orientations.
+   *
+   * @note To unset the preferred orientation, orientation should be set NO_ORIENTATION_PREFERENCE.
+   */
+  void SetPreferredOrientation( WindowOrientation orientation );
+
+  /**
+   * @brief Gets the preferred orientation.
+   * @SINCE_1_0.0
+   * @return The preferred orientation if previously set, or none
+   */
+  WindowOrientation GetPreferredOrientation();
+
+  /**
+   * @DEPRECATED_1_4.19 Was not intended for Application developers
+   * @brief Returns an empty handle.
+   * @note  Not intended for application developers.
+   * @SINCE_1_0.0
+   * @return An empty handle
+   */
+  DragAndDropDetector GetDragAndDropDetector() const DALI_DEPRECATED_API;
+
+  /**
+   * @brief Gets the native handle of the window.
+   *
+   * When users call this function, it wraps the actual type used by the underlying window system.
+   * @SINCE_1_0.0
+   * @return The native handle of the Window or an empty handle
+   */
+  Any GetNativeHandle() const;
+
+  /**
+   * @brief Sets whether window accepts focus or not.
+   *
+   * @SINCE_1_2.60
+   * @param[in] accept If focus is accepted or not. Default is true.
+   */
+  void SetAcceptFocus( bool accept );
+
+  /**
+   * @brief Returns whether window accepts focus or not.
+   *
+   * @SINCE_1_2.60
+   * @return True if the window accept focus, false otherwise
+   */
+  bool IsFocusAcceptable() const;
+
+  /**
+   * @brief Shows the window if it is hidden.
+   * @SINCE_1_2.60
+   */
+  void Show();
+
+  /**
+   * @brief Hides the window if it is showing.
+   * @SINCE_1_2.60
+   */
+  void Hide();
+
+  /**
+   * @brief Returns whether the window is visible or not.
+   * @SINCE_1_2.60
+   * @return True if the window is visible, false otherwise.
+   */
+  bool IsVisible() const;
+
+  /**
+   * @brief Gets the count of supported auxiliary hints of the window.
+   * @SINCE_1_2.60
+   * @return The number of supported auxiliary hints.
+   *
+   * @note The window auxiliary hint is the value which is used to decide which actions should be made available to the user by the window manager.
+   * If you want to set specific hint to your window, then you should check whether it exists in the supported auxiliary hints.
+   */
+  unsigned int GetSupportedAuxiliaryHintCount() const;
+
+  /**
+   * @brief Gets the supported auxiliary hint string of the window.
+   * @SINCE_1_2.60
+   * @param[in] index The index of the supported auxiliary hint lists
+   * @return The auxiliary hint string of the index.
+   *
+   * @note The window auxiliary hint is the value which is used to decide which actions should be made available to the user by the window manager.
+   * If you want to set specific hint to your window, then you should check whether it exists in the supported auxiliary hints.
+   */
+  std::string GetSupportedAuxiliaryHint( unsigned int index ) const;
+
+  /**
+   * @brief Creates an auxiliary hint of the window.
+   * @SINCE_1_2.60
+   * @param[in] hint The auxiliary hint string.
+   * @param[in] value The value string.
+   * @return The ID of created auxiliary hint, or @c 0 on failure.
+   */
+  unsigned int AddAuxiliaryHint( const std::string& hint, const std::string& value );
+
+  /**
+   * @brief Removes an auxiliary hint of the window.
+   * @SINCE_1_2.60
+   * @param[in] id The ID of the auxiliary hint.
+   * @return True if no error occurred, false otherwise.
+   */
+  bool RemoveAuxiliaryHint( unsigned int id );
+
+  /**
+   * @brief Changes a value of the auxiliary hint.
+   * @SINCE_1_2.60
+   * @param[in] id The auxiliary hint ID.
+   * @param[in] value The value string to be set.
+   * @return True if no error occurred, false otherwise.
+   */
+  bool SetAuxiliaryHintValue( unsigned int id, const std::string& value );
+
+  /**
+   * @brief Gets a value of the auxiliary hint.
+   * @SINCE_1_2.60
+   * @param[in] id The auxiliary hint ID.
+   * @return The string value of the auxiliary hint ID, or an empty string if none exists.
+   */
+  std::string GetAuxiliaryHintValue( unsigned int id ) const;
+
+  /**
+   * @brief Gets a ID of the auxiliary hint string.
+   * @SINCE_1_2.60
+   * @param[in] hint The auxiliary hint string.
+   * @return The ID of the auxiliary hint string, or @c 0 if none exists.
+   */
+  unsigned int GetAuxiliaryHintId( const std::string& hint ) const;
+
+  /**
+   * @brief Sets a region to accept input events.
+   * @SINCE_1_2.60
+   * @param[in] inputRegion The region to accept input events.
+   */
+  void SetInputRegion( const Rect< int >& inputRegion );
+
+  /**
+   * @brief Sets a window type.
+   * @SINCE_1_2.60
+   * @param[in] type The window type.
+   * @remarks The default window type is NORMAL.
+   */
+  void SetType( Type type );
+
+  /**
+   * @brief Gets a window type.
+   * @SINCE_1_2.60
+   * @return A window type.
+   */
+  Type GetType() const;
+
+  /**
+   * @brief Sets a priority level for the specified notification window.
+   * @SINCE_1_2.60
+   * @param[in] level The notification window level.
+   * @return True if no error occurred, false otherwise.
+   * @PRIVLEVEL_PUBLIC
+   * @PRIVILEGE_WINDOW_PRIORITY
+   * @remarks This can be used for a notification type window only. The default level is NotificationLevel::NONE.
+   */
+  bool SetNotificationLevel( NotificationLevel::Type level );
+
+  /**
+   * @brief Gets a priority level for the specified notification window.
+   * @SINCE_1_2.60
+   * @return The notification window level.
+   * @remarks This can be used for a notification type window only.
+   */
+  NotificationLevel::Type GetNotificationLevel() const;
+
+  /**
+   * @brief Sets a transparent window's visual state to opaque.
+   * @details If a visual state of a transparent window is opaque,
+   * then the window manager could handle it as an opaque window when calculating visibility.
+   * @SINCE_1_2.60
+   * @param[in] opaque Whether the window's visual state is opaque.
+   * @remarks This will have no effect on an opaque window.
+   * It doesn't change transparent window to opaque window but lets the window manager know the visual state of the window.
+   */
+  void SetOpaqueState( bool opaque );
+
+  /**
+   * @brief Returns whether a transparent window's visual state is opaque or not.
+   * @SINCE_1_2.60
+   * @return True if the window's visual state is opaque, false otherwise.
+   * @remarks The return value has no meaning on an opaque window.
+   */
+  bool IsOpaqueState() const;
+
+  /**
+   * @brief Sets a window's screen off mode.
+   * @details This API is useful when the application needs to keep the display turned on.
+   * If the application sets the screen mode to #::Dali::Window::ScreenOffMode::NEVER to its window and the window is shown,
+   * the window manager requests the display system to keep the display on as long as the window is shown.
+   * If the window is no longer shown, then the window manager requests the display system to go back to normal operation.
+   * @SINCE_1_2.60
+   * @param[in] screenOffMode The screen mode.
+   * @return True if no error occurred, false otherwise.
+   * @PRIVLEVEL_PUBLIC
+   * @PRIVILEGE_DISPLAY
+   */
+  bool SetScreenOffMode(ScreenOffMode::Type screenOffMode);
+
+  /**
+   * @brief Gets a screen off mode of the window.
+   * @SINCE_1_2.60
+   * @return The screen off mode.
+   */
+  ScreenOffMode::Type GetScreenOffMode() const;
+
+  /**
+   * @brief Sets preferred brightness of the window.
+   * @details This API is useful when the application needs to change the brightness of the screen when it is appeared on the screen.
+   * If the brightness has been set and the window is shown, the window manager requests the display system to change the brightness to the provided value.
+   * If the window is no longer shown, then the window manager requests the display system to go back to default brightness.
+   * A value less than 0 results in default brightness and a value greater than 100 results in maximum brightness.
+   * @SINCE_1_2.60
+   * @param[in] brightness The preferred brightness (0 to 100).
+   * @return True if no error occurred, false otherwise.
+   * @PRIVLEVEL_PUBLIC
+   * @PRIVILEGE_DISPLAY
+   */
+  bool SetBrightness( int brightness );
+
+  /**
+   * @brief Gets preferred brightness of the window.
+   * @SINCE_1_2.60
+   * @return The preferred brightness.
+   */
+  int GetBrightness() const;
+
+  /**
+   * @brief Sets a size of the window.
+   *
+   * @SINCE_1_2.60
+   * @param[in] size The new window size
+   */
+  void SetSize( WindowSize size );
+
+  /**
+   * @brief Gets a size of the window.
+   *
+   * @SINCE_1_2.60
+   * @return The size of the window
+   */
+  WindowSize GetSize() const;
+
+  /**
+   * @brief Sets a position of the window.
+   *
+   * @SINCE_1_2.60
+   * @param[in] position The new window position
+   */
+  void SetPosition( WindowPosition position );
+
+  /**
+   * @brief Gets a position of the window.
+   *
+   * @SINCE_1_2.60
+   * @return The position of the window
+   */
+  WindowPosition GetPosition() const;
+
+  /**
+   * @brief Sets whether the window is transparent or not.
+   *
+   * @SINCE_1_2.60
+   * @param[in] transparent Whether the window is transparent
+   */
+  void SetTransparency( bool transparent );
+
+public: // Signals
+  /**
+   * @DEPRECATED_1_4.9
+   * @brief The user should connect to this signal to get a timing when indicator was shown / hidden.
+   * @SINCE_1_0.0
+   * @return The signal to connect to
+   */
+  IndicatorSignalType& IndicatorVisibilityChangedSignal() DALI_DEPRECATED_API;
+
+  /**
+   * @DEPRECATED_1_4.35
+   * @brief The user should connect to this signal to get a timing when window gains focus or loses focus.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( bool focusIn );
+   * @endcode
+   * The parameter is true if window gains focus, otherwise false.
+   *
+   * @SINCE_1_2.60
+   * @return The signal to connect to
+   */
+  FocusSignalType& FocusChangedSignal() DALI_DEPRECATED_API;
+
+  /**
+   * @brief This signal is emitted when the window is resized.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( int width, int height );
+   * @endcode
+   * The parameters are the resized width and height.
+   *
+   * @SINCE_1_2.60
+   * @return The signal to connect to
+   */
+  ResizedSignalType& ResizedSignal() DALI_DEPRECATED_API;
+
+  /**
+   * @brief The user should connect to this signal to get a timing when window gains focus or loses focus.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( Window window, bool focusIn );
+   * @endcode
+   * The parameter is true if window gains focus, otherwise false.
+   * and window means this signal was called from what window
+   *
+   * @SINCE_1_4.35
+   * @return The signal to connect to
+   */
+  FocusChangeSignalType& FocusChangeSignal();
+
+  /**
+   * @brief This signal is emitted when the window is resized.
+   *
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName( Window window, int width, int height );
+   * @endcode
+   * The parameters are the resized width and height.
+   * and window means this signal was called from what window
+   *
+   * @SINCE_1_4.35
+   * @return The signal to connect to
+   */
+  ResizeSignalType& ResizeSignal();
+
+public: // Not intended for application developers
+  /// @cond internal
+  /**
+   * @brief This constructor is used by Dali::Application::GetWindow().
+   * @SINCE_1_0.0
+   * @param[in] window A pointer to the Window
+   */
+  explicit DALI_INTERNAL Window( Internal::Adaptor::Window* window );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // __DALI_WINDOW_H__
diff --git a/dali/public-api/capture/capture.h b/dali/public-api/capture/capture.h
new file mode 100755 (executable)
index 0000000..5119203
--- /dev/null
@@ -0,0 +1,222 @@
+#ifndef DALI_CAPTURE_H
+#define DALI_CAPTURE_H
+
+/*
+ * Copyright (c) 2018 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 HEADERS
+#include <dali/public-api/actors/actor.h>
+#include <dali/public-api/signals/dali-signal.h>
+#include <dali/public-api/actors/camera-actor.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class Capture;
+}
+}
+
+/**
+ * @brief Capture snapshots the current scene and save as a file.
+ *
+ * @SINCE_1_3_4
+ *
+ * Applications should follow the example below to create capture :
+ *
+ * @code
+ * Capture capture = Capture::New();
+ * @endcode
+ *
+ * If required, you can also connect class member function to a signal :
+ *
+ * @code
+ * capture.FinishedSignal().Connect(this, &CaptureSceneExample::OnCaptureFinished);
+ * @endcode
+ *
+ * At the connected class member function, you can know whether capture finish state.
+ *
+ * @code
+ * void CaptureSceneExample::OnCaptureFinished( Capture capture, Capture::FinishState state )
+ * {
+ *   if ( state == Capture::FinishState::SUCCEEDED )
+ *   {
+ *     // Do something
+ *   }
+ *   else
+ *   {
+ *     // Do something
+ *   }
+ * }
+ * @endcode
+ */
+class DALI_ADAPTOR_API Capture : public BaseHandle
+{
+
+public:
+
+  /**
+   * @brief The enumerations used for checking capture success
+   * @SINCE_1_3_4
+   */
+  enum class FinishState
+  {
+    SUCCEEDED, ///< Succeeded in saving the result after capture
+    FAILED     ///< Failed to capture by time out or to save the result
+  };
+
+  /**
+   * @brief Typedef for finished signals sent by this class.
+   *
+   * @SINCE_1_3_4
+   */
+  typedef Signal< void ( Capture, Capture::FinishState ) > CaptureFinishedSignalType;
+
+  /**
+   * @brief Create an uninitialized Capture; this can be initialized with Actor::New().
+   *
+   * @SINCE_1_3_4
+   *
+   * Calling member functions with an uninitialized Dali::Object is not allowed.
+   */
+  Capture();
+
+  /**
+   * @brief Create an initialized Capture.
+   *
+   * @SINCE_1_3_4
+   *
+   * @return A handle to a newly allocated Dali resource.
+   * @note Projection mode of default cameraActor is Dali::Camera::PERSPECTIVE_PROJECTION
+   */
+  static Capture New();
+
+  /**
+   * @brief Create an initialized Capture.
+   *
+   * @SINCE_1_3_4
+   *
+   * @param[in] cameraActor An initialized CameraActor.
+   * @return A handle to a newly allocated Dali resource.
+   */
+  static Capture New( Dali::CameraActor cameraActor );
+
+  /**
+   * @brief Downcast an Object handle to Capture handle.
+   *
+   * @SINCE_1_3_4
+   *
+   * If handle points to a Capture object the downcast produces valid
+   * handle. If not the returned handle is left uninitialized.
+   *
+   * @param[in] handle to An object.
+   * @return handle to a Capture object or an uninitialized handle.
+   */
+  static Capture DownCast( BaseHandle handle );
+
+  /**
+   * @brief Dali::Actor is intended as a base class.
+   *
+   * @SINCE_1_3_4
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   */
+  ~Capture();
+
+  /**
+   * @brief This copy constructor is required for (smart) pointer semantics.
+   *
+   * @SINCE_1_3_4
+   *
+   * @param[in] copy A reference to the copied handle.
+   */
+  Capture( const Capture& copy );
+
+  /**
+   * @brief This assignment operator is required for (smart) pointer semantics.
+   *
+   * @SINCE_1_3_4
+   *
+   * @param[in] rhs  A reference to the copied handle.
+   * @return A reference to this.
+   */
+  Capture& operator=( const Capture& rhs );
+
+  /**
+   * @brief Start capture and save the image as a file.
+   *
+   * @SINCE_1_3_4
+   *
+   * @param[in] source source actor to be used for capture.
+   * @param[in] size captured size.
+   * @param[in] path image file path to be saved as a file.
+   * @param[in] clearColor background color of captured scene
+   */
+  void Start( Actor source, const Vector2& size, const std::string &path, const Vector4& clearColor );
+
+  /**
+   * @brief Start capture and save the image as a file.
+   *
+   * @SINCE_1_3_4
+   *
+   * @param[in] source source actor to be used for capture.
+   * @param[in] size captured size.
+   * @param[in] path image file path to be saved as a file.
+   * @note Clear color is transparent.
+   */
+  void Start( Actor source, const Vector2& size, const std::string &path );
+
+  /**
+   * @brief Get finished signal.
+   *
+   * @SINCE_1_3_4
+   *
+   * @return finished signal instance.
+   */
+  CaptureFinishedSignalType& FinishedSignal();
+
+public: // Not intended for application developers
+  /// @cond internal
+  /**
+   * @brief This constructor is used by New() methods.
+   *
+   * @SINCE_1_3_4
+   *
+   * @param[in] internal A pointer to a newly allocated Dali resource.
+   */
+  explicit DALI_INTERNAL Capture( Internal::Adaptor::Capture* internal );
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+
+} // namespace Dali
+
+#endif // DALI_CAPTURE_H
diff --git a/dali/public-api/dali-adaptor-common.h b/dali/public-api/dali-adaptor-common.h
new file mode 100755 (executable)
index 0000000..c0a5651
--- /dev/null
@@ -0,0 +1,55 @@
+#ifndef DALI_ADAPTOR_COMMON_H
+#define DALI_ADAPTOR_COMMON_H
+
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// EXTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
+/*
+ * Definitions for shared library support.
+ *
+ * If a library is configured with --enable-exportall or --enable-debug
+ * then HIDE_DALI_INTERNALS is not defined, and nothing is hidden.
+ * If it is configured without these options (the default), then HIDE_INTERNALS
+ * is defined when building the library, visibility is automatically hidden, and the explicit
+ * defines below come into use.
+ * When building a library that uses DALI, HIDE_DALI_INTERNALS.
+ */
+#if __GNUC__ >= 4
+#  ifndef HIDE_DALI_INTERNALS
+#    define DALI_ADAPTOR_API
+#  else
+#    define DALI_ADAPTOR_API __attribute__ ((visibility ("default")))
+#  endif
+#else
+#ifdef WIN32
+#ifdef BUILDING_DALI_ADAPTOR
+/** Visibility attribute to hide declarations */
+#  define DALI_ADAPTOR_API __declspec(dllexport)
+#else
+/** Visibility attribute to hide declarations */
+#  define DALI_ADAPTOR_API __declspec(dllimport)
+#endif
+#else
+/** Visibility attribute to show declarations */
+#  define DALI_ADAPTOR_API
+#endif
+#endif
+
+#endif // DALI_ADAPTOR_COMMON_H
diff --git a/dali/public-api/dali-adaptor-version.cpp b/dali/public-api/dali-adaptor-version.cpp
new file mode 100644 (file)
index 0000000..d5c97a2
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// HEADER
+#include <dali/public-api/dali-adaptor-version.h>
+
+// EXTERNAL INCLUDES
+#ifdef DEBUG_ENABLED
+#include <iostream>
+#endif
+
+namespace Dali
+{
+
+const unsigned int ADAPTOR_MAJOR_VERSION = 1;
+const unsigned int ADAPTOR_MINOR_VERSION = 5;
+const unsigned int ADAPTOR_MICRO_VERSION = 8;
+const char * const ADAPTOR_BUILD_DATE    = __DATE__ " " __TIME__;
+
+#ifdef DEBUG_ENABLED
+namespace
+{
+/// Allows the printing of the version number ONLY when debug is enabled
+struct PrintVersion
+{
+  PrintVersion()
+  {
+    std::cerr << "DALi Adaptor:   " << ADAPTOR_MAJOR_VERSION << "." << ADAPTOR_MINOR_VERSION << "." << ADAPTOR_MICRO_VERSION << " (" << ADAPTOR_BUILD_DATE << ")" << std::endl;
+  }
+};
+PrintVersion ADAPTOR_VERSION;
+} // unnamed namespace
+#endif
+
+} // namespace Dali
diff --git a/dali/public-api/dali-adaptor-version.h b/dali/public-api/dali-adaptor-version.h
new file mode 100755 (executable)
index 0000000..8772b9b
--- /dev/null
@@ -0,0 +1,32 @@
+#ifndef DALI_ADAPTOR_VERSION_H
+#define DALI_ADAPTOR_VERSION_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+DALI_ADAPTOR_API extern const unsigned int ADAPTOR_MAJOR_VERSION; ///< The major version number of the Adaptor.
+DALI_ADAPTOR_API extern const unsigned int ADAPTOR_MINOR_VERSION; ///< The minor version number of the Adaptor.
+DALI_ADAPTOR_API extern const unsigned int ADAPTOR_MICRO_VERSION; ///< The micro version number of the Adaptor.
+DALI_ADAPTOR_API extern const char * const ADAPTOR_BUILD_DATE;    ///< The date/time the Adaptor library was built.
+} // namespace Dali
+
+#endif // DALI_ADAPTOR_VERSION_H
diff --git a/dali/public-api/file.list b/dali/public-api/file.list
new file mode 100644 (file)
index 0000000..219b9c4
--- /dev/null
@@ -0,0 +1,55 @@
+
+
+SET( adaptor_public_api_src_files
+  ${adaptor_public_api_dir}/adaptor-framework/application.cpp 
+  ${adaptor_public_api_dir}/adaptor-framework/key.cpp 
+  ${adaptor_public_api_dir}/adaptor-framework/window.cpp 
+  ${adaptor_public_api_dir}/adaptor-framework/timer.cpp 
+  ${adaptor_public_api_dir}/adaptor-framework/tts-player.cpp 
+  ${adaptor_public_api_dir}/adaptor-framework/native-image-source.cpp 
+  ${adaptor_public_api_dir}/adaptor-framework/widget.cpp 
+  ${adaptor_public_api_dir}/adaptor-framework/widget-application.cpp 
+  ${adaptor_public_api_dir}/adaptor-framework/widget-impl.cpp 
+  ${adaptor_public_api_dir}/dali-adaptor-version.cpp
+)
+
+
+SET( public_api_header_files
+  ${adaptor_public_api_dir}/dali-adaptor-version.h 
+  ${adaptor_public_api_dir}/dali-adaptor-common.h
+)
+
+
+SET( public_api_adaptor_framework_header_files
+  ${adaptor_public_api_dir}/adaptor-framework/application.h 
+  ${adaptor_public_api_dir}/adaptor-framework/application-configuration.h 
+  ${adaptor_public_api_dir}/adaptor-framework/device-status.h 
+  ${adaptor_public_api_dir}/adaptor-framework/input-method.h 
+  ${adaptor_public_api_dir}/adaptor-framework/key.h 
+  ${adaptor_public_api_dir}/adaptor-framework/key-grab.h 
+  ${adaptor_public_api_dir}/adaptor-framework/style-change.h 
+  ${adaptor_public_api_dir}/adaptor-framework/timer.h 
+  ${adaptor_public_api_dir}/adaptor-framework/tts-player.h 
+  ${adaptor_public_api_dir}/adaptor-framework/native-image-source.h 
+  ${adaptor_public_api_dir}/adaptor-framework/window.h 
+  ${adaptor_public_api_dir}/adaptor-framework/widget.h 
+  ${adaptor_public_api_dir}/adaptor-framework/widget-application.h 
+  ${adaptor_public_api_dir}/adaptor-framework/widget-impl.h
+)
+
+# wearable and watch extra public headers
+SET( adaptor_dali_wearable_header_file
+  ${adaptor_public_api_dir}/watch/dali-wearable.h
+)
+
+# wearable and watch extra public headers
+SET( public_dali_watch_header_files
+  ${adaptor_public_api_dir}/watch/watch-application.h 
+  ${adaptor_public_api_dir}/watch/watch-time.h
+)
+
+# wearable and watch extra public headers
+SET( public_dali_capture_header_files
+  ${adaptor_public_api_dir}/capture/capture.h
+)
+
diff --git a/dali/public-api/watch/dali-wearable.h b/dali/public-api/watch/dali-wearable.h
new file mode 100644 (file)
index 0000000..e122322
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef DALI_WEARABLE_H
+#define DALI_WEARABLE_H
+
+/*
+ * Copyright (c) 2019 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 <dali/public-api/watch/watch-application.h>
+#include <dali/public-api/capture/capture.h>
+
+#endif // DALI_WEARABLE_H
diff --git a/dali/public-api/watch/watch-application.h b/dali/public-api/watch/watch-application.h
new file mode 100755 (executable)
index 0000000..df59ef5
--- /dev/null
@@ -0,0 +1,216 @@
+#ifndef DALI_WATCH_APPLICATION_H
+#define DALI_WATCH_APPLICATION_H
+
+/*
+ * Copyright (c) 2019 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/object/base-handle.h>
+#include <dali/public-api/signals/callback.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+#include <dali/public-api/adaptor-framework/application.h>
+#include <dali/public-api/watch/watch-time.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+namespace Internal DALI_INTERNAL
+{
+namespace Adaptor
+{
+class WatchApplication;
+}
+}
+
+/**
+ * @brief A WatchApplication class object should be created by every watch application
+ * that wishes to use Dali.
+ *
+ * It provides a means for initialising the resources required by the Dali::Core.
+ * Like Application class, the WatchApplication class manages Tizen watch application life cycle.
+ *
+ * The WatchApplication class emits additional signals which are availalble only in the watch application
+ * (TimeTick, AmbientTick, AmbientChanged)
+ *
+ * This feature is supported in wearable applications only.
+ *
+ * WatchApplication should follow the example below:
+ *
+ * @code
+ * class ExampleController: public ConnectionTracker
+ * {
+ * public:
+ *   ExampleController( WatchApplication& application )
+ *   : mApplication( application )
+ *   {
+ *     mApplication.InitSignal().Connect( this, &ExampleController::Create );
+ *   }
+ *
+ *   void Create( Application& application )
+ *   {
+ *     // Create Dali components...
+ *   }
+ *  ...
+ * private:
+ *   WatchApplication&  mApplication;
+ * };
+ *
+ * int DALI_ADAPTOR_API main (int argc, char **argv)
+ * {
+ *   WatchApplication app = WatchApplication::New(&argc, &argv);
+ *   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
+ *
+ * When the above options are found, they are stripped from argv, and argc is updated appropriately.
+ * @SINCE_1_1.37
+ */
+
+class DALI_ADAPTOR_API WatchApplication : public Application
+{
+public:
+  typedef Signal< void (Application&, const WatchTime&) > WatchTimeSignal; ///< Watch pointer signal callback type @SINCE_1_1.37
+  typedef Signal< void (Application&, bool) > WatchBoolSignal; ///< Watch bool signal callback type @SINCE_1_1.37
+
+public:
+
+  /**
+   * @brief This is the constructor for applications without an argument list.
+   * @SINCE_1_1.37
+   * @return A handle to the WatchApplication
+   */
+  static WatchApplication New();
+
+  /**
+   * @brief This is the constructor for applications.
+   *
+   * @SINCE_1_1.37
+   * @param[in,out]  argc        A pointer to the number of arguments
+   * @param[in,out]  argv        A pointer the the argument list
+   * @return A handle to the WatchApplication
+   */
+  static WatchApplication New( int* argc, char **argv[] );
+
+  /**
+   * @brief This is the constructor for applications with a name
+   *
+   * @SINCE_1_1.37
+   * @param[in,out]  argc        A pointer to the number of arguments
+   * @param[in,out]  argv        A pointer the the argument list
+   * @param[in]      stylesheet  The path to user defined theme file
+   * @return A handle to the WatchApplication
+   */
+  static WatchApplication New( int* argc, char **argv[], const std::string& stylesheet );
+
+  /**
+   * @brief Construct an empty handle
+   * @SINCE_1_1.37
+   */
+  WatchApplication();
+
+  /**
+   * @brief Copy Constructor
+   * @SINCE_1_1.37
+   * @param[in] implementation The WatchApplication implementation
+   */
+  WatchApplication( const WatchApplication& implementation );
+
+  /**
+   * @brief Assignment operator
+   * @SINCE_1_1.37
+   * @param[in] application Handle to an object
+   * @return A reference to this
+   */
+  WatchApplication& operator=( const WatchApplication& application );
+
+  /**
+   * @brief Destructor
+   *
+   * This is non-virtual since derived Handle types must not contain data or virtual methods.
+   * @SINCE_1_1.37
+   */
+  ~WatchApplication();
+
+public:
+  /**
+   * @brief This signal is emitted at every second
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(Application& application, const WatchTime& time);
+   * @endcode
+   * time(watch time handle) will not be available after returning this callback. It will be freed by the framework.
+   * @SINCE_1_1.37
+   * @return The signal to connect to
+   */
+  WatchTimeSignal& TimeTickSignal();
+
+  /**
+   * @brief This signal is emitted at each minute in ambient mode
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(Application& application, const WatchTime& time);
+   * @endcode
+   * time(watch time handle) will not be available after returning this callback. It will be freed by the framework.
+   * @SINCE_1_1.37
+   * @remarks http://tizen.org/privilege/alarm.set privilege is needed to receive ambient ticks at each minute.
+   * The AmbientTickSignal() will be ignored if your app doesn't have the privilege
+   * @return The signal to connect to
+   */
+  WatchTimeSignal& AmbientTickSignal();
+
+  /**
+   * @brief This signal is emitted when the device enters or exits ambient mode
+   * A callback of the following type may be connected:
+   * @code
+   *   void YourCallbackName(Application& application, bool ambient);
+   * @endcode
+   * ambient_mode If true the device enters the ambient mode, otherwise false
+   * @SINCE_1_1.37
+   * @return The signal to connect to
+   */
+  WatchBoolSignal& AmbientChangedSignal();
+
+public: // Not intended for application developers
+  /// @cond internal
+  /**
+   * @brief Internal constructor
+   * @SINCE_1_1.37
+   */
+  explicit DALI_INTERNAL WatchApplication(Internal::Adaptor::WatchApplication* implementation);
+  /// @endcond
+};
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // DALI_WATCH_APPLICATION_H
diff --git a/dali/public-api/watch/watch-time.h b/dali/public-api/watch/watch-time.h
new file mode 100755 (executable)
index 0000000..f8d4a3c
--- /dev/null
@@ -0,0 +1,208 @@
+#ifndef DALI_WATCH_TIME_H
+#define DALI_WATCH_TIME_H
+
+/*
+ * Copyright (c) 2019 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 <time.h>
+#include <dali/public-api/dali-core.h>
+
+// INTERNAL INCLUDES
+#include <dali/public-api/dali-adaptor-common.h>
+
+namespace Dali
+{
+/**
+ * @addtogroup dali_adaptor_framework
+ * @{
+ */
+
+/**
+ * @brief The WatchTime class is used to get time for the WatchApplication.
+ *
+ * A WatchTime has a time handle from watch application framework.
+ * You can get time(hour, minute, second, millisecond) and date(year, month, day)
+ * on receiving timeTick signal.
+ * @SINCE_1_1.37
+ */
+class DALI_ADAPTOR_API WatchTime
+{
+public:
+
+  /**
+   * @brief Constructor.
+   * @SINCE_1_1.37
+   */
+  WatchTime();
+
+  /**
+   * @brief Destructor.
+   * @SINCE_1_1.37
+   */
+  ~WatchTime();
+
+  /**
+   * @brief Returns the current hour.
+   *
+   * @SINCE_1_1.37
+   * @return The current hour
+   * @note The return value is always positive.
+   * @pre The WatchTime needs to be initialized.
+   */
+  int GetHour() const;
+
+  /**
+   * @brief Returns the current hour24.
+   *
+   * @SINCE_1_1.37
+   * @return The current hour(the 24-hour clock)
+   * @note The return value is always positive.
+   * @pre The WatchTime needs to be initialized.
+   */
+  int GetHour24() const;
+
+  /**
+   * @brief Returns the current minute.
+   *
+   * @SINCE_1_1.37
+   * @return The current minute
+   * @note The return value is always positive.
+   * @pre The WatchTime needs to be initialized.
+   */
+  int GetMinute() const;
+
+  /**
+   * @brief Returns the current second.
+   *
+   * @SINCE_1_1.37
+   * @return The current second
+   * @note The return value is always positive.
+   * @pre The WatchTime needs to be initialized.
+   */
+  int GetSecond() const;
+
+  /**
+   * @brief Returns the current millisecond.
+   *
+   * @SINCE_1_2_32
+   * @return The current millisecond
+   * @note The return value is always positive.
+   * @pre The WatchTime needs to be initialized.
+   */
+  int GetMillisecond() const;
+
+  /**
+   * @brief Returns the current year.
+   *
+   * @SINCE_1_2_32
+   * @return The current year
+   * @note The return value is always positive.
+   * @pre The WatchTime needs to be initialized.
+   */
+  int GetYear() const;
+
+  /**
+   * @brief Returns the current month.
+   *
+   * @SINCE_1_2_32
+   * @return The current month
+   * @note The return value is always positive.
+   * @pre The WatchTime needs to be initialized.
+   */
+  int GetMonth() const;
+
+  /**
+   * @brief Returns the current day.
+   *
+   * @SINCE_1_2_32
+   * @return The current day
+   * @note The return value is always positive.
+   * @pre The WatchTime needs to be initialized.
+   */
+  int GetDay() const;
+
+  /**
+   * @brief Returns the current day of week.
+   *
+   * @details The value returns from 1 (Sunday) to 7 (Saturday).
+   *
+   * @SINCE_1_2_32
+   * @return The current day of week
+   * @note The return value is always positive.
+   * @pre The WatchTime needs to be initialized.
+   */
+  int GetDayOfWeek() const;
+
+  /**
+   * @brief Returns the UTC time. (Coordinated Universal Time)
+   *
+   * @details Regarding struct tm (the return value), please refer to the site :
+   * http://www.cplusplus.com/reference/ctime/tm/
+   *
+   * @SINCE_1_2_32
+   * @return The UTC time
+   * @pre The WatchTime needs to be initialized.
+   */
+  struct tm GetUtcTime() const;
+
+  /**
+   * @brief Returns the UTC timestamp.
+   *
+   * @SINCE_1_2_32
+   * @return The UTC timestamp
+   * @pre The WatchTime needs to be initialized.
+   */
+  time_t GetUtcTimeStamp() const;
+
+  /**
+   * @brief Returns the ID of timezone.
+   *
+   * @details The timezone ID, according to the IANA(Internet Assigned Numbers Authority)
+   * If you want to see more information, please refer to the site :
+   * https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
+   *
+   * @SINCE_1_2_32
+   * @return The ID of timezone
+   * @pre The WatchTime needs to be initialized.
+   */
+  const char* GetTimeZone() const;
+
+  /**
+   * @brief Returns the daylight saving time status.
+   *
+   * @SINCE_1_2_32
+   * @return The Daylight Saving Time status
+   * @pre The WatchTime needs to be initialized.
+   */
+  bool GetDaylightSavingTimeStatus() const;
+
+public: // Not intended for application developers
+  DALI_INTERNAL WatchTime(void *time_handle);
+
+private:  // Internal Data
+
+  struct Impl;
+  Impl* mImpl;
+};
+
+/**
+ * @}
+ */
+} // namespace Dali
+
+#endif // DALI_WATCH_TIME_H
diff --git a/doc/dali-adaptor-doc.h b/doc/dali-adaptor-doc.h
new file mode 100644 (file)
index 0000000..bdded7b
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef DALI_ADAPTOR_DOC_H
+#define DALI_ADAPTOR_DOC_H
+
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+/**
+ * @defgroup dali_adaptor DALi Adaptor
+ *
+ * @brief DALi Adaptor is a platform adaptation layer.
+ *
+ * It initializes and sets up DALi appropriately and
+ * provides many platform-related services with its internal module,
+ * platform abstraction. Several signals can be connected to it to keep you informed when
+ * certain platform-related activities occur.
+ *
+ * @section dali_adaptor_overview Overview
+ *
+ * DALi Adaptor consists of the following groups of API:
+ *
+ * <table>
+ * <tr>
+ *    <th>API Group</th>
+ *    <th>Description</th>
+ * </tr>
+ * <tr>
+ *    <td>@ref dali_adaptor_framework</td>
+ *    <td>Classes for the adaption layer.</td>
+ * </tr>
+ * </table>
+ *
+ * \ifnot show_tizen_feature
+ *
+ * @section dali_toolkit_feature Related Features
+ * This API is related with the following features:\n
+ *    - http://tizen.org/feature/opengles.version.2_0\n
+ *
+ * It is recommended to design feature related codes in your application for reliability.\n
+ *
+ * You can check if a device supports the related features for this API by using @ref CAPI_SYSTEM_SYSTEM_INFO_MODULE, thereby controlling the procedure of your application.\n
+ *
+ * To ensure your application is only running on the device with specific features, please define the features in your manifest file using the manifest editor in the SDK.\n
+ *
+ * More details on featuring your application can be found from <a href="https://docs.tizen.org/application/tizen-studio/native-tools/manifest-text-editor#feature-element"><b>Feature Element</b>.</a>
+ *
+ * \endif
+ *
+ * @ingroup dali
+ * @{
+ *   @defgroup dali_adaptor_framework Adaptor Framework
+ *   @brief Classes for the adaption layer.
+ * @}
+ */
+
+#endif  /* DALI_ADAPTOR_DOC_H */
diff --git a/doc/file.list b/doc/file.list
new file mode 100644 (file)
index 0000000..3d29204
--- /dev/null
@@ -0,0 +1,3 @@
+SET( package_doxy_files
+  ${package_doxy_dir}/dali-adaptor-doc.h
+)
diff --git a/packaging/dali-adaptor.spec b/packaging/dali-adaptor.spec
new file mode 100644 (file)
index 0000000..879b25c
--- /dev/null
@@ -0,0 +1,667 @@
+# NOTES
+# This spec file is used to build DALi Adaptor for different Tizen Profiles
+# Current profiles are:  Mobile, TV, Wearable, Common
+#
+# The profile variable is defined outside of the spec file in a build.conf file.
+# It will contain the profile and whether or not to build with X11 or Wayland
+#
+# gbs will try to download the build.conf for the platform automatically from the repo location when
+# 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
+
+Name:       dali-adaptor
+Summary:    The DALi Tizen Adaptor
+Version:    1.5.8
+Release:    1
+Group:      System/Libraries
+License:    Apache-2.0 and BSD-3-Clause and MIT
+URL:        https://review.tizen.org/git/?p=platform/core/uifw/dali-adaptor.git;a=summary
+Source0:    %{name}-%{version}.tar.gz
+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+Requires:       giflib
+Provides: libdali-adaptor-cxx11.so
+Provides: libdali-adaptor-cxx11.so.0
+Provides: libdali-adaptor-cxx11.so.0.0.0
+Provides: libdali-adaptor.so
+Provides: libdali-adaptor.so.0
+Provides: libdali-adaptor.so.0.0.0
+
+%define tizen_platform_config_supported 1
+BuildRequires:  pkgconfig(libtzplatform-config)
+
+# 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)
+BuildRequires:  pkgconfig(screen_connector_provider)
+%endif
+
+BuildRequires:  pkgconfig(gles20)
+BuildRequires:  pkgconfig(glesv2)
+BuildRequires:  pkgconfig(ttrace)
+
+BuildRequires:  dali-devel
+BuildRequires:  dali-integration-devel
+
+BuildRequires:  pkgconfig
+BuildRequires:  gawk
+BuildRequires:  cmake
+BuildRequires:  giflib-devel
+BuildRequires:  pkgconfig(fontconfig)
+BuildRequires:  libjpeg-turbo-devel
+BuildRequires:  pkgconfig(vconf)
+BuildRequires:  tts-devel
+BuildRequires:  pkgconfig(dlog)
+BuildRequires:  libdrm-devel
+BuildRequires:  pkgconfig(libexif)
+BuildRequires:  pkgconfig(libpng)
+BuildRequires:  pkgconfig(egl)
+BuildRequires:  libcurl-devel
+BuildRequires:  pkgconfig(harfbuzz)
+BuildRequires:  fribidi-devel
+
+BuildRequires:  pkgconfig(capi-system-info)
+BuildRequires:  pkgconfig(capi-system-sensor)
+
+BuildRequires:  pkgconfig(cairo)
+
+BuildRequires:  pkgconfig(wayland-egl)
+BuildRequires:  pkgconfig(wayland-client)
+BuildRequires:  wayland-devel
+BuildRequires:  wayland-extension-client-devel
+
+# dali-adaptor uses ecore mainloop
+%if 0%{?tizen_version_major} >= 5
+BuildRequires:  pkgconfig(ecore-wl2)
+BuildRequires:  pkgconfig(wayland-egl-tizen)
+%else
+BuildRequires:  pkgconfig(ecore-wayland)
+%endif
+
+# dali-adaptor needs tbm_surface in tizen 3.0 wayland
+BuildRequires:  pkgconfig(libtbm)
+
+# for dali-adaptor
+BuildRequires:  pkgconfig(appcore-ui)
+BuildRequires:  pkgconfig(appcore-widget-base)
+BuildRequires:  pkgconfig(bundle)
+BuildRequires:  pkgconfig(capi-appfw-app-common)
+BuildRequires:  pkgconfig(capi-appfw-app-control)
+BuildRequires:  pkgconfig(ecore-imf)
+
+BuildRequires:  pkgconfig(capi-system-system-settings)
+
+# for feedback plugin
+BuildRequires:  pkgconfig(mm-sound)
+BuildRequires:  pkgconfig(feedback)
+
+# 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
+Requires:       %{name}
+%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
+Requires:       %{name}
+%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
+Requires:       %{name}
+%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
+Requires:       %{name}
+%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
+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
+Requires:       %{name}
+%description profile_common
+The DALi Tizen Adaptor for common.
+%endif
+
+##############################
+# devel
+##############################
+%package devel
+Summary:    Development components for the DALi Tizen Adaptor
+Group:      Development/Building
+Requires:   %{name} = %{version}-%{release}
+Requires:   %{name}-integration-devel = %{version}-%{release}
+
+%description devel
+Development components for the DALi Tizen Adaptor - public headers and package configs
+
+##############################
+# integration-devel
+##############################
+%package integration-devel
+Summary:    Integration development package for the Adaptor
+Group:      Development/Building
+Requires:   %{name} = %{version}-%{release}
+
+%description integration-devel
+Integration development package for the Adaptor - headers for integrating with an adaptor library.
+
+##############################
+# Dali Feedback Plugin
+##############################
+%package dali-feedback-plugin
+Summary:    Plugin to play haptic and audio feedback for Dali
+Group:      System/Libraries
+Requires:   %{name} = %{version}-%{release}
+%description dali-feedback-plugin
+Feedback plugin to play haptic and audio feedback for Dali
+
+##############################
+# Preparation
+##############################
+%prep
+%setup -q
+
+#Use TZ_PATH when tizen version is 3.x or greater
+
+%define dali_data_rw_dir         %TZ_SYS_RO_SHARE/dali/
+%define dali_data_ro_dir         %TZ_SYS_RO_SHARE/dali/
+%define font_preloaded_path      %TZ_SYS_RO_SHARE/fonts/
+%define font_downloaded_path     %TZ_SYS_SHARE/fonts/
+%define font_application_path    %TZ_SYS_RO_SHARE/app_fonts/
+%define font_configuration_file  %TZ_SYS_ETC/fonts/conf.avail/99-slp.conf
+
+%define user_shader_cache_dir    %{dali_data_ro_dir}/core/shaderbin/
+%define dali_plugin_sound_files  /plugins/sounds/
+
+##############################
+# Build
+##############################
+%build
+PREFIX+="/usr"
+CXXFLAGS+=" -Wall -g -Os -fPIC -fvisibility-inlines-hidden -fdata-sections -ffunction-sections -DGL_GLEXT_PROTOTYPES"
+LDFLAGS+=" -Wl,--rpath=%{_libdir} -Wl,--as-needed -Wl,--gc-sections -lttrace -Wl,-Bsymbolic-functions "
+
+%ifarch %{arm}
+CXXFLAGS+=" -D_ARCH_ARM_ -lgcc"
+%endif
+
+CFLAGS+=" -DWAYLAND"
+CXXFLAGS+=" -DWAYLAND"
+cmake_flags=" -DENABLE_WAYLAND=ON"
+
+# Use this conditional when Tizen version is 5.x or greater
+%if 0%{?tizen_version_major} >= 5
+CXXFLAGS+=" -DOVER_TIZEN_VERSION_5"
+
+# Need Ecore-Wayland2 when Tizen version is 5.x or greater
+CFLAGS+=" -DECORE_WAYLAND2 -DEFL_BETA_API_SUPPORT"
+CXXFLAGS+=" -DECORE_WAYLAND2 -DEFL_BETA_API_SUPPORT"
+cmake_flags+=" -DENABLE_ECORE_WAYLAND2=ON"
+%endif
+
+%if 0%{?enable_debug}
+cmake_flags+=" -DCMAKE_BUILD_TYPE=Debug"
+%endif
+
+%if 0%{?enable_trace}
+cmake_flags+=" -DENABLE_TRACE=ON"
+%endif
+
+%if 0%{?enable_appfw}
+cmake_flags+=" -DUSE_APPFW"
+%endif
+
+libtoolize --force
+cd %{_builddir}/%{name}-%{version}/build/tizen
+
+DALI_DATA_RW_DIR="%{dali_data_rw_dir}" ; export DALI_DATA_RW_DIR
+DALI_DATA_RO_DIR="%{dali_data_ro_dir}"  ; export DALI_DATA_RO_DIR
+FONT_PRELOADED_PATH="%{font_preloaded_path}" ; export FONT_PRELOADED_PATH
+FONT_DOWNLOADED_PATH="%{font_downloaded_path}" ; export FONT_DOWNLOADED_PATH
+FONT_APPLICATION_PATH="%{font_application_path}"  ; export FONT_APPLICATION_PATH
+FONT_CONFIGURATION_FILE="%{font_configuration_file}" ; export FONT_CONFIGURATION_FILE
+%if 0%{?tizen_platform_config_supported}
+TIZEN_PLATFORM_CONFIG_SUPPORTED="%{tizen_platform_config_supported}" ; export TIZEN_PLATFORM_CONFIG_SUPPORTED
+%endif
+
+cmake_flags+=" -DCMAKE_INSTALL_PREFIX=$PREFIX"
+cmake_flags+=" -DCMAKE_INSTALL_LIBDIR=%{_libdir}"
+cmake_flags+=" -DCMAKE_INSTALL_INCLUDEDIR=%{_includedir}"
+cmake_flags+=" -DENABLE_TIZEN_MAJOR_VERSION=%{tizen_version_major}"
+cmake_flags+=" -DENABLE_FEEDBACK=YES"
+cmake_flags+=" -DENABLE_APPFW=YES"
+
+# Set up the build via Cmake
+#######################################################################
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if mobile || "undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
+
+mkdir mobile
+pushd mobile
+
+cmake -DENABLE_PROFILE=MOBILE $cmake_flags ..
+
+# Build.
+make %{?jobs:-j%jobs}
+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"
+
+mkdir tv
+pushd tv
+
+cmake -DENABLE_PROFILE=TV $cmake_flags ..
+
+# Build.
+make %{?jobs:-j%jobs}
+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"
+
+mkdir wearable
+pushd wearable
+
+cmake -DENABLE_PROFILE=WEARABLE $cmake_flags ..
+
+# Build.
+make %{?jobs:-j%jobs}
+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"
+
+mkdir ivi
+pushd ivi
+
+cmake -DENABLE_PROFILE=IVI $cmake_flags ..
+
+# Build.
+make %{?jobs:-j%jobs}
+popd
+
+%endif
+
+#######################################################################
+# common
+# This is for backward-compatibility. This does not deteriorate 4.0 Configurability
+# if common ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "mobile"
+
+mkdir common
+pushd common
+
+cmake -DENABLE_PROFILE=COMMON $cmake_flags ..
+
+# Build.
+make %{?jobs:-j%jobs}
+popd
+
+%endif
+
+##############################
+# Installation
+##############################
+%install
+rm -rf %{buildroot}
+
+pushd %{_builddir}/%{name}-%{version}/build/tizen
+
+# if mobile || "undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
+pushd mobile
+%make_install
+%if "%{?profile}" != "mobile"
+pushd  %{buildroot}%{_libdir}
+cp libdali-adaptor.so.*.*.* libdali-adaptor.so.mobile # If we're only building this profile, then there's no need to copy the lib
+popd
+make clean # So that we can gather symbol/size information for only one profile if we're building all profiles
+%endif
+popd
+%endif
+
+# if tv ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "common" && "%{?profile}" != "ivi" && "%{?profile}" != "mobile"
+pushd tv
+%make_install
+%if "%{?profile}" != "tv"
+pushd  %{buildroot}%{_libdir}
+cp libdali-adaptor.so.*.*.* libdali-adaptor.so.tv # If we're only building this profile, then there's no need to copy the lib
+popd
+make clean # So that we can gather symbol/size information for only one profile if we're building all profiles
+%endif
+popd
+%endif
+
+# if wearable || "undefined"
+%if "%{?profile}" != "mobile" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
+pushd wearable
+%make_install
+%if "%{?profile}" != "wearable"
+pushd  %{buildroot}%{_libdir}
+cp libdali-adaptor.so.*.*.* libdali-adaptor.so.wearable # If we're only building this profile, then there's no need to copy the lib
+popd
+make clean # So that we can gather symbol/size information for only one profile if we're building all profiles
+%endif
+popd
+%endif
+
+# if ivi ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "common" && "%{?profile}" != "mobile"
+pushd ivi
+%make_install
+%if "%{?profile}" != "ivi"
+pushd  %{buildroot}%{_libdir}
+cp libdali-adaptor.so.*.*.* libdali-adaptor.so.ivi # If we're only building this profile, then there's no need to copy the lib
+popd
+make clean # So that we can gather symbol/size information for only one profile if we're building all profiles
+%endif
+popd
+%endif
+
+# if common ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "mobile"
+pushd common
+%make_install
+# No clean so we can gather symbol/size information for the common profile
+popd
+%endif
+
+# Create links to ensure linking with cxx11 library is preserved
+pushd  %{buildroot}%{_libdir}
+ln -sf libdali-adaptor.so libdali-adaptor-cxx11.so
+ln -sf libdali-adaptor.so libdali-adaptor-cxx11.so.0
+ln -sf libdali-adaptor.so libdali-adaptor-cxx11.so.0.0.0
+popd
+
+# Create a symbolic link in integration-api to preserve legacy repo build
+pushd %{buildroot}%{_includedir}/dali/integration-api
+ln -sf adaptor-framework adaptors
+popd
+
+##############################
+# Upgrade order:
+# 1 - Pre Install new package
+# 2 - Install new package
+# 3 - Post install new package
+# 4 - Pre uninstall old package
+# 5 - Remove files not overwritten by new package
+# 6 - Post uninstall old package
+##############################
+
+##############################
+# Adaptor package Commands
+%pre
+exit 0
+
+%post
+pushd %{_libdir}
+for i in mobile tv wearable ivi; do [[ -f libdali-adaptor.so.$i ]] && ln -sf libdali-adaptor.so.$i libdali-adaptor.so.0.0.0; done
+popd
+/sbin/ldconfig
+exit 0
+
+%preun
+exit 0
+
+%postun
+/sbin/ldconfig
+exit 0
+
+##############################
+# Mobile Profile Commands
+# if mobile || "undefined"
+# No need to create a symbolic link on install required if only building this profile
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
+%post profile_mobile
+%if "%{?profile}" != "mobile"
+pushd %{_libdir}
+ln -sf libdali-adaptor.so.mobile libdali-adaptor.so.0.0.0
+popd
+%endif
+/sbin/ldconfig
+exit 0
+
+%postun profile_mobile
+/sbin/ldconfig
+exit 0
+%endif
+
+##############################
+# TV Profile Commands
+# No need to create a symbolic link on install required if only building this profile
+%if "%{?profile}" != "wearable" && "%{?profile}" != "common" && "%{?profile}" != "ivi" && "%{?profile}" != "mobile"
+%post profile_tv
+%if "%{?profile}" != "tv"
+pushd %{_libdir}
+ln -sf libdali-adaptor.so.tv libdali-adaptor.so.0.0.0
+popd
+%endif
+/sbin/ldconfig
+exit 0
+
+%postun profile_tv
+/sbin/ldconfig
+exit 0
+%endif
+
+##############################
+# Wearable Profile Commands
+# No need to create a symbolic link on install required if only building this profile
+%if "%{?profile}" != "mobile" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
+%post profile_wearable
+%if "%{?profile}" != "wearable"
+pushd %{_libdir}
+ln -sf libdali-adaptor.so.wearable libdali-adaptor.so.0.0.0
+popd
+%endif
+/sbin/ldconfig
+exit 0
+
+%postun profile_wearable
+/sbin/ldconfig
+exit 0
+%endif
+
+##############################
+# IVI Profile Commands
+# No need to create a symbolic link on install required if only building this profile
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "common" && "%{?profile}" != "mobile"
+%post profile_ivi
+%if "%{?profile}" != "ivi"
+pushd %{_libdir}
+ln -sf libdali-adaptor.so.ivi libdali-adaptor.so.0.0.0
+popd
+%endif
+/sbin/ldconfig
+exit 0
+
+%postun profile_ivi
+/sbin/ldconfig
+exit 0
+%endif
+
+##############################
+# Common Profile Commands
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "mobile"
+%post profile_common
+/sbin/ldconfig
+exit 0
+
+%postun profile_common
+/sbin/ldconfig
+exit 0
+%endif
+
+##############################
+# Files in Binary Packages
+##############################
+
+%files
+%manifest dali-adaptor.manifest
+%defattr(-,root,root,-)
+%dir %{user_shader_cache_dir}
+%{_bindir}/*
+%license LICENSE
+%defattr(-,root,root,-)
+%{_libdir}/libdali-adaptor-cxx11.so
+%{_libdir}/libdali-adaptor-cxx11.so.0
+%{_libdir}/libdali-adaptor-cxx11.so.0.0.0
+%{_libdir}/libdali-adaptor.so
+%{_libdir}/libdali-adaptor.so.0
+%{_libdir}/libdali-adaptor.so.0.0.0
+
+#################################################
+
+%files dali-feedback-plugin
+%manifest dali-adaptor.manifest
+%defattr(-,root,root,-)
+%{_libdir}/libdali-feedback-plugin-cxx11.so*
+%{dali_plugin_sound_files}/*
+
+#################################################
+
+# if common ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "mobile"
+%files profile_common
+%manifest dali-adaptor.manifest
+# default .so files are housed in the main pkg.
+%endif
+
+# if mobile || "undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
+%files profile_mobile
+%manifest dali-adaptor.manifest
+%defattr(-,root,root,-)
+%if "%{?profile}" != "mobile"
+%{_libdir}/libdali-adaptor.so.mobile
+%endif
+%endif
+
+# if tv ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "common" && "%{?profile}" != "ivi" && "%{?profile}" != "mobile"
+%files profile_tv
+%manifest dali-adaptor.manifest
+%defattr(-,root,root,-)
+%if "%{?profile}" != "tv"
+%{_libdir}/libdali-adaptor.so.tv
+%endif
+%endif
+
+# if wearable || "undefined"
+%if "%{?profile}" != "mobile" && "%{?profile}" != "tv" && "%{?profile}" != "ivi" && "%{?profile}" != "common"
+%files profile_wearable
+%manifest dali-adaptor.manifest
+%defattr(-,root,root,-)
+%if "%{?profile}" != "wearable"
+%{_libdir}/libdali-adaptor.so.wearable
+%endif
+%endif
+
+# if ivi ||"undefined"
+%if "%{?profile}" != "wearable" && "%{?profile}" != "tv" && "%{?profile}" != "common" && "%{?profile}" != "mobile"
+%files profile_ivi
+%manifest dali-adaptor.manifest
+%defattr(-,root,root,-)
+%if "%{?profile}" != "ivi"
+%{_libdir}/libdali-adaptor.so.ivi
+%endif
+%endif
+
+%files devel
+%defattr(-,root,root,-)
+%{_includedir}/dali/dali.h
+%{_includedir}/dali/public-api/*
+%{_includedir}/dali/devel-api/*
+%{_includedir}/dali/doc/*
+%{_libdir}/pkgconfig/dali-adaptor.pc
+
+%files integration-devel
+%defattr(-,root,root,-)
+%{_includedir}/dali/integration-api/adaptor-framework/*
+%{_includedir}/dali/integration-api/adaptors
+%{_libdir}/pkgconfig/dali-adaptor-integration.pc
diff --git a/plugins/dali-feedback.cpp b/plugins/dali-feedback.cpp
new file mode 100644 (file)
index 0000000..c53935f
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018 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.
+ *
+ */
+
+#define LOG_TAG "DALI_FEEDBACK"
+
+// CLASS HEADER
+#include "dali-feedback.h"
+
+// EXTERNAL INCLUDES
+#include <iostream>
+#include <fstream>
+#include <feedback.h>
+#include <mm_sound.h>
+#include <mm_sound_private.h>
+
+#include <dlog.h>
+
+#define DEBUG_PRINTF(fmt, arg...)  LOGD(" " fmt, ##arg)
+
+using std::string;
+using namespace Dali;
+
+// The plugin factories
+extern "C" DALI_ADAPTOR_API Dali::FeedbackPlugin* CreateFeedbackPlugin(void)
+{
+  return new Dali::Plugin::DaliFeedback;
+}
+
+namespace Dali
+{
+
+namespace Plugin
+{
+
+DaliFeedback::DaliFeedback()
+{
+  feedback_initialize();
+}
+
+DaliFeedback::~DaliFeedback()
+{
+  feedback_deinitialize();
+}
+
+void DaliFeedback::PlayHaptic( const std::string& filePath )
+{
+}
+
+void DaliFeedback::PlayHapticMonotone( unsigned int duration )
+{
+}
+
+void DaliFeedback::StopHaptic()
+{
+}
+
+int DaliFeedback::PlaySound( const std::string& fileName )
+{
+  int handle = -1;
+  int errorCode = mm_sound_play_keysound( fileName.c_str(), VOLUME_TYPE_SYSTEM & VOLUME_GAIN_TOUCH );
+  if( errorCode < 0 )
+  {
+    DEBUG_PRINTF( "PlaySound() %s failed with error code = %d\n", fileName.c_str(), errorCode );
+  }
+
+  return handle;
+}
+
+void DaliFeedback::StopSound( int handle )
+{
+  int errorCode = mm_sound_stop_sound( handle );
+  if( errorCode < 0 )
+  {
+    DEBUG_PRINTF( "StopSound() handle = %d failed with error code = %d\n", handle, errorCode);
+  }
+  else
+  {
+    DEBUG_PRINTF( "stop handle %d success\n", handle );
+  }
+}
+
+void DaliFeedback::PlayFeedbackPattern( int type, int pattern )
+{
+  int errorCode = feedback_play_type( static_cast<feedback_type_e>(type), static_cast<feedback_pattern_e>(pattern) );
+  if( errorCode != 0 )
+  {
+    DEBUG_PRINTF( "DaliFeedback::PlayFeedbackPattern() with type = %d, pattern = %d returned with error = %d\n", (int)type, (int)pattern, errorCode );
+  }
+}
+
+} // namespace Plugin
+
+} // namespace Dali
+
diff --git a/plugins/dali-feedback.h b/plugins/dali-feedback.h
new file mode 100644 (file)
index 0000000..93c63d2
--- /dev/null
@@ -0,0 +1,85 @@
+#ifndef FEEDBACK_PLUGIN_H
+#define FEEDBACK_PLUGIN_H
+
+/*
+ * Copyright (c) 2019 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 <dali/devel-api/adaptor-framework/feedback-plugin.h>
+
+namespace Dali
+{
+
+namespace Plugin
+{
+
+/**
+ * Plays feedback effects for Dali-Toolkit UI Controls.
+ */
+class DaliFeedback : public Dali::FeedbackPlugin
+{
+
+public: // Construction & Destruction
+
+  /**
+   * Constructor
+   */
+  DaliFeedback();
+
+  /**
+   * Destructor
+   */
+  virtual ~DaliFeedback();
+
+public: // FeedbackPlugin overrides
+
+  /**
+   * @copydoc Dali::Integration::FeedbackPlugin::PlayHaptic()
+   */
+  void PlayHaptic( const std::string& filePath );
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::PlayHapticMonotone()
+   */
+  void PlayHapticMonotone( unsigned int duration );
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::StopHaptic()
+   */
+  void StopHaptic();
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::PlaySound()
+   */
+  int PlaySound( const std::string& fileName );
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::StopSound()
+   */
+  void StopSound( int handle );
+
+  /**
+   * @copydoc Dali::FeedbackPlugin::PlayFeedbackPattern()
+   */
+  void PlayFeedbackPattern( int type, int pattern );
+};
+
+}  // namespace Plugin
+
+}  // namespace Dali
+
+#endif // FEEDBACK_PLUGIN_H
diff --git a/plugins/file.list b/plugins/file.list
new file mode 100644 (file)
index 0000000..f6b39fa
--- /dev/null
@@ -0,0 +1,7 @@
+# Add local source files here
+
+SET( feedback_plugin_src_files
+      ${plugin_src_dir}/dali-feedback.cpp
+)
+
+SET( dali_plugin_sound_files ${plugin_src_dir}/sounds/touch.wav )
\ No newline at end of file
diff --git a/plugins/sounds/file.list b/plugins/sounds/file.list
new file mode 100644 (file)
index 0000000..734874f
--- /dev/null
@@ -0,0 +1,4 @@
+# Files to install here
+
+dali_plugin_sound_files =\
+    $(plugin_sounds_dir)/*.wav
\ No newline at end of file
diff --git a/plugins/sounds/touch.wav b/plugins/sounds/touch.wav
new file mode 100644 (file)
index 0000000..ef6e6ae
Binary files /dev/null and b/plugins/sounds/touch.wav differ
diff --git a/third-party/file.list b/third-party/file.list
new file mode 100644 (file)
index 0000000..955fc9e
--- /dev/null
@@ -0,0 +1,34 @@
+
+
+SET( static_libraries_glyphy_src_files
+  ${adaptor_thirdparty_dir}/glyphy/glyphy-arcs.cc
+  ${adaptor_thirdparty_dir}/glyphy/glyphy-blob-impl.cc
+  ${adaptor_thirdparty_dir}/glyphy/glyphy-extents.cc
+  ${adaptor_thirdparty_dir}/glyphy/glyphy-outline.cc
+  ${adaptor_thirdparty_dir}/glyphy/glyphy-sdf.cc
+  ${adaptor_thirdparty_dir}/glyphy/vector-font-cache.cpp
+)
+
+
+SET( static_libraries_libunibreak_src_files
+  ${adaptor_thirdparty_dir}/libunibreak/linebreak.c
+  ${adaptor_thirdparty_dir}/libunibreak/linebreakdata.c
+  ${adaptor_thirdparty_dir}/libunibreak/linebreakdef.c
+  ${adaptor_thirdparty_dir}/libunibreak/wordbreak.c
+  ${adaptor_thirdparty_dir}/libunibreak/unibreakbase.c
+  ${adaptor_thirdparty_dir}/libunibreak/unibreakdef.c
+)
+
+SET( adaptor_resampler_src_files
+    ${adaptor_thirdparty_dir}/resampler/resampler.cpp
+)
+
+SET( adaptor_windows_platform_src_files
+    ${adaptor_thirdparty_dir}/windows-platform/dlfcn.cpp
+    ${adaptor_thirdparty_dir}/windows-platform/environment.cpp
+    ${adaptor_thirdparty_dir}/windows-platform/network.cpp
+    ${adaptor_thirdparty_dir}/windows-platform/thread.cpp
+    ${adaptor_thirdparty_dir}/windows-platform/Win32File/CustomFile.cpp
+    ${adaptor_thirdparty_dir}/windows-platform/Win32File/MemFile.cpp
+    ${adaptor_thirdparty_dir}/windows-platform/Win32File/OriginalFile.cpp
+)
\ No newline at end of file
diff --git a/third-party/glyphy/glyphy-arc-bezier.hh b/third-party/glyphy/glyphy-arc-bezier.hh
new file mode 100644 (file)
index 0000000..4716e5e
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2012,2013 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+#ifndef GLYPHY_ARC_BEZIER_HH
+#define GLYPHY_ARC_BEZIER_HH
+
+#include "glyphy-common.hh"
+#include "glyphy-geometry.hh"
+
+namespace GLyphy {
+namespace ArcBezier {
+
+using namespace Geometry;
+
+
+class MaxDeviationApproximatorExact
+{
+  public:
+  /* Returns 3 max(abs(d₀ t (1-t)² + d₁ t² (1-t)) for 0≤t≤1. */
+  static double approximate_deviation (double d0, double d1)
+  {
+    double candidates[4] = {0,1};
+    unsigned int num_candidates = 2;
+    if (d0 == d1)
+      candidates[num_candidates++] = .5;
+    else {
+      double delta = d0*d0 - d0*d1 + d1*d1;
+      double t2 = 1. / (3 * (d0 - d1));
+      double t0 = (2 * d0 - d1) * t2;
+      if (delta == 0)
+        candidates[num_candidates++] = t0;
+      else if (delta > 0) {
+        /* This code can be optimized to avoid the sqrt if the solution
+         * is not feasible (ie. lies outside (0,1)).  I have implemented
+         * that in cairo-spline.c:_cairo_spline_bound().  Can be reused
+         * here.
+         */
+        double t1 = sqrt (delta) * t2;
+        candidates[num_candidates++] = t0 - t1;
+        candidates[num_candidates++] = t0 + t1;
+      }
+    }
+
+    double e = 0;
+    for (unsigned int i = 0; i < num_candidates; i++) {
+      double t = candidates[i];
+      double ee;
+      if (t < 0. || t > 1.)
+        continue;
+      ee = fabs (3 * t * (1-t) * (d0 * (1 - t) + d1 * t));
+      e = std::max (e, ee);
+    }
+
+    return e;
+  }
+};
+
+
+
+template <class MaxDeviationApproximator>
+class ArcBezierErrorApproximatorBehdad
+{
+  public:
+  static double approximate_bezier_arc_error (const Bezier &b0, const Arc &a)
+  {
+    assert (b0.p0 == a.p0);
+    assert (b0.p3 == a.p1);
+
+    double ea;
+    Bezier b1 = a.approximate_bezier (&ea);
+
+    assert (b0.p0 == b1.p0);
+    assert (b0.p3 == b1.p3);
+
+    Vector v0 = b1.p1 - b0.p1;
+    Vector v1 = b1.p2 - b0.p2;
+
+    Vector b = (b0.p3 - b0.p0).normalized ();
+    v0 = v0.rebase (b);
+    v1 = v1.rebase (b);
+
+    Vector v (MaxDeviationApproximator::approximate_deviation (v0.dx, v1.dx),
+              MaxDeviationApproximator::approximate_deviation (v0.dy, v1.dy));
+
+    /* Edge cases: If d*d is too close too large default to a weak bound. */
+    if (a.d * a.d > 1. - 1e-4)
+      return ea + v.len ();
+
+    /* If the wedge doesn't contain control points, default to weak bound. */
+    if (!a.wedge_contains_point (b0.p1) || !a.wedge_contains_point (b0.p2))
+      return ea + v.len ();
+
+    /* If straight line, return the max ortho deviation. */
+    if (fabs (a.d) < 1e-6)
+      return ea + v.dy;
+
+    /* We made sure that fabs(a.d) < 1 */
+    double tan_half_alpha = fabs (tan2atan (a.d));
+
+    double tan_v = v.dx / v.dy;
+
+    double eb;
+    if (fabs (tan_v) <= tan_half_alpha)
+      return ea + v.len ();
+
+    double c2 = (a.p1 - a.p0).len () * .5;
+    double r = a.radius ();
+
+    eb = Vector (c2 + v.dx, c2 / tan_half_alpha + v.dy).len () - r;
+    assert (eb >= 0);
+
+    return ea + eb;
+  }
+};
+
+
+
+template <class ArcBezierErrorApproximator>
+class ArcBezierApproximatorMidpointSimple
+{
+  public:
+  static const Arc approximate_bezier_with_arc (const Bezier &b, double *error)
+  {
+    Arc a (b.p0, b.p3, b.midpoint (), false);
+
+    *error = ArcBezierErrorApproximator::approximate_bezier_arc_error (b, a);
+
+    return a;
+  }
+};
+
+template <class ArcBezierErrorApproximator>
+class ArcBezierApproximatorMidpointTwoPart
+{
+  public:
+  static const Arc approximate_bezier_with_arc (const Bezier &b, double *error, double mid_t = .5)
+  {
+    Pair<Bezier > pair = b.split (mid_t);
+    Point m = pair.second.p0;
+
+    Arc a0 (b.p0, m, b.p3, true);
+    Arc a1 (m, b.p3, b.p0, true);
+
+    double e0 = ArcBezierErrorApproximator::approximate_bezier_arc_error (pair.first, a0);
+    double e1 = ArcBezierErrorApproximator::approximate_bezier_arc_error (pair.second, a1);
+    *error = std::max (e0, e1);
+
+    return Arc (b.p0, b.p3, m, false);
+  }
+};
+
+template <class ArcBezierErrorApproximator>
+class ArcBezierApproximatorQuantized
+{
+  public:
+  ArcBezierApproximatorQuantized (double _max_d = GLYPHY_INFINITY, unsigned int _d_bits = 0) :
+    max_d (_max_d), d_bits (_d_bits) {};
+
+  protected:
+  double max_d;
+  unsigned int d_bits;
+
+  public:
+  const Arc approximate_bezier_with_arc (const Bezier &b, double *error) const
+  {
+    double mid_t = .5;
+    Arc a (b.p0, b.p3, b.point (mid_t), false);
+    Arc orig_a = a;
+
+    if (std::isfinite (max_d)) {
+      assert (max_d >= 0);
+      if (fabs (a.d) > max_d)
+        a.d = a.d < 0 ? -max_d : max_d;
+    }
+    if (d_bits && max_d != 0) {
+      assert (std::isfinite (max_d));
+      assert (fabs (a.d) <= max_d);
+      int mult = (1 << (d_bits - 1)) - 1;
+      int id = round (a.d / max_d * mult);
+      assert (-mult <= id && id <= mult);
+      a.d = id * max_d / mult;
+      assert (fabs (a.d) <= max_d);
+    }
+
+    /* Error introduced by arc quantization */
+    double ed = fabs (a.d - orig_a.d) * (a.p1 - a.p0).len () * .5;
+
+    ArcBezierApproximatorMidpointTwoPart<ArcBezierErrorApproximator>
+            ::approximate_bezier_with_arc (b, error, mid_t);
+
+    if (ed) {
+      *error += ed;
+
+      /* Try a simple one-arc approx which works with the quantized arc.
+       * May produce smaller error bound. */
+      double e = ArcBezierErrorApproximator::approximate_bezier_arc_error (b, a);
+      if (e < *error)
+        *error = e;
+    }
+
+    return a;
+  }
+};
+
+typedef MaxDeviationApproximatorExact MaxDeviationApproximatorDefault;
+typedef ArcBezierErrorApproximatorBehdad<MaxDeviationApproximatorDefault> ArcBezierErrorApproximatorDefault;
+typedef ArcBezierApproximatorMidpointTwoPart<ArcBezierErrorApproximatorDefault> ArcBezierApproximatorDefault;
+typedef ArcBezierApproximatorQuantized<ArcBezierErrorApproximatorDefault> ArcBezierApproximatorQuantizedDefault;
+
+} /* namespace ArcBezier */
+} /* namespace GLyphy */
+
+#endif /* GLYPHY_ARC_BEZIER_HH */
diff --git a/third-party/glyphy/glyphy-arcs-bezier.hh b/third-party/glyphy/glyphy-arcs-bezier.hh
new file mode 100644 (file)
index 0000000..28ebc6b
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+#ifndef GLYPHY_ARCS_BEZIER_HH
+#define GLYPHY_ARCS_BEZIER_HH
+
+#include "glyphy-common.hh"
+#include "glyphy-geometry.hh"
+#include "glyphy-arc-bezier.hh"
+
+namespace GLyphy {
+namespace ArcsBezier {
+
+using namespace Geometry;
+using namespace ArcBezier;
+
+template <class ArcBezierApproximator>
+class ArcsBezierApproximatorSpringSystem
+{
+  static inline void calc_arcs (const Bezier &b,
+                                const std::vector<double> &t,
+                                const ArcBezierApproximator &appx,
+                                std::vector<double> &e,
+                                std::vector<Arc > &arcs,
+                                double &max_e, double &min_e)
+  {
+    unsigned int n = t.size () - 1;
+    e.resize (n);
+    arcs.clear ();
+    max_e = 0;
+    min_e = GLYPHY_INFINITY;
+    for (unsigned int i = 0; i < n; i++)
+    {
+      Bezier segment = b.segment (t[i], t[i + 1]);
+      arcs.push_back (appx.approximate_bezier_with_arc (segment, &e[i]));
+
+      max_e = std::max (max_e, e[i]);
+      min_e = std::min (min_e, e[i]);
+    }
+  }
+
+  static inline void jiggle (const Bezier &b,
+                             const ArcBezierApproximator &appx,
+                             std::vector<double> &t,
+                             std::vector<double> &e,
+                             std::vector<Arc > &arcs,
+                             double &max_e, double &min_e,
+                             double tolerance,
+                             unsigned int &n_jiggle)
+  {
+    unsigned int n = t.size () - 1;
+    unsigned int max_jiggle = log2 (n) + 1;
+    unsigned int s;
+    for (s = 0; s < max_jiggle; s++)
+    {
+      double total = 0;
+      for (unsigned int i = 0; i < n; i++) {
+        double l = t[i + 1] - t[i];
+        double k_inv = l * pow (e[i], -.3);
+        total += k_inv;
+        e[i] = k_inv;
+      }
+      for (unsigned int i = 0; i < n; i++) {
+        double k_inv = e[i];
+        double l = k_inv / total;
+        t[i + 1] = t[i] + l;
+      }
+      t[n] = 1.0; // Do this to get real 1.0, not .9999999999999998!
+
+      calc_arcs (b, t, appx, e, arcs, max_e, min_e);
+
+      n_jiggle++;
+      if (max_e < tolerance || (2 * min_e - max_e > tolerance))
+        break;
+    }
+  }
+
+  public:
+  static void approximate_bezier_with_arcs (const Bezier &b,
+                                            double tolerance,
+                                            const ArcBezierApproximator &appx,
+                                            std::vector<Arc> &arcs,
+                                            double *perror,
+                                            unsigned int max_segments = 100)
+  {
+    std::vector<double> t;
+    std::vector<double> e;
+    double max_e, min_e;
+    unsigned int n_jiggle = 0;
+
+    /* Technically speaking we can bsearch for n. */
+    for (unsigned int n = 1; n <= max_segments; n++)
+    {
+      t.resize (n + 1);
+      for (unsigned int i = 0; i < n; i++)
+        t[i] = double (i) / n;
+      t[n] = 1.0; // Do this out of the loop to get real 1.0, not .9999999999999998!
+
+      calc_arcs (b, t, appx, e, arcs, max_e, min_e);
+
+      for (unsigned int i = 0; i < n; i++)
+        if (e[i] <= tolerance) {
+          jiggle (b, appx, t, e, arcs, max_e, min_e, tolerance, n_jiggle);
+          break;
+        }
+
+      if (max_e <= tolerance)
+        break;
+    }
+    if (perror)
+      *perror = max_e;
+  }
+};
+
+} /* namespace ArcsBezier */
+} /* namespace GLyphy */
+
+#endif /* GLYPHY_ARCS_BEZIER_HH */
diff --git a/third-party/glyphy/glyphy-arcs.cc b/third-party/glyphy/glyphy-arcs.cc
new file mode 100644 (file)
index 0000000..8e42194
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju, Wojciech Baranowski
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// Glyphy is written using C style casts
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+
+#include "glyphy-common.hh"
+#include "glyphy-geometry.hh"
+#include "glyphy-arcs-bezier.hh"
+
+using namespace GLyphy::Geometry;
+using namespace GLyphy::ArcsBezier;
+
+
+
+/*
+ * Approximate outlines with multiple arcs
+ */
+
+
+struct glyphy_arc_accumulator_t {
+  unsigned int refcount;
+
+  double tolerance;
+  unsigned int d_bits;
+  glyphy_arc_endpoint_accumulator_callback_t  callback;
+  void                                       *user_data;
+
+  glyphy_point_t start_point;
+  glyphy_point_t current_point;
+  bool           need_moveto;
+  unsigned int   num_endpoints;
+  double max_error;
+  glyphy_bool_t success;
+};
+
+
+glyphy_arc_accumulator_t *
+glyphy_arc_accumulator_create (void)
+{
+  glyphy_arc_accumulator_t *acc = (glyphy_arc_accumulator_t *) calloc (1, sizeof (glyphy_arc_accumulator_t));
+
+  /**
+   * In the original file, a pointer 'acc' returned from 'calloc' may be NULL, and it is dereferenced.
+   * To prevent Null Pointer Dereference, we add to check NULL value here.
+   */
+  if( acc )
+  {
+    acc->refcount = 1;
+
+    acc->tolerance = 5e-4;
+    acc->d_bits = 8;
+    acc->callback = NULL;
+    acc->user_data = NULL;
+
+    glyphy_arc_accumulator_reset (acc);
+  }
+
+  return acc;
+}
+
+void
+glyphy_arc_accumulator_reset (glyphy_arc_accumulator_t *acc)
+{
+  acc->start_point = acc->current_point = Point (0, 0);
+  acc->need_moveto = true;
+  acc->num_endpoints = 0;
+  acc->max_error = 0;
+  acc->success = true;
+}
+
+void
+glyphy_arc_accumulator_destroy (glyphy_arc_accumulator_t *acc)
+{
+  if (!acc || --acc->refcount)
+    return;
+
+  free (acc);
+}
+
+/* Configure acc */
+
+void
+glyphy_arc_accumulator_set_tolerance (glyphy_arc_accumulator_t *acc,
+                                      double                    tolerance)
+{
+  acc->tolerance = tolerance;
+}
+
+double
+glyphy_arc_accumulator_get_tolerance (glyphy_arc_accumulator_t *acc)
+{
+  return acc->tolerance;
+}
+
+void
+glyphy_arc_accumulator_set_callback (glyphy_arc_accumulator_t *acc,
+                                     glyphy_arc_endpoint_accumulator_callback_t callback,
+                                     void                     *user_data)
+{
+  acc->callback = callback;
+  acc->user_data = user_data;
+}
+
+void
+glyphy_arc_accumulator_get_callback (glyphy_arc_accumulator_t  *acc,
+                                     glyphy_arc_endpoint_accumulator_callback_t *callback,
+                                     void                     **user_data)
+{
+  *callback = acc->callback;
+  *user_data = acc->user_data;
+}
+
+/* Accumulation results */
+
+double
+glyphy_arc_accumulator_get_error (glyphy_arc_accumulator_t *acc)
+{
+  return acc->max_error;
+}
+
+glyphy_bool_t
+glyphy_arc_accumulator_successful (glyphy_arc_accumulator_t *acc)
+{
+  return acc->success;
+}
+
+
+/* Accumulate */
+
+static void
+emit (glyphy_arc_accumulator_t *acc, const Point &p, double d)
+{
+  glyphy_arc_endpoint_t endpoint = {p, d};
+  acc->success = acc->success && acc->callback (&endpoint, acc->user_data);
+  if (acc->success) {
+    acc->num_endpoints++;
+    acc->current_point = p;
+  }
+}
+
+static void
+accumulate (glyphy_arc_accumulator_t *acc, const Point &p, double d)
+{
+  if (Point (acc->current_point) == p)
+    return;
+  if (d == GLYPHY_INFINITY) {
+    /* Emit moveto lazily, for cleaner outlines */
+    acc->need_moveto = true;
+    acc->current_point = p;
+    return;
+  }
+  if (acc->need_moveto) {
+    emit (acc, acc->current_point, GLYPHY_INFINITY);
+    if (acc->success) {
+      acc->start_point = acc->current_point;
+      acc->need_moveto = false;
+    }
+  }
+  emit (acc, p, d);
+}
+
+static void
+move_to (glyphy_arc_accumulator_t *acc, const Point &p)
+{
+  if (!acc->num_endpoints || p != acc->current_point)
+    accumulate (acc, p, GLYPHY_INFINITY);
+}
+
+static void
+arc_to (glyphy_arc_accumulator_t *acc, const Point &p1, double d)
+{
+  accumulate (acc, p1, d);
+}
+
+static void
+bezier (glyphy_arc_accumulator_t *acc, const Bezier &b)
+{
+  double e;
+
+  std::vector<Arc> arcs;
+  typedef ArcBezierApproximatorQuantizedDefault _ArcBezierApproximator;
+  _ArcBezierApproximator appx (GLYPHY_MAX_D, acc->d_bits);
+  ArcsBezierApproximatorSpringSystem<_ArcBezierApproximator>
+    ::approximate_bezier_with_arcs (b, acc->tolerance, appx, arcs, &e);
+
+  acc->max_error = std::max (acc->max_error, e);
+
+  move_to (acc, b.p0);
+  for (unsigned int i = 0; i < arcs.size (); i++)
+    arc_to (acc, arcs[i].p1, arcs[i].d);
+}
+
+static void
+close_path (glyphy_arc_accumulator_t *acc)
+{
+  if (!acc->need_moveto && Point (acc->current_point) != Point (acc->start_point))
+    arc_to (acc, acc->start_point, 0);
+}
+
+void
+glyphy_arc_accumulator_move_to (glyphy_arc_accumulator_t *acc,
+                                const glyphy_point_t *p0)
+{
+  move_to (acc, *p0);
+}
+
+void
+glyphy_arc_accumulator_line_to (glyphy_arc_accumulator_t *acc,
+                                const glyphy_point_t *p1)
+{
+  arc_to (acc, *p1, 0);
+}
+
+void
+glyphy_arc_accumulator_conic_to (glyphy_arc_accumulator_t *acc,
+                                 const glyphy_point_t *p1,
+                                 const glyphy_point_t *p2)
+{
+  bezier (acc, Bezier (acc->current_point,
+                       Point (acc->current_point).lerp (2/3., *p1),
+                       Point (*p2).lerp (2/3., *p1),
+                       *p2));
+}
+
+void
+glyphy_arc_accumulator_cubic_to (glyphy_arc_accumulator_t *acc,
+                                 const glyphy_point_t *p1,
+                                 const glyphy_point_t *p2,
+                                 const glyphy_point_t *p3)
+{
+  bezier (acc, Bezier (acc->current_point, *p1, *p2, *p3));
+}
+
+void
+glyphy_arc_accumulator_arc_to (glyphy_arc_accumulator_t *acc,
+                               const glyphy_point_t *p1,
+                               double         d)
+{
+  arc_to (acc, *p1, d);
+}
+
+void
+glyphy_arc_accumulator_close_path (glyphy_arc_accumulator_t *acc)
+{
+  close_path (acc);
+}
+
+
+
+/*
+ * Outline extents from arc list
+ */
+
+
+void
+glyphy_arc_list_extents (const glyphy_arc_endpoint_t *endpoints,
+                         unsigned int                 num_endpoints,
+                         glyphy_extents_t            *extents)
+{
+  Point p0 (0, 0);
+  glyphy_extents_clear (extents);
+  for (unsigned int i = 0; i < num_endpoints; i++) {
+    const glyphy_arc_endpoint_t &endpoint = endpoints[i];
+    if (endpoint.d == GLYPHY_INFINITY) {
+      p0 = endpoint.p;
+      continue;
+    }
+    Arc arc (p0, endpoint.p, endpoint.d);
+    p0 = endpoint.p;
+
+    glyphy_extents_t arc_extents;
+    arc.extents (arc_extents);
+    glyphy_extents_extend (extents, &arc_extents);
+  }
+}
+
+#pragma GCC diagnostic pop
diff --git a/third-party/glyphy/glyphy-blob-impl.cc b/third-party/glyphy/glyphy-blob-impl.cc
new file mode 100644 (file)
index 0000000..a6dc849
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju, Wojciech Baranowski
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// Glyphy is written using C style casts
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+
+#include "glyphy-common.hh"
+#include "glyphy-geometry.hh"
+
+#define GRID_SIZE 24
+
+using namespace GLyphy::Geometry;
+
+
+#define UPPER_BITS(v,bits,total_bits) ((v) >> ((total_bits) - (bits)))
+#define LOWER_BITS(v,bits,total_bits) ((v) & ((1 << (bits)) - 1))
+
+#define MAX_X 4095
+#define MAX_Y 4095
+
+static inline glyphy_rgba_t
+arc_endpoint_encode (unsigned int ix, unsigned int iy, double d)
+{
+  glyphy_rgba_t v;
+
+  /* 12 bits for each of x and y, 8 bits for d */
+  assert (ix <= MAX_X);
+  assert (iy <= MAX_Y);
+  unsigned int id;
+  if (std::isinf (d))
+    id = 0;
+  else {
+    assert (fabs (d) <= GLYPHY_MAX_D);
+    id = 128 + lround (d * 127 / GLYPHY_MAX_D);
+  }
+  assert (id < 256);
+
+  v.r = id;
+  v.g = LOWER_BITS (ix, 8, 12);
+  v.b = LOWER_BITS (iy, 8, 12);
+  v.a = ((ix >> 8) << 4) | (iy >> 8);
+  return v;
+}
+
+static inline glyphy_rgba_t
+arc_list_encode (unsigned int offset, unsigned int num_points, int side)
+{
+  glyphy_rgba_t v;
+  v.r = 0; // unused for arc-list encoding
+  v.g = UPPER_BITS (offset, 8, 16);
+  v.b = LOWER_BITS (offset, 8, 16);
+  v.a = LOWER_BITS (num_points, 8, 8);
+  if (side < 0 && !num_points)
+    v.a = 255;
+  return v;
+}
+
+static inline glyphy_rgba_t
+line_encode (const Line &line)
+{
+  Line l = line.normalized ();
+  double angle = l.n.angle ();
+  double distance = l.c;
+
+  int ia = lround (-angle / M_PI * 0x7FFF);
+  unsigned int ua = ia + 0x8000;
+  assert (0 == (ua & ~0xFFFF));
+
+  int id = lround (distance * 0x1FFF);
+  unsigned int ud = id + 0x4000;
+  assert (0 == (ud & ~0x7FFF));
+
+  /* Marker for line-encoded */
+  ud |= 0x8000;
+
+  glyphy_rgba_t v;
+  v.r = ud >> 8;
+  v.g = ud & 0xFF;
+  v.b = ua >> 8;
+  v.a = ua & 0xFF;
+  return v;
+}
+
+
+/* Given a cell, fills the vector closest_arcs with arcs that may be closest to some point in the cell.
+ * Uses idea that all close arcs to cell must be ~close to center of cell.
+ */
+static void
+closest_arcs_to_cell (Point c0, Point c1, /* corners */
+                      double faraway,
+                      const glyphy_arc_endpoint_t *endpoints,
+                      unsigned int num_endpoints,
+                      std::vector<glyphy_arc_endpoint_t> &near_endpoints,
+                      int *side)
+{
+  // Find distance between cell center
+  Point c = c0.midpoint (c1);
+  double min_dist = glyphy_sdf_from_arc_list (endpoints, num_endpoints, &c, NULL);
+
+  *side = min_dist >= 0 ? +1 : -1;
+  min_dist = fabs (min_dist);
+  std::vector<Arc> near_arcs;
+
+  // If d is the distance from the center of the square to the nearest arc, then
+  // all nearest arcs to the square must be at most almost [d + half_diagonal] from the center.
+  double half_diagonal = (c - c0).len ();
+  double radius_squared = pow (min_dist + half_diagonal, 2);
+  if (min_dist - half_diagonal <= faraway) {
+    Point p0 (0, 0);
+    for (unsigned int i = 0; i < num_endpoints; i++) {
+      const glyphy_arc_endpoint_t &endpoint = endpoints[i];
+      if (endpoint.d == GLYPHY_INFINITY) {
+        p0 = endpoint.p;
+        continue;
+      }
+      Arc arc (p0, endpoint.p, endpoint.d);
+      p0 = endpoint.p;
+
+      if (arc.squared_distance_to_point (c) <= radius_squared)
+        near_arcs.push_back (arc);
+    }
+  }
+
+  Point p1 = Point (0, 0);
+  for (unsigned i = 0; i < near_arcs.size (); i++)
+  {
+    Arc arc = near_arcs[i];
+
+    if (i == 0 || p1 != arc.p0) {
+      glyphy_arc_endpoint_t endpoint = {arc.p0, GLYPHY_INFINITY};
+      near_endpoints.push_back (endpoint);
+      p1 = arc.p0;
+    }
+
+    glyphy_arc_endpoint_t endpoint = {arc.p1, arc.d};
+    near_endpoints.push_back (endpoint);
+    p1 = arc.p1;
+  }
+}
+
+
+glyphy_bool_t
+glyphy_arc_list_encode_blob (const glyphy_arc_endpoint_t *endpoints,
+                             unsigned int                 num_endpoints,
+                             glyphy_rgba_t               *blob,
+                             unsigned int                 blob_size,
+                             double                       faraway,
+                             double                       avg_fetch_desired,
+                             double                      *avg_fetch_achieved,
+                             unsigned int                *output_len,
+                             unsigned int                *nominal_width,  /* 8bit */
+                             unsigned int                *nominal_height, /* 8bit */
+                             glyphy_extents_t            *pextents)
+{
+  glyphy_extents_t extents;
+  glyphy_extents_clear (&extents);
+
+  glyphy_arc_list_extents (endpoints, num_endpoints, &extents);
+
+  if (glyphy_extents_is_empty (&extents)) {
+    *pextents = extents;
+    if (!blob_size)
+      return false;
+    *blob = arc_list_encode (0, 0, +1);
+    *avg_fetch_achieved = 1;
+    *output_len = 1;
+    *nominal_width = *nominal_height = 1;
+    return true;
+  }
+
+  /* Add antialiasing padding */
+  extents.min_x -= faraway;
+  extents.min_y -= faraway;
+  extents.max_x += faraway;
+  extents.max_y += faraway;
+
+  double glyph_width = extents.max_x - extents.min_x;
+  double glyph_height = extents.max_y - extents.min_y;
+  double unit = std::max (glyph_width, glyph_height);
+
+  unsigned int grid_w = GRID_SIZE;
+  unsigned int grid_h = GRID_SIZE;
+
+  if (glyph_width > glyph_height) {
+    while ((grid_h - 1) * unit / grid_w > glyph_height)
+      grid_h--;
+    glyph_height = grid_h * unit / grid_w;
+    extents.max_y = extents.min_y + glyph_height;
+  } else {
+    while ((grid_w - 1) * unit / grid_h > glyph_width)
+      grid_w--;
+    glyph_width = grid_w * unit / grid_h;
+    extents.max_x = extents.min_x + glyph_width;
+  }
+
+  double cell_unit = unit / std::max (grid_w, grid_h);
+
+  std::vector<glyphy_rgba_t> tex_data;
+  std::vector<glyphy_arc_endpoint_t> near_endpoints;
+
+  unsigned int header_length = grid_w * grid_h;
+  unsigned int offset = header_length;
+  tex_data.resize (header_length);
+  Point origin = Point (extents.min_x, extents.min_y);
+  unsigned int total_arcs = 0;
+
+  for (unsigned int row = 0; row < grid_h; row++)
+    for (unsigned int col = 0; col < grid_w; col++)
+    {
+      Point cp0 = origin + Vector ((col + 0) * cell_unit, (row + 0) * cell_unit);
+      Point cp1 = origin + Vector ((col + 1) * cell_unit, (row + 1) * cell_unit);
+      near_endpoints.clear ();
+
+      int side;
+      closest_arcs_to_cell (cp0, cp1,
+                            faraway,
+                            endpoints, num_endpoints,
+                            near_endpoints,
+                            &side);
+
+#define QUANTIZE_X(X) (lround (MAX_X * ((X - extents.min_x) / glyph_width )))
+#define QUANTIZE_Y(Y) (lround (MAX_Y * ((Y - extents.min_y) / glyph_height)))
+#define DEQUANTIZE_X(X) (double (X) / MAX_X * glyph_width  + extents.min_x)
+#define DEQUANTIZE_Y(Y) (double (Y) / MAX_Y * glyph_height + extents.min_y)
+#define SNAP(P) (Point (DEQUANTIZE_X (QUANTIZE_X ((P).x)), DEQUANTIZE_Y (QUANTIZE_Y ((P).y))))
+
+      if (near_endpoints.size () == 2 && near_endpoints[1].d == 0) {
+              Point c (extents.min_x + glyph_width * .5, extents.min_y + glyph_height * .5);
+              Line line (SNAP (near_endpoints[0].p), SNAP (near_endpoints[1].p));
+              line.c -= line.n * Vector (c);
+              line.c /= unit;
+              tex_data[row * grid_w + col] = line_encode (line);
+              continue;
+      }
+
+      /* If the arclist is two arcs that can be combined in encoding if reordered,
+       * do that. */
+      if (near_endpoints.size () == 4 &&
+          std::isinf (near_endpoints[2].d) &&
+          near_endpoints[0].p.x == near_endpoints[3].p.x &&
+          near_endpoints[0].p.y == near_endpoints[3].p.y)
+      {
+              glyphy_arc_endpoint_t e0, e1, e2;
+              e0 = near_endpoints[2];
+              e1 = near_endpoints[3];
+              e2 = near_endpoints[1];
+              near_endpoints.resize (0);
+              near_endpoints.push_back (e0);
+              near_endpoints.push_back (e1);
+              near_endpoints.push_back (e2);
+      }
+
+      for (unsigned i = 0; i < near_endpoints.size (); i++) {
+        glyphy_arc_endpoint_t &endpoint = near_endpoints[i];
+        tex_data.push_back (arc_endpoint_encode (QUANTIZE_X(endpoint.p.x), QUANTIZE_Y(endpoint.p.y), endpoint.d));
+      }
+
+      unsigned int current_endpoints = tex_data.size () - offset;
+
+      if (current_endpoints)
+      {
+        /* See if we can fulfill this cell by using already-encoded arcs */
+        const glyphy_rgba_t *needle = &tex_data[offset];
+        unsigned int needle_len = current_endpoints;
+        const glyphy_rgba_t *haystack = &tex_data[header_length];
+        unsigned int haystack_len = offset - header_length;
+
+        bool found = false;
+        while (haystack_len >= needle_len) {
+          /* Trick: we don't care about first endpoint's d value, so skip one
+           * byte in comparison.  This works because arc_encode() packs the
+           * d value in the first byte. */
+          if (0 == memcmp (1 + (const char *) needle,
+                           1 + (const char *) haystack,
+                           needle_len * sizeof (*needle) - 1)) {
+            found = true;
+            break;
+          }
+          haystack++;
+          haystack_len--;
+        }
+        if (found) {
+          unsigned int new_offset = haystack - &tex_data[0];
+          tex_data.resize (offset);
+          haystack = needle = NULL; /* Invalidated by the resize. */
+          offset = new_offset;
+        }
+      }
+      else
+        offset = 0;
+
+      tex_data[row * grid_w + col] = arc_list_encode (offset, current_endpoints, side);
+      offset = tex_data.size ();
+
+      total_arcs += current_endpoints;
+    }
+
+  if (avg_fetch_achieved)
+    *avg_fetch_achieved = 1 + double (total_arcs) / (grid_w * grid_h);
+
+  *pextents = extents;
+
+  if (tex_data.size () > blob_size)
+    return false;
+
+  memcpy (blob, &tex_data[0], tex_data.size () * sizeof(tex_data[0]));
+  *output_len = tex_data.size ();
+  *nominal_width = grid_w;
+  *nominal_height = grid_h;
+
+  return true;
+}
+
+#pragma GCC diagnostic pop
diff --git a/third-party/glyphy/glyphy-common.hh b/third-party/glyphy/glyphy-common.hh
new file mode 100644 (file)
index 0000000..7c11687
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+#ifndef GLYPHY_COMMON_HH
+#define GLYPHY_COMMON_HH
+
+#include "glyphy.h"
+
+#include <cmath>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <vector>
+#include <algorithm>
+
+#ifndef GLYPHY_EPSILON
+#  define GLYPHY_EPSILON  1e-5
+#endif
+#ifndef GLYPHY_INFINITY
+#  define GLYPHY_INFINITY INFINITY
+#endif
+
+
+static inline bool
+iszero (double v)
+{
+  return fabs (v) < 2 * GLYPHY_EPSILON;
+}
+
+
+#define GLYPHY_MAX_D .5
+
+#undef  ARRAY_LENGTH
+#define ARRAY_LENGTH(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
+
+#define _ASSERT_STATIC1(_line, _cond) typedef int _static_assert_on_line_##_line##_failed[(_cond)?1:-1]
+#define _ASSERT_STATIC0(_line, _cond) _ASSERT_STATIC1 (_line, (_cond))
+#define ASSERT_STATIC(_cond) _ASSERT_STATIC0 (__LINE__, (_cond))
+
+#ifdef __ANDROID__
+#define log2(x) (log(x) / log(2.0))
+#endif
+
+#endif /* GLYPHY_COMMON_HH */
diff --git a/third-party/glyphy/glyphy-extents.cc b/third-party/glyphy/glyphy-extents.cc
new file mode 100644 (file)
index 0000000..e69e176
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glyphy-common.hh"
+
+
+void
+glyphy_extents_clear (glyphy_extents_t *extents)
+{
+  extents->min_x =  GLYPHY_INFINITY;
+  extents->min_y =  GLYPHY_INFINITY;
+  extents->max_x = -GLYPHY_INFINITY;
+  extents->max_y = -GLYPHY_INFINITY;
+}
+
+glyphy_bool_t
+glyphy_extents_is_empty (const glyphy_extents_t *extents)
+{
+  return std::isinf (extents->min_x);
+}
+
+void
+glyphy_extents_add (glyphy_extents_t     *extents,
+                    const glyphy_point_t *p)
+{
+  if (glyphy_extents_is_empty (extents)) {
+    extents->min_x = extents->max_x = p->x;
+    extents->min_y = extents->max_y = p->y;
+    return;
+  }
+  extents->min_x = std::min (extents->min_x, p->x);
+  extents->min_y = std::min (extents->min_y, p->y);
+  extents->max_x = std::max (extents->max_x, p->x);
+  extents->max_y = std::max (extents->max_y, p->y);
+}
+
+void
+glyphy_extents_extend (glyphy_extents_t       *extents,
+                       const glyphy_extents_t *other)
+{
+  if (glyphy_extents_is_empty (other))
+    return;
+  if (glyphy_extents_is_empty (extents)) {
+    *extents = *other;
+    return;
+  }
+  extents->min_x = std::min (extents->min_x, other->min_x);
+  extents->min_y = std::min (extents->min_y, other->min_y);
+  extents->max_x = std::max (extents->max_x, other->max_x);
+  extents->max_y = std::max (extents->max_y, other->max_y);
+}
+
+glyphy_bool_t
+glyphy_extents_includes (const glyphy_extents_t *extents,
+                         const glyphy_point_t   *p)
+{
+  return extents->min_x <= p->x && p->x <= extents->max_x &&
+         extents->min_y <= p->y && p->y <= extents->max_y;
+}
+
+void
+glyphy_extents_scale (glyphy_extents_t *extents,
+                      double            x_scale,
+                      double            y_scale)
+{
+  extents->min_x *= x_scale;
+  extents->max_x *= x_scale;
+  extents->min_y *= y_scale;
+  extents->max_y *= y_scale;
+}
diff --git a/third-party/glyphy/glyphy-freetype.h b/third-party/glyphy/glyphy-freetype.h
new file mode 100644 (file)
index 0000000..6105e88
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+/* Intentionally doesn't have include guards */
+
+#include "glyphy.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+
+static int
+glyphy_freetype_move_to(FT_Vector *to,
+                        glyphy_arc_accumulator_t *acc)
+{
+  glyphy_point_t p1 = {static_cast<double>(to->x), static_cast<double>(to->y)};
+  glyphy_arc_accumulator_close_path (acc);
+  glyphy_arc_accumulator_move_to (acc, &p1);
+  return glyphy_arc_accumulator_successful (acc) ? FT_Err_Ok : FT_Err_Out_Of_Memory;
+}
+
+static int
+glyphy_freetype_line_to(FT_Vector *to,
+                        glyphy_arc_accumulator_t *acc)
+{
+  glyphy_point_t p1 = {static_cast<double>(to->x), static_cast<double>(to->y)};
+  glyphy_arc_accumulator_line_to (acc, &p1);
+  return glyphy_arc_accumulator_successful (acc) ? FT_Err_Ok : FT_Err_Out_Of_Memory;
+}
+
+static int
+glyphy_freetype_conic_to(FT_Vector *control, FT_Vector *to,
+                         glyphy_arc_accumulator_t *acc)
+{
+  glyphy_point_t p1 = {static_cast<double>(control->x), static_cast<double>(control->y)};
+  glyphy_point_t p2 = {static_cast<double>(to->x), static_cast<double>(to->y)};
+  glyphy_arc_accumulator_conic_to (acc, &p1, &p2);
+  return glyphy_arc_accumulator_successful (acc) ? FT_Err_Ok : FT_Err_Out_Of_Memory;
+}
+
+static int
+glyphy_freetype_cubic_to(FT_Vector *control1, FT_Vector *control2, FT_Vector *to,
+                         glyphy_arc_accumulator_t *acc)
+{
+  glyphy_point_t p1 = {static_cast<double>(control1->x), static_cast<double>(control1->y)};
+  glyphy_point_t p2 = {static_cast<double>(control2->x), static_cast<double>(control2->y)};
+  glyphy_point_t p3 = {static_cast<double>(to->x), static_cast<double>(to->y)};
+  glyphy_arc_accumulator_cubic_to (acc, &p1, &p2, &p3);
+  return glyphy_arc_accumulator_successful (acc) ? FT_Err_Ok : FT_Err_Out_Of_Memory;
+}
+
+static FT_Error
+glyphy_freetype_outline_decompose(const FT_Outline         *outline,
+                                  glyphy_arc_accumulator_t *acc)
+{
+  const FT_Outline_Funcs outline_funcs = {
+    (FT_Outline_MoveToFunc) glyphy_freetype_move_to,
+    (FT_Outline_LineToFunc) glyphy_freetype_line_to,
+    (FT_Outline_ConicToFunc) glyphy_freetype_conic_to,
+    (FT_Outline_CubicToFunc) glyphy_freetype_cubic_to,
+    0, /* shift */
+    0, /* delta */
+  };
+
+  return FT_Outline_Decompose ((FT_Outline *) outline, &outline_funcs, acc);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/third-party/glyphy/glyphy-geometry.hh b/third-party/glyphy/glyphy-geometry.hh
new file mode 100644 (file)
index 0000000..bf76761
--- /dev/null
@@ -0,0 +1,722 @@
+/*
+ * Copyright 2012,2013 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+#ifndef GLYPHY_GEOMETRY_HH
+#define GLYPHY_GEOMETRY_HH
+
+// Glyphy is written using C style casts
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+
+#include "glyphy-common.hh"
+
+namespace GLyphy {
+namespace Geometry {
+
+template <typename Type> struct Pair;
+struct Vector;
+struct SignedVector;
+struct Point;
+struct Line;
+struct Segment;
+struct Arc;
+struct Bezier;
+
+/* returns tan (2 * atan (d)) */
+inline double tan2atan (double d) { return 2 * d / (1 - d*d); }
+
+/* returns sin (2 * atan (d)) */
+inline double sin2atan (double d) { return 2 * d / (1 + d*d); }
+
+/* returns cos (2 * atan (d)) */
+inline double cos2atan (double d) { return (1 - d*d) / (1 + d*d); }
+
+template <typename Type>
+struct Pair {
+  typedef Type ElementType;
+
+  inline Pair (const Type &first_, const Type &second_) : first (first_), second (second_) {}
+
+  Type first, second;
+};
+
+struct Point : glyphy_point_t {
+  inline Point (double x_, double y_) { x = x_; y = y_; }
+  inline explicit Point (const Vector &v);
+  inline Point (const glyphy_point_t &p) { *(glyphy_point_t *)this = p; }
+
+  inline bool operator == (const Point &p) const;
+  inline bool operator != (const Point &p) const;
+  inline Point& operator+= (const Vector &v);
+  inline Point& operator-= (const Vector &v);
+  inline const Point operator+ (const Vector &v) const;
+  inline const Point operator- (const Vector &v) const;
+  inline const Vector operator- (const Point &p) const;
+  inline const Point midpoint (const Point &p) const;
+  inline const Line bisector (const Point &p) const;
+  inline double distance_to_point (const Point &p) const; /* distance to point! */
+  inline double squared_distance_to_point (const Point &p) const; /* square of distance to point! */
+
+  inline bool is_finite (void) const;
+  inline const Point lerp (const double &a, const Point &p) const;
+};
+
+struct Vector {
+  inline Vector (double dx_, double dy_) : dx (dx_), dy (dy_) {}
+  inline explicit Vector (const Point &p) : dx (p.x), dy (p.y) {}
+
+  inline bool operator == (const Vector &v) const;
+  inline bool operator != (const Vector &v) const;
+  inline const Vector operator+ (void) const;
+  inline const Vector operator- (void) const;
+  inline Vector& operator+= (const Vector &v);
+  inline Vector& operator-= (const Vector &v);
+  inline Vector& operator*= (const double &s);
+  inline Vector& operator/= (const double &s);
+  inline const Vector operator+ (const Vector &v) const;
+  inline const Vector operator- (const Vector &v) const;
+  inline const Vector operator* (const double &s) const;
+  inline const Vector operator/ (const double &s) const;
+  inline double operator* (const Vector &v) const; /* dot product */
+  inline const Point operator+ (const Point &p) const;
+
+  inline bool is_nonzero (void) const;
+  inline double len (void) const;
+  inline double len2 (void) const;
+  inline const Vector normalized (void) const;
+  inline const Vector ortho (void) const;
+  inline const Vector normal (void) const; /* ortho().normalized() */
+  inline double angle (void) const;
+
+  inline const Vector rebase (const Vector &bx, const Vector &by) const;
+  inline const Vector rebase (const Vector &bx) const;
+
+  double dx, dy;
+};
+
+struct SignedVector : Vector {
+  inline SignedVector (const Vector &v, bool negative_) : Vector (v), negative (negative_) {}
+
+  inline bool operator == (const SignedVector &v) const;
+  inline bool operator != (const SignedVector &v) const;
+  inline const SignedVector operator- (void) const;
+
+  bool negative;
+};
+
+struct Line {
+  inline Line (double a_, double b_, double c_) : n (a_, b_), c (c_) {}
+  inline Line (Vector n_, double c_) : n (n_), c (c_) {}
+  inline Line (const Point &p0, const Point &p1) :
+               n ((p1 - p0).ortho ()), c (n * Vector (p0)) {}
+
+  inline const Point operator+ (const Line &l) const; /* line intersection! */
+  inline const SignedVector operator- (const Point &p) const; /* shortest vector from point to line */
+
+
+  inline const Line normalized (void) const;
+  inline const Vector normal (void) const;
+
+  Vector n; /* line normal */
+  double c; /* n.dx*x + n.dy*y = c */
+};
+
+struct Segment {
+  inline Segment (const Point &p0_, const Point &p1_) :
+                  p0 (p0_), p1 (p1_) {}
+
+  inline const SignedVector operator- (const Point &p) const; /* shortest vector from point to ***line*** */
+  inline double distance_to_point (const Point &p) const; /* shortest distance from point to segment */
+  inline double squared_distance_to_point (const Point &p) const; /* shortest distance squared from point to segment */
+  inline bool contains_in_span (const Point &p) const; /* is p in the stripe formed by sliding this segment? */
+  inline double max_distance_to_arc (const Arc &a) const;
+
+
+  Point p0;
+  Point p1;
+};
+
+
+
+struct Arc {
+  inline Arc (const Point &p0_, const Point &p1_, const Point &pm, bool complement) :
+              p0 (p0_), p1 (p1_),
+              d (p0_ == pm || p1_ == pm ? 0 :
+                 tan (((p1_-pm).angle () - (p0_-pm).angle ()) / 2 - (complement ? 0 : M_PI_2))) {}
+  inline Arc (const Point &p0_, const Point &p1_, const double &d_) :
+              p0 (p0_), p1 (p1_), d (d_) {}
+  inline Arc (const Point &center, double radius, const double &a0, const double &a1, bool complement) :
+              p0 (center + Vector (cos(a0),sin(a0)) * radius),
+              p1 (center + Vector (cos(a1),sin(a1)) * radius),
+              d (tan ((a1 - a0) / 4 - (complement ? 0 : M_PI_2))) {}
+  inline Arc (const glyphy_arc_t &a) : p0 (a.p0), p1 (a.p1), d (a.d) {}
+  inline operator glyphy_arc_t (void) const { glyphy_arc_t a = {p0, p1, d}; return a; }
+
+  inline bool operator == (const Arc &a) const;
+  inline bool operator != (const Arc &a) const;
+  inline const SignedVector operator- (const Point &p) const; /* shortest vector from point to arc */
+
+  inline double radius (void) const;
+  inline const Point center (void) const;
+  inline const Pair<Vector> tangents (void) const;
+
+  inline Bezier approximate_bezier (double *error) const;
+
+  inline bool wedge_contains_point (const Point &p) const;
+  inline double distance_to_point (const Point &p) const;
+  inline double squared_distance_to_point (const Point &p) const;
+  inline double extended_dist (const Point &p) const;
+
+  inline void extents (glyphy_extents_t &extents) const;
+
+  Point p0, p1;
+  double d; /* Depth */
+};
+
+struct Bezier {
+  inline Bezier (const Point &p0_, const Point &p1_,
+                 const Point &p2_, const Point &p3_) :
+                 p0 (p0_), p1 (p1_), p2 (p2_), p3 (p3_) {}
+
+  inline const Point point (const double &t) const;
+  inline const Point midpoint (void) const;
+  inline const Vector tangent (const double &t) const;
+  inline const Vector d_tangent (const double &t) const;
+  inline double curvature (const double &t) const;
+  inline const Pair<Bezier> split (const double &t) const;
+  inline const Pair<Bezier> halve (void) const;
+  inline const Bezier segment (const double &t0, const double &t1) const;
+
+  Point p0, p1, p2, p3;
+};
+
+
+/* Implementations */
+
+
+/* Point */
+
+inline Point::Point (const Vector &v) {
+  x = v.dx;
+  y = v.dy;
+}
+inline bool Point::operator == (const Point &p) const {
+  return x == p.x && y == p.y;
+}
+inline bool Point::operator != (const Point &p) const {
+  return !(*this == p);
+}
+inline Point& Point::operator+= (const Vector &v) {
+  x += v.dx;
+  y += v.dy;
+  return *this;
+}
+inline Point& Point::operator-= (const Vector &v) {
+  x -= v.dx;
+  y -= v.dy;
+  return *this;
+}
+inline const Point Point::operator+ (const Vector &v) const {
+  return Point (*this) += v;
+}
+inline const Point Point::operator- (const Vector &v) const {
+  return Point (*this) -= v;
+}
+inline const Vector Point::operator- (const Point &p) const {
+  return Vector (x - p.x, y - p.y);
+}
+
+inline const Point Point::midpoint (const Point &p) const {
+  return *this + (p - *this) / 2;
+}
+inline const Line Point::bisector (const Point &p) const {
+  Vector d = p - *this;
+  return Line (d.dx * 2, d.dy * 2, d * Vector (p) + d * Vector (*this));
+}
+
+inline double Point::distance_to_point (const Point &p) const {
+  return ((*this) - p).len ();
+}
+
+inline double Point::squared_distance_to_point (const Point &p) const {
+  return ((*this) - p).len2 ();
+}
+
+inline bool Point::is_finite (void) const {
+  return std::isfinite (x) && std::isfinite (y);
+}
+inline const Point Point::lerp (const double &a, const Point &p) const {
+  /* The following two cases are special-cased to get better floating
+   * point stability.  We require that points that are the same be
+   * bit-equal. */
+  if (a == 0)   return *this;
+  if (a == 1.0) return p;
+  return Point ((1-a) * x + a * p.x, (1-a) * y + a * p.y);
+}
+
+
+/* Vector */
+
+inline bool Vector::operator == (const Vector &v) const {
+  return dx == v.dx && dy == v.dy;
+}
+inline bool Vector::operator != (const Vector &v) const {
+  return !(*this == v);
+}
+inline const Vector Vector::operator+ (void) const {
+  return *this;
+}
+inline const Vector Vector::operator- (void) const {
+  return Vector (-dx, -dy);
+}
+inline Vector& Vector::operator+= (const Vector &v) {
+  dx += v.dx;
+  dy += v.dy;
+  return *this;
+}
+inline Vector& Vector::operator-= (const Vector &v) {
+  dx -= v.dx;
+  dy -= v.dy;
+  return *this;
+}
+inline Vector& Vector::operator*= (const double &s) {
+  dx *= s;
+  dy *= s;
+  return *this;
+}
+inline Vector& Vector::operator/= (const double &s) {
+  dx /= s;
+  dy /= s;
+  return *this;
+}
+inline const Vector Vector::operator+ (const Vector &v) const {
+  return Vector (*this) += v;
+}
+inline const Vector Vector::operator- (const Vector &v) const {
+  return Vector (*this) -= v;
+}
+inline const Vector Vector::operator* (const double &s) const {
+  return Vector (*this) *= s;
+}
+inline const Vector operator* (const double &s, const Vector &v) {
+  return v * s;
+}
+inline const Vector Vector::operator/ (const double &s) const {
+  return Vector (*this) /= s;
+}
+inline double Vector::operator* (const Vector &v) const { /* dot product */
+  return dx * v.dx + dy * v.dy;
+}
+inline const Point Vector::operator+ (const Point &p) const {
+  return p + *this;
+}
+
+inline bool Vector::is_nonzero (void) const {
+  return dx || dy;
+}
+inline double Vector::len (void) const {
+  return hypot (dx, dy);
+}
+inline double Vector::len2 (void) const {
+  return dx * dx + dy * dy;
+}
+inline const Vector Vector::normalized (void) const {
+  double d = len ();
+  return d ? *this / d : *this;
+}
+inline const Vector Vector::ortho (void) const {
+  return Vector (-dy, dx);
+}
+inline const Vector Vector::normal (void) const {
+  return ortho ().normalized ();
+}
+inline double Vector::angle (void) const {
+  return atan2 (dy, dx);
+}
+
+inline const Vector Vector::rebase (const Vector &bx,
+                                    const Vector &by) const {
+  return Vector (*this * bx, *this * by);
+}
+inline const Vector Vector::rebase (const Vector &bx) const {
+  return rebase (bx, bx.ortho ());
+}
+
+
+/* SignedVector */
+
+inline bool SignedVector::operator == (const SignedVector &v) const {
+  return (const Vector &)(*this) == (const Vector &)(v) && negative == v.negative;
+}
+inline bool SignedVector::operator != (const SignedVector &v) const {
+  return !(*this == v);
+}
+inline const SignedVector SignedVector::operator- (void) const {
+  return SignedVector (-(const Vector &)(*this), !negative);
+}
+
+
+/* Line */
+
+inline const Point Line::operator+ (const Line &l) const {
+  double det = n.dx * l.n.dy - n.dy * l.n.dx;
+  if (!det)
+    return Point (GLYPHY_INFINITY, GLYPHY_INFINITY);
+  return Point ((c * l.n.dy - n.dy * l.c) / det,
+                       (n.dx * l.c - c * l.n.dx) / det);
+}
+inline const SignedVector Line::operator- (const Point &p) const {
+  double mag = -(n * Vector (p) - c) / n.len ();
+  return SignedVector (n.normalized () * mag, mag < 0); /******************************************************************************************* FIX. *************************************/
+}
+
+inline const SignedVector operator- (const Point &p, const Line &l) {
+  return -(l - p);
+}
+
+inline const Line Line::normalized (void) const {
+  double d = n.len ();
+  return d ? Line (n / d, c / d) : *this;
+}
+inline const Vector Line::normal (void) const {
+  return n;
+}
+
+/* Segment */
+inline const SignedVector Segment::operator- (const Point &p) const {
+  /* shortest vector from point to line */
+  return p - Line (p1, p0); /************************************************************************************************** Should the order (p1, p0) depend on d?? ***********************/
+}
+
+/* Segment */
+inline bool Segment::contains_in_span (const Point &p) const {
+  if (p0 == p1)
+    return false;
+
+  /* shortest vector from point to line */
+  Line temp (p0, p1);
+  double mag = -(temp.n * Vector (p) - temp.c) / temp.n.len ();
+  Vector y (temp.n.normalized () * mag);
+  Point z = y + p;
+
+  // Check if z is between p0 and p1.
+
+  if (fabs (p1.y - p0.y) > fabs (p1.x - p0.x)) {
+    return ((z.y - p0.y > 0 && p1.y - p0.y > z.y - p0.y) ||
+            (z.y - p0.y < 0 && p1.y - p0.y < z.y - p0.y));
+  }
+  else {
+    return ((0 < z.x - p0.x && z.x - p0.x < p1.x - p0.x) ||
+            (0 > z.x - p0.x && z.x - p0.x > p1.x - p0.x));
+  }
+}
+
+inline double Segment::distance_to_point (const Point &p) const {
+  if (p0 == p1)
+    return 0;
+
+  // Check if z is between p0 and p1.
+  Line temp (p0, p1);
+  if (contains_in_span (p))
+    return -(temp.n * Vector (p) - temp.c) / temp.n.len ();
+
+  double dist_p_p0 = p.distance_to_point (p0);
+  double dist_p_p1 = p.distance_to_point (p1);
+  return (dist_p_p0 < dist_p_p1 ? dist_p_p0 : dist_p_p1) * (-(temp.n * Vector (p) - temp.c) < 0 ? -1 : 1);
+}
+
+
+inline double Segment::squared_distance_to_point (const Point &p) const {
+  if (p0 == p1)
+    return 0;
+
+  // Check if z is between p0 and p1.
+  Line temp (p0, p1);
+  if (contains_in_span (p))
+    return (temp.n * Vector (p) - temp.c) * (temp.n * Vector (p) - temp.c) / (temp.n * temp.n);
+
+  double dist_p_p0 = p.squared_distance_to_point (p0);
+  double dist_p_p1 = p.squared_distance_to_point (p1);
+  return (dist_p_p0 < dist_p_p1 ? dist_p_p0 : dist_p_p1);
+}
+
+
+inline double Segment::max_distance_to_arc (const Arc &a) const {
+  double max_distance = fabs(a.distance_to_point(p0)) ;
+  return  max_distance >  fabs(a.distance_to_point(p1)) ? max_distance : fabs(a.distance_to_point(p1)) ;
+}
+
+
+
+/* Arc */
+
+inline bool Arc::operator == (const Arc &a) const {
+  return p0 == a.p0 && p1 == a.p1 && d == a.d;
+}
+inline bool Arc::operator != (const Arc &a) const {
+  return !(*this == a);
+}
+
+
+inline const SignedVector Arc::operator- (const Point &p) const {
+
+  if (fabs(d) < 1e-5) {
+    Segment arc_segment (p0, p1);
+    return arc_segment - p;
+  }
+  if (wedge_contains_point (p)){
+    Vector difference = (center () - p).normalized () * fabs (p.distance_to_point (center ()) - radius ());
+
+    return SignedVector  (difference, ((p - center ()).len () < radius ()) ^ (d < 0));
+  }
+  double d0 = p.squared_distance_to_point (p0);
+  double d1 = p.squared_distance_to_point (p1);
+
+  Arc other_arc (p0, p1, (1.0 + d) / (1.0 - d));  /********************************* NOT Robust. But works? *****************/
+  Vector normal = center () - (d0 < d1 ? p0 : p1) ;
+
+  if (normal.len() == 0)
+    return SignedVector (Vector (0, 0), true);    /************************************ Check sign of this S.D. *************/
+
+  return SignedVector (Line (normal.dx, normal.dy, normal * Vector ((d0 < d1 ? p0 : p1))) - p, !other_arc.wedge_contains_point(p));
+}
+
+inline const SignedVector operator- (const Point &p, const Arc &a) {
+  return -(a - p);
+}
+
+
+
+inline double Arc::radius (void) const
+{
+  return fabs ((p1 - p0).len () / (2 * sin2atan (d)));
+}
+
+inline const Point Arc::center (void) const
+{
+  return (p0.midpoint (p1)) + (p1 - p0).ortho () / (2 * tan2atan (d));
+}
+
+inline const Pair<Vector> Arc::tangents (void) const
+{
+  Vector dp = (p1 - p0) * .5;
+  Vector pp = dp.ortho () * -sin2atan (d);
+  dp = dp * cos2atan (d);
+  return Pair<Vector> (dp + pp, dp - pp);
+}
+
+
+
+inline Bezier Arc::approximate_bezier (double *error) const
+{
+  Vector dp = p1 - p0;
+  Vector pp = dp.ortho ();
+
+  if (error)
+    *error = dp.len () * pow (fabs (d), 5) / (54 * (1 + d*d));
+
+  dp *= ((1 - d*d) / 3);
+  pp *= (2 * d / 3);
+
+  Point p0s = p0 + dp - pp;
+  Point p1s = p1 - dp - pp;
+
+  return Bezier (p0, p0s, p1s, p1);
+}
+
+
+inline bool Arc::wedge_contains_point (const Point &p) const
+{
+  Pair<Vector> t = tangents ();
+  if (fabs (d) <= 1)
+    return (p - p0) * t.first  >= 0 && (p - p1) * t.second <= 0;
+  else
+    return (p - p0) * t.first  >= 0 || (p - p1) * t.second <= 0;
+}
+
+
+/* Distance may not always be positive, but will be to an endpoint whenever necessary. */
+inline double Arc::distance_to_point (const Point &p) const {
+  if (fabs(d) < 1e-5) {
+    Segment arc_segment (p0, p1);
+    return arc_segment.distance_to_point (p);
+  }
+
+  SignedVector difference = *this - p;
+
+  if (wedge_contains_point (p) && fabs(d) > 1e-5)
+    return fabs (p.distance_to_point (center ()) - radius ()) * (difference.negative ? -1 : 1);
+  double d1 = p.squared_distance_to_point (p0);
+  double d2 = p.squared_distance_to_point (p1);
+  return (d1 < d2 ? sqrt(d1) : sqrt(d2)) * (difference.negative ? -1 : 1);
+}
+
+/* Distance will be to an endpoint whenever necessary. */
+inline double Arc::squared_distance_to_point (const Point &p) const {
+  if (fabs(d) < 1e-5) {
+    Segment arc_segment (p0, p1);
+    return arc_segment.squared_distance_to_point (p);
+  }
+
+  //SignedVector difference = *this - p;
+
+  if (wedge_contains_point (p) && fabs(d) > 1e-5) {
+    double answer = p.distance_to_point (center ()) - radius ();
+    return answer * answer;
+  }
+  double d1 = p.squared_distance_to_point (p0);
+  double d2 = p.squared_distance_to_point (p1);
+  return (d1 < d2 ? d1 : d2);
+}
+
+inline double Arc::extended_dist (const Point &p) const {
+  Point m = p0.lerp (.5, p1);
+  Vector dp = p1 - p0;
+  Vector pp = dp.ortho ();
+  /*
+   * In the original file, there was no explicit cast to float.
+   */
+  float d2 = static_cast<float>( tan2atan (d) );
+  if ((p - m) * (p1 - m) < 0)
+    return (p - p0) * (pp + dp * d2).normalized ();
+  else
+    return (p - p1) * (pp - dp * d2).normalized ();
+}
+
+inline void Arc::extents (glyphy_extents_t &extents) const {
+  glyphy_extents_clear (&extents);
+  glyphy_extents_add (&extents, &p0);
+  glyphy_extents_add (&extents, &p1);
+  Point c = center ();
+  double r = radius ();
+  Point p[4] = {c + r * Vector (-1,  0),
+                c + r * Vector (+1,  0),
+                c + r * Vector ( 0, -1),
+                c + r * Vector ( 0, +1)};
+  for (unsigned int i = 0; i < 4; i++)
+    if (wedge_contains_point (p[i]))
+      glyphy_extents_add (&extents, &p[i]);
+}
+
+
+/* Bezier */
+
+inline const Point Bezier::point (const double &t) const {
+  Point p01 = p0.lerp (t, p1);
+  Point p12 = p1.lerp (t, p2);
+  Point p23 = p2.lerp (t, p3);
+  Point p012 = p01.lerp (t, p12);
+  Point p123 = p12.lerp (t, p23);
+  Point p0123 = p012.lerp (t, p123);
+  return p0123;
+}
+
+inline const Point Bezier::midpoint (void) const
+{
+  Point p01 = p0.midpoint (p1);
+  Point p12 = p1.midpoint (p2);
+  Point p23 = p2.midpoint (p3);
+  Point p012 = p01.midpoint (p12);
+  Point p123 = p12.midpoint (p23);
+  Point p0123 = p012.midpoint (p123);
+  return p0123;
+}
+
+inline const Vector Bezier::tangent (const double &t) const
+{
+  double t_2_0 = t * t;
+  double t_0_2 = (1 - t) * (1 - t);
+
+  double _1__4t_1_0_3t_2_0 = 1 - 4 * t + 3 * t_2_0;
+  double _2t_1_0_3t_2_0    =     2 * t - 3 * t_2_0;
+
+  return Vector (-3 * p0.x * t_0_2
+                        +3 * p1.x * _1__4t_1_0_3t_2_0
+                        +3 * p2.x * _2t_1_0_3t_2_0
+                        +3 * p3.x * t_2_0,
+                        -3 * p0.y * t_0_2
+                        +3 * p1.y * _1__4t_1_0_3t_2_0
+                        +3 * p2.y * _2t_1_0_3t_2_0
+                        +3 * p3.y * t_2_0);
+}
+
+inline const Vector Bezier::d_tangent (const double &t) const {
+  return Vector (6 * ((-p0.x + 3*p1.x - 3*p2.x + p3.x) * t + (p0.x - 2*p1.x + p2.x)),
+                        6 * ((-p0.y + 3*p1.y - 3*p2.y + p3.y) * t + (p0.y - 2*p1.y + p2.y)));
+}
+
+inline double Bezier::curvature (const double &t) const {
+  Vector dpp = tangent (t).ortho ();
+  Vector ddp = d_tangent (t);
+  /* normal vector len squared */
+  double len = dpp.len ();
+  double curvature = (dpp * ddp) / (len * len * len);
+  return curvature;
+}
+
+inline const Pair<Bezier > Bezier::split (const double &t) const {
+  Point p01 = p0.lerp (t, p1);
+  Point p12 = p1.lerp (t, p2);
+  Point p23 = p2.lerp (t, p3);
+  Point p012 = p01.lerp (t, p12);
+  Point p123 = p12.lerp (t, p23);
+  Point p0123 = p012.lerp (t, p123);
+  return Pair<Bezier> (Bezier (p0, p01, p012, p0123),
+                       Bezier (p0123, p123, p23, p3));
+}
+
+inline const Pair<Bezier > Bezier::halve (void) const
+{
+  Point p01 = p0.midpoint (p1);
+  Point p12 = p1.midpoint (p2);
+  Point p23 = p2.midpoint (p3);
+  Point p012 = p01.midpoint (p12);
+  Point p123 = p12.midpoint (p23);
+  Point p0123 = p012.midpoint (p123);
+  return Pair<Bezier> (Bezier (p0, p01, p012, p0123),
+                       Bezier (p0123, p123, p23, p3));
+}
+
+inline const Bezier Bezier::segment (const double &t0, const double &t1) const
+{
+  Point p01 = p0.lerp (t0, p1);
+  Point p12 = p1.lerp (t0, p2);
+  Point p23 = p2.lerp (t0, p3);
+  Point p012 = p01.lerp (t0, p12);
+  Point p123 = p12.lerp (t0, p23);
+  Point p0123 = p012.lerp (t0, p123);
+
+  Point q01 = p0.lerp (t1, p1);
+  Point q12 = p1.lerp (t1, p2);
+  Point q23 = p2.lerp (t1, p3);
+  Point q012 = q01.lerp (t1, q12);
+  Point q123 = q12.lerp (t1, q23);
+  Point q0123 = q012.lerp (t1, q123);
+
+  return Bezier (p0123,
+                 p0123 + (p123 - p0123) * ((t1 - t0) / (1 - t0)),
+                 q0123 + (q012 - q0123) * ((t1 - t0) / t1),
+                 q0123);
+}
+
+} /* namespace Geometry */
+} /* namespace GLyphy */
+
+#pragma GCC diagnostic pop
+
+#endif /* GLYPHY_GEOMETRY_HH */
diff --git a/third-party/glyphy/glyphy-outline.cc b/third-party/glyphy/glyphy-outline.cc
new file mode 100644 (file)
index 0000000..3ff6875
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+// Glyphy is written using C style casts
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+
+#include "glyphy-common.hh"
+#include "glyphy-geometry.hh"
+
+using namespace GLyphy::Geometry;
+
+
+void
+glyphy_outline_reverse (glyphy_arc_endpoint_t *endpoints,
+                        unsigned int           num_endpoints)
+{
+  if (!num_endpoints)
+    return;
+
+  // Shift the d's first
+  double d0 = endpoints[0].d;
+  for (unsigned int i = 0; i < num_endpoints - 1; i++)
+    endpoints[i].d = endpoints[i + 1].d == GLYPHY_INFINITY ? GLYPHY_INFINITY : -endpoints[i + 1].d;
+  endpoints[num_endpoints - 1].d = d0;
+
+  // Reverse
+  for (unsigned int i = 0, j = num_endpoints - 1; i < j; i++, j--) {
+    glyphy_arc_endpoint_t t = endpoints[i];
+    endpoints[i] = endpoints[j];
+    endpoints[j] = t;
+  }
+}
+
+
+static bool
+winding (const glyphy_arc_endpoint_t *endpoints,
+         unsigned int                 num_endpoints)
+{
+  /*
+   * Algorithm:
+   *
+   * - Find the lowest-x part of the contour,
+   * - If the point is an endpoint:
+   *   o compare the angle of the incoming and outgoing edges of that point
+   *     to find out whether it's CW or CCW,
+   * - Otherwise, compare the y of the two endpoints of the arc with lowest-x point.
+   *
+   * Note:
+   *
+   * We can use a simpler algorithm here: Act as if arcs are lines, then use the
+   * triangle method to calculate the signed area of the contour and get the sign.
+   * It should work for all cases we care about.  The only case failing would be
+   * that of two endpoints and two arcs.  But we can even special-case that.
+   */
+
+  unsigned int corner = 1;
+  for (unsigned int i = 2; i < num_endpoints; i++)
+    if (endpoints[i].p.x < endpoints[corner].p.x ||
+        (endpoints[i].p.x == endpoints[corner].p.x &&
+         endpoints[i].p.y < endpoints[corner].p.y))
+      corner = i;
+
+  double min_x = endpoints[corner].p.x;
+  int winner = -1;
+  Point p0 (0, 0);
+  for (unsigned int i = 0; i < num_endpoints; i++) {
+    const glyphy_arc_endpoint_t &endpoint = endpoints[i];
+    if (endpoint.d == GLYPHY_INFINITY || endpoint.d == 0 /* arcs only, not lines */) {
+      p0 = endpoint.p;
+      continue;
+    }
+    Arc arc (p0, endpoint.p, endpoint.d);
+    p0 = endpoint.p;
+
+    Point c = arc.center ();
+    double r = arc.radius ();
+    if (c.x - r < min_x && arc.wedge_contains_point (c - Vector (r, 0))) {
+      min_x = c.x - r;
+      winner = i;
+    }
+  }
+
+  if (winner == -1)
+  {
+    // Corner is lowest-x.  Find the tangents of the two arcs connected to the
+    // corner and compare the tangent angles to get contour direction.
+    const glyphy_arc_endpoint_t ethis = endpoints[corner];
+    const glyphy_arc_endpoint_t eprev = endpoints[corner - 1];
+    const glyphy_arc_endpoint_t enext = endpoints[corner < num_endpoints - 1 ? corner + 1 : 1];
+    double in  = (-Arc (eprev.p, ethis.p, ethis.d).tangents ().second).angle ();
+    double out = (+Arc (ethis.p, enext.p, enext.d).tangents ().first ).angle ();
+    return out > in;
+  }
+  else
+  {
+    // Easy.
+    return endpoints[winner].d < 0;
+  }
+
+  return false;
+}
+
+
+static int
+categorize (double v, double ref)
+{
+  return v < ref - GLYPHY_EPSILON ? -1 : v > ref + GLYPHY_EPSILON ? +1 : 0;
+}
+
+static bool
+is_zero (double v)
+{
+  return fabs (v) < GLYPHY_EPSILON;
+}
+
+static bool
+even_odd (const glyphy_arc_endpoint_t *c_endpoints,
+          unsigned int                 num_c_endpoints,
+          const glyphy_arc_endpoint_t *endpoints,
+          unsigned int                 num_endpoints)
+{
+  /*
+   * Algorithm:
+   *
+   * - For a point on the contour, draw a halfline in a direction
+   *   (eg. decreasing x) to infinity,
+   * - Count how many times it crosses all other contours,
+   * - Pay special attention to points falling exactly on the halfline,
+   *   specifically, they count as +.5 or -.5, depending the direction
+   *   of crossing.
+   *
+   * All this counting is extremely tricky:
+   *
+   * - Floating point equality cannot be relied on here,
+   * - Lots of arc analysis needed,
+   * - Without having a point that we know falls /inside/ the contour,
+   *   there are legitimate cases that we simply cannot handle using
+   *   this algorithm.  For example, imagine the following glyph shape:
+   *
+   *         +---------+
+   *         | +-----+ |
+   *         |  \   /  |
+   *         |   \ /   |
+   *         +----o----+
+   *
+   *   If the glyph is defined as two outlines, and when analysing the
+   *   inner outline we happen to pick the point denoted by 'o' for
+   *   analysis, there simply is no way to differentiate this case from
+   *   the following case:
+   *
+   *         +---------+
+   *         |         |
+   *         |         |
+   *         |         |
+   *         +----o----+
+   *             / \
+   *            /   \
+   *           +-----+
+   *
+   *   However, in one, the triangle should be filled in, and in the other
+   *   filled out.
+   *
+   *   One way to work around this may be to do the analysis for all endpoints
+   *   on the outline and take majority.  But even that can fail in more
+   *   extreme yet legitimate cases, such as this one:
+   *
+   *           +--+--+
+   *           | / \ |
+   *           |/   \|
+   *           +     +
+   *           |\   /|
+   *           | \ / |
+   *           +--o--+
+   *
+   *   The only correct algorithm I can think of requires a point that falls
+   *   fully inside the outline.  While we can try finding such a point (not
+   *   dissimilar to the winding algorithm), it's beyond what I'm willing to
+   *   implement right now.
+   */
+
+  const Point p = c_endpoints[0].p;
+
+  double count = 0;
+  Point p0 (0, 0);
+  for (unsigned int i = 0; i < num_endpoints; i++) {
+    const glyphy_arc_endpoint_t &endpoint = endpoints[i];
+    if (endpoint.d == GLYPHY_INFINITY) {
+      p0 = endpoint.p;
+      continue;
+    }
+    Arc arc (p0, endpoint.p, endpoint.d);
+    p0 = endpoint.p;
+
+    /*
+     * Skip our own contour
+     */
+    if (&endpoint >= c_endpoints && &endpoint < c_endpoints + num_c_endpoints)
+      continue;
+
+    /* End-point y's compared to the ref point; lt, eq, or gt */
+    unsigned s0 = categorize (arc.p0.y, p.y);
+    unsigned s1 = categorize (arc.p1.y, p.y);
+
+    if (is_zero (arc.d))
+    {
+      /* Line */
+
+      if (!s0 || !s1)
+      {
+        /*
+         * Add +.5 / -.5 for each endpoint on the halfline, depending on
+         * crossing direction.
+         */
+        Pair<Vector> t = arc.tangents ();
+        if (!s0 && arc.p0.x < p.x + GLYPHY_EPSILON)
+          count += .5 * categorize (t.first.dy, 0);
+        if (!s1 && arc.p1.x < p.x + GLYPHY_EPSILON)
+          count += .5 * categorize (t.second.dy, 0);
+        continue;
+      }
+
+      if (s0 == s1)
+        continue; // Segment fully above or below the halfline
+
+      // Find x pos that the line segment would intersect the half-line.
+      double x = arc.p0.x + (arc.p1.x - arc.p0.x) * ((p.y - arc.p0.y) / (arc.p1.y - arc.p0.y));
+
+      if (x >= p.x - GLYPHY_EPSILON)
+        continue; // Does not intersect halfline
+
+      count++; // Add one for full crossing
+      continue;
+    }
+    else
+    {
+      /* Arc */
+
+      if (!s0 || !s1)
+      {
+        /*
+         * Add +.5 / -.5 for each endpoint on the halfline, depending on
+         * crossing direction.
+         */
+        Pair<Vector> t = arc.tangents ();
+
+        /* Arc-specific logic:
+         * If the tangent has dy==0, use the other endpoint's
+         * y value to decide which way the arc will be heading.
+         */
+        if (is_zero (t.first.dy))
+          t.first.dy  = +categorize (arc.p1.y, p.y);
+        if (is_zero (t.second.dy))
+          t.second.dy = -categorize (arc.p0.y, p.y);
+
+        if (!s0 && arc.p0.x < p.x + GLYPHY_EPSILON)
+          count += .5 * categorize (t.first.dy, 0);
+        if (!s1 && arc.p1.x < p.x + GLYPHY_EPSILON)
+          count += .5 * categorize (t.second.dy, 0);
+      }
+
+      Point c = arc.center ();
+      double r = arc.radius ();
+      if (c.x - r >= p.x)
+        continue; // No chance
+      /* Solve for arc crossing line with y = p.y */
+      double dy = p.y - c.y;
+      double x2 = r * r - dy * dy;
+      if (x2 <= GLYPHY_EPSILON)
+        continue; // Negative delta, no crossing
+      double dx = sqrt (x2);
+      /* There's two candidate points on the arc with the same y as the
+       * ref point. */
+      Point pp[2] = { Point (c.x - dx, p.y),
+                      Point (c.x + dx, p.y) };
+
+#define POINTS_EQ(a,b) (is_zero (a.x - b.x) && is_zero (a.y - b.y))
+      for (unsigned int i = 0; i < ARRAY_LENGTH (pp); i++)
+      {
+        /* Make sure we don't double-count endpoints that fall on the
+         * halfline as we already accounted for those above */
+        if (!POINTS_EQ (pp[i], arc.p0) && !POINTS_EQ (pp[i], arc.p1) &&
+            pp[i].x < p.x - GLYPHY_EPSILON && arc.wedge_contains_point (pp[i]))
+          count++; // Add one for full crossing
+      }
+#undef POINTS_EQ
+    }
+  }
+
+  return !(int (floor (count)) & 1);
+}
+
+static bool
+process_contour (glyphy_arc_endpoint_t       *endpoints,
+                 unsigned int                 num_endpoints,
+                 const glyphy_arc_endpoint_t *all_endpoints,
+                 unsigned int                 num_all_endpoints,
+                 bool                         inverse)
+{
+  /*
+   * Algorithm:
+   *
+   * - Find the winding direction and even-odd number,
+   * - If the two disagree, reverse the contour, inplace.
+   */
+
+  if (!num_endpoints)
+    return false;
+
+  if (num_endpoints < 3) {
+    abort (); // Don't expect this
+    return false; // Need at least two arcs
+  }
+  if (Point (endpoints[0].p) != Point (endpoints[num_endpoints-1].p)) {
+    abort (); // Don't expect this
+    return false; // Need a closed contour
+   }
+
+  if (inverse ^
+      winding (endpoints, num_endpoints) ^
+      even_odd (endpoints, num_endpoints, all_endpoints, num_all_endpoints))
+  {
+    glyphy_outline_reverse (endpoints, num_endpoints);
+    return true;
+  }
+
+  return false;
+}
+
+/* Returns true if outline was modified */
+glyphy_bool_t
+glyphy_outline_winding_from_even_odd (glyphy_arc_endpoint_t *endpoints,
+                                      unsigned int           num_endpoints,
+                                      glyphy_bool_t          inverse)
+{
+  /*
+   * Algorithm:
+   *
+   * - Process one contour at a time.
+   */
+
+  unsigned int start = 0;
+  bool ret = false;
+  for (unsigned int i = 1; i < num_endpoints; i++) {
+    const glyphy_arc_endpoint_t &endpoint = endpoints[i];
+    if (endpoint.d == GLYPHY_INFINITY) {
+      ret = ret | process_contour (endpoints + start, i - start, endpoints, num_endpoints, bool (inverse));
+      start = i;
+    }
+  }
+  ret = ret | process_contour (endpoints + start, num_endpoints - start, endpoints, num_endpoints, bool (inverse));
+  return ret;
+}
+
+#pragma GCC diagnostic pop
diff --git a/third-party/glyphy/glyphy-sdf.cc b/third-party/glyphy/glyphy-sdf.cc
new file mode 100644 (file)
index 0000000..e0aa1af
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju, Wojciech Baranowski
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "glyphy-common.hh"
+#include "glyphy-geometry.hh"
+
+using namespace GLyphy::Geometry;
+
+double
+glyphy_sdf_from_arc_list (const glyphy_arc_endpoint_t *endpoints,
+                          unsigned int                 num_endpoints,
+                          const glyphy_point_t        *p,
+                          glyphy_point_t              *closest_p /* may be NULL; TBD not implemented yet */)
+{
+  Point c = *p;
+  Point p0 (0, 0);
+  Arc closest_arc (p0, p0, 0);
+  double min_dist = GLYPHY_INFINITY;
+  int side = 0;
+  for (unsigned int i = 0; i < num_endpoints; i++) {
+    const glyphy_arc_endpoint_t &endpoint = endpoints[i];
+    if (endpoint.d == GLYPHY_INFINITY) {
+      p0 = endpoint.p;
+      continue;
+    }
+    Arc arc (p0, endpoint.p, endpoint.d);
+    p0 = endpoint.p;
+
+    if (arc.wedge_contains_point (c)) {
+      double sdist = arc.distance_to_point (c); /* TODO This distance has the wrong sign.  Fix */
+      double udist = fabs (sdist) * (1 - GLYPHY_EPSILON);
+      if (udist <= min_dist) {
+        min_dist = udist;
+        side = sdist >= 0 ? -1 : +1;
+      }
+    } else {
+      double udist = std::min ((arc.p0 - c).len (), (arc.p1 - c).len ());
+      if (udist < min_dist) {
+        min_dist = udist;
+        side = 0; /* unsure */
+        closest_arc = arc;
+      } else if (side == 0 && udist == min_dist) {
+        /* If this new distance is the same as the current minimum,
+         * compare extended distances.  Take the sign from the arc
+         * with larger extended distance. */
+        double old_ext_dist = closest_arc.extended_dist (c);
+        double new_ext_dist = arc.extended_dist (c);
+
+        double ext_dist = fabs (new_ext_dist) <= fabs (old_ext_dist) ?
+                          old_ext_dist : new_ext_dist;
+
+        /* For emboldening and stuff: */
+        // min_dist = fabs (ext_dist);
+        side = ext_dist >= 0 ? +1 : -1;
+      }
+    }
+  }
+
+  if (side == 0) {
+    // Technically speaking this should not happen, but it does.  So try to fix it.
+    double ext_dist = closest_arc.extended_dist (c);
+    side = ext_dist >= 0 ? +1 : -1;
+  }
+
+  return side * min_dist;
+}
diff --git a/third-party/glyphy/glyphy.h b/third-party/glyphy/glyphy.h
new file mode 100644 (file)
index 0000000..087587b
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2012 Google, Inc. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Google Author(s): Behdad Esfahbod, Maysum Panju
+ */
+
+#ifndef GLYPHY_H
+#define GLYPHY_H
+
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef int glyphy_bool_t;
+
+typedef struct {
+  double x;
+  double y;
+} glyphy_point_t;
+
+/*
+ * Geometry extents
+ */
+
+typedef struct {
+  double min_x;
+  double min_y;
+  double max_x;
+  double max_y;
+} glyphy_extents_t;
+
+void
+glyphy_extents_clear (glyphy_extents_t *extents);
+
+glyphy_bool_t
+glyphy_extents_is_empty (const glyphy_extents_t *extents);
+
+void
+glyphy_extents_add (glyphy_extents_t     *extents,
+                    const glyphy_point_t *p);
+
+void
+glyphy_extents_extend (glyphy_extents_t       *extents,
+                       const glyphy_extents_t *other);
+
+glyphy_bool_t
+glyphy_extents_includes (const glyphy_extents_t *extents,
+                         const glyphy_point_t   *p);
+
+void
+glyphy_extents_scale (glyphy_extents_t *extents,
+                      double            x_scale,
+                      double            y_scale);
+
+/*
+ * Circular arcs
+ */
+
+typedef struct {
+  glyphy_point_t p0;
+  glyphy_point_t p1;
+  double d;
+} glyphy_arc_t;
+
+/*
+ * Approximate outlines with multiple arcs
+ */
+
+typedef struct {
+  glyphy_point_t p;
+  double d;
+} glyphy_arc_endpoint_t;
+
+typedef glyphy_bool_t (*glyphy_arc_endpoint_accumulator_callback_t) (glyphy_arc_endpoint_t *endpoint,
+                                                                     void                  *user_data);
+
+typedef struct glyphy_arc_accumulator_t glyphy_arc_accumulator_t;
+
+glyphy_arc_accumulator_t *
+glyphy_arc_accumulator_create (void);
+
+void
+glyphy_arc_accumulator_destroy (glyphy_arc_accumulator_t *acc);
+
+void
+glyphy_arc_accumulator_reset (glyphy_arc_accumulator_t *acc);
+
+/* Configure accumulator */
+
+void
+glyphy_arc_accumulator_set_tolerance (glyphy_arc_accumulator_t *acc,
+                                      double                    tolerance);
+
+double
+glyphy_arc_accumulator_get_tolerance (glyphy_arc_accumulator_t *acc);
+
+void
+glyphy_arc_accumulator_set_callback (glyphy_arc_accumulator_t *acc,
+                                     glyphy_arc_endpoint_accumulator_callback_t callback,
+                                     void                     *user_data);
+
+void
+glyphy_arc_accumulator_get_callback (glyphy_arc_accumulator_t  *acc,
+                                     glyphy_arc_endpoint_accumulator_callback_t *callback,
+                                     void                     **user_data);
+
+/* Accumulation results */
+
+double
+glyphy_arc_accumulator_get_error (glyphy_arc_accumulator_t *acc);
+
+glyphy_bool_t
+glyphy_arc_accumulator_successful (glyphy_arc_accumulator_t *acc);
+
+
+/* Accumulate */
+
+void
+glyphy_arc_accumulator_move_to (glyphy_arc_accumulator_t *acc,
+                                const glyphy_point_t *p0);
+
+void
+glyphy_arc_accumulator_line_to (glyphy_arc_accumulator_t *acc,
+                                const glyphy_point_t *p1);
+
+void
+glyphy_arc_accumulator_conic_to (glyphy_arc_accumulator_t *acc,
+                                 const glyphy_point_t *p1,
+                                 const glyphy_point_t *p2);
+
+void
+glyphy_arc_accumulator_cubic_to (glyphy_arc_accumulator_t *acc,
+                                 const glyphy_point_t *p1,
+                                 const glyphy_point_t *p2,
+                                 const glyphy_point_t *p3);
+
+void
+glyphy_arc_accumulator_arc_to (glyphy_arc_accumulator_t *acc,
+                               const glyphy_point_t *p1,
+                               double                d);
+
+void
+glyphy_arc_accumulator_close_path (glyphy_arc_accumulator_t *acc);
+
+void
+glyphy_arc_list_extents (const glyphy_arc_endpoint_t *endpoints,
+                         unsigned int                 num_endpoints,
+                         glyphy_extents_t            *extents);
+
+/*
+ * Modify outlines for proper consumption
+ */
+
+void
+glyphy_outline_reverse (glyphy_arc_endpoint_t *endpoints,
+                        unsigned int           num_endpoints);
+
+/* Returns true if outline was modified */
+glyphy_bool_t
+glyphy_outline_winding_from_even_odd (glyphy_arc_endpoint_t *endpoints,
+                                      unsigned int           num_endpoints,
+                                      glyphy_bool_t          inverse);
+
+/*
+ * Encode an arc outline into binary blob for fast SDF calculation
+ */
+
+typedef Dali::TextAbstraction::VectorBlob glyphy_rgba_t;
+
+glyphy_bool_t
+glyphy_arc_list_encode_blob (const glyphy_arc_endpoint_t *endpoints,
+                             unsigned int                 num_endpoints,
+                             glyphy_rgba_t               *blob,
+                             unsigned int                 blob_size,
+                             double                       faraway,
+                             double                       avg_fetch_desired,
+                             double                      *avg_fetch_achieved,
+                             unsigned int                *output_len,
+                             unsigned int                *nominal_width,  /* 6bit */
+                             unsigned int                *nominal_height, /* 6bit */
+                             glyphy_extents_t            *extents);
+
+/*
+ * Calculate signed-distance-field from (encoded) arc list
+ */
+
+double
+glyphy_sdf_from_arc_list (const glyphy_arc_endpoint_t *endpoints,
+                          unsigned int                 num_endpoints,
+                          const glyphy_point_t        *p,
+                          glyphy_point_t              *closest_p /* may be NULL; TBD not implemented yet */);
+
+double
+glyphy_sdf_from_blob (const glyphy_rgba_t  *blob,
+                      unsigned int          nominal_width,
+                      unsigned int          nominal_height,
+                      const glyphy_point_t *p,
+                      glyphy_point_t       *closest_p /* may be NULL; TBD not implemented yet */);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GLYPHY_H */
diff --git a/third-party/glyphy/vector-font-cache.cpp b/third-party/glyphy/vector-font-cache.cpp
new file mode 100644 (file)
index 0000000..64f364b
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2019 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 <third-party/glyphy/vector-font-cache.h>
+
+// EXTERNAL INCLUDES
+#include <vector>
+#include <math.h>
+
+// INTERNAL INCLUDES
+#include <third-party/glyphy/glyphy.h>
+#include <third-party/glyphy/glyphy-freetype.h>
+
+using namespace std;
+
+namespace
+{
+
+const unsigned int INITIAL_GLYPH_CAPACITY = 50;
+const double MIN_FONT_SIZE = 10;
+
+static glyphy_bool_t
+accumulate_endpoint( glyphy_arc_endpoint_t*         endpoint,
+                     vector<glyphy_arc_endpoint_t>* endpoints )
+{
+  endpoints->push_back( *endpoint );
+  return true;
+}
+
+} // unnamed namespace
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+typedef vector<VectorBlob> BlobArray;
+
+struct VectorGlyph
+{
+  /**
+   * @brief Create a vector-based glyph.
+   */
+  static VectorGlyph* New( FT_Face face,
+                           FontId fontId,
+                           GlyphIndex index,
+                           glyphy_arc_accumulator_t* accumulator )
+  {
+    VectorGlyph* newGlyph = new VectorGlyph();
+    newGlyph->blobData.resize( 1024 * 16 );
+
+    if( FT_Err_Ok != FT_Load_Glyph( face,
+                                    index,
+                                    FT_LOAD_NO_BITMAP |
+                                    FT_LOAD_NO_HINTING |
+                                    FT_LOAD_NO_AUTOHINT |
+                                    FT_LOAD_NO_SCALE |
+                                    FT_LOAD_LINEAR_DESIGN |
+                                    FT_LOAD_IGNORE_TRANSFORM))
+    {
+      DALI_LOG_ERROR( "FT_Load_Glyph failed\n" );
+      delete newGlyph;
+      return NULL;
+    }
+
+    const double upem = static_cast<double>( face->units_per_EM );
+    const double tolerance = upem * 1.0f/2048.0f;
+
+    glyphy_arc_accumulator_reset( accumulator);
+    glyphy_arc_accumulator_set_tolerance( accumulator, tolerance );
+
+    vector<glyphy_arc_endpoint_t> endpoints;
+    glyphy_arc_accumulator_set_callback( accumulator,
+                                         reinterpret_cast<glyphy_arc_endpoint_accumulator_callback_t>( accumulate_endpoint ),
+                                         &endpoints );
+
+    if( FT_Err_Ok != glyphy_freetype_outline_decompose( &face->glyph->outline, accumulator ) )
+    {
+      DALI_LOG_ERROR( "glyphy_freetype_outline_decompose failed\n" );
+      delete newGlyph;
+      return NULL;
+    }
+
+    DALI_ASSERT_DEBUG( glyphy_arc_accumulator_get_error(accumulator) <= tolerance && "glyphy_arc_accumulator_get_error > tolerance" );
+
+    if( endpoints.size() )
+    {
+      glyphy_outline_winding_from_even_odd( &endpoints[0], static_cast<unsigned int>( endpoints.size() ), false );
+    }
+
+    unsigned int blobLength( 0 );
+    double averageFetchAchieved( 0.0 );
+    if (!glyphy_arc_list_encode_blob( endpoints.size() ? &endpoints[0] : NULL,
+                                      static_cast<unsigned int>( endpoints.size() ),
+                                      &newGlyph->blobData[0],
+                                      static_cast<unsigned int>( newGlyph->blobData.capacity() ),
+                                      upem / ( MIN_FONT_SIZE * M_SQRT2 ),
+                                      4,
+                                      &averageFetchAchieved,
+                                      &blobLength,
+                                      &newGlyph->nominalWidth,
+                                      &newGlyph->nominalHeight,
+                                      &newGlyph->extents ) )
+    {
+      DALI_LOG_ERROR( "glyphy_arc_list_encode_blob failed\n" );
+      delete newGlyph;
+      return NULL;
+    }
+    newGlyph->blobData.resize( blobLength );
+
+    glyphy_extents_scale( &newGlyph->extents, 1.0/upem, 1.0/upem );
+
+    newGlyph->glyphInfo.fontId = fontId;
+    newGlyph->glyphInfo.index  = index;
+
+    if( glyphy_extents_is_empty( &newGlyph->extents ) )
+    {
+      newGlyph->glyphInfo.width  = 0.0f;
+      newGlyph->glyphInfo.height = 0.0f;
+
+      newGlyph->glyphInfo.xBearing = 0.0f;
+      newGlyph->glyphInfo.yBearing = 0.0f;
+    }
+    else
+    {
+      newGlyph->glyphInfo.width  = static_cast<float>( newGlyph->extents.max_x - newGlyph->extents.min_x );
+      newGlyph->glyphInfo.height = static_cast<float>( newGlyph->extents.max_y - newGlyph->extents.min_y );
+
+      newGlyph->glyphInfo.xBearing = static_cast<float>( newGlyph->extents.min_x );
+      newGlyph->glyphInfo.yBearing = newGlyph->glyphInfo.height + static_cast<float>( newGlyph->extents.min_y );
+    }
+
+    newGlyph->glyphInfo.advance = static_cast<float>( static_cast<double>( face->glyph->metrics.horiAdvance ) / upem );
+    newGlyph->glyphInfo.scaleFactor = 0.0f;
+
+    return newGlyph;
+  }
+
+  VectorGlyph()
+  : advance( 0.0 ),
+    nominalWidth( 0 ),
+    nominalHeight( 0 ),
+    glyphInfo(),
+    blobData()
+  {
+    glyphy_extents_clear( &extents );
+  }
+
+  glyphy_extents_t extents;
+  double           advance;
+  unsigned int     nominalWidth;
+  unsigned int     nominalHeight;
+  GlyphInfo        glyphInfo;
+  BlobArray        blobData;
+};
+
+typedef vector<VectorGlyph*> GlyphCache;
+
+struct VectorFont
+{
+  VectorFont( FT_Face face )
+  : mFace( face ),
+    mGlyphCache()
+  {
+    mGlyphCache.reserve( INITIAL_GLYPH_CAPACITY );
+  }
+
+  FT_Face    mFace;
+  GlyphCache mGlyphCache;
+};
+
+struct VectorFontCache::Impl
+{
+  Impl( FT_Library freeTypeLibrary )
+  : mFreeTypeLibrary( freeTypeLibrary ),
+    mIdLookup(),
+    mVectorFonts(),
+    mAccumulator( NULL )
+  {
+    mAccumulator = glyphy_arc_accumulator_create();
+  }
+
+  ~Impl()
+  {
+    glyphy_arc_accumulator_destroy( mAccumulator );
+  }
+
+private:
+
+  // Declared private and left undefined to avoid copies.
+  Impl( const Impl& );
+  // Declared private and left undefined to avoid copies.
+  Impl& operator=( const Impl& );
+
+public:
+
+  FT_Library mFreeTypeLibrary; ///< A handle to a FreeType library instance.
+
+  vector<string> mIdLookup;
+
+  vector<VectorFont*> mVectorFonts;
+
+  glyphy_arc_accumulator_t* mAccumulator;
+};
+
+VectorFontCache::VectorFontCache( FT_Library freeTypeLibrary )
+: mImpl( NULL )
+{
+  mImpl = new Impl( freeTypeLibrary );
+}
+
+VectorFontCache::~VectorFontCache()
+{
+  delete mImpl;
+}
+
+FontId VectorFontCache::GetFontId( const std::string& url )
+{
+  FontId id( 0 );
+
+  if( mImpl )
+  {
+    if( ! FindFont( url, id ) )
+    {
+      id = CreateFont( url );
+    }
+  }
+
+  return id;
+}
+
+void VectorFontCache::GetGlyphMetrics( FontId vectorFontId, GlyphInfo& glyphInfo )
+{
+  if( mImpl )
+  {
+    if( vectorFontId > 0 &&
+        vectorFontId-1 < mImpl->mVectorFonts.size() )
+    {
+      VectorFont* font = mImpl->mVectorFonts[ vectorFontId-1 ];
+      GlyphCache& cache = font->mGlyphCache;
+
+      bool foundGlyph( false );
+      unsigned int foundIndex( 0 );
+      for( unsigned int i=0; i<cache.size(); ++i )
+      {
+        VectorGlyph* glyph = cache[i];
+
+        if( glyph->glyphInfo.index == glyphInfo.index )
+        {
+          foundIndex = i;
+          foundGlyph = true;
+          break;
+        }
+      }
+
+      if( foundGlyph )
+      {
+        VectorGlyph* glyph = cache[foundIndex];
+        // Note - this clobbers the original fontId, but helps avoid duplicating identical blobs
+        // e.g. if when the same font family is requested in different point-sizes
+        glyphInfo = glyph->glyphInfo;
+      }
+      else
+      {
+        VectorGlyph* newGlyph = VectorGlyph::New( font->mFace,
+                                                  glyphInfo.fontId,
+                                                  glyphInfo.index,
+                                                  mImpl->mAccumulator );
+
+        if( newGlyph )
+        {
+          glyphInfo = newGlyph->glyphInfo;
+
+          cache.push_back( newGlyph );
+        }
+      }
+    }
+  }
+}
+
+void VectorFontCache::GetVectorBlob( FontId vectorFontId,
+                                     FontId fontId,
+                                     GlyphIndex glyphIndex,
+                                     VectorBlob*& blob,
+                                     unsigned int& blobLength,
+                                     unsigned int& nominalWidth,
+                                     unsigned int& nominalHeight )
+{
+  if( mImpl )
+  {
+    if( vectorFontId > 0 &&
+        vectorFontId-1 < mImpl->mVectorFonts.size() )
+    {
+      VectorFont* font = mImpl->mVectorFonts[ vectorFontId-1 ];
+      GlyphCache& cache = font->mGlyphCache;
+
+      bool foundGlyph( false );
+      unsigned int foundIndex( 0 );
+      for( unsigned int i=0; i<cache.size(); ++i )
+      {
+        VectorGlyph* glyph = cache[i];
+
+        if( glyph->glyphInfo.index == glyphIndex )
+        {
+          foundIndex = i;
+          foundGlyph = true;
+          break;
+        }
+      }
+
+      if( foundGlyph )
+      {
+        VectorGlyph* glyph = cache[foundIndex];
+
+        blob          = &glyph->blobData[0];
+        blobLength    = static_cast<unsigned int>( glyph->blobData.size() );
+        nominalWidth  = glyph->nominalWidth;
+        nominalHeight = glyph->nominalHeight;
+      }
+      else
+      {
+        VectorGlyph* newGlyph = VectorGlyph::New( font->mFace, fontId, glyphIndex, mImpl->mAccumulator );
+
+        if( newGlyph )
+        {
+          blob          = &newGlyph->blobData[0];
+          blobLength    = static_cast<unsigned int>( newGlyph->blobData.size() );
+          nominalWidth  = newGlyph->nominalWidth;
+          nominalHeight = newGlyph->nominalHeight;
+
+          cache.push_back( newGlyph );
+        }
+      }
+    }
+  }
+}
+
+bool VectorFontCache::FindFont( const string& url, FontId& vectorFontId ) const
+{
+  vectorFontId = 0u;
+
+  const vector<string>& idLookup = mImpl->mIdLookup;
+
+  for( unsigned int i=0; i<idLookup.size(); ++i, ++vectorFontId )
+  {
+    if( url == idLookup[i] )
+    {
+      ++vectorFontId;
+      return true;
+    }
+  }
+
+  return false;
+}
+
+FontId VectorFontCache::CreateFont( const string& url )
+{
+  FontId id( 0 );
+
+  // Create & cache new font face
+  FT_Face face;
+  int error = FT_New_Face( mImpl->mFreeTypeLibrary,
+                           url.c_str(),
+                           0,
+                           &face );
+
+  if( FT_Err_Ok == error )
+  {
+    mImpl->mIdLookup.push_back( url );
+    id = static_cast<FontId>( mImpl->mIdLookup.size() );
+
+    VectorFont* newFont = new VectorFont( face );
+    mImpl->mVectorFonts.push_back( newFont );
+
+    DALI_ASSERT_DEBUG( mImpl->mIdLookup.size() == mImpl->mVectorFonts.size() );
+  }
+
+  return id;
+}
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
diff --git a/third-party/glyphy/vector-font-cache.h b/third-party/glyphy/vector-font-cache.h
new file mode 100644 (file)
index 0000000..46e6a00
--- /dev/null
@@ -0,0 +1,125 @@
+#ifndef DALI_INTERNAL_TEXT_ABSTRACTION_VECTOR_FONT_CACHE_H
+#define DALI_INTERNAL_TEXT_ABSTRACTION_VECTOR_FONT_CACHE_H
+
+/*
+ * Copyright (c) 2019 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 <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_GLYPH_H
+#include <dali/integration-api/debug.h>
+
+// INTERNAL INCLUDES
+#include <dali/devel-api/text-abstraction/glyph-info.h>
+#include <dali/devel-api/text-abstraction/text-abstraction-definitions.h>
+
+namespace Dali
+{
+
+namespace TextAbstraction
+{
+
+namespace Internal
+{
+
+/**
+ * A cache of vector-based font data.
+ */
+class VectorFontCache
+{
+public:
+
+  /**
+   * Constructor
+   */
+  VectorFontCache( FT_Library freeTypeLibrary );
+
+  /**
+   * Destructor
+   */
+  ~VectorFontCache();
+
+  /**
+   * @brief Get the font ID for a vector-based font.
+   *
+   * @param[in] url The path to the font file.
+   * @return A valid font ID, or zero if the font does not exist.
+   */
+  FontId GetFontId( const std::string& url );
+
+  /**
+   * @brief Get the unscaled metrics for a glyph.
+   *
+   * @param[in] vectorFontId The font ID for a vector-based font.
+   * @param[in,out] array A glyph-info structure with initialized FontId & GlyphIndex value.
+   * On return the size, bearing and advance values will be set.
+   */
+  void GetGlyphMetrics( FontId vectorFontId, GlyphInfo& glyph_info );
+
+  /**
+   * @brief Get the vector representation of a glyph.
+   *
+   * @param[in] vectorFontId The font ID for a vector-based font.
+   * @param[in] fontId The equivalent font ID.
+   * @param[in] glyphIndex The index of a glyph within the specified font.
+   * @param[out] blob A blob of data; this is owned by VectorFontCache and should be copied by the caller of GetVectorBlob().
+   * @param[out] blobLength The length of the blob data, or zero if the blob creation failed.
+   * @param[out] nominalWidth The width of the blob.
+   * @param[out] nominalHeight The height of the blob.
+   */
+  void GetVectorBlob( FontId vectorFontId, FontId fontId, GlyphIndex glyphIndex, VectorBlob*& blob, unsigned int& blobLength, unsigned int& nominalWidth, unsigned int& nominalHeight );
+
+private:
+
+  /**
+   * @brief Get the font ID for a vector-based font.
+   *
+   * @param[in] url The path to the font file.
+   * @param[out] fontId A valid font ID, or zero if the font does not exist.
+   * @return True if the font was found.
+   */
+  bool FindFont( const std::string& url, FontId& fontId ) const;
+
+  /**
+   * @brief Add a new vector-based font to the cache.
+   *
+   * @param[in] url The path to the font file.
+   * @return A valid font ID, or zero if the font does not exist.
+   */
+  FontId CreateFont( const std::string& url );
+
+  // Undefined copy constructor.
+  VectorFontCache( const VectorFontCache& );
+
+  // Undefined assignment constructor.
+  VectorFontCache& operator=( const VectorFontCache& );
+
+private:
+
+  struct Impl;
+  Impl* mImpl;
+};
+
+} // namespace Internal
+
+} // namespace TextAbstraction
+
+} // namespace Dali
+
+#endif // DALI_INTERNAL_TEXT_ABSTRACTION_VECTOR_FONT_CACHE_H
diff --git a/third-party/libunibreak/AUTHORS b/third-party/libunibreak/AUTHORS
new file mode 100644 (file)
index 0000000..1b4f4b4
--- /dev/null
@@ -0,0 +1,11 @@
+Wu Yongwei.  Designed and implemented the original liblinebreak.
+Current maintainer of libunibreak.
+
+Nikolay Pultsin.  Put forward the original requirements on liblinebreak,
+performed tests, and made a lot of suggestions on the initial versions.
+
+Thomas Klausner.  Autoconfiscated and libtoolized liblinebreak.
+
+Tom Hacohen.  Added word boundaries support.
+
+Petr Filipsky.  Added incremental processing for line-breaking.
diff --git a/third-party/libunibreak/LICENCE b/third-party/libunibreak/LICENCE
new file mode 100644 (file)
index 0000000..3eda8d5
--- /dev/null
@@ -0,0 +1,20 @@
+Copyright (C) 2008-2015 Wu Yongwei <wuyongwei at gmail dot com>
+Copyright (C) 2012-2015 Tom Hacohen <tom at stosb dot com>
+Copyright (C) 2013 Petr Filipsky <philodej at gmail dot com>
+
+This software is provided 'as-is', without any express or implied
+warranty.  In no event will the author be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+1. The origin of this software must not be misrepresented; you must not
+   claim that you wrote the original software.  If you use this software
+   in a product, an acknowledgement in the product documentation would
+   be appreciated but is not required.
+2. Altered source versions must be plainly marked as such, and must not
+   be misrepresented as being the original software.
+3. This notice may not be removed or altered from any source
+   distribution.
diff --git a/third-party/libunibreak/README.md b/third-party/libunibreak/README.md
new file mode 100644 (file)
index 0000000..52cd738
--- /dev/null
@@ -0,0 +1,87 @@
+LIBUNIBREAK
+===========
+
+Overview
+--------
+
+This is the README file for libunibreak, an implementation of the line
+breaking and word breaking algorithms as described in [Unicode Standard
+Annex 14] [1] and [Unicode Standard Annex 29] [2].  Check the project's
+[home page] [3] for up-to-date information.
+
+  [1]: http://www.unicode.org/reports/tr14/tr14-30.html
+  [2]: http://www.unicode.org/reports/tr29/tr29-21.html
+  [3]: https://github.com/adah1972/libunibreak
+
+
+Licence
+-------
+
+This library is released under an open-source licence, the zlib/libpng
+licence.  Please check the file *LICENCE* for details.
+
+Apart from using the algorithm, part of the code is derived from the
+[Unicode Public Data] [4], and the [Unicode Terms of Use] [5] may apply.
+
+  [4]: http://www.unicode.org/Public/
+  [5]: http://www.unicode.org/copyright.html
+
+
+Installation
+------------
+
+There are three ways to build the library:
+
+1. On \*NIX systems supported by the autoconfiscation tools, do the
+   normal
+
+        ./configure
+        make
+        sudo make install
+
+   to build and install both the dynamic and static libraries.  In
+   addition, one may
+   - type `make doc` to generate the doxygen documentation; or
+   - type `make linebreakdata` to regenerate *linebreakdata.c* from
+     *LineBreak.txt*.
+   - type `make wordbreakdata` to regenerate *wordbreakdata.c* from
+     *WordBreakProperty.txt*.
+
+2. On systems where GCC and Binutils are supported, one can type
+
+        cd src
+        cp -p Makefile.gcc Makefile
+        make
+
+   to build the static library.  In addition, one may
+   - type `make debug` or `make release` to explicitly generate the
+     debug or release build;
+   - type `make doc` to generate the doxygen documentation; or
+   - type `make linebreakdata` to regenerate *linebreakdata.c* from
+     *LineBreak.txt*.
+   - type `make wordbreakdata` to regenerate *wordbreakdata.c* from
+     *WordBreakProperty.txt*.
+
+3. On Windows, apart from using method 1 (Cygwin/MSYS) and method 2
+   (MinGW), MSVC can also be used.  Type
+
+        cd src
+        nmake -f Makefile.msvc
+
+   to build the static library.  By default the debug release is built.
+   To build the release version
+
+        nmake -f Makefile.msvc CFG="libunibreak - Win32 Release"
+
+
+Documentation
+-------------
+
+Check the generated document *doc/html/linebreak\_8h.html* and
+*doc/html/wordbreak\_8h.html* in the downloaded file for the public
+interfaces exposed to applications.
+
+
+<!--
+vim:autoindent:expandtab:formatoptions=tcqlmn:textwidth=72:
+-->
diff --git a/third-party/libunibreak/linebreak.c b/third-party/libunibreak/linebreak.c
new file mode 100644 (file)
index 0000000..2b28f05
--- /dev/null
@@ -0,0 +1,801 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Line breaking in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2008-2015 Wu Yongwei <wuyongwei at gmail dot com>
+ * Copyright (C) 2013 Petr Filipsky <philodej at gmail dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ * The main reference is Unicode Standard Annex 14 (UAX #14):
+ *      <URL:http://www.unicode.org/reports/tr14/>
+ *
+ * When this library was designed, this annex was at Revision 19, for
+ * Unicode 5.0.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-19.html>
+ *
+ * This library has been updated according to Revision 33, for
+ * Unicode 7.0.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-33.html>
+ *
+ * The Unicode Terms of Use are available at
+ *      <URL:http://www.unicode.org/copyright.html>
+ */
+
+/**
+ * @file    linebreak.c
+ *
+ * Implementation of the line breaking algorithm as described in Unicode
+ * Standard Annex 14.
+ *
+ * @version 2.7, 2015/04/18
+ * @author  Wu Yongwei
+ * @author  Petr Filipsky
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+#include "linebreak.h"
+#include "linebreakdef.h"
+
+/**
+ * Special value used internally to indicate an undefined break result.
+ */
+#define LINEBREAK_UNDEFINED -1
+
+/**
+ * Size of the second-level index to the line breaking properties.
+ */
+#define LINEBREAK_INDEX_SIZE 40
+
+/**
+ * Enumeration of break actions.  They are used in the break action
+ * pair table below.
+ */
+enum BreakAction
+{
+    DIR_BRK,        /**< Direct break opportunity */
+    IND_BRK,        /**< Indirect break opportunity */
+    CMI_BRK,        /**< Indirect break opportunity for combining marks */
+    CMP_BRK,        /**< Prohibited break for combining marks */
+    PRH_BRK         /**< Prohibited break */
+};
+
+/**
+ * Break action pair table.  This is a direct mapping of Table 2 of
+ * Unicode Standard Annex 14, Revision 30.
+ */
+static enum BreakAction baTable[LBP_RI][LBP_RI] = {
+    {   /* OP */
+        PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK,
+        CMP_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK, PRH_BRK,
+        PRH_BRK },
+    {   /* CL */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, PRH_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* CP */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, PRH_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* QU */
+        PRH_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK },
+    {   /* GL */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK },
+    {   /* NS */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* EX */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* SY */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, IND_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* IS */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, IND_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* PR */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        DIR_BRK },
+    {   /* PO */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, IND_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* NU */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* AL */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, IND_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* HL */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, IND_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* ID */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, IND_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* IN */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* HY */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, DIR_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, IND_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* BA */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, DIR_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* BB */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK },
+    {   /* B2 */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, PRH_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* ZW */
+        DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* CM */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, IND_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* WJ */
+        IND_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK,
+        IND_BRK },
+    {   /* H2 */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, IND_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, IND_BRK, IND_BRK,
+        DIR_BRK },
+    {   /* H3 */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, IND_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, IND_BRK,
+        DIR_BRK },
+    {   /* JL */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, IND_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK,
+        DIR_BRK },
+    {   /* JV */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, IND_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, IND_BRK, IND_BRK,
+        DIR_BRK },
+    {   /* JT */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, IND_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, IND_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, IND_BRK,
+        DIR_BRK },
+    {   /* RI */
+        DIR_BRK, PRH_BRK, PRH_BRK, IND_BRK, IND_BRK, IND_BRK, PRH_BRK,
+        PRH_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        DIR_BRK, DIR_BRK, IND_BRK, IND_BRK, DIR_BRK, DIR_BRK, PRH_BRK,
+        CMI_BRK, PRH_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK, DIR_BRK,
+        IND_BRK },
+};
+
+/**
+ * Struct for the second-level index to the line breaking properties.
+ */
+struct LineBreakPropertiesIndex
+{
+    utf32_t end;                    /**< End coding point */
+    struct LineBreakProperties *lbp;/**< Pointer to line breaking properties */
+};
+
+/**
+ * Second-level index to the line breaking properties.
+ */
+static struct LineBreakPropertiesIndex lb_prop_index[LINEBREAK_INDEX_SIZE] =
+{
+    { 0xFFFFFFFF, lb_prop_default }
+};
+
+/**
+ * Initializes the second-level index to the line breaking properties.
+ * If it is not called, the performance of #get_char_lb_class_lang (and
+ * thus the main functionality) can be pretty bad, especially for big
+ * code points like those of Chinese.
+ */
+void init_linebreak(void)
+{
+    size_t i;
+    size_t iPropDefault;
+    size_t len;
+    size_t step;
+
+    len = 0;
+    while (lb_prop_default[len].prop != LBP_Undefined)
+        ++len;
+    step = len / LINEBREAK_INDEX_SIZE;
+    iPropDefault = 0;
+    for (i = 0; i < LINEBREAK_INDEX_SIZE; ++i)
+    {
+        lb_prop_index[i].lbp = lb_prop_default + iPropDefault;
+        iPropDefault += step;
+        lb_prop_index[i].end = lb_prop_default[iPropDefault].start - 1;
+    }
+    lb_prop_index[--i].end = 0xFFFFFFFF;
+}
+
+/**
+ * Gets the language-specific line breaking properties.
+ *
+ * @param lang  language of the text
+ * @return      pointer to the language-specific line breaking
+ *              properties array if found; \c NULL otherwise
+ */
+static struct LineBreakProperties *get_lb_prop_lang(const char *lang)
+{
+    struct LineBreakPropertiesLang *lbplIter;
+    if (lang != NULL)
+    {
+        for (lbplIter = lb_prop_lang_map; lbplIter->lang != NULL; ++lbplIter)
+        {
+            if (strncmp(lang, lbplIter->lang, lbplIter->namelen) == 0)
+            {
+                return lbplIter->lbp;
+            }
+        }
+    }
+    return NULL;
+}
+
+/**
+ * Gets the line breaking class of a character from a line breaking
+ * properties array.
+ *
+ * @param ch   character to check
+ * @param lbp  pointer to the line breaking properties array
+ * @return     the line breaking class if found; \c LBP_XX otherwise
+ */
+static enum LineBreakClass get_char_lb_class(
+        utf32_t ch,
+        struct LineBreakProperties *lbp)
+{
+    while (lbp->prop != LBP_Undefined && ch >= lbp->start)
+    {
+        if (ch <= lbp->end)
+            return lbp->prop;
+        ++lbp;
+    }
+    return LBP_XX;
+}
+
+/**
+ * Gets the line breaking class of a character from the default line
+ * breaking properties array.
+ *
+ * @param ch  character to check
+ * @return    the line breaking class if found; \c LBP_XX otherwise
+ */
+static enum LineBreakClass get_char_lb_class_default(
+        utf32_t ch)
+{
+    size_t i = 0;
+    while (ch > lb_prop_index[i].end)
+        ++i;
+    assert(i < LINEBREAK_INDEX_SIZE);
+    return get_char_lb_class(ch, lb_prop_index[i].lbp);
+}
+
+/**
+ * Gets the line breaking class of a character for a specific
+ * language.  This function will check the language-specific data first,
+ * and then the default data if there is no language-specific property
+ * available for the character.
+ *
+ * @param ch       character to check
+ * @param lbpLang  pointer to the language-specific line breaking
+ *                 properties array
+ * @return         the line breaking class if found; \c LBP_XX
+ *                 otherwise
+ */
+static enum LineBreakClass get_char_lb_class_lang(
+        utf32_t ch,
+        struct LineBreakProperties *lbpLang)
+{
+    enum LineBreakClass lbcResult;
+
+    /* Find the language-specific line breaking class for a character */
+    if (lbpLang)
+    {
+        lbcResult = get_char_lb_class(ch, lbpLang);
+        if (lbcResult != LBP_XX)
+            return lbcResult;
+    }
+
+    /* Find the generic language-specific line breaking class, if no
+     * language context is provided, or language-specific data are not
+     * available for the specific character in the specified language */
+    return get_char_lb_class_default(ch);
+}
+
+/**
+ * Resolves the line breaking class for certain ambiguous or complicated
+ * characters.  They are treated in a simplistic way in this
+ * implementation.
+ *
+ * @param lbc   line breaking class to resolve
+ * @param lang  language of the text
+ * @return      the resolved line breaking class
+ */
+static enum LineBreakClass resolve_lb_class(
+        enum LineBreakClass lbc,
+        const char *lang)
+{
+    switch (lbc)
+    {
+    case LBP_AI:
+        if (lang != NULL &&
+                (strncmp(lang, "zh", 2) == 0 || /* Chinese */
+                 strncmp(lang, "ja", 2) == 0 || /* Japanese */
+                 strncmp(lang, "ko", 2) == 0))  /* Korean */
+        {
+            return LBP_ID;
+        }
+        else
+        {
+            return LBP_AL;
+        }
+    case LBP_CJ:
+        /* Simplified for `normal' line breaking.  See
+         * <url:http://www.unicode.org/reports/tr14/tr14-30.html#CJ>
+         * for details. */
+        return LBP_ID;
+    case LBP_SA:
+    case LBP_SG:
+    case LBP_XX:
+        return LBP_AL;
+    default:
+        return lbc;
+    }
+}
+
+/**
+ * Treats specially for the first character in a line.
+ *
+ * @param[in,out] lbpCtx  pointer to the line breaking context
+ * @pre                   \a lbpCtx->lbcCur has a valid line break class
+ * @post                  \a lbpCtx->lbcCur has the updated line break class
+ */
+static void treat_first_char(
+        struct LineBreakContext *lbpCtx)
+{
+    switch (lbpCtx->lbcCur)
+    {
+    case LBP_LF:
+    case LBP_NL:
+        lbpCtx->lbcCur = LBP_BK;        /* Rule LB5 */
+        break;
+    case LBP_CB:
+        lbpCtx->lbcCur = LBP_BA;        /* Rule LB20 */
+        break;
+    case LBP_SP:
+        lbpCtx->lbcCur = LBP_WJ;        /* Leading space treated as WJ */
+        break;
+    case LBP_HL:
+        lbpCtx->fLb21aHebrew = 1;       /* Rule LB21a */
+    default:
+        break;
+    }
+}
+
+/**
+ * Tries telling the line break opportunity by simple rules.
+ *
+ * @param[in,out] lbpCtx  pointer to the line breaking context
+ * @pre                   \a lbpCtx->lbcCur has the current line break
+ *                        class; and \a lbpCtx->lbcNew has the line
+ *                        break class for the next character
+ * @post                  \a lbpCtx->lbcCur has the updated line break
+ *                        class
+ * @return                break result, one of #LINEBREAK_MUSTBREAK,
+ *                        #LINEBREAK_ALLOWBREAK, and #LINEBREAK_NOBREAK
+ *                        if identified; or #LINEBREAK_UNDEFINED if
+ *                        table lookup is needed
+ */
+static int get_lb_result_simple(
+        struct LineBreakContext *lbpCtx)
+{
+    if (lbpCtx->lbcCur == LBP_BK
+        || (lbpCtx->lbcCur == LBP_CR && lbpCtx->lbcNew != LBP_LF))
+    {
+        return LINEBREAK_MUSTBREAK;     /* Rules LB4 and LB5 */
+    }
+
+    switch (lbpCtx->lbcNew)
+    {
+    case LBP_SP:
+        return LINEBREAK_NOBREAK;       /* Rule LB7; no change to lbcCur */
+    case LBP_BK:
+    case LBP_LF:
+    case LBP_NL:
+        lbpCtx->lbcCur = LBP_BK;        /* Mandatory break after */
+        return LINEBREAK_NOBREAK;       /* Rule LB6 */
+    case LBP_CR:
+        lbpCtx->lbcCur = LBP_CR;
+        return LINEBREAK_NOBREAK;       /* Rule LB6 */
+    case LBP_CB:
+        lbpCtx->lbcCur = LBP_BA;
+        return LINEBREAK_ALLOWBREAK;    /* Rule LB20 */
+    default:
+        return LINEBREAK_UNDEFINED;     /* Table lookup is needed */
+    }
+}
+
+/**
+ * Tells the line break opportunity by table lookup.
+ *
+ * @param[in,out] lbpCtx  pointer to the line breaking context
+ * @pre                   \a lbpCtx->lbcCur has the current line break
+ *                        class; \a lbpCtx->lbcLast has the line break
+ *                        class for the last character; and \a
+ *                        lbcCur->lbcNew has the line break class for
+ *                        the next character
+ * @post                  \a lbpCtx->lbcCur has the updated line break
+ *                        class
+ * @return                break result, one of #LINEBREAK_MUSTBREAK,
+ *                        #LINEBREAK_ALLOWBREAK, and #LINEBREAK_NOBREAK
+ */
+static int get_lb_result_lookup(
+        struct LineBreakContext *lbpCtx)
+{
+    int brk = LINEBREAK_UNDEFINED;
+
+    assert((lbpCtx->lbcCur > 0) && (lbpCtx->lbcCur <= LBP_RI));
+    assert((lbpCtx->lbcNew > 0) && (lbpCtx->lbcNew <= LBP_RI));
+
+    /* Fix for Hangul word wrap */
+    enum LineBreakClass lbcCur, lbcNew;
+
+    switch (lbpCtx->lbcCur)
+    {
+    case LBP_H2:        /**< Hangul LV */
+    case LBP_H3:        /**< Hangul LVT */
+    case LBP_JL:        /**< Hangul L Jamo */
+    case LBP_JV:        /**< Hangul V Jamo */
+    case LBP_JT:        /**< Hangul T Jamo */
+        lbcCur = LBP_AL;
+        break;
+    default:
+        lbcCur = lbpCtx->lbcCur;
+        break;
+    }
+
+    switch (lbpCtx->lbcNew)
+    {
+    case LBP_H2:        /**< Hangul LV */
+    case LBP_H3:        /**< Hangul LVT */
+    case LBP_JL:        /**< Hangul L Jamo */
+    case LBP_JV:        /**< Hangul V Jamo */
+    case LBP_JT:        /**< Hangul T Jamo */
+        lbcNew = LBP_AL;
+        break;
+    default:
+        lbcNew = lbpCtx->lbcNew;
+        break;
+    }
+
+    switch (baTable[lbcCur - 1][lbcNew - 1])
+    /* END */
+    {
+    case DIR_BRK:
+        brk = LINEBREAK_ALLOWBREAK;
+        break;
+    case CMI_BRK:
+    case IND_BRK:
+        brk = (lbpCtx->lbcLast == LBP_SP)
+            ? LINEBREAK_ALLOWBREAK
+            : LINEBREAK_NOBREAK;
+        break;
+    case CMP_BRK:
+        brk = LINEBREAK_NOBREAK;
+        if (lbpCtx->lbcLast != LBP_SP)
+            return brk;                 /* Do not update lbcCur */
+        break;
+    case PRH_BRK:
+        brk = LINEBREAK_NOBREAK;
+        break;
+    }
+
+    /* Special processing due to rule LB21a */
+    if (lbpCtx->fLb21aHebrew &&
+        (lbpCtx->lbcCur == LBP_HY || lbpCtx->lbcCur == LBP_BA))
+    {
+        brk = LINEBREAK_NOBREAK;
+        lbpCtx->fLb21aHebrew = 0;
+    }
+    else if (!(lbpCtx->lbcNew == LBP_HY || lbpCtx->lbcNew == LBP_BA))
+    {
+        lbpCtx->fLb21aHebrew = (lbpCtx->lbcNew == LBP_HL);
+    }
+
+    lbpCtx->lbcCur = lbpCtx->lbcNew;
+    return brk;
+}
+
+/**
+ * Initializes line breaking context for a given language.
+ *
+ * @param[in,out] lbpCtx  pointer to the line breaking context
+ * @param[in]     ch      the first character to process
+ * @param[in]     lang    language of the input
+ * @post                  the line breaking context is initialized
+ */
+void lb_init_break_context(
+        struct LineBreakContext *lbpCtx,
+        utf32_t ch,
+        const char *lang)
+{
+    lbpCtx->lang = lang;
+    lbpCtx->lbpLang = get_lb_prop_lang(lang);
+    lbpCtx->lbcLast = LBP_Undefined;
+    lbpCtx->lbcNew = LBP_Undefined;
+    lbpCtx->lbcCur = resolve_lb_class(
+                        get_char_lb_class_lang(ch, lbpCtx->lbpLang),
+                        lbpCtx->lang);
+    lbpCtx->fLb21aHebrew = 0;
+    treat_first_char(lbpCtx);
+}
+
+/**
+ * Updates LineBreakingContext for the next code point and returns
+ * the detected break.
+ *
+ * @param[in,out] lbpCtx  pointer to the line breaking context
+ * @param[in]     ch      Unicode code point
+ * @return                break result, one of #LINEBREAK_MUSTBREAK,
+ *                        #LINEBREAK_ALLOWBREAK, and #LINEBREAK_NOBREAK
+ * @post                  the line breaking context is updated
+ */
+int lb_process_next_char(
+        struct LineBreakContext *lbpCtx,
+        utf32_t ch )
+{
+    int brk;
+
+    lbpCtx->lbcLast = lbpCtx->lbcNew;
+    lbpCtx->lbcNew = get_char_lb_class_lang(ch, lbpCtx->lbpLang);
+    brk = get_lb_result_simple(lbpCtx);
+    switch (brk)
+    {
+    case LINEBREAK_MUSTBREAK:
+        lbpCtx->lbcCur = resolve_lb_class(lbpCtx->lbcNew, lbpCtx->lang);
+        treat_first_char(lbpCtx);
+        break;
+    case LINEBREAK_UNDEFINED:
+        lbpCtx->lbcNew = resolve_lb_class(lbpCtx->lbcNew, lbpCtx->lang);
+        brk = get_lb_result_lookup(lbpCtx);
+        break;
+    default:
+        break;
+    }
+    return brk;
+}
+
+/**
+ * Sets the line breaking information for a generic input string.
+ *
+ * @param[in]  s             input string
+ * @param[in]  len           length of the input
+ * @param[in]  lang          language of the input
+ * @param[out] brks          pointer to the output breaking data,
+ *                           containing #LINEBREAK_MUSTBREAK,
+ *                           #LINEBREAK_ALLOWBREAK, #LINEBREAK_NOBREAK,
+ *                           or #LINEBREAK_INSIDEACHAR
+ * @param[in] get_next_char  function to get the next UTF-32 character
+ */
+void set_linebreaks(
+        const void *s,
+        size_t len,
+        const char *lang,
+        char *brks,
+        get_next_char_t get_next_char)
+{
+    utf32_t ch;
+    struct LineBreakContext lbCtx;
+    size_t posCur = 0;
+    size_t posLast = 0;
+
+    --posLast;  /* To be ++'d later */
+    ch = get_next_char(s, len, &posCur);
+    if (ch == EOS)
+        return;
+    lb_init_break_context(&lbCtx, ch, lang);
+
+    /* Process a line till an explicit break or end of string */
+    for (;;)
+    {
+        for (++posLast; posLast < posCur - 1; ++posLast)
+        {
+            brks[posLast] = LINEBREAK_INSIDEACHAR;
+        }
+        assert(posLast == posCur - 1);
+        ch = get_next_char(s, len, &posCur);
+        if (ch == EOS)
+            break;
+        brks[posLast] = lb_process_next_char(&lbCtx, ch);
+    }
+
+    assert(posLast == posCur - 1 && posCur <= len);
+    /* Break after the last character */
+    brks[posLast] = LINEBREAK_MUSTBREAK;
+    /* When the input contains incomplete sequences */
+    while (posCur < len)
+    {
+        brks[posCur++] = LINEBREAK_INSIDEACHAR;
+    }
+}
+
+/**
+ * Sets the line breaking information for a UTF-8 input string.
+ *
+ * @param[in]  s     input UTF-8 string
+ * @param[in]  len   length of the input
+ * @param[in]  lang  language of the input
+ * @param[out] brks  pointer to the output breaking data, containing
+ *                   #LINEBREAK_MUSTBREAK, #LINEBREAK_ALLOWBREAK,
+ *                   #LINEBREAK_NOBREAK, or #LINEBREAK_INSIDEACHAR
+ */
+void set_linebreaks_utf8(
+        const utf8_t *s,
+        size_t len,
+        const char *lang,
+        char *brks)
+{
+    set_linebreaks(s, len, lang, brks,
+                   (get_next_char_t)ub_get_next_char_utf8);
+}
+
+/**
+ * Sets the line breaking information for a UTF-16 input string.
+ *
+ * @param[in]  s     input UTF-16 string
+ * @param[in]  len   length of the input
+ * @param[in]  lang  language of the input
+ * @param[out] brks  pointer to the output breaking data, containing
+ *                   #LINEBREAK_MUSTBREAK, #LINEBREAK_ALLOWBREAK,
+ *                   #LINEBREAK_NOBREAK, or #LINEBREAK_INSIDEACHAR
+ */
+void set_linebreaks_utf16(
+        const utf16_t *s,
+        size_t len,
+        const char *lang,
+        char *brks)
+{
+    set_linebreaks(s, len, lang, brks,
+                   (get_next_char_t)ub_get_next_char_utf16);
+}
+
+/**
+ * Sets the line breaking information for a UTF-32 input string.
+ *
+ * @param[in]  s     input UTF-32 string
+ * @param[in]  len   length of the input
+ * @param[in]  lang  language of the input
+ * @param[out] brks  pointer to the output breaking data, containing
+ *                   #LINEBREAK_MUSTBREAK, #LINEBREAK_ALLOWBREAK,
+ *                   #LINEBREAK_NOBREAK, or #LINEBREAK_INSIDEACHAR
+ */
+void set_linebreaks_utf32(
+        const utf32_t *s,
+        size_t len,
+        const char *lang,
+        char *brks)
+{
+    set_linebreaks(s, len, lang, brks,
+                   (get_next_char_t)ub_get_next_char_utf32);
+}
+
+/**
+ * Tells whether a line break can occur between two Unicode characters.
+ * This is a wrapper function to expose a simple interface.  Generally
+ * speaking, it is better to use #set_linebreaks_utf32 instead, since
+ * complicated cases involving combining marks, spaces, etc. cannot be
+ * correctly processed.
+ *
+ * @param char1  the first Unicode character
+ * @param char2  the second Unicode character
+ * @param lang   language of the input
+ * @return       one of #LINEBREAK_MUSTBREAK, #LINEBREAK_ALLOWBREAK,
+ *               #LINEBREAK_NOBREAK, or #LINEBREAK_INSIDEACHAR
+ */
+int is_line_breakable(
+        utf32_t char1,
+        utf32_t char2,
+        const char *lang)
+{
+    utf32_t s[2];
+    char brks[2];
+    s[0] = char1;
+    s[1] = char2;
+    set_linebreaks_utf32(s, 2, lang, brks);
+    return brks[0];
+}
diff --git a/third-party/libunibreak/linebreak.h b/third-party/libunibreak/linebreak.h
new file mode 100644 (file)
index 0000000..68c8e41
--- /dev/null
@@ -0,0 +1,78 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Line breaking in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2008-2015 Wu Yongwei <wuyongwei at gmail dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ * The main reference is Unicode Standard Annex 14 (UAX #14):
+ *      <URL:http://www.unicode.org/reports/tr14/>
+ *
+ * When this library was designed, this annex was at Revision 19, for
+ * Unicode 5.0.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-19.html>
+ *
+ * This library has been updated according to Revision 33, for
+ * Unicode 7.0.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-33.html>
+ *
+ * The Unicode Terms of Use are available at
+ *      <URL:http://www.unicode.org/copyright.html>
+ */
+
+/**
+ * @file    linebreak.h
+ *
+ * Header file for the line breaking algorithm.
+ *
+ * @version 2.4, 2015/04/18
+ * @author  Wu Yongwei
+ */
+
+#ifndef LINEBREAK_H
+#define LINEBREAK_H
+
+#include <stddef.h>
+#include "unibreakbase.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LINEBREAK_MUSTBREAK     0   /**< Break is mandatory */
+#define LINEBREAK_ALLOWBREAK    1   /**< Break is allowed */
+#define LINEBREAK_NOBREAK       2   /**< No break is possible */
+#define LINEBREAK_INSIDEACHAR   3   /**< A UTF-8/16 sequence is unfinished */
+
+void init_linebreak(void);
+void set_linebreaks_utf8(
+        const utf8_t *s, size_t len, const char *lang, char *brks);
+void set_linebreaks_utf16(
+        const utf16_t *s, size_t len, const char *lang, char *brks);
+void set_linebreaks_utf32(
+        const utf32_t *s, size_t len, const char *lang, char *brks);
+int is_line_breakable(utf32_t char1, utf32_t char2, const char *lang);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LINEBREAK_H */
diff --git a/third-party/libunibreak/linebreakdata.c b/third-party/libunibreak/linebreakdata.c
new file mode 100644 (file)
index 0000000..d4bc8d8
--- /dev/null
@@ -0,0 +1,2065 @@
+/* The content of this file is generated from:
+# LineBreak-7.0.0.txt
+# Date: 2014-02-28, 23:15:00 GMT [KW, LI]
+*/
+
+#include "linebreakdef.h"
+
+/** Default line breaking properties as from the Unicode Web site. */
+struct LineBreakProperties lb_prop_default[] = {
+       { 0x0000, 0x0008, LBP_CM },
+       { 0x0009, 0x0009, LBP_BA },
+       { 0x000A, 0x000A, LBP_LF },
+       { 0x000B, 0x000C, LBP_BK },
+       { 0x000D, 0x000D, LBP_CR },
+       { 0x000E, 0x001F, LBP_CM },
+       { 0x0020, 0x0020, LBP_SP },
+       { 0x0021, 0x0021, LBP_EX },
+       { 0x0022, 0x0022, LBP_QU },
+       { 0x0023, 0x0023, LBP_AL },
+       { 0x0024, 0x0024, LBP_PR },
+       { 0x0025, 0x0025, LBP_PO },
+       { 0x0026, 0x0026, LBP_AL },
+       { 0x0027, 0x0027, LBP_QU },
+       { 0x0028, 0x0028, LBP_OP },
+       { 0x0029, 0x0029, LBP_CP },
+       { 0x002A, 0x002A, LBP_AL },
+       { 0x002B, 0x002B, LBP_PR },
+       { 0x002C, 0x002C, LBP_IS },
+       { 0x002D, 0x002D, LBP_HY },
+       { 0x002E, 0x002E, LBP_IS },
+       { 0x002F, 0x002F, LBP_SY },
+       { 0x0030, 0x0039, LBP_NU },
+       { 0x003A, 0x003B, LBP_IS },
+       { 0x003C, 0x003E, LBP_AL },
+       { 0x003F, 0x003F, LBP_EX },
+       { 0x0040, 0x005A, LBP_AL },
+       { 0x005B, 0x005B, LBP_OP },
+       { 0x005C, 0x005C, LBP_PR },
+       { 0x005D, 0x005D, LBP_CP },
+       { 0x005E, 0x007A, LBP_AL },
+       { 0x007B, 0x007B, LBP_OP },
+       { 0x007C, 0x007C, LBP_BA },
+       { 0x007D, 0x007D, LBP_CL },
+       { 0x007E, 0x007E, LBP_AL },
+       { 0x007F, 0x0084, LBP_CM },
+       { 0x0085, 0x0085, LBP_NL },
+       { 0x0086, 0x009F, LBP_CM },
+       { 0x00A0, 0x00A0, LBP_GL },
+       { 0x00A1, 0x00A1, LBP_OP },
+       { 0x00A2, 0x00A2, LBP_PO },
+       { 0x00A3, 0x00A5, LBP_PR },
+       { 0x00A6, 0x00A6, LBP_AL },
+       { 0x00A7, 0x00A8, LBP_AI },
+       { 0x00A9, 0x00A9, LBP_AL },
+       { 0x00AA, 0x00AA, LBP_AI },
+       { 0x00AB, 0x00AB, LBP_QU },
+       { 0x00AC, 0x00AC, LBP_AL },
+       { 0x00AD, 0x00AD, LBP_BA },
+       { 0x00AE, 0x00AF, LBP_AL },
+       { 0x00B0, 0x00B0, LBP_PO },
+       { 0x00B1, 0x00B1, LBP_PR },
+       { 0x00B2, 0x00B3, LBP_AI },
+       { 0x00B4, 0x00B4, LBP_BB },
+       { 0x00B5, 0x00B5, LBP_AL },
+       { 0x00B6, 0x00BA, LBP_AI },
+       { 0x00BB, 0x00BB, LBP_QU },
+       { 0x00BC, 0x00BE, LBP_AI },
+       { 0x00BF, 0x00BF, LBP_OP },
+       { 0x00C0, 0x00D6, LBP_AL },
+       { 0x00D7, 0x00D7, LBP_AI },
+       { 0x00D8, 0x00F6, LBP_AL },
+       { 0x00F7, 0x00F7, LBP_AI },
+       { 0x00F8, 0x02C6, LBP_AL },
+       { 0x02C7, 0x02C7, LBP_AI },
+       { 0x02C8, 0x02C8, LBP_BB },
+       { 0x02C9, 0x02CB, LBP_AI },
+       { 0x02CC, 0x02CC, LBP_BB },
+       { 0x02CD, 0x02CD, LBP_AI },
+       { 0x02CE, 0x02CF, LBP_AL },
+       { 0x02D0, 0x02D0, LBP_AI },
+       { 0x02D1, 0x02D7, LBP_AL },
+       { 0x02D8, 0x02DB, LBP_AI },
+       { 0x02DC, 0x02DC, LBP_AL },
+       { 0x02DD, 0x02DD, LBP_AI },
+       { 0x02DE, 0x02DE, LBP_AL },
+       { 0x02DF, 0x02DF, LBP_BB },
+       { 0x02E0, 0x02FF, LBP_AL },
+       { 0x0300, 0x034E, LBP_CM },
+       { 0x034F, 0x034F, LBP_GL },
+       { 0x0350, 0x035B, LBP_CM },
+       { 0x035C, 0x0362, LBP_GL },
+       { 0x0363, 0x036F, LBP_CM },
+       { 0x0370, 0x037D, LBP_AL },
+       { 0x037E, 0x037E, LBP_IS },
+       { 0x037F, 0x0482, LBP_AL },
+       { 0x0483, 0x0489, LBP_CM },
+       { 0x048A, 0x0587, LBP_AL },
+       { 0x0589, 0x0589, LBP_IS },
+       { 0x058A, 0x058A, LBP_BA },
+       { 0x058D, 0x058E, LBP_AL },
+       { 0x058F, 0x058F, LBP_PR },
+       { 0x0591, 0x05BD, LBP_CM },
+       { 0x05BE, 0x05BE, LBP_BA },
+       { 0x05BF, 0x05BF, LBP_CM },
+       { 0x05C0, 0x05C0, LBP_AL },
+       { 0x05C1, 0x05C2, LBP_CM },
+       { 0x05C3, 0x05C3, LBP_AL },
+       { 0x05C4, 0x05C5, LBP_CM },
+       { 0x05C6, 0x05C6, LBP_EX },
+       { 0x05C7, 0x05C7, LBP_CM },
+       { 0x05D0, 0x05F2, LBP_HL },
+       { 0x05F3, 0x0608, LBP_AL },
+       { 0x0609, 0x060B, LBP_PO },
+       { 0x060C, 0x060D, LBP_IS },
+       { 0x060E, 0x060F, LBP_AL },
+       { 0x0610, 0x061A, LBP_CM },
+       { 0x061B, 0x061B, LBP_EX },
+       { 0x061C, 0x061C, LBP_CM },
+       { 0x061E, 0x061F, LBP_EX },
+       { 0x0620, 0x064A, LBP_AL },
+       { 0x064B, 0x065F, LBP_CM },
+       { 0x0660, 0x0669, LBP_NU },
+       { 0x066A, 0x066A, LBP_PO },
+       { 0x066B, 0x066C, LBP_NU },
+       { 0x066D, 0x066F, LBP_AL },
+       { 0x0670, 0x0670, LBP_CM },
+       { 0x0671, 0x06D3, LBP_AL },
+       { 0x06D4, 0x06D4, LBP_EX },
+       { 0x06D5, 0x06D5, LBP_AL },
+       { 0x06D6, 0x06DC, LBP_CM },
+       { 0x06DD, 0x06DE, LBP_AL },
+       { 0x06DF, 0x06E4, LBP_CM },
+       { 0x06E5, 0x06E6, LBP_AL },
+       { 0x06E7, 0x06E8, LBP_CM },
+       { 0x06E9, 0x06E9, LBP_AL },
+       { 0x06EA, 0x06ED, LBP_CM },
+       { 0x06EE, 0x06EF, LBP_AL },
+       { 0x06F0, 0x06F9, LBP_NU },
+       { 0x06FA, 0x0710, LBP_AL },
+       { 0x0711, 0x0711, LBP_CM },
+       { 0x0712, 0x072F, LBP_AL },
+       { 0x0730, 0x074A, LBP_CM },
+       { 0x074D, 0x07A5, LBP_AL },
+       { 0x07A6, 0x07B0, LBP_CM },
+       { 0x07B1, 0x07B1, LBP_AL },
+       { 0x07C0, 0x07C9, LBP_NU },
+       { 0x07CA, 0x07EA, LBP_AL },
+       { 0x07EB, 0x07F3, LBP_CM },
+       { 0x07F4, 0x07F7, LBP_AL },
+       { 0x07F8, 0x07F8, LBP_IS },
+       { 0x07F9, 0x07F9, LBP_EX },
+       { 0x07FA, 0x0815, LBP_AL },
+       { 0x0816, 0x0819, LBP_CM },
+       { 0x081A, 0x081A, LBP_AL },
+       { 0x081B, 0x0823, LBP_CM },
+       { 0x0824, 0x0824, LBP_AL },
+       { 0x0825, 0x0827, LBP_CM },
+       { 0x0828, 0x0828, LBP_AL },
+       { 0x0829, 0x082D, LBP_CM },
+       { 0x0830, 0x0858, LBP_AL },
+       { 0x0859, 0x085B, LBP_CM },
+       { 0x085E, 0x08B2, LBP_AL },
+       { 0x08E4, 0x0903, LBP_CM },
+       { 0x0904, 0x0939, LBP_AL },
+       { 0x093A, 0x093C, LBP_CM },
+       { 0x093D, 0x093D, LBP_AL },
+       { 0x093E, 0x094F, LBP_CM },
+       { 0x0950, 0x0950, LBP_AL },
+       { 0x0951, 0x0957, LBP_CM },
+       { 0x0958, 0x0961, LBP_AL },
+       { 0x0962, 0x0963, LBP_CM },
+       { 0x0964, 0x0965, LBP_BA },
+       { 0x0966, 0x096F, LBP_NU },
+       { 0x0970, 0x0980, LBP_AL },
+       { 0x0981, 0x0983, LBP_CM },
+       { 0x0985, 0x09B9, LBP_AL },
+       { 0x09BC, 0x09BC, LBP_CM },
+       { 0x09BD, 0x09BD, LBP_AL },
+       { 0x09BE, 0x09CD, LBP_CM },
+       { 0x09CE, 0x09CE, LBP_AL },
+       { 0x09D7, 0x09D7, LBP_CM },
+       { 0x09DC, 0x09E1, LBP_AL },
+       { 0x09E2, 0x09E3, LBP_CM },
+       { 0x09E6, 0x09EF, LBP_NU },
+       { 0x09F0, 0x09F1, LBP_AL },
+       { 0x09F2, 0x09F3, LBP_PO },
+       { 0x09F4, 0x09F8, LBP_AL },
+       { 0x09F9, 0x09F9, LBP_PO },
+       { 0x09FA, 0x09FA, LBP_AL },
+       { 0x09FB, 0x09FB, LBP_PR },
+       { 0x0A01, 0x0A03, LBP_CM },
+       { 0x0A05, 0x0A39, LBP_AL },
+       { 0x0A3C, 0x0A51, LBP_CM },
+       { 0x0A59, 0x0A5E, LBP_AL },
+       { 0x0A66, 0x0A6F, LBP_NU },
+       { 0x0A70, 0x0A71, LBP_CM },
+       { 0x0A72, 0x0A74, LBP_AL },
+       { 0x0A75, 0x0A83, LBP_CM },
+       { 0x0A85, 0x0AB9, LBP_AL },
+       { 0x0ABC, 0x0ABC, LBP_CM },
+       { 0x0ABD, 0x0ABD, LBP_AL },
+       { 0x0ABE, 0x0ACD, LBP_CM },
+       { 0x0AD0, 0x0AE1, LBP_AL },
+       { 0x0AE2, 0x0AE3, LBP_CM },
+       { 0x0AE6, 0x0AEF, LBP_NU },
+       { 0x0AF0, 0x0AF0, LBP_AL },
+       { 0x0AF1, 0x0AF1, LBP_PR },
+       { 0x0B01, 0x0B03, LBP_CM },
+       { 0x0B05, 0x0B39, LBP_AL },
+       { 0x0B3C, 0x0B3C, LBP_CM },
+       { 0x0B3D, 0x0B3D, LBP_AL },
+       { 0x0B3E, 0x0B57, LBP_CM },
+       { 0x0B5C, 0x0B61, LBP_AL },
+       { 0x0B62, 0x0B63, LBP_CM },
+       { 0x0B66, 0x0B6F, LBP_NU },
+       { 0x0B70, 0x0B77, LBP_AL },
+       { 0x0B82, 0x0B82, LBP_CM },
+       { 0x0B83, 0x0BB9, LBP_AL },
+       { 0x0BBE, 0x0BCD, LBP_CM },
+       { 0x0BD0, 0x0BD0, LBP_AL },
+       { 0x0BD7, 0x0BD7, LBP_CM },
+       { 0x0BE6, 0x0BEF, LBP_NU },
+       { 0x0BF0, 0x0BF8, LBP_AL },
+       { 0x0BF9, 0x0BF9, LBP_PR },
+       { 0x0BFA, 0x0BFA, LBP_AL },
+       { 0x0C00, 0x0C03, LBP_CM },
+       { 0x0C05, 0x0C3D, LBP_AL },
+       { 0x0C3E, 0x0C56, LBP_CM },
+       { 0x0C58, 0x0C61, LBP_AL },
+       { 0x0C62, 0x0C63, LBP_CM },
+       { 0x0C66, 0x0C6F, LBP_NU },
+       { 0x0C78, 0x0C7F, LBP_AL },
+       { 0x0C81, 0x0C83, LBP_CM },
+       { 0x0C85, 0x0CB9, LBP_AL },
+       { 0x0CBC, 0x0CBC, LBP_CM },
+       { 0x0CBD, 0x0CBD, LBP_AL },
+       { 0x0CBE, 0x0CD6, LBP_CM },
+       { 0x0CDE, 0x0CE1, LBP_AL },
+       { 0x0CE2, 0x0CE3, LBP_CM },
+       { 0x0CE6, 0x0CEF, LBP_NU },
+       { 0x0CF1, 0x0CF2, LBP_AL },
+       { 0x0D01, 0x0D03, LBP_CM },
+       { 0x0D05, 0x0D3D, LBP_AL },
+       { 0x0D3E, 0x0D4D, LBP_CM },
+       { 0x0D4E, 0x0D4E, LBP_AL },
+       { 0x0D57, 0x0D57, LBP_CM },
+       { 0x0D60, 0x0D61, LBP_AL },
+       { 0x0D62, 0x0D63, LBP_CM },
+       { 0x0D66, 0x0D6F, LBP_NU },
+       { 0x0D70, 0x0D75, LBP_AL },
+       { 0x0D79, 0x0D79, LBP_PO },
+       { 0x0D7A, 0x0D7F, LBP_AL },
+       { 0x0D82, 0x0D83, LBP_CM },
+       { 0x0D85, 0x0DC6, LBP_AL },
+       { 0x0DCA, 0x0DDF, LBP_CM },
+       { 0x0DE6, 0x0DEF, LBP_NU },
+       { 0x0DF2, 0x0DF3, LBP_CM },
+       { 0x0DF4, 0x0DF4, LBP_AL },
+       { 0x0E01, 0x0E3A, LBP_SA },
+       { 0x0E3F, 0x0E3F, LBP_PR },
+       { 0x0E40, 0x0E4E, LBP_SA },
+       { 0x0E4F, 0x0E4F, LBP_AL },
+       { 0x0E50, 0x0E59, LBP_NU },
+       { 0x0E5A, 0x0E5B, LBP_BA },
+       { 0x0E81, 0x0ECD, LBP_SA },
+       { 0x0ED0, 0x0ED9, LBP_NU },
+       { 0x0EDC, 0x0EDF, LBP_SA },
+       { 0x0F00, 0x0F00, LBP_AL },
+       { 0x0F01, 0x0F04, LBP_BB },
+       { 0x0F05, 0x0F05, LBP_AL },
+       { 0x0F06, 0x0F07, LBP_BB },
+       { 0x0F08, 0x0F08, LBP_GL },
+       { 0x0F09, 0x0F0A, LBP_BB },
+       { 0x0F0B, 0x0F0B, LBP_BA },
+       { 0x0F0C, 0x0F0C, LBP_GL },
+       { 0x0F0D, 0x0F11, LBP_EX },
+       { 0x0F12, 0x0F12, LBP_GL },
+       { 0x0F13, 0x0F13, LBP_AL },
+       { 0x0F14, 0x0F14, LBP_EX },
+       { 0x0F15, 0x0F17, LBP_AL },
+       { 0x0F18, 0x0F19, LBP_CM },
+       { 0x0F1A, 0x0F1F, LBP_AL },
+       { 0x0F20, 0x0F29, LBP_NU },
+       { 0x0F2A, 0x0F33, LBP_AL },
+       { 0x0F34, 0x0F34, LBP_BA },
+       { 0x0F35, 0x0F35, LBP_CM },
+       { 0x0F36, 0x0F36, LBP_AL },
+       { 0x0F37, 0x0F37, LBP_CM },
+       { 0x0F38, 0x0F38, LBP_AL },
+       { 0x0F39, 0x0F39, LBP_CM },
+       { 0x0F3A, 0x0F3A, LBP_OP },
+       { 0x0F3B, 0x0F3B, LBP_CL },
+       { 0x0F3C, 0x0F3C, LBP_OP },
+       { 0x0F3D, 0x0F3D, LBP_CL },
+       { 0x0F3E, 0x0F3F, LBP_CM },
+       { 0x0F40, 0x0F6C, LBP_AL },
+       { 0x0F71, 0x0F7E, LBP_CM },
+       { 0x0F7F, 0x0F7F, LBP_BA },
+       { 0x0F80, 0x0F84, LBP_CM },
+       { 0x0F85, 0x0F85, LBP_BA },
+       { 0x0F86, 0x0F87, LBP_CM },
+       { 0x0F88, 0x0F8C, LBP_AL },
+       { 0x0F8D, 0x0FBC, LBP_CM },
+       { 0x0FBE, 0x0FBF, LBP_BA },
+       { 0x0FC0, 0x0FC5, LBP_AL },
+       { 0x0FC6, 0x0FC6, LBP_CM },
+       { 0x0FC7, 0x0FCF, LBP_AL },
+       { 0x0FD0, 0x0FD1, LBP_BB },
+       { 0x0FD2, 0x0FD2, LBP_BA },
+       { 0x0FD3, 0x0FD3, LBP_BB },
+       { 0x0FD4, 0x0FD8, LBP_AL },
+       { 0x0FD9, 0x0FDA, LBP_GL },
+       { 0x1000, 0x103F, LBP_SA },
+       { 0x1040, 0x1049, LBP_NU },
+       { 0x104A, 0x104B, LBP_BA },
+       { 0x104C, 0x104F, LBP_AL },
+       { 0x1050, 0x108F, LBP_SA },
+       { 0x1090, 0x1099, LBP_NU },
+       { 0x109A, 0x109F, LBP_SA },
+       { 0x10A0, 0x10FF, LBP_AL },
+       { 0x1100, 0x115F, LBP_JL },
+       { 0x1160, 0x11A7, LBP_JV },
+       { 0x11A8, 0x11FF, LBP_JT },
+       { 0x1200, 0x135A, LBP_AL },
+       { 0x135D, 0x135F, LBP_CM },
+       { 0x1360, 0x1360, LBP_AL },
+       { 0x1361, 0x1361, LBP_BA },
+       { 0x1362, 0x13F4, LBP_AL },
+       { 0x1400, 0x1400, LBP_BA },
+       { 0x1401, 0x167F, LBP_AL },
+       { 0x1680, 0x1680, LBP_BA },
+       { 0x1681, 0x169A, LBP_AL },
+       { 0x169B, 0x169B, LBP_OP },
+       { 0x169C, 0x169C, LBP_CL },
+       { 0x16A0, 0x16EA, LBP_AL },
+       { 0x16EB, 0x16ED, LBP_BA },
+       { 0x16EE, 0x1711, LBP_AL },
+       { 0x1712, 0x1714, LBP_CM },
+       { 0x1720, 0x1731, LBP_AL },
+       { 0x1732, 0x1734, LBP_CM },
+       { 0x1735, 0x1736, LBP_BA },
+       { 0x1740, 0x1751, LBP_AL },
+       { 0x1752, 0x1753, LBP_CM },
+       { 0x1760, 0x1770, LBP_AL },
+       { 0x1772, 0x1773, LBP_CM },
+       { 0x1780, 0x17D3, LBP_SA },
+       { 0x17D4, 0x17D5, LBP_BA },
+       { 0x17D6, 0x17D6, LBP_NS },
+       { 0x17D7, 0x17D7, LBP_SA },
+       { 0x17D8, 0x17D8, LBP_BA },
+       { 0x17D9, 0x17D9, LBP_AL },
+       { 0x17DA, 0x17DA, LBP_BA },
+       { 0x17DB, 0x17DB, LBP_PR },
+       { 0x17DC, 0x17DD, LBP_SA },
+       { 0x17E0, 0x17E9, LBP_NU },
+       { 0x17F0, 0x1801, LBP_AL },
+       { 0x1802, 0x1803, LBP_EX },
+       { 0x1804, 0x1805, LBP_BA },
+       { 0x1806, 0x1806, LBP_BB },
+       { 0x1807, 0x1807, LBP_AL },
+       { 0x1808, 0x1809, LBP_EX },
+       { 0x180A, 0x180A, LBP_AL },
+       { 0x180B, 0x180D, LBP_CM },
+       { 0x180E, 0x180E, LBP_GL },
+       { 0x1810, 0x1819, LBP_NU },
+       { 0x1820, 0x18A8, LBP_AL },
+       { 0x18A9, 0x18A9, LBP_CM },
+       { 0x18AA, 0x191E, LBP_AL },
+       { 0x1920, 0x193B, LBP_CM },
+       { 0x1940, 0x1940, LBP_AL },
+       { 0x1944, 0x1945, LBP_EX },
+       { 0x1946, 0x194F, LBP_NU },
+       { 0x1950, 0x19C9, LBP_SA },
+       { 0x19D0, 0x19D9, LBP_NU },
+       { 0x19DA, 0x19DF, LBP_SA },
+       { 0x19E0, 0x1A16, LBP_AL },
+       { 0x1A17, 0x1A1B, LBP_CM },
+       { 0x1A1E, 0x1A1F, LBP_AL },
+       { 0x1A20, 0x1A7C, LBP_SA },
+       { 0x1A7F, 0x1A7F, LBP_CM },
+       { 0x1A80, 0x1A99, LBP_NU },
+       { 0x1AA0, 0x1AAD, LBP_SA },
+       { 0x1AB0, 0x1B04, LBP_CM },
+       { 0x1B05, 0x1B33, LBP_AL },
+       { 0x1B34, 0x1B44, LBP_CM },
+       { 0x1B45, 0x1B4B, LBP_AL },
+       { 0x1B50, 0x1B59, LBP_NU },
+       { 0x1B5A, 0x1B5B, LBP_BA },
+       { 0x1B5C, 0x1B5C, LBP_AL },
+       { 0x1B5D, 0x1B60, LBP_BA },
+       { 0x1B61, 0x1B6A, LBP_AL },
+       { 0x1B6B, 0x1B73, LBP_CM },
+       { 0x1B74, 0x1B7C, LBP_AL },
+       { 0x1B80, 0x1B82, LBP_CM },
+       { 0x1B83, 0x1BA0, LBP_AL },
+       { 0x1BA1, 0x1BAD, LBP_CM },
+       { 0x1BAE, 0x1BAF, LBP_AL },
+       { 0x1BB0, 0x1BB9, LBP_NU },
+       { 0x1BBA, 0x1BE5, LBP_AL },
+       { 0x1BE6, 0x1BF3, LBP_CM },
+       { 0x1BFC, 0x1C23, LBP_AL },
+       { 0x1C24, 0x1C37, LBP_CM },
+       { 0x1C3B, 0x1C3F, LBP_BA },
+       { 0x1C40, 0x1C49, LBP_NU },
+       { 0x1C4D, 0x1C4F, LBP_AL },
+       { 0x1C50, 0x1C59, LBP_NU },
+       { 0x1C5A, 0x1C7D, LBP_AL },
+       { 0x1C7E, 0x1C7F, LBP_BA },
+       { 0x1CC0, 0x1CC7, LBP_AL },
+       { 0x1CD0, 0x1CD2, LBP_CM },
+       { 0x1CD3, 0x1CD3, LBP_AL },
+       { 0x1CD4, 0x1CE8, LBP_CM },
+       { 0x1CE9, 0x1CEC, LBP_AL },
+       { 0x1CED, 0x1CED, LBP_CM },
+       { 0x1CEE, 0x1CF1, LBP_AL },
+       { 0x1CF2, 0x1CF4, LBP_CM },
+       { 0x1CF5, 0x1CF6, LBP_AL },
+       { 0x1CF8, 0x1CF9, LBP_CM },
+       { 0x1D00, 0x1DBF, LBP_AL },
+       { 0x1DC0, 0x1DFF, LBP_CM },
+       { 0x1E00, 0x1FFC, LBP_AL },
+       { 0x1FFD, 0x1FFD, LBP_BB },
+       { 0x1FFE, 0x1FFE, LBP_AL },
+       { 0x2000, 0x2006, LBP_BA },
+       { 0x2007, 0x2007, LBP_GL },
+       { 0x2008, 0x200A, LBP_BA },
+       { 0x200B, 0x200B, LBP_ZW },
+       { 0x200C, 0x200F, LBP_CM },
+       { 0x2010, 0x2010, LBP_BA },
+       { 0x2011, 0x2011, LBP_GL },
+       { 0x2012, 0x2013, LBP_BA },
+       { 0x2014, 0x2014, LBP_B2 },
+       { 0x2015, 0x2016, LBP_AI },
+       { 0x2017, 0x2017, LBP_AL },
+       { 0x2018, 0x2019, LBP_QU },
+       { 0x201A, 0x201A, LBP_OP },
+       { 0x201B, 0x201D, LBP_QU },
+       { 0x201E, 0x201E, LBP_OP },
+       { 0x201F, 0x201F, LBP_QU },
+       { 0x2020, 0x2021, LBP_AI },
+       { 0x2022, 0x2023, LBP_AL },
+       { 0x2024, 0x2026, LBP_IN },
+       { 0x2027, 0x2027, LBP_BA },
+       { 0x2028, 0x2029, LBP_BK },
+       { 0x202A, 0x202E, LBP_CM },
+       { 0x202F, 0x202F, LBP_GL },
+       { 0x2030, 0x2037, LBP_PO },
+       { 0x2038, 0x2038, LBP_AL },
+       { 0x2039, 0x203A, LBP_QU },
+       { 0x203B, 0x203B, LBP_AI },
+       { 0x203C, 0x203D, LBP_NS },
+       { 0x203E, 0x2043, LBP_AL },
+       { 0x2044, 0x2044, LBP_IS },
+       { 0x2045, 0x2045, LBP_OP },
+       { 0x2046, 0x2046, LBP_CL },
+       { 0x2047, 0x2049, LBP_NS },
+       { 0x204A, 0x2055, LBP_AL },
+       { 0x2056, 0x2056, LBP_BA },
+       { 0x2057, 0x2057, LBP_AL },
+       { 0x2058, 0x205B, LBP_BA },
+       { 0x205C, 0x205C, LBP_AL },
+       { 0x205D, 0x205F, LBP_BA },
+       { 0x2060, 0x2060, LBP_WJ },
+       { 0x2061, 0x2064, LBP_AL },
+       { 0x2066, 0x206F, LBP_CM },
+       { 0x2070, 0x2071, LBP_AL },
+       { 0x2074, 0x2074, LBP_AI },
+       { 0x2075, 0x207C, LBP_AL },
+       { 0x207D, 0x207D, LBP_OP },
+       { 0x207E, 0x207E, LBP_CL },
+       { 0x207F, 0x207F, LBP_AI },
+       { 0x2080, 0x2080, LBP_AL },
+       { 0x2081, 0x2084, LBP_AI },
+       { 0x2085, 0x208C, LBP_AL },
+       { 0x208D, 0x208D, LBP_OP },
+       { 0x208E, 0x208E, LBP_CL },
+       { 0x2090, 0x209C, LBP_AL },
+       { 0x20A0, 0x20A6, LBP_PR },
+       { 0x20A7, 0x20A7, LBP_PO },
+       { 0x20A8, 0x20B5, LBP_PR },
+       { 0x20B6, 0x20B6, LBP_PO },
+       { 0x20B7, 0x20BA, LBP_PR },
+       { 0x20BB, 0x20BB, LBP_PO },
+       { 0x20BC, 0x20CF, LBP_PR },
+       { 0x20D0, 0x20F0, LBP_CM },
+       { 0x2100, 0x2102, LBP_AL },
+       { 0x2103, 0x2103, LBP_PO },
+       { 0x2104, 0x2104, LBP_AL },
+       { 0x2105, 0x2105, LBP_AI },
+       { 0x2106, 0x2108, LBP_AL },
+       { 0x2109, 0x2109, LBP_PO },
+       { 0x210A, 0x2112, LBP_AL },
+       { 0x2113, 0x2113, LBP_AI },
+       { 0x2114, 0x2115, LBP_AL },
+       { 0x2116, 0x2116, LBP_PR },
+       { 0x2117, 0x2120, LBP_AL },
+       { 0x2121, 0x2122, LBP_AI },
+       { 0x2123, 0x212A, LBP_AL },
+       { 0x212B, 0x212B, LBP_AI },
+       { 0x212C, 0x2153, LBP_AL },
+       { 0x2154, 0x2155, LBP_AI },
+       { 0x2156, 0x215A, LBP_AL },
+       { 0x215B, 0x215B, LBP_AI },
+       { 0x215C, 0x215D, LBP_AL },
+       { 0x215E, 0x215E, LBP_AI },
+       { 0x215F, 0x215F, LBP_AL },
+       { 0x2160, 0x216B, LBP_AI },
+       { 0x216C, 0x216F, LBP_AL },
+       { 0x2170, 0x2179, LBP_AI },
+       { 0x217A, 0x2188, LBP_AL },
+       { 0x2189, 0x2199, LBP_AI },
+       { 0x219A, 0x21D1, LBP_AL },
+       { 0x21D2, 0x21D2, LBP_AI },
+       { 0x21D3, 0x21D3, LBP_AL },
+       { 0x21D4, 0x21D4, LBP_AI },
+       { 0x21D5, 0x21FF, LBP_AL },
+       { 0x2200, 0x2200, LBP_AI },
+       { 0x2201, 0x2201, LBP_AL },
+       { 0x2202, 0x2203, LBP_AI },
+       { 0x2204, 0x2206, LBP_AL },
+       { 0x2207, 0x2208, LBP_AI },
+       { 0x2209, 0x220A, LBP_AL },
+       { 0x220B, 0x220B, LBP_AI },
+       { 0x220C, 0x220E, LBP_AL },
+       { 0x220F, 0x220F, LBP_AI },
+       { 0x2210, 0x2210, LBP_AL },
+       { 0x2211, 0x2211, LBP_AI },
+       { 0x2212, 0x2213, LBP_PR },
+       { 0x2214, 0x2214, LBP_AL },
+       { 0x2215, 0x2215, LBP_AI },
+       { 0x2216, 0x2219, LBP_AL },
+       { 0x221A, 0x221A, LBP_AI },
+       { 0x221B, 0x221C, LBP_AL },
+       { 0x221D, 0x2220, LBP_AI },
+       { 0x2221, 0x2222, LBP_AL },
+       { 0x2223, 0x2223, LBP_AI },
+       { 0x2224, 0x2224, LBP_AL },
+       { 0x2225, 0x2225, LBP_AI },
+       { 0x2226, 0x2226, LBP_AL },
+       { 0x2227, 0x222C, LBP_AI },
+       { 0x222D, 0x222D, LBP_AL },
+       { 0x222E, 0x222E, LBP_AI },
+       { 0x222F, 0x2233, LBP_AL },
+       { 0x2234, 0x2237, LBP_AI },
+       { 0x2238, 0x223B, LBP_AL },
+       { 0x223C, 0x223D, LBP_AI },
+       { 0x223E, 0x2247, LBP_AL },
+       { 0x2248, 0x2248, LBP_AI },
+       { 0x2249, 0x224B, LBP_AL },
+       { 0x224C, 0x224C, LBP_AI },
+       { 0x224D, 0x2251, LBP_AL },
+       { 0x2252, 0x2252, LBP_AI },
+       { 0x2253, 0x225F, LBP_AL },
+       { 0x2260, 0x2261, LBP_AI },
+       { 0x2262, 0x2263, LBP_AL },
+       { 0x2264, 0x2267, LBP_AI },
+       { 0x2268, 0x2269, LBP_AL },
+       { 0x226A, 0x226B, LBP_AI },
+       { 0x226C, 0x226D, LBP_AL },
+       { 0x226E, 0x226F, LBP_AI },
+       { 0x2270, 0x2281, LBP_AL },
+       { 0x2282, 0x2283, LBP_AI },
+       { 0x2284, 0x2285, LBP_AL },
+       { 0x2286, 0x2287, LBP_AI },
+       { 0x2288, 0x2294, LBP_AL },
+       { 0x2295, 0x2295, LBP_AI },
+       { 0x2296, 0x2298, LBP_AL },
+       { 0x2299, 0x2299, LBP_AI },
+       { 0x229A, 0x22A4, LBP_AL },
+       { 0x22A5, 0x22A5, LBP_AI },
+       { 0x22A6, 0x22BE, LBP_AL },
+       { 0x22BF, 0x22BF, LBP_AI },
+       { 0x22C0, 0x2307, LBP_AL },
+       { 0x2308, 0x2308, LBP_OP },
+       { 0x2309, 0x2309, LBP_CL },
+       { 0x230A, 0x230A, LBP_OP },
+       { 0x230B, 0x230B, LBP_CL },
+       { 0x230C, 0x2311, LBP_AL },
+       { 0x2312, 0x2312, LBP_AI },
+       { 0x2313, 0x2319, LBP_AL },
+       { 0x231A, 0x231B, LBP_ID },
+       { 0x231C, 0x2328, LBP_AL },
+       { 0x2329, 0x2329, LBP_OP },
+       { 0x232A, 0x232A, LBP_CL },
+       { 0x232B, 0x23EF, LBP_AL },
+       { 0x23F0, 0x23F3, LBP_ID },
+       { 0x23F4, 0x244A, LBP_AL },
+       { 0x2460, 0x24FE, LBP_AI },
+       { 0x24FF, 0x24FF, LBP_AL },
+       { 0x2500, 0x254B, LBP_AI },
+       { 0x254C, 0x254F, LBP_AL },
+       { 0x2550, 0x2574, LBP_AI },
+       { 0x2575, 0x257F, LBP_AL },
+       { 0x2580, 0x258F, LBP_AI },
+       { 0x2590, 0x2591, LBP_AL },
+       { 0x2592, 0x2595, LBP_AI },
+       { 0x2596, 0x259F, LBP_AL },
+       { 0x25A0, 0x25A1, LBP_AI },
+       { 0x25A2, 0x25A2, LBP_AL },
+       { 0x25A3, 0x25A9, LBP_AI },
+       { 0x25AA, 0x25B1, LBP_AL },
+       { 0x25B2, 0x25B3, LBP_AI },
+       { 0x25B4, 0x25B5, LBP_AL },
+       { 0x25B6, 0x25B7, LBP_AI },
+       { 0x25B8, 0x25BB, LBP_AL },
+       { 0x25BC, 0x25BD, LBP_AI },
+       { 0x25BE, 0x25BF, LBP_AL },
+       { 0x25C0, 0x25C1, LBP_AI },
+       { 0x25C2, 0x25C5, LBP_AL },
+       { 0x25C6, 0x25C8, LBP_AI },
+       { 0x25C9, 0x25CA, LBP_AL },
+       { 0x25CB, 0x25CB, LBP_AI },
+       { 0x25CC, 0x25CD, LBP_AL },
+       { 0x25CE, 0x25D1, LBP_AI },
+       { 0x25D2, 0x25E1, LBP_AL },
+       { 0x25E2, 0x25E5, LBP_AI },
+       { 0x25E6, 0x25EE, LBP_AL },
+       { 0x25EF, 0x25EF, LBP_AI },
+       { 0x25F0, 0x25FF, LBP_AL },
+       { 0x2600, 0x2603, LBP_ID },
+       { 0x2604, 0x2604, LBP_AL },
+       { 0x2605, 0x2606, LBP_AI },
+       { 0x2607, 0x2608, LBP_AL },
+       { 0x2609, 0x2609, LBP_AI },
+       { 0x260A, 0x260D, LBP_AL },
+       { 0x260E, 0x260F, LBP_AI },
+       { 0x2610, 0x2613, LBP_AL },
+       { 0x2614, 0x2615, LBP_ID },
+       { 0x2616, 0x2617, LBP_AI },
+       { 0x2618, 0x2618, LBP_ID },
+       { 0x2619, 0x2619, LBP_AL },
+       { 0x261A, 0x261F, LBP_ID },
+       { 0x2620, 0x2638, LBP_AL },
+       { 0x2639, 0x263B, LBP_ID },
+       { 0x263C, 0x263F, LBP_AL },
+       { 0x2640, 0x2640, LBP_AI },
+       { 0x2641, 0x2641, LBP_AL },
+       { 0x2642, 0x2642, LBP_AI },
+       { 0x2643, 0x265F, LBP_AL },
+       { 0x2660, 0x2661, LBP_AI },
+       { 0x2662, 0x2662, LBP_AL },
+       { 0x2663, 0x2665, LBP_AI },
+       { 0x2666, 0x2666, LBP_AL },
+       { 0x2667, 0x2667, LBP_AI },
+       { 0x2668, 0x2668, LBP_ID },
+       { 0x2669, 0x266A, LBP_AI },
+       { 0x266B, 0x266B, LBP_AL },
+       { 0x266C, 0x266D, LBP_AI },
+       { 0x266E, 0x266E, LBP_AL },
+       { 0x266F, 0x266F, LBP_AI },
+       { 0x2670, 0x267E, LBP_AL },
+       { 0x267F, 0x267F, LBP_ID },
+       { 0x2680, 0x269D, LBP_AL },
+       { 0x269E, 0x269F, LBP_AI },
+       { 0x26A0, 0x26BC, LBP_AL },
+       { 0x26BD, 0x26C8, LBP_ID },
+       { 0x26C9, 0x26CC, LBP_AI },
+       { 0x26CD, 0x26CD, LBP_ID },
+       { 0x26CE, 0x26CE, LBP_AL },
+       { 0x26CF, 0x26D1, LBP_ID },
+       { 0x26D2, 0x26D2, LBP_AI },
+       { 0x26D3, 0x26D4, LBP_ID },
+       { 0x26D5, 0x26D7, LBP_AI },
+       { 0x26D8, 0x26D9, LBP_ID },
+       { 0x26DA, 0x26DB, LBP_AI },
+       { 0x26DC, 0x26DC, LBP_ID },
+       { 0x26DD, 0x26DE, LBP_AI },
+       { 0x26DF, 0x26E1, LBP_ID },
+       { 0x26E2, 0x26E2, LBP_AL },
+       { 0x26E3, 0x26E3, LBP_AI },
+       { 0x26E4, 0x26E7, LBP_AL },
+       { 0x26E8, 0x26E9, LBP_AI },
+       { 0x26EA, 0x26EA, LBP_ID },
+       { 0x26EB, 0x26F0, LBP_AI },
+       { 0x26F1, 0x26F5, LBP_ID },
+       { 0x26F6, 0x26F6, LBP_AI },
+       { 0x26F7, 0x26FA, LBP_ID },
+       { 0x26FB, 0x26FC, LBP_AI },
+       { 0x26FD, 0x2704, LBP_ID },
+       { 0x2705, 0x2707, LBP_AL },
+       { 0x2708, 0x270D, LBP_ID },
+       { 0x270E, 0x2756, LBP_AL },
+       { 0x2757, 0x2757, LBP_AI },
+       { 0x2758, 0x275A, LBP_AL },
+       { 0x275B, 0x2760, LBP_QU },
+       { 0x2761, 0x2761, LBP_AL },
+       { 0x2762, 0x2763, LBP_EX },
+       { 0x2764, 0x2767, LBP_AL },
+       { 0x2768, 0x2768, LBP_OP },
+       { 0x2769, 0x2769, LBP_CL },
+       { 0x276A, 0x276A, LBP_OP },
+       { 0x276B, 0x276B, LBP_CL },
+       { 0x276C, 0x276C, LBP_OP },
+       { 0x276D, 0x276D, LBP_CL },
+       { 0x276E, 0x276E, LBP_OP },
+       { 0x276F, 0x276F, LBP_CL },
+       { 0x2770, 0x2770, LBP_OP },
+       { 0x2771, 0x2771, LBP_CL },
+       { 0x2772, 0x2772, LBP_OP },
+       { 0x2773, 0x2773, LBP_CL },
+       { 0x2774, 0x2774, LBP_OP },
+       { 0x2775, 0x2775, LBP_CL },
+       { 0x2776, 0x2793, LBP_AI },
+       { 0x2794, 0x27C4, LBP_AL },
+       { 0x27C5, 0x27C5, LBP_OP },
+       { 0x27C6, 0x27C6, LBP_CL },
+       { 0x27C7, 0x27E5, LBP_AL },
+       { 0x27E6, 0x27E6, LBP_OP },
+       { 0x27E7, 0x27E7, LBP_CL },
+       { 0x27E8, 0x27E8, LBP_OP },
+       { 0x27E9, 0x27E9, LBP_CL },
+       { 0x27EA, 0x27EA, LBP_OP },
+       { 0x27EB, 0x27EB, LBP_CL },
+       { 0x27EC, 0x27EC, LBP_OP },
+       { 0x27ED, 0x27ED, LBP_CL },
+       { 0x27EE, 0x27EE, LBP_OP },
+       { 0x27EF, 0x27EF, LBP_CL },
+       { 0x27F0, 0x2982, LBP_AL },
+       { 0x2983, 0x2983, LBP_OP },
+       { 0x2984, 0x2984, LBP_CL },
+       { 0x2985, 0x2985, LBP_OP },
+       { 0x2986, 0x2986, LBP_CL },
+       { 0x2987, 0x2987, LBP_OP },
+       { 0x2988, 0x2988, LBP_CL },
+       { 0x2989, 0x2989, LBP_OP },
+       { 0x298A, 0x298A, LBP_CL },
+       { 0x298B, 0x298B, LBP_OP },
+       { 0x298C, 0x298C, LBP_CL },
+       { 0x298D, 0x298D, LBP_OP },
+       { 0x298E, 0x298E, LBP_CL },
+       { 0x298F, 0x298F, LBP_OP },
+       { 0x2990, 0x2990, LBP_CL },
+       { 0x2991, 0x2991, LBP_OP },
+       { 0x2992, 0x2992, LBP_CL },
+       { 0x2993, 0x2993, LBP_OP },
+       { 0x2994, 0x2994, LBP_CL },
+       { 0x2995, 0x2995, LBP_OP },
+       { 0x2996, 0x2996, LBP_CL },
+       { 0x2997, 0x2997, LBP_OP },
+       { 0x2998, 0x2998, LBP_CL },
+       { 0x2999, 0x29D7, LBP_AL },
+       { 0x29D8, 0x29D8, LBP_OP },
+       { 0x29D9, 0x29D9, LBP_CL },
+       { 0x29DA, 0x29DA, LBP_OP },
+       { 0x29DB, 0x29DB, LBP_CL },
+       { 0x29DC, 0x29FB, LBP_AL },
+       { 0x29FC, 0x29FC, LBP_OP },
+       { 0x29FD, 0x29FD, LBP_CL },
+       { 0x29FE, 0x2B54, LBP_AL },
+       { 0x2B55, 0x2B59, LBP_AI },
+       { 0x2B5A, 0x2CEE, LBP_AL },
+       { 0x2CEF, 0x2CF1, LBP_CM },
+       { 0x2CF2, 0x2CF3, LBP_AL },
+       { 0x2CF9, 0x2CF9, LBP_EX },
+       { 0x2CFA, 0x2CFC, LBP_BA },
+       { 0x2CFD, 0x2CFD, LBP_AL },
+       { 0x2CFE, 0x2CFE, LBP_EX },
+       { 0x2CFF, 0x2CFF, LBP_BA },
+       { 0x2D00, 0x2D6F, LBP_AL },
+       { 0x2D70, 0x2D70, LBP_BA },
+       { 0x2D7F, 0x2D7F, LBP_CM },
+       { 0x2D80, 0x2DDE, LBP_AL },
+       { 0x2DE0, 0x2DFF, LBP_CM },
+       { 0x2E00, 0x2E0D, LBP_QU },
+       { 0x2E0E, 0x2E15, LBP_BA },
+       { 0x2E16, 0x2E16, LBP_AL },
+       { 0x2E17, 0x2E17, LBP_BA },
+       { 0x2E18, 0x2E18, LBP_OP },
+       { 0x2E19, 0x2E19, LBP_BA },
+       { 0x2E1A, 0x2E1B, LBP_AL },
+       { 0x2E1C, 0x2E1D, LBP_QU },
+       { 0x2E1E, 0x2E1F, LBP_AL },
+       { 0x2E20, 0x2E21, LBP_QU },
+       { 0x2E22, 0x2E22, LBP_OP },
+       { 0x2E23, 0x2E23, LBP_CL },
+       { 0x2E24, 0x2E24, LBP_OP },
+       { 0x2E25, 0x2E25, LBP_CL },
+       { 0x2E26, 0x2E26, LBP_OP },
+       { 0x2E27, 0x2E27, LBP_CL },
+       { 0x2E28, 0x2E28, LBP_OP },
+       { 0x2E29, 0x2E29, LBP_CL },
+       { 0x2E2A, 0x2E2D, LBP_BA },
+       { 0x2E2E, 0x2E2E, LBP_EX },
+       { 0x2E2F, 0x2E2F, LBP_AL },
+       { 0x2E30, 0x2E31, LBP_BA },
+       { 0x2E32, 0x2E32, LBP_AL },
+       { 0x2E33, 0x2E34, LBP_BA },
+       { 0x2E35, 0x2E39, LBP_AL },
+       { 0x2E3A, 0x2E3B, LBP_B2 },
+       { 0x2E3C, 0x2E3E, LBP_BA },
+       { 0x2E3F, 0x2E3F, LBP_AL },
+       { 0x2E40, 0x2E41, LBP_BA },
+       { 0x2E42, 0x2E42, LBP_OP },
+       { 0x2E80, 0x2FFB, LBP_ID },
+       { 0x3000, 0x3000, LBP_BA },
+       { 0x3001, 0x3002, LBP_CL },
+       { 0x3003, 0x3004, LBP_ID },
+       { 0x3005, 0x3005, LBP_NS },
+       { 0x3006, 0x3007, LBP_ID },
+       { 0x3008, 0x3008, LBP_OP },
+       { 0x3009, 0x3009, LBP_CL },
+       { 0x300A, 0x300A, LBP_OP },
+       { 0x300B, 0x300B, LBP_CL },
+       { 0x300C, 0x300C, LBP_OP },
+       { 0x300D, 0x300D, LBP_CL },
+       { 0x300E, 0x300E, LBP_OP },
+       { 0x300F, 0x300F, LBP_CL },
+       { 0x3010, 0x3010, LBP_OP },
+       { 0x3011, 0x3011, LBP_CL },
+       { 0x3012, 0x3013, LBP_ID },
+       { 0x3014, 0x3014, LBP_OP },
+       { 0x3015, 0x3015, LBP_CL },
+       { 0x3016, 0x3016, LBP_OP },
+       { 0x3017, 0x3017, LBP_CL },
+       { 0x3018, 0x3018, LBP_OP },
+       { 0x3019, 0x3019, LBP_CL },
+       { 0x301A, 0x301A, LBP_OP },
+       { 0x301B, 0x301B, LBP_CL },
+       { 0x301C, 0x301C, LBP_NS },
+       { 0x301D, 0x301D, LBP_OP },
+       { 0x301E, 0x301F, LBP_CL },
+       { 0x3020, 0x3029, LBP_ID },
+       { 0x302A, 0x302F, LBP_CM },
+       { 0x3030, 0x3034, LBP_ID },
+       { 0x3035, 0x3035, LBP_CM },
+       { 0x3036, 0x303A, LBP_ID },
+       { 0x303B, 0x303C, LBP_NS },
+       { 0x303D, 0x303F, LBP_ID },
+       { 0x3041, 0x3041, LBP_CJ },
+       { 0x3042, 0x3042, LBP_ID },
+       { 0x3043, 0x3043, LBP_CJ },
+       { 0x3044, 0x3044, LBP_ID },
+       { 0x3045, 0x3045, LBP_CJ },
+       { 0x3046, 0x3046, LBP_ID },
+       { 0x3047, 0x3047, LBP_CJ },
+       { 0x3048, 0x3048, LBP_ID },
+       { 0x3049, 0x3049, LBP_CJ },
+       { 0x304A, 0x3062, LBP_ID },
+       { 0x3063, 0x3063, LBP_CJ },
+       { 0x3064, 0x3082, LBP_ID },
+       { 0x3083, 0x3083, LBP_CJ },
+       { 0x3084, 0x3084, LBP_ID },
+       { 0x3085, 0x3085, LBP_CJ },
+       { 0x3086, 0x3086, LBP_ID },
+       { 0x3087, 0x3087, LBP_CJ },
+       { 0x3088, 0x308D, LBP_ID },
+       { 0x308E, 0x308E, LBP_CJ },
+       { 0x308F, 0x3094, LBP_ID },
+       { 0x3095, 0x3096, LBP_CJ },
+       { 0x3099, 0x309A, LBP_CM },
+       { 0x309B, 0x309E, LBP_NS },
+       { 0x309F, 0x309F, LBP_ID },
+       { 0x30A0, 0x30A0, LBP_NS },
+       { 0x30A1, 0x30A1, LBP_CJ },
+       { 0x30A2, 0x30A2, LBP_ID },
+       { 0x30A3, 0x30A3, LBP_CJ },
+       { 0x30A4, 0x30A4, LBP_ID },
+       { 0x30A5, 0x30A5, LBP_CJ },
+       { 0x30A6, 0x30A6, LBP_ID },
+       { 0x30A7, 0x30A7, LBP_CJ },
+       { 0x30A8, 0x30A8, LBP_ID },
+       { 0x30A9, 0x30A9, LBP_CJ },
+       { 0x30AA, 0x30C2, LBP_ID },
+       { 0x30C3, 0x30C3, LBP_CJ },
+       { 0x30C4, 0x30E2, LBP_ID },
+       { 0x30E3, 0x30E3, LBP_CJ },
+       { 0x30E4, 0x30E4, LBP_ID },
+       { 0x30E5, 0x30E5, LBP_CJ },
+       { 0x30E6, 0x30E6, LBP_ID },
+       { 0x30E7, 0x30E7, LBP_CJ },
+       { 0x30E8, 0x30ED, LBP_ID },
+       { 0x30EE, 0x30EE, LBP_CJ },
+       { 0x30EF, 0x30F4, LBP_ID },
+       { 0x30F5, 0x30F6, LBP_CJ },
+       { 0x30F7, 0x30FA, LBP_ID },
+       { 0x30FB, 0x30FB, LBP_NS },
+       { 0x30FC, 0x30FC, LBP_CJ },
+       { 0x30FD, 0x30FE, LBP_NS },
+       { 0x30FF, 0x31E3, LBP_ID },
+       { 0x31F0, 0x31FF, LBP_CJ },
+       { 0x3200, 0x3247, LBP_ID },
+       { 0x3248, 0x324F, LBP_AI },
+       { 0x3250, 0x4DBF, LBP_ID },
+       { 0x4DC0, 0x4DFF, LBP_AL },
+       { 0x4E00, 0xA014, LBP_ID },
+       { 0xA015, 0xA015, LBP_NS },
+       { 0xA016, 0xA4C6, LBP_ID },
+       { 0xA4D0, 0xA4FD, LBP_AL },
+       { 0xA4FE, 0xA4FF, LBP_BA },
+       { 0xA500, 0xA60C, LBP_AL },
+       { 0xA60D, 0xA60D, LBP_BA },
+       { 0xA60E, 0xA60E, LBP_EX },
+       { 0xA60F, 0xA60F, LBP_BA },
+       { 0xA610, 0xA61F, LBP_AL },
+       { 0xA620, 0xA629, LBP_NU },
+       { 0xA62A, 0xA66E, LBP_AL },
+       { 0xA66F, 0xA672, LBP_CM },
+       { 0xA673, 0xA673, LBP_AL },
+       { 0xA674, 0xA67D, LBP_CM },
+       { 0xA67E, 0xA69D, LBP_AL },
+       { 0xA69F, 0xA69F, LBP_CM },
+       { 0xA6A0, 0xA6EF, LBP_AL },
+       { 0xA6F0, 0xA6F1, LBP_CM },
+       { 0xA6F2, 0xA6F2, LBP_AL },
+       { 0xA6F3, 0xA6F7, LBP_BA },
+       { 0xA700, 0xA801, LBP_AL },
+       { 0xA802, 0xA802, LBP_CM },
+       { 0xA803, 0xA805, LBP_AL },
+       { 0xA806, 0xA806, LBP_CM },
+       { 0xA807, 0xA80A, LBP_AL },
+       { 0xA80B, 0xA80B, LBP_CM },
+       { 0xA80C, 0xA822, LBP_AL },
+       { 0xA823, 0xA827, LBP_CM },
+       { 0xA828, 0xA837, LBP_AL },
+       { 0xA838, 0xA838, LBP_PO },
+       { 0xA839, 0xA873, LBP_AL },
+       { 0xA874, 0xA875, LBP_BB },
+       { 0xA876, 0xA877, LBP_EX },
+       { 0xA880, 0xA881, LBP_CM },
+       { 0xA882, 0xA8B3, LBP_AL },
+       { 0xA8B4, 0xA8C4, LBP_CM },
+       { 0xA8CE, 0xA8CF, LBP_BA },
+       { 0xA8D0, 0xA8D9, LBP_NU },
+       { 0xA8E0, 0xA8F1, LBP_CM },
+       { 0xA8F2, 0xA8FB, LBP_AL },
+       { 0xA900, 0xA909, LBP_NU },
+       { 0xA90A, 0xA925, LBP_AL },
+       { 0xA926, 0xA92D, LBP_CM },
+       { 0xA92E, 0xA92F, LBP_BA },
+       { 0xA930, 0xA946, LBP_AL },
+       { 0xA947, 0xA953, LBP_CM },
+       { 0xA95F, 0xA95F, LBP_AL },
+       { 0xA960, 0xA97C, LBP_JL },
+       { 0xA980, 0xA983, LBP_CM },
+       { 0xA984, 0xA9B2, LBP_AL },
+       { 0xA9B3, 0xA9C0, LBP_CM },
+       { 0xA9C1, 0xA9C6, LBP_AL },
+       { 0xA9C7, 0xA9C9, LBP_BA },
+       { 0xA9CA, 0xA9CF, LBP_AL },
+       { 0xA9D0, 0xA9D9, LBP_NU },
+       { 0xA9DE, 0xA9DF, LBP_AL },
+       { 0xA9E0, 0xA9EF, LBP_SA },
+       { 0xA9F0, 0xA9F9, LBP_NU },
+       { 0xA9FA, 0xA9FE, LBP_SA },
+       { 0xAA00, 0xAA28, LBP_AL },
+       { 0xAA29, 0xAA36, LBP_CM },
+       { 0xAA40, 0xAA42, LBP_AL },
+       { 0xAA43, 0xAA43, LBP_CM },
+       { 0xAA44, 0xAA4B, LBP_AL },
+       { 0xAA4C, 0xAA4D, LBP_CM },
+       { 0xAA50, 0xAA59, LBP_NU },
+       { 0xAA5C, 0xAA5C, LBP_AL },
+       { 0xAA5D, 0xAA5F, LBP_BA },
+       { 0xAA60, 0xAADF, LBP_SA },
+       { 0xAAE0, 0xAAEA, LBP_AL },
+       { 0xAAEB, 0xAAEF, LBP_CM },
+       { 0xAAF0, 0xAAF1, LBP_BA },
+       { 0xAAF2, 0xAAF4, LBP_AL },
+       { 0xAAF5, 0xAAF6, LBP_CM },
+       { 0xAB01, 0xABE2, LBP_AL },
+       { 0xABE3, 0xABEA, LBP_CM },
+       { 0xABEB, 0xABEB, LBP_BA },
+       { 0xABEC, 0xABED, LBP_CM },
+       { 0xABF0, 0xABF9, LBP_NU },
+       { 0xAC00, 0xAC00, LBP_H2 },
+       { 0xAC01, 0xAC1B, LBP_H3 },
+       { 0xAC1C, 0xAC1C, LBP_H2 },
+       { 0xAC1D, 0xAC37, LBP_H3 },
+       { 0xAC38, 0xAC38, LBP_H2 },
+       { 0xAC39, 0xAC53, LBP_H3 },
+       { 0xAC54, 0xAC54, LBP_H2 },
+       { 0xAC55, 0xAC6F, LBP_H3 },
+       { 0xAC70, 0xAC70, LBP_H2 },
+       { 0xAC71, 0xAC8B, LBP_H3 },
+       { 0xAC8C, 0xAC8C, LBP_H2 },
+       { 0xAC8D, 0xACA7, LBP_H3 },
+       { 0xACA8, 0xACA8, LBP_H2 },
+       { 0xACA9, 0xACC3, LBP_H3 },
+       { 0xACC4, 0xACC4, LBP_H2 },
+       { 0xACC5, 0xACDF, LBP_H3 },
+       { 0xACE0, 0xACE0, LBP_H2 },
+       { 0xACE1, 0xACFB, LBP_H3 },
+       { 0xACFC, 0xACFC, LBP_H2 },
+       { 0xACFD, 0xAD17, LBP_H3 },
+       { 0xAD18, 0xAD18, LBP_H2 },
+       { 0xAD19, 0xAD33, LBP_H3 },
+       { 0xAD34, 0xAD34, LBP_H2 },
+       { 0xAD35, 0xAD4F, LBP_H3 },
+       { 0xAD50, 0xAD50, LBP_H2 },
+       { 0xAD51, 0xAD6B, LBP_H3 },
+       { 0xAD6C, 0xAD6C, LBP_H2 },
+       { 0xAD6D, 0xAD87, LBP_H3 },
+       { 0xAD88, 0xAD88, LBP_H2 },
+       { 0xAD89, 0xADA3, LBP_H3 },
+       { 0xADA4, 0xADA4, LBP_H2 },
+       { 0xADA5, 0xADBF, LBP_H3 },
+       { 0xADC0, 0xADC0, LBP_H2 },
+       { 0xADC1, 0xADDB, LBP_H3 },
+       { 0xADDC, 0xADDC, LBP_H2 },
+       { 0xADDD, 0xADF7, LBP_H3 },
+       { 0xADF8, 0xADF8, LBP_H2 },
+       { 0xADF9, 0xAE13, LBP_H3 },
+       { 0xAE14, 0xAE14, LBP_H2 },
+       { 0xAE15, 0xAE2F, LBP_H3 },
+       { 0xAE30, 0xAE30, LBP_H2 },
+       { 0xAE31, 0xAE4B, LBP_H3 },
+       { 0xAE4C, 0xAE4C, LBP_H2 },
+       { 0xAE4D, 0xAE67, LBP_H3 },
+       { 0xAE68, 0xAE68, LBP_H2 },
+       { 0xAE69, 0xAE83, LBP_H3 },
+       { 0xAE84, 0xAE84, LBP_H2 },
+       { 0xAE85, 0xAE9F, LBP_H3 },
+       { 0xAEA0, 0xAEA0, LBP_H2 },
+       { 0xAEA1, 0xAEBB, LBP_H3 },
+       { 0xAEBC, 0xAEBC, LBP_H2 },
+       { 0xAEBD, 0xAED7, LBP_H3 },
+       { 0xAED8, 0xAED8, LBP_H2 },
+       { 0xAED9, 0xAEF3, LBP_H3 },
+       { 0xAEF4, 0xAEF4, LBP_H2 },
+       { 0xAEF5, 0xAF0F, LBP_H3 },
+       { 0xAF10, 0xAF10, LBP_H2 },
+       { 0xAF11, 0xAF2B, LBP_H3 },
+       { 0xAF2C, 0xAF2C, LBP_H2 },
+       { 0xAF2D, 0xAF47, LBP_H3 },
+       { 0xAF48, 0xAF48, LBP_H2 },
+       { 0xAF49, 0xAF63, LBP_H3 },
+       { 0xAF64, 0xAF64, LBP_H2 },
+       { 0xAF65, 0xAF7F, LBP_H3 },
+       { 0xAF80, 0xAF80, LBP_H2 },
+       { 0xAF81, 0xAF9B, LBP_H3 },
+       { 0xAF9C, 0xAF9C, LBP_H2 },
+       { 0xAF9D, 0xAFB7, LBP_H3 },
+       { 0xAFB8, 0xAFB8, LBP_H2 },
+       { 0xAFB9, 0xAFD3, LBP_H3 },
+       { 0xAFD4, 0xAFD4, LBP_H2 },
+       { 0xAFD5, 0xAFEF, LBP_H3 },
+       { 0xAFF0, 0xAFF0, LBP_H2 },
+       { 0xAFF1, 0xB00B, LBP_H3 },
+       { 0xB00C, 0xB00C, LBP_H2 },
+       { 0xB00D, 0xB027, LBP_H3 },
+       { 0xB028, 0xB028, LBP_H2 },
+       { 0xB029, 0xB043, LBP_H3 },
+       { 0xB044, 0xB044, LBP_H2 },
+       { 0xB045, 0xB05F, LBP_H3 },
+       { 0xB060, 0xB060, LBP_H2 },
+       { 0xB061, 0xB07B, LBP_H3 },
+       { 0xB07C, 0xB07C, LBP_H2 },
+       { 0xB07D, 0xB097, LBP_H3 },
+       { 0xB098, 0xB098, LBP_H2 },
+       { 0xB099, 0xB0B3, LBP_H3 },
+       { 0xB0B4, 0xB0B4, LBP_H2 },
+       { 0xB0B5, 0xB0CF, LBP_H3 },
+       { 0xB0D0, 0xB0D0, LBP_H2 },
+       { 0xB0D1, 0xB0EB, LBP_H3 },
+       { 0xB0EC, 0xB0EC, LBP_H2 },
+       { 0xB0ED, 0xB107, LBP_H3 },
+       { 0xB108, 0xB108, LBP_H2 },
+       { 0xB109, 0xB123, LBP_H3 },
+       { 0xB124, 0xB124, LBP_H2 },
+       { 0xB125, 0xB13F, LBP_H3 },
+       { 0xB140, 0xB140, LBP_H2 },
+       { 0xB141, 0xB15B, LBP_H3 },
+       { 0xB15C, 0xB15C, LBP_H2 },
+       { 0xB15D, 0xB177, LBP_H3 },
+       { 0xB178, 0xB178, LBP_H2 },
+       { 0xB179, 0xB193, LBP_H3 },
+       { 0xB194, 0xB194, LBP_H2 },
+       { 0xB195, 0xB1AF, LBP_H3 },
+       { 0xB1B0, 0xB1B0, LBP_H2 },
+       { 0xB1B1, 0xB1CB, LBP_H3 },
+       { 0xB1CC, 0xB1CC, LBP_H2 },
+       { 0xB1CD, 0xB1E7, LBP_H3 },
+       { 0xB1E8, 0xB1E8, LBP_H2 },
+       { 0xB1E9, 0xB203, LBP_H3 },
+       { 0xB204, 0xB204, LBP_H2 },
+       { 0xB205, 0xB21F, LBP_H3 },
+       { 0xB220, 0xB220, LBP_H2 },
+       { 0xB221, 0xB23B, LBP_H3 },
+       { 0xB23C, 0xB23C, LBP_H2 },
+       { 0xB23D, 0xB257, LBP_H3 },
+       { 0xB258, 0xB258, LBP_H2 },
+       { 0xB259, 0xB273, LBP_H3 },
+       { 0xB274, 0xB274, LBP_H2 },
+       { 0xB275, 0xB28F, LBP_H3 },
+       { 0xB290, 0xB290, LBP_H2 },
+       { 0xB291, 0xB2AB, LBP_H3 },
+       { 0xB2AC, 0xB2AC, LBP_H2 },
+       { 0xB2AD, 0xB2C7, LBP_H3 },
+       { 0xB2C8, 0xB2C8, LBP_H2 },
+       { 0xB2C9, 0xB2E3, LBP_H3 },
+       { 0xB2E4, 0xB2E4, LBP_H2 },
+       { 0xB2E5, 0xB2FF, LBP_H3 },
+       { 0xB300, 0xB300, LBP_H2 },
+       { 0xB301, 0xB31B, LBP_H3 },
+       { 0xB31C, 0xB31C, LBP_H2 },
+       { 0xB31D, 0xB337, LBP_H3 },
+       { 0xB338, 0xB338, LBP_H2 },
+       { 0xB339, 0xB353, LBP_H3 },
+       { 0xB354, 0xB354, LBP_H2 },
+       { 0xB355, 0xB36F, LBP_H3 },
+       { 0xB370, 0xB370, LBP_H2 },
+       { 0xB371, 0xB38B, LBP_H3 },
+       { 0xB38C, 0xB38C, LBP_H2 },
+       { 0xB38D, 0xB3A7, LBP_H3 },
+       { 0xB3A8, 0xB3A8, LBP_H2 },
+       { 0xB3A9, 0xB3C3, LBP_H3 },
+       { 0xB3C4, 0xB3C4, LBP_H2 },
+       { 0xB3C5, 0xB3DF, LBP_H3 },
+       { 0xB3E0, 0xB3E0, LBP_H2 },
+       { 0xB3E1, 0xB3FB, LBP_H3 },
+       { 0xB3FC, 0xB3FC, LBP_H2 },
+       { 0xB3FD, 0xB417, LBP_H3 },
+       { 0xB418, 0xB418, LBP_H2 },
+       { 0xB419, 0xB433, LBP_H3 },
+       { 0xB434, 0xB434, LBP_H2 },
+       { 0xB435, 0xB44F, LBP_H3 },
+       { 0xB450, 0xB450, LBP_H2 },
+       { 0xB451, 0xB46B, LBP_H3 },
+       { 0xB46C, 0xB46C, LBP_H2 },
+       { 0xB46D, 0xB487, LBP_H3 },
+       { 0xB488, 0xB488, LBP_H2 },
+       { 0xB489, 0xB4A3, LBP_H3 },
+       { 0xB4A4, 0xB4A4, LBP_H2 },
+       { 0xB4A5, 0xB4BF, LBP_H3 },
+       { 0xB4C0, 0xB4C0, LBP_H2 },
+       { 0xB4C1, 0xB4DB, LBP_H3 },
+       { 0xB4DC, 0xB4DC, LBP_H2 },
+       { 0xB4DD, 0xB4F7, LBP_H3 },
+       { 0xB4F8, 0xB4F8, LBP_H2 },
+       { 0xB4F9, 0xB513, LBP_H3 },
+       { 0xB514, 0xB514, LBP_H2 },
+       { 0xB515, 0xB52F, LBP_H3 },
+       { 0xB530, 0xB530, LBP_H2 },
+       { 0xB531, 0xB54B, LBP_H3 },
+       { 0xB54C, 0xB54C, LBP_H2 },
+       { 0xB54D, 0xB567, LBP_H3 },
+       { 0xB568, 0xB568, LBP_H2 },
+       { 0xB569, 0xB583, LBP_H3 },
+       { 0xB584, 0xB584, LBP_H2 },
+       { 0xB585, 0xB59F, LBP_H3 },
+       { 0xB5A0, 0xB5A0, LBP_H2 },
+       { 0xB5A1, 0xB5BB, LBP_H3 },
+       { 0xB5BC, 0xB5BC, LBP_H2 },
+       { 0xB5BD, 0xB5D7, LBP_H3 },
+       { 0xB5D8, 0xB5D8, LBP_H2 },
+       { 0xB5D9, 0xB5F3, LBP_H3 },
+       { 0xB5F4, 0xB5F4, LBP_H2 },
+       { 0xB5F5, 0xB60F, LBP_H3 },
+       { 0xB610, 0xB610, LBP_H2 },
+       { 0xB611, 0xB62B, LBP_H3 },
+       { 0xB62C, 0xB62C, LBP_H2 },
+       { 0xB62D, 0xB647, LBP_H3 },
+       { 0xB648, 0xB648, LBP_H2 },
+       { 0xB649, 0xB663, LBP_H3 },
+       { 0xB664, 0xB664, LBP_H2 },
+       { 0xB665, 0xB67F, LBP_H3 },
+       { 0xB680, 0xB680, LBP_H2 },
+       { 0xB681, 0xB69B, LBP_H3 },
+       { 0xB69C, 0xB69C, LBP_H2 },
+       { 0xB69D, 0xB6B7, LBP_H3 },
+       { 0xB6B8, 0xB6B8, LBP_H2 },
+       { 0xB6B9, 0xB6D3, LBP_H3 },
+       { 0xB6D4, 0xB6D4, LBP_H2 },
+       { 0xB6D5, 0xB6EF, LBP_H3 },
+       { 0xB6F0, 0xB6F0, LBP_H2 },
+       { 0xB6F1, 0xB70B, LBP_H3 },
+       { 0xB70C, 0xB70C, LBP_H2 },
+       { 0xB70D, 0xB727, LBP_H3 },
+       { 0xB728, 0xB728, LBP_H2 },
+       { 0xB729, 0xB743, LBP_H3 },
+       { 0xB744, 0xB744, LBP_H2 },
+       { 0xB745, 0xB75F, LBP_H3 },
+       { 0xB760, 0xB760, LBP_H2 },
+       { 0xB761, 0xB77B, LBP_H3 },
+       { 0xB77C, 0xB77C, LBP_H2 },
+       { 0xB77D, 0xB797, LBP_H3 },
+       { 0xB798, 0xB798, LBP_H2 },
+       { 0xB799, 0xB7B3, LBP_H3 },
+       { 0xB7B4, 0xB7B4, LBP_H2 },
+       { 0xB7B5, 0xB7CF, LBP_H3 },
+       { 0xB7D0, 0xB7D0, LBP_H2 },
+       { 0xB7D1, 0xB7EB, LBP_H3 },
+       { 0xB7EC, 0xB7EC, LBP_H2 },
+       { 0xB7ED, 0xB807, LBP_H3 },
+       { 0xB808, 0xB808, LBP_H2 },
+       { 0xB809, 0xB823, LBP_H3 },
+       { 0xB824, 0xB824, LBP_H2 },
+       { 0xB825, 0xB83F, LBP_H3 },
+       { 0xB840, 0xB840, LBP_H2 },
+       { 0xB841, 0xB85B, LBP_H3 },
+       { 0xB85C, 0xB85C, LBP_H2 },
+       { 0xB85D, 0xB877, LBP_H3 },
+       { 0xB878, 0xB878, LBP_H2 },
+       { 0xB879, 0xB893, LBP_H3 },
+       { 0xB894, 0xB894, LBP_H2 },
+       { 0xB895, 0xB8AF, LBP_H3 },
+       { 0xB8B0, 0xB8B0, LBP_H2 },
+       { 0xB8B1, 0xB8CB, LBP_H3 },
+       { 0xB8CC, 0xB8CC, LBP_H2 },
+       { 0xB8CD, 0xB8E7, LBP_H3 },
+       { 0xB8E8, 0xB8E8, LBP_H2 },
+       { 0xB8E9, 0xB903, LBP_H3 },
+       { 0xB904, 0xB904, LBP_H2 },
+       { 0xB905, 0xB91F, LBP_H3 },
+       { 0xB920, 0xB920, LBP_H2 },
+       { 0xB921, 0xB93B, LBP_H3 },
+       { 0xB93C, 0xB93C, LBP_H2 },
+       { 0xB93D, 0xB957, LBP_H3 },
+       { 0xB958, 0xB958, LBP_H2 },
+       { 0xB959, 0xB973, LBP_H3 },
+       { 0xB974, 0xB974, LBP_H2 },
+       { 0xB975, 0xB98F, LBP_H3 },
+       { 0xB990, 0xB990, LBP_H2 },
+       { 0xB991, 0xB9AB, LBP_H3 },
+       { 0xB9AC, 0xB9AC, LBP_H2 },
+       { 0xB9AD, 0xB9C7, LBP_H3 },
+       { 0xB9C8, 0xB9C8, LBP_H2 },
+       { 0xB9C9, 0xB9E3, LBP_H3 },
+       { 0xB9E4, 0xB9E4, LBP_H2 },
+       { 0xB9E5, 0xB9FF, LBP_H3 },
+       { 0xBA00, 0xBA00, LBP_H2 },
+       { 0xBA01, 0xBA1B, LBP_H3 },
+       { 0xBA1C, 0xBA1C, LBP_H2 },
+       { 0xBA1D, 0xBA37, LBP_H3 },
+       { 0xBA38, 0xBA38, LBP_H2 },
+       { 0xBA39, 0xBA53, LBP_H3 },
+       { 0xBA54, 0xBA54, LBP_H2 },
+       { 0xBA55, 0xBA6F, LBP_H3 },
+       { 0xBA70, 0xBA70, LBP_H2 },
+       { 0xBA71, 0xBA8B, LBP_H3 },
+       { 0xBA8C, 0xBA8C, LBP_H2 },
+       { 0xBA8D, 0xBAA7, LBP_H3 },
+       { 0xBAA8, 0xBAA8, LBP_H2 },
+       { 0xBAA9, 0xBAC3, LBP_H3 },
+       { 0xBAC4, 0xBAC4, LBP_H2 },
+       { 0xBAC5, 0xBADF, LBP_H3 },
+       { 0xBAE0, 0xBAE0, LBP_H2 },
+       { 0xBAE1, 0xBAFB, LBP_H3 },
+       { 0xBAFC, 0xBAFC, LBP_H2 },
+       { 0xBAFD, 0xBB17, LBP_H3 },
+       { 0xBB18, 0xBB18, LBP_H2 },
+       { 0xBB19, 0xBB33, LBP_H3 },
+       { 0xBB34, 0xBB34, LBP_H2 },
+       { 0xBB35, 0xBB4F, LBP_H3 },
+       { 0xBB50, 0xBB50, LBP_H2 },
+       { 0xBB51, 0xBB6B, LBP_H3 },
+       { 0xBB6C, 0xBB6C, LBP_H2 },
+       { 0xBB6D, 0xBB87, LBP_H3 },
+       { 0xBB88, 0xBB88, LBP_H2 },
+       { 0xBB89, 0xBBA3, LBP_H3 },
+       { 0xBBA4, 0xBBA4, LBP_H2 },
+       { 0xBBA5, 0xBBBF, LBP_H3 },
+       { 0xBBC0, 0xBBC0, LBP_H2 },
+       { 0xBBC1, 0xBBDB, LBP_H3 },
+       { 0xBBDC, 0xBBDC, LBP_H2 },
+       { 0xBBDD, 0xBBF7, LBP_H3 },
+       { 0xBBF8, 0xBBF8, LBP_H2 },
+       { 0xBBF9, 0xBC13, LBP_H3 },
+       { 0xBC14, 0xBC14, LBP_H2 },
+       { 0xBC15, 0xBC2F, LBP_H3 },
+       { 0xBC30, 0xBC30, LBP_H2 },
+       { 0xBC31, 0xBC4B, LBP_H3 },
+       { 0xBC4C, 0xBC4C, LBP_H2 },
+       { 0xBC4D, 0xBC67, LBP_H3 },
+       { 0xBC68, 0xBC68, LBP_H2 },
+       { 0xBC69, 0xBC83, LBP_H3 },
+       { 0xBC84, 0xBC84, LBP_H2 },
+       { 0xBC85, 0xBC9F, LBP_H3 },
+       { 0xBCA0, 0xBCA0, LBP_H2 },
+       { 0xBCA1, 0xBCBB, LBP_H3 },
+       { 0xBCBC, 0xBCBC, LBP_H2 },
+       { 0xBCBD, 0xBCD7, LBP_H3 },
+       { 0xBCD8, 0xBCD8, LBP_H2 },
+       { 0xBCD9, 0xBCF3, LBP_H3 },
+       { 0xBCF4, 0xBCF4, LBP_H2 },
+       { 0xBCF5, 0xBD0F, LBP_H3 },
+       { 0xBD10, 0xBD10, LBP_H2 },
+       { 0xBD11, 0xBD2B, LBP_H3 },
+       { 0xBD2C, 0xBD2C, LBP_H2 },
+       { 0xBD2D, 0xBD47, LBP_H3 },
+       { 0xBD48, 0xBD48, LBP_H2 },
+       { 0xBD49, 0xBD63, LBP_H3 },
+       { 0xBD64, 0xBD64, LBP_H2 },
+       { 0xBD65, 0xBD7F, LBP_H3 },
+       { 0xBD80, 0xBD80, LBP_H2 },
+       { 0xBD81, 0xBD9B, LBP_H3 },
+       { 0xBD9C, 0xBD9C, LBP_H2 },
+       { 0xBD9D, 0xBDB7, LBP_H3 },
+       { 0xBDB8, 0xBDB8, LBP_H2 },
+       { 0xBDB9, 0xBDD3, LBP_H3 },
+       { 0xBDD4, 0xBDD4, LBP_H2 },
+       { 0xBDD5, 0xBDEF, LBP_H3 },
+       { 0xBDF0, 0xBDF0, LBP_H2 },
+       { 0xBDF1, 0xBE0B, LBP_H3 },
+       { 0xBE0C, 0xBE0C, LBP_H2 },
+       { 0xBE0D, 0xBE27, LBP_H3 },
+       { 0xBE28, 0xBE28, LBP_H2 },
+       { 0xBE29, 0xBE43, LBP_H3 },
+       { 0xBE44, 0xBE44, LBP_H2 },
+       { 0xBE45, 0xBE5F, LBP_H3 },
+       { 0xBE60, 0xBE60, LBP_H2 },
+       { 0xBE61, 0xBE7B, LBP_H3 },
+       { 0xBE7C, 0xBE7C, LBP_H2 },
+       { 0xBE7D, 0xBE97, LBP_H3 },
+       { 0xBE98, 0xBE98, LBP_H2 },
+       { 0xBE99, 0xBEB3, LBP_H3 },
+       { 0xBEB4, 0xBEB4, LBP_H2 },
+       { 0xBEB5, 0xBECF, LBP_H3 },
+       { 0xBED0, 0xBED0, LBP_H2 },
+       { 0xBED1, 0xBEEB, LBP_H3 },
+       { 0xBEEC, 0xBEEC, LBP_H2 },
+       { 0xBEED, 0xBF07, LBP_H3 },
+       { 0xBF08, 0xBF08, LBP_H2 },
+       { 0xBF09, 0xBF23, LBP_H3 },
+       { 0xBF24, 0xBF24, LBP_H2 },
+       { 0xBF25, 0xBF3F, LBP_H3 },
+       { 0xBF40, 0xBF40, LBP_H2 },
+       { 0xBF41, 0xBF5B, LBP_H3 },
+       { 0xBF5C, 0xBF5C, LBP_H2 },
+       { 0xBF5D, 0xBF77, LBP_H3 },
+       { 0xBF78, 0xBF78, LBP_H2 },
+       { 0xBF79, 0xBF93, LBP_H3 },
+       { 0xBF94, 0xBF94, LBP_H2 },
+       { 0xBF95, 0xBFAF, LBP_H3 },
+       { 0xBFB0, 0xBFB0, LBP_H2 },
+       { 0xBFB1, 0xBFCB, LBP_H3 },
+       { 0xBFCC, 0xBFCC, LBP_H2 },
+       { 0xBFCD, 0xBFE7, LBP_H3 },
+       { 0xBFE8, 0xBFE8, LBP_H2 },
+       { 0xBFE9, 0xC003, LBP_H3 },
+       { 0xC004, 0xC004, LBP_H2 },
+       { 0xC005, 0xC01F, LBP_H3 },
+       { 0xC020, 0xC020, LBP_H2 },
+       { 0xC021, 0xC03B, LBP_H3 },
+       { 0xC03C, 0xC03C, LBP_H2 },
+       { 0xC03D, 0xC057, LBP_H3 },
+       { 0xC058, 0xC058, LBP_H2 },
+       { 0xC059, 0xC073, LBP_H3 },
+       { 0xC074, 0xC074, LBP_H2 },
+       { 0xC075, 0xC08F, LBP_H3 },
+       { 0xC090, 0xC090, LBP_H2 },
+       { 0xC091, 0xC0AB, LBP_H3 },
+       { 0xC0AC, 0xC0AC, LBP_H2 },
+       { 0xC0AD, 0xC0C7, LBP_H3 },
+       { 0xC0C8, 0xC0C8, LBP_H2 },
+       { 0xC0C9, 0xC0E3, LBP_H3 },
+       { 0xC0E4, 0xC0E4, LBP_H2 },
+       { 0xC0E5, 0xC0FF, LBP_H3 },
+       { 0xC100, 0xC100, LBP_H2 },
+       { 0xC101, 0xC11B, LBP_H3 },
+       { 0xC11C, 0xC11C, LBP_H2 },
+       { 0xC11D, 0xC137, LBP_H3 },
+       { 0xC138, 0xC138, LBP_H2 },
+       { 0xC139, 0xC153, LBP_H3 },
+       { 0xC154, 0xC154, LBP_H2 },
+       { 0xC155, 0xC16F, LBP_H3 },
+       { 0xC170, 0xC170, LBP_H2 },
+       { 0xC171, 0xC18B, LBP_H3 },
+       { 0xC18C, 0xC18C, LBP_H2 },
+       { 0xC18D, 0xC1A7, LBP_H3 },
+       { 0xC1A8, 0xC1A8, LBP_H2 },
+       { 0xC1A9, 0xC1C3, LBP_H3 },
+       { 0xC1C4, 0xC1C4, LBP_H2 },
+       { 0xC1C5, 0xC1DF, LBP_H3 },
+       { 0xC1E0, 0xC1E0, LBP_H2 },
+       { 0xC1E1, 0xC1FB, LBP_H3 },
+       { 0xC1FC, 0xC1FC, LBP_H2 },
+       { 0xC1FD, 0xC217, LBP_H3 },
+       { 0xC218, 0xC218, LBP_H2 },
+       { 0xC219, 0xC233, LBP_H3 },
+       { 0xC234, 0xC234, LBP_H2 },
+       { 0xC235, 0xC24F, LBP_H3 },
+       { 0xC250, 0xC250, LBP_H2 },
+       { 0xC251, 0xC26B, LBP_H3 },
+       { 0xC26C, 0xC26C, LBP_H2 },
+       { 0xC26D, 0xC287, LBP_H3 },
+       { 0xC288, 0xC288, LBP_H2 },
+       { 0xC289, 0xC2A3, LBP_H3 },
+       { 0xC2A4, 0xC2A4, LBP_H2 },
+       { 0xC2A5, 0xC2BF, LBP_H3 },
+       { 0xC2C0, 0xC2C0, LBP_H2 },
+       { 0xC2C1, 0xC2DB, LBP_H3 },
+       { 0xC2DC, 0xC2DC, LBP_H2 },
+       { 0xC2DD, 0xC2F7, LBP_H3 },
+       { 0xC2F8, 0xC2F8, LBP_H2 },
+       { 0xC2F9, 0xC313, LBP_H3 },
+       { 0xC314, 0xC314, LBP_H2 },
+       { 0xC315, 0xC32F, LBP_H3 },
+       { 0xC330, 0xC330, LBP_H2 },
+       { 0xC331, 0xC34B, LBP_H3 },
+       { 0xC34C, 0xC34C, LBP_H2 },
+       { 0xC34D, 0xC367, LBP_H3 },
+       { 0xC368, 0xC368, LBP_H2 },
+       { 0xC369, 0xC383, LBP_H3 },
+       { 0xC384, 0xC384, LBP_H2 },
+       { 0xC385, 0xC39F, LBP_H3 },
+       { 0xC3A0, 0xC3A0, LBP_H2 },
+       { 0xC3A1, 0xC3BB, LBP_H3 },
+       { 0xC3BC, 0xC3BC, LBP_H2 },
+       { 0xC3BD, 0xC3D7, LBP_H3 },
+       { 0xC3D8, 0xC3D8, LBP_H2 },
+       { 0xC3D9, 0xC3F3, LBP_H3 },
+       { 0xC3F4, 0xC3F4, LBP_H2 },
+       { 0xC3F5, 0xC40F, LBP_H3 },
+       { 0xC410, 0xC410, LBP_H2 },
+       { 0xC411, 0xC42B, LBP_H3 },
+       { 0xC42C, 0xC42C, LBP_H2 },
+       { 0xC42D, 0xC447, LBP_H3 },
+       { 0xC448, 0xC448, LBP_H2 },
+       { 0xC449, 0xC463, LBP_H3 },
+       { 0xC464, 0xC464, LBP_H2 },
+       { 0xC465, 0xC47F, LBP_H3 },
+       { 0xC480, 0xC480, LBP_H2 },
+       { 0xC481, 0xC49B, LBP_H3 },
+       { 0xC49C, 0xC49C, LBP_H2 },
+       { 0xC49D, 0xC4B7, LBP_H3 },
+       { 0xC4B8, 0xC4B8, LBP_H2 },
+       { 0xC4B9, 0xC4D3, LBP_H3 },
+       { 0xC4D4, 0xC4D4, LBP_H2 },
+       { 0xC4D5, 0xC4EF, LBP_H3 },
+       { 0xC4F0, 0xC4F0, LBP_H2 },
+       { 0xC4F1, 0xC50B, LBP_H3 },
+       { 0xC50C, 0xC50C, LBP_H2 },
+       { 0xC50D, 0xC527, LBP_H3 },
+       { 0xC528, 0xC528, LBP_H2 },
+       { 0xC529, 0xC543, LBP_H3 },
+       { 0xC544, 0xC544, LBP_H2 },
+       { 0xC545, 0xC55F, LBP_H3 },
+       { 0xC560, 0xC560, LBP_H2 },
+       { 0xC561, 0xC57B, LBP_H3 },
+       { 0xC57C, 0xC57C, LBP_H2 },
+       { 0xC57D, 0xC597, LBP_H3 },
+       { 0xC598, 0xC598, LBP_H2 },
+       { 0xC599, 0xC5B3, LBP_H3 },
+       { 0xC5B4, 0xC5B4, LBP_H2 },
+       { 0xC5B5, 0xC5CF, LBP_H3 },
+       { 0xC5D0, 0xC5D0, LBP_H2 },
+       { 0xC5D1, 0xC5EB, LBP_H3 },
+       { 0xC5EC, 0xC5EC, LBP_H2 },
+       { 0xC5ED, 0xC607, LBP_H3 },
+       { 0xC608, 0xC608, LBP_H2 },
+       { 0xC609, 0xC623, LBP_H3 },
+       { 0xC624, 0xC624, LBP_H2 },
+       { 0xC625, 0xC63F, LBP_H3 },
+       { 0xC640, 0xC640, LBP_H2 },
+       { 0xC641, 0xC65B, LBP_H3 },
+       { 0xC65C, 0xC65C, LBP_H2 },
+       { 0xC65D, 0xC677, LBP_H3 },
+       { 0xC678, 0xC678, LBP_H2 },
+       { 0xC679, 0xC693, LBP_H3 },
+       { 0xC694, 0xC694, LBP_H2 },
+       { 0xC695, 0xC6AF, LBP_H3 },
+       { 0xC6B0, 0xC6B0, LBP_H2 },
+       { 0xC6B1, 0xC6CB, LBP_H3 },
+       { 0xC6CC, 0xC6CC, LBP_H2 },
+       { 0xC6CD, 0xC6E7, LBP_H3 },
+       { 0xC6E8, 0xC6E8, LBP_H2 },
+       { 0xC6E9, 0xC703, LBP_H3 },
+       { 0xC704, 0xC704, LBP_H2 },
+       { 0xC705, 0xC71F, LBP_H3 },
+       { 0xC720, 0xC720, LBP_H2 },
+       { 0xC721, 0xC73B, LBP_H3 },
+       { 0xC73C, 0xC73C, LBP_H2 },
+       { 0xC73D, 0xC757, LBP_H3 },
+       { 0xC758, 0xC758, LBP_H2 },
+       { 0xC759, 0xC773, LBP_H3 },
+       { 0xC774, 0xC774, LBP_H2 },
+       { 0xC775, 0xC78F, LBP_H3 },
+       { 0xC790, 0xC790, LBP_H2 },
+       { 0xC791, 0xC7AB, LBP_H3 },
+       { 0xC7AC, 0xC7AC, LBP_H2 },
+       { 0xC7AD, 0xC7C7, LBP_H3 },
+       { 0xC7C8, 0xC7C8, LBP_H2 },
+       { 0xC7C9, 0xC7E3, LBP_H3 },
+       { 0xC7E4, 0xC7E4, LBP_H2 },
+       { 0xC7E5, 0xC7FF, LBP_H3 },
+       { 0xC800, 0xC800, LBP_H2 },
+       { 0xC801, 0xC81B, LBP_H3 },
+       { 0xC81C, 0xC81C, LBP_H2 },
+       { 0xC81D, 0xC837, LBP_H3 },
+       { 0xC838, 0xC838, LBP_H2 },
+       { 0xC839, 0xC853, LBP_H3 },
+       { 0xC854, 0xC854, LBP_H2 },
+       { 0xC855, 0xC86F, LBP_H3 },
+       { 0xC870, 0xC870, LBP_H2 },
+       { 0xC871, 0xC88B, LBP_H3 },
+       { 0xC88C, 0xC88C, LBP_H2 },
+       { 0xC88D, 0xC8A7, LBP_H3 },
+       { 0xC8A8, 0xC8A8, LBP_H2 },
+       { 0xC8A9, 0xC8C3, LBP_H3 },
+       { 0xC8C4, 0xC8C4, LBP_H2 },
+       { 0xC8C5, 0xC8DF, LBP_H3 },
+       { 0xC8E0, 0xC8E0, LBP_H2 },
+       { 0xC8E1, 0xC8FB, LBP_H3 },
+       { 0xC8FC, 0xC8FC, LBP_H2 },
+       { 0xC8FD, 0xC917, LBP_H3 },
+       { 0xC918, 0xC918, LBP_H2 },
+       { 0xC919, 0xC933, LBP_H3 },
+       { 0xC934, 0xC934, LBP_H2 },
+       { 0xC935, 0xC94F, LBP_H3 },
+       { 0xC950, 0xC950, LBP_H2 },
+       { 0xC951, 0xC96B, LBP_H3 },
+       { 0xC96C, 0xC96C, LBP_H2 },
+       { 0xC96D, 0xC987, LBP_H3 },
+       { 0xC988, 0xC988, LBP_H2 },
+       { 0xC989, 0xC9A3, LBP_H3 },
+       { 0xC9A4, 0xC9A4, LBP_H2 },
+       { 0xC9A5, 0xC9BF, LBP_H3 },
+       { 0xC9C0, 0xC9C0, LBP_H2 },
+       { 0xC9C1, 0xC9DB, LBP_H3 },
+       { 0xC9DC, 0xC9DC, LBP_H2 },
+       { 0xC9DD, 0xC9F7, LBP_H3 },
+       { 0xC9F8, 0xC9F8, LBP_H2 },
+       { 0xC9F9, 0xCA13, LBP_H3 },
+       { 0xCA14, 0xCA14, LBP_H2 },
+       { 0xCA15, 0xCA2F, LBP_H3 },
+       { 0xCA30, 0xCA30, LBP_H2 },
+       { 0xCA31, 0xCA4B, LBP_H3 },
+       { 0xCA4C, 0xCA4C, LBP_H2 },
+       { 0xCA4D, 0xCA67, LBP_H3 },
+       { 0xCA68, 0xCA68, LBP_H2 },
+       { 0xCA69, 0xCA83, LBP_H3 },
+       { 0xCA84, 0xCA84, LBP_H2 },
+       { 0xCA85, 0xCA9F, LBP_H3 },
+       { 0xCAA0, 0xCAA0, LBP_H2 },
+       { 0xCAA1, 0xCABB, LBP_H3 },
+       { 0xCABC, 0xCABC, LBP_H2 },
+       { 0xCABD, 0xCAD7, LBP_H3 },
+       { 0xCAD8, 0xCAD8, LBP_H2 },
+       { 0xCAD9, 0xCAF3, LBP_H3 },
+       { 0xCAF4, 0xCAF4, LBP_H2 },
+       { 0xCAF5, 0xCB0F, LBP_H3 },
+       { 0xCB10, 0xCB10, LBP_H2 },
+       { 0xCB11, 0xCB2B, LBP_H3 },
+       { 0xCB2C, 0xCB2C, LBP_H2 },
+       { 0xCB2D, 0xCB47, LBP_H3 },
+       { 0xCB48, 0xCB48, LBP_H2 },
+       { 0xCB49, 0xCB63, LBP_H3 },
+       { 0xCB64, 0xCB64, LBP_H2 },
+       { 0xCB65, 0xCB7F, LBP_H3 },
+       { 0xCB80, 0xCB80, LBP_H2 },
+       { 0xCB81, 0xCB9B, LBP_H3 },
+       { 0xCB9C, 0xCB9C, LBP_H2 },
+       { 0xCB9D, 0xCBB7, LBP_H3 },
+       { 0xCBB8, 0xCBB8, LBP_H2 },
+       { 0xCBB9, 0xCBD3, LBP_H3 },
+       { 0xCBD4, 0xCBD4, LBP_H2 },
+       { 0xCBD5, 0xCBEF, LBP_H3 },
+       { 0xCBF0, 0xCBF0, LBP_H2 },
+       { 0xCBF1, 0xCC0B, LBP_H3 },
+       { 0xCC0C, 0xCC0C, LBP_H2 },
+       { 0xCC0D, 0xCC27, LBP_H3 },
+       { 0xCC28, 0xCC28, LBP_H2 },
+       { 0xCC29, 0xCC43, LBP_H3 },
+       { 0xCC44, 0xCC44, LBP_H2 },
+       { 0xCC45, 0xCC5F, LBP_H3 },
+       { 0xCC60, 0xCC60, LBP_H2 },
+       { 0xCC61, 0xCC7B, LBP_H3 },
+       { 0xCC7C, 0xCC7C, LBP_H2 },
+       { 0xCC7D, 0xCC97, LBP_H3 },
+       { 0xCC98, 0xCC98, LBP_H2 },
+       { 0xCC99, 0xCCB3, LBP_H3 },
+       { 0xCCB4, 0xCCB4, LBP_H2 },
+       { 0xCCB5, 0xCCCF, LBP_H3 },
+       { 0xCCD0, 0xCCD0, LBP_H2 },
+       { 0xCCD1, 0xCCEB, LBP_H3 },
+       { 0xCCEC, 0xCCEC, LBP_H2 },
+       { 0xCCED, 0xCD07, LBP_H3 },
+       { 0xCD08, 0xCD08, LBP_H2 },
+       { 0xCD09, 0xCD23, LBP_H3 },
+       { 0xCD24, 0xCD24, LBP_H2 },
+       { 0xCD25, 0xCD3F, LBP_H3 },
+       { 0xCD40, 0xCD40, LBP_H2 },
+       { 0xCD41, 0xCD5B, LBP_H3 },
+       { 0xCD5C, 0xCD5C, LBP_H2 },
+       { 0xCD5D, 0xCD77, LBP_H3 },
+       { 0xCD78, 0xCD78, LBP_H2 },
+       { 0xCD79, 0xCD93, LBP_H3 },
+       { 0xCD94, 0xCD94, LBP_H2 },
+       { 0xCD95, 0xCDAF, LBP_H3 },
+       { 0xCDB0, 0xCDB0, LBP_H2 },
+       { 0xCDB1, 0xCDCB, LBP_H3 },
+       { 0xCDCC, 0xCDCC, LBP_H2 },
+       { 0xCDCD, 0xCDE7, LBP_H3 },
+       { 0xCDE8, 0xCDE8, LBP_H2 },
+       { 0xCDE9, 0xCE03, LBP_H3 },
+       { 0xCE04, 0xCE04, LBP_H2 },
+       { 0xCE05, 0xCE1F, LBP_H3 },
+       { 0xCE20, 0xCE20, LBP_H2 },
+       { 0xCE21, 0xCE3B, LBP_H3 },
+       { 0xCE3C, 0xCE3C, LBP_H2 },
+       { 0xCE3D, 0xCE57, LBP_H3 },
+       { 0xCE58, 0xCE58, LBP_H2 },
+       { 0xCE59, 0xCE73, LBP_H3 },
+       { 0xCE74, 0xCE74, LBP_H2 },
+       { 0xCE75, 0xCE8F, LBP_H3 },
+       { 0xCE90, 0xCE90, LBP_H2 },
+       { 0xCE91, 0xCEAB, LBP_H3 },
+       { 0xCEAC, 0xCEAC, LBP_H2 },
+       { 0xCEAD, 0xCEC7, LBP_H3 },
+       { 0xCEC8, 0xCEC8, LBP_H2 },
+       { 0xCEC9, 0xCEE3, LBP_H3 },
+       { 0xCEE4, 0xCEE4, LBP_H2 },
+       { 0xCEE5, 0xCEFF, LBP_H3 },
+       { 0xCF00, 0xCF00, LBP_H2 },
+       { 0xCF01, 0xCF1B, LBP_H3 },
+       { 0xCF1C, 0xCF1C, LBP_H2 },
+       { 0xCF1D, 0xCF37, LBP_H3 },
+       { 0xCF38, 0xCF38, LBP_H2 },
+       { 0xCF39, 0xCF53, LBP_H3 },
+       { 0xCF54, 0xCF54, LBP_H2 },
+       { 0xCF55, 0xCF6F, LBP_H3 },
+       { 0xCF70, 0xCF70, LBP_H2 },
+       { 0xCF71, 0xCF8B, LBP_H3 },
+       { 0xCF8C, 0xCF8C, LBP_H2 },
+       { 0xCF8D, 0xCFA7, LBP_H3 },
+       { 0xCFA8, 0xCFA8, LBP_H2 },
+       { 0xCFA9, 0xCFC3, LBP_H3 },
+       { 0xCFC4, 0xCFC4, LBP_H2 },
+       { 0xCFC5, 0xCFDF, LBP_H3 },
+       { 0xCFE0, 0xCFE0, LBP_H2 },
+       { 0xCFE1, 0xCFFB, LBP_H3 },
+       { 0xCFFC, 0xCFFC, LBP_H2 },
+       { 0xCFFD, 0xD017, LBP_H3 },
+       { 0xD018, 0xD018, LBP_H2 },
+       { 0xD019, 0xD033, LBP_H3 },
+       { 0xD034, 0xD034, LBP_H2 },
+       { 0xD035, 0xD04F, LBP_H3 },
+       { 0xD050, 0xD050, LBP_H2 },
+       { 0xD051, 0xD06B, LBP_H3 },
+       { 0xD06C, 0xD06C, LBP_H2 },
+       { 0xD06D, 0xD087, LBP_H3 },
+       { 0xD088, 0xD088, LBP_H2 },
+       { 0xD089, 0xD0A3, LBP_H3 },
+       { 0xD0A4, 0xD0A4, LBP_H2 },
+       { 0xD0A5, 0xD0BF, LBP_H3 },
+       { 0xD0C0, 0xD0C0, LBP_H2 },
+       { 0xD0C1, 0xD0DB, LBP_H3 },
+       { 0xD0DC, 0xD0DC, LBP_H2 },
+       { 0xD0DD, 0xD0F7, LBP_H3 },
+       { 0xD0F8, 0xD0F8, LBP_H2 },
+       { 0xD0F9, 0xD113, LBP_H3 },
+       { 0xD114, 0xD114, LBP_H2 },
+       { 0xD115, 0xD12F, LBP_H3 },
+       { 0xD130, 0xD130, LBP_H2 },
+       { 0xD131, 0xD14B, LBP_H3 },
+       { 0xD14C, 0xD14C, LBP_H2 },
+       { 0xD14D, 0xD167, LBP_H3 },
+       { 0xD168, 0xD168, LBP_H2 },
+       { 0xD169, 0xD183, LBP_H3 },
+       { 0xD184, 0xD184, LBP_H2 },
+       { 0xD185, 0xD19F, LBP_H3 },
+       { 0xD1A0, 0xD1A0, LBP_H2 },
+       { 0xD1A1, 0xD1BB, LBP_H3 },
+       { 0xD1BC, 0xD1BC, LBP_H2 },
+       { 0xD1BD, 0xD1D7, LBP_H3 },
+       { 0xD1D8, 0xD1D8, LBP_H2 },
+       { 0xD1D9, 0xD1F3, LBP_H3 },
+       { 0xD1F4, 0xD1F4, LBP_H2 },
+       { 0xD1F5, 0xD20F, LBP_H3 },
+       { 0xD210, 0xD210, LBP_H2 },
+       { 0xD211, 0xD22B, LBP_H3 },
+       { 0xD22C, 0xD22C, LBP_H2 },
+       { 0xD22D, 0xD247, LBP_H3 },
+       { 0xD248, 0xD248, LBP_H2 },
+       { 0xD249, 0xD263, LBP_H3 },
+       { 0xD264, 0xD264, LBP_H2 },
+       { 0xD265, 0xD27F, LBP_H3 },
+       { 0xD280, 0xD280, LBP_H2 },
+       { 0xD281, 0xD29B, LBP_H3 },
+       { 0xD29C, 0xD29C, LBP_H2 },
+       { 0xD29D, 0xD2B7, LBP_H3 },
+       { 0xD2B8, 0xD2B8, LBP_H2 },
+       { 0xD2B9, 0xD2D3, LBP_H3 },
+       { 0xD2D4, 0xD2D4, LBP_H2 },
+       { 0xD2D5, 0xD2EF, LBP_H3 },
+       { 0xD2F0, 0xD2F0, LBP_H2 },
+       { 0xD2F1, 0xD30B, LBP_H3 },
+       { 0xD30C, 0xD30C, LBP_H2 },
+       { 0xD30D, 0xD327, LBP_H3 },
+       { 0xD328, 0xD328, LBP_H2 },
+       { 0xD329, 0xD343, LBP_H3 },
+       { 0xD344, 0xD344, LBP_H2 },
+       { 0xD345, 0xD35F, LBP_H3 },
+       { 0xD360, 0xD360, LBP_H2 },
+       { 0xD361, 0xD37B, LBP_H3 },
+       { 0xD37C, 0xD37C, LBP_H2 },
+       { 0xD37D, 0xD397, LBP_H3 },
+       { 0xD398, 0xD398, LBP_H2 },
+       { 0xD399, 0xD3B3, LBP_H3 },
+       { 0xD3B4, 0xD3B4, LBP_H2 },
+       { 0xD3B5, 0xD3CF, LBP_H3 },
+       { 0xD3D0, 0xD3D0, LBP_H2 },
+       { 0xD3D1, 0xD3EB, LBP_H3 },
+       { 0xD3EC, 0xD3EC, LBP_H2 },
+       { 0xD3ED, 0xD407, LBP_H3 },
+       { 0xD408, 0xD408, LBP_H2 },
+       { 0xD409, 0xD423, LBP_H3 },
+       { 0xD424, 0xD424, LBP_H2 },
+       { 0xD425, 0xD43F, LBP_H3 },
+       { 0xD440, 0xD440, LBP_H2 },
+       { 0xD441, 0xD45B, LBP_H3 },
+       { 0xD45C, 0xD45C, LBP_H2 },
+       { 0xD45D, 0xD477, LBP_H3 },
+       { 0xD478, 0xD478, LBP_H2 },
+       { 0xD479, 0xD493, LBP_H3 },
+       { 0xD494, 0xD494, LBP_H2 },
+       { 0xD495, 0xD4AF, LBP_H3 },
+       { 0xD4B0, 0xD4B0, LBP_H2 },
+       { 0xD4B1, 0xD4CB, LBP_H3 },
+       { 0xD4CC, 0xD4CC, LBP_H2 },
+       { 0xD4CD, 0xD4E7, LBP_H3 },
+       { 0xD4E8, 0xD4E8, LBP_H2 },
+       { 0xD4E9, 0xD503, LBP_H3 },
+       { 0xD504, 0xD504, LBP_H2 },
+       { 0xD505, 0xD51F, LBP_H3 },
+       { 0xD520, 0xD520, LBP_H2 },
+       { 0xD521, 0xD53B, LBP_H3 },
+       { 0xD53C, 0xD53C, LBP_H2 },
+       { 0xD53D, 0xD557, LBP_H3 },
+       { 0xD558, 0xD558, LBP_H2 },
+       { 0xD559, 0xD573, LBP_H3 },
+       { 0xD574, 0xD574, LBP_H2 },
+       { 0xD575, 0xD58F, LBP_H3 },
+       { 0xD590, 0xD590, LBP_H2 },
+       { 0xD591, 0xD5AB, LBP_H3 },
+       { 0xD5AC, 0xD5AC, LBP_H2 },
+       { 0xD5AD, 0xD5C7, LBP_H3 },
+       { 0xD5C8, 0xD5C8, LBP_H2 },
+       { 0xD5C9, 0xD5E3, LBP_H3 },
+       { 0xD5E4, 0xD5E4, LBP_H2 },
+       { 0xD5E5, 0xD5FF, LBP_H3 },
+       { 0xD600, 0xD600, LBP_H2 },
+       { 0xD601, 0xD61B, LBP_H3 },
+       { 0xD61C, 0xD61C, LBP_H2 },
+       { 0xD61D, 0xD637, LBP_H3 },
+       { 0xD638, 0xD638, LBP_H2 },
+       { 0xD639, 0xD653, LBP_H3 },
+       { 0xD654, 0xD654, LBP_H2 },
+       { 0xD655, 0xD66F, LBP_H3 },
+       { 0xD670, 0xD670, LBP_H2 },
+       { 0xD671, 0xD68B, LBP_H3 },
+       { 0xD68C, 0xD68C, LBP_H2 },
+       { 0xD68D, 0xD6A7, LBP_H3 },
+       { 0xD6A8, 0xD6A8, LBP_H2 },
+       { 0xD6A9, 0xD6C3, LBP_H3 },
+       { 0xD6C4, 0xD6C4, LBP_H2 },
+       { 0xD6C5, 0xD6DF, LBP_H3 },
+       { 0xD6E0, 0xD6E0, LBP_H2 },
+       { 0xD6E1, 0xD6FB, LBP_H3 },
+       { 0xD6FC, 0xD6FC, LBP_H2 },
+       { 0xD6FD, 0xD717, LBP_H3 },
+       { 0xD718, 0xD718, LBP_H2 },
+       { 0xD719, 0xD733, LBP_H3 },
+       { 0xD734, 0xD734, LBP_H2 },
+       { 0xD735, 0xD74F, LBP_H3 },
+       { 0xD750, 0xD750, LBP_H2 },
+       { 0xD751, 0xD76B, LBP_H3 },
+       { 0xD76C, 0xD76C, LBP_H2 },
+       { 0xD76D, 0xD787, LBP_H3 },
+       { 0xD788, 0xD788, LBP_H2 },
+       { 0xD789, 0xD7A3, LBP_H3 },
+       { 0xD7B0, 0xD7C6, LBP_JV },
+       { 0xD7CB, 0xD7FB, LBP_JT },
+       { 0xD800, 0xDFFF, LBP_SG },
+       { 0xE000, 0xF8FF, LBP_XX },
+       { 0xF900, 0xFAFF, LBP_ID },
+       { 0xFB00, 0xFB17, LBP_AL },
+       { 0xFB1D, 0xFB1D, LBP_HL },
+       { 0xFB1E, 0xFB1E, LBP_CM },
+       { 0xFB1F, 0xFB28, LBP_HL },
+       { 0xFB29, 0xFB29, LBP_AL },
+       { 0xFB2A, 0xFB4F, LBP_HL },
+       { 0xFB50, 0xFD3D, LBP_AL },
+       { 0xFD3E, 0xFD3E, LBP_CL },
+       { 0xFD3F, 0xFD3F, LBP_OP },
+       { 0xFD50, 0xFDFB, LBP_AL },
+       { 0xFDFC, 0xFDFC, LBP_PO },
+       { 0xFDFD, 0xFDFD, LBP_AL },
+       { 0xFE00, 0xFE0F, LBP_CM },
+       { 0xFE10, 0xFE10, LBP_IS },
+       { 0xFE11, 0xFE12, LBP_CL },
+       { 0xFE13, 0xFE14, LBP_IS },
+       { 0xFE15, 0xFE16, LBP_EX },
+       { 0xFE17, 0xFE17, LBP_OP },
+       { 0xFE18, 0xFE18, LBP_CL },
+       { 0xFE19, 0xFE19, LBP_IN },
+       { 0xFE20, 0xFE2D, LBP_CM },
+       { 0xFE30, 0xFE34, LBP_ID },
+       { 0xFE35, 0xFE35, LBP_OP },
+       { 0xFE36, 0xFE36, LBP_CL },
+       { 0xFE37, 0xFE37, LBP_OP },
+       { 0xFE38, 0xFE38, LBP_CL },
+       { 0xFE39, 0xFE39, LBP_OP },
+       { 0xFE3A, 0xFE3A, LBP_CL },
+       { 0xFE3B, 0xFE3B, LBP_OP },
+       { 0xFE3C, 0xFE3C, LBP_CL },
+       { 0xFE3D, 0xFE3D, LBP_OP },
+       { 0xFE3E, 0xFE3E, LBP_CL },
+       { 0xFE3F, 0xFE3F, LBP_OP },
+       { 0xFE40, 0xFE40, LBP_CL },
+       { 0xFE41, 0xFE41, LBP_OP },
+       { 0xFE42, 0xFE42, LBP_CL },
+       { 0xFE43, 0xFE43, LBP_OP },
+       { 0xFE44, 0xFE44, LBP_CL },
+       { 0xFE45, 0xFE46, LBP_ID },
+       { 0xFE47, 0xFE47, LBP_OP },
+       { 0xFE48, 0xFE48, LBP_CL },
+       { 0xFE49, 0xFE4F, LBP_ID },
+       { 0xFE50, 0xFE50, LBP_CL },
+       { 0xFE51, 0xFE51, LBP_ID },
+       { 0xFE52, 0xFE52, LBP_CL },
+       { 0xFE54, 0xFE55, LBP_NS },
+       { 0xFE56, 0xFE57, LBP_EX },
+       { 0xFE58, 0xFE58, LBP_ID },
+       { 0xFE59, 0xFE59, LBP_OP },
+       { 0xFE5A, 0xFE5A, LBP_CL },
+       { 0xFE5B, 0xFE5B, LBP_OP },
+       { 0xFE5C, 0xFE5C, LBP_CL },
+       { 0xFE5D, 0xFE5D, LBP_OP },
+       { 0xFE5E, 0xFE5E, LBP_CL },
+       { 0xFE5F, 0xFE68, LBP_ID },
+       { 0xFE69, 0xFE69, LBP_PR },
+       { 0xFE6A, 0xFE6A, LBP_PO },
+       { 0xFE6B, 0xFE6B, LBP_ID },
+       { 0xFE70, 0xFEFC, LBP_AL },
+       { 0xFEFF, 0xFEFF, LBP_WJ },
+       { 0xFF01, 0xFF01, LBP_EX },
+       { 0xFF02, 0xFF03, LBP_ID },
+       { 0xFF04, 0xFF04, LBP_PR },
+       { 0xFF05, 0xFF05, LBP_PO },
+       { 0xFF06, 0xFF07, LBP_ID },
+       { 0xFF08, 0xFF08, LBP_OP },
+       { 0xFF09, 0xFF09, LBP_CL },
+       { 0xFF0A, 0xFF0B, LBP_ID },
+       { 0xFF0C, 0xFF0C, LBP_CL },
+       { 0xFF0D, 0xFF0D, LBP_ID },
+       { 0xFF0E, 0xFF0E, LBP_CL },
+       { 0xFF0F, 0xFF19, LBP_ID },
+       { 0xFF1A, 0xFF1B, LBP_NS },
+       { 0xFF1C, 0xFF1E, LBP_ID },
+       { 0xFF1F, 0xFF1F, LBP_EX },
+       { 0xFF20, 0xFF3A, LBP_ID },
+       { 0xFF3B, 0xFF3B, LBP_OP },
+       { 0xFF3C, 0xFF3C, LBP_ID },
+       { 0xFF3D, 0xFF3D, LBP_CL },
+       { 0xFF3E, 0xFF5A, LBP_ID },
+       { 0xFF5B, 0xFF5B, LBP_OP },
+       { 0xFF5C, 0xFF5C, LBP_ID },
+       { 0xFF5D, 0xFF5D, LBP_CL },
+       { 0xFF5E, 0xFF5E, LBP_ID },
+       { 0xFF5F, 0xFF5F, LBP_OP },
+       { 0xFF60, 0xFF61, LBP_CL },
+       { 0xFF62, 0xFF62, LBP_OP },
+       { 0xFF63, 0xFF64, LBP_CL },
+       { 0xFF65, 0xFF65, LBP_NS },
+       { 0xFF66, 0xFF66, LBP_AL },
+       { 0xFF67, 0xFF70, LBP_CJ },
+       { 0xFF71, 0xFF9D, LBP_AL },
+       { 0xFF9E, 0xFF9F, LBP_NS },
+       { 0xFFA0, 0xFFDC, LBP_AL },
+       { 0xFFE0, 0xFFE0, LBP_PO },
+       { 0xFFE1, 0xFFE1, LBP_PR },
+       { 0xFFE2, 0xFFE4, LBP_ID },
+       { 0xFFE5, 0xFFE6, LBP_PR },
+       { 0xFFE8, 0xFFEE, LBP_AL },
+       { 0xFFF9, 0xFFFB, LBP_CM },
+       { 0xFFFC, 0xFFFC, LBP_CB },
+       { 0xFFFD, 0xFFFD, LBP_AI },
+       { 0x10000, 0x100FA, LBP_AL },
+       { 0x10100, 0x10102, LBP_BA },
+       { 0x10107, 0x101FC, LBP_AL },
+       { 0x101FD, 0x101FD, LBP_CM },
+       { 0x10280, 0x102D0, LBP_AL },
+       { 0x102E0, 0x102E0, LBP_CM },
+       { 0x102E1, 0x10375, LBP_AL },
+       { 0x10376, 0x1037A, LBP_CM },
+       { 0x10380, 0x1039D, LBP_AL },
+       { 0x1039F, 0x1039F, LBP_BA },
+       { 0x103A0, 0x103CF, LBP_AL },
+       { 0x103D0, 0x103D0, LBP_BA },
+       { 0x103D1, 0x1049D, LBP_AL },
+       { 0x104A0, 0x104A9, LBP_NU },
+       { 0x10500, 0x10855, LBP_AL },
+       { 0x10857, 0x10857, LBP_BA },
+       { 0x10858, 0x1091B, LBP_AL },
+       { 0x1091F, 0x1091F, LBP_BA },
+       { 0x10920, 0x10A00, LBP_AL },
+       { 0x10A01, 0x10A0F, LBP_CM },
+       { 0x10A10, 0x10A33, LBP_AL },
+       { 0x10A38, 0x10A3F, LBP_CM },
+       { 0x10A40, 0x10A47, LBP_AL },
+       { 0x10A50, 0x10A57, LBP_BA },
+       { 0x10A58, 0x10AE4, LBP_AL },
+       { 0x10AE5, 0x10AE6, LBP_CM },
+       { 0x10AEB, 0x10AEF, LBP_AL },
+       { 0x10AF0, 0x10AF5, LBP_BA },
+       { 0x10AF6, 0x10AF6, LBP_IN },
+       { 0x10B00, 0x10B35, LBP_AL },
+       { 0x10B39, 0x10B3F, LBP_BA },
+       { 0x10B40, 0x10E7E, LBP_AL },
+       { 0x11000, 0x11002, LBP_CM },
+       { 0x11003, 0x11037, LBP_AL },
+       { 0x11038, 0x11046, LBP_CM },
+       { 0x11047, 0x11048, LBP_BA },
+       { 0x11049, 0x11065, LBP_AL },
+       { 0x11066, 0x1106F, LBP_NU },
+       { 0x1107F, 0x11082, LBP_CM },
+       { 0x11083, 0x110AF, LBP_AL },
+       { 0x110B0, 0x110BA, LBP_CM },
+       { 0x110BB, 0x110BD, LBP_AL },
+       { 0x110BE, 0x110C1, LBP_BA },
+       { 0x110D0, 0x110E8, LBP_AL },
+       { 0x110F0, 0x110F9, LBP_NU },
+       { 0x11100, 0x11102, LBP_CM },
+       { 0x11103, 0x11126, LBP_AL },
+       { 0x11127, 0x11134, LBP_CM },
+       { 0x11136, 0x1113F, LBP_NU },
+       { 0x11140, 0x11143, LBP_BA },
+       { 0x11150, 0x11172, LBP_AL },
+       { 0x11173, 0x11173, LBP_CM },
+       { 0x11174, 0x11174, LBP_AL },
+       { 0x11175, 0x11175, LBP_BB },
+       { 0x11176, 0x11176, LBP_AL },
+       { 0x11180, 0x11182, LBP_CM },
+       { 0x11183, 0x111B2, LBP_AL },
+       { 0x111B3, 0x111C0, LBP_CM },
+       { 0x111C1, 0x111C4, LBP_AL },
+       { 0x111C5, 0x111C6, LBP_BA },
+       { 0x111C7, 0x111C7, LBP_AL },
+       { 0x111C8, 0x111C8, LBP_BA },
+       { 0x111CD, 0x111CD, LBP_AL },
+       { 0x111D0, 0x111D9, LBP_NU },
+       { 0x111DA, 0x1122B, LBP_AL },
+       { 0x1122C, 0x11237, LBP_CM },
+       { 0x11238, 0x11239, LBP_BA },
+       { 0x1123A, 0x1123A, LBP_AL },
+       { 0x1123B, 0x1123C, LBP_BA },
+       { 0x1123D, 0x112DE, LBP_AL },
+       { 0x112DF, 0x112EA, LBP_CM },
+       { 0x112F0, 0x112F9, LBP_NU },
+       { 0x11301, 0x11303, LBP_CM },
+       { 0x11305, 0x11339, LBP_AL },
+       { 0x1133C, 0x1133C, LBP_CM },
+       { 0x1133D, 0x1133D, LBP_AL },
+       { 0x1133E, 0x11357, LBP_CM },
+       { 0x1135D, 0x11361, LBP_AL },
+       { 0x11362, 0x11374, LBP_CM },
+       { 0x11480, 0x114AF, LBP_AL },
+       { 0x114B0, 0x114C3, LBP_CM },
+       { 0x114C4, 0x114C7, LBP_AL },
+       { 0x114D0, 0x114D9, LBP_NU },
+       { 0x11580, 0x115AE, LBP_AL },
+       { 0x115AF, 0x115C0, LBP_CM },
+       { 0x115C1, 0x115C1, LBP_BB },
+       { 0x115C2, 0x115C3, LBP_BA },
+       { 0x115C4, 0x115C5, LBP_EX },
+       { 0x115C6, 0x115C8, LBP_AL },
+       { 0x115C9, 0x115C9, LBP_BA },
+       { 0x11600, 0x1162F, LBP_AL },
+       { 0x11630, 0x11640, LBP_CM },
+       { 0x11641, 0x11642, LBP_BA },
+       { 0x11643, 0x11644, LBP_AL },
+       { 0x11650, 0x11659, LBP_NU },
+       { 0x11680, 0x116AA, LBP_AL },
+       { 0x116AB, 0x116B7, LBP_CM },
+       { 0x116C0, 0x116C9, LBP_NU },
+       { 0x118A0, 0x118DF, LBP_AL },
+       { 0x118E0, 0x118E9, LBP_NU },
+       { 0x118EA, 0x1246E, LBP_AL },
+       { 0x12470, 0x12474, LBP_BA },
+       { 0x13000, 0x13257, LBP_AL },
+       { 0x13258, 0x1325A, LBP_OP },
+       { 0x1325B, 0x1325D, LBP_CL },
+       { 0x1325E, 0x13281, LBP_AL },
+       { 0x13282, 0x13282, LBP_CL },
+       { 0x13283, 0x13285, LBP_AL },
+       { 0x13286, 0x13286, LBP_OP },
+       { 0x13287, 0x13287, LBP_CL },
+       { 0x13288, 0x13288, LBP_OP },
+       { 0x13289, 0x13289, LBP_CL },
+       { 0x1328A, 0x13378, LBP_AL },
+       { 0x13379, 0x13379, LBP_OP },
+       { 0x1337A, 0x1337B, LBP_CL },
+       { 0x1337C, 0x16A5E, LBP_AL },
+       { 0x16A60, 0x16A69, LBP_NU },
+       { 0x16A6E, 0x16A6F, LBP_BA },
+       { 0x16AD0, 0x16AED, LBP_AL },
+       { 0x16AF0, 0x16AF4, LBP_CM },
+       { 0x16AF5, 0x16AF5, LBP_BA },
+       { 0x16B00, 0x16B2F, LBP_AL },
+       { 0x16B30, 0x16B36, LBP_CM },
+       { 0x16B37, 0x16B39, LBP_BA },
+       { 0x16B3A, 0x16B43, LBP_AL },
+       { 0x16B44, 0x16B44, LBP_BA },
+       { 0x16B45, 0x16B45, LBP_AL },
+       { 0x16B50, 0x16B59, LBP_NU },
+       { 0x16B5B, 0x16F50, LBP_AL },
+       { 0x16F51, 0x16F92, LBP_CM },
+       { 0x16F93, 0x16F9F, LBP_AL },
+       { 0x1B000, 0x1B001, LBP_ID },
+       { 0x1BC00, 0x1BC9C, LBP_AL },
+       { 0x1BC9D, 0x1BC9E, LBP_CM },
+       { 0x1BC9F, 0x1BC9F, LBP_BA },
+       { 0x1BCA0, 0x1BCA3, LBP_CM },
+       { 0x1D000, 0x1D164, LBP_AL },
+       { 0x1D165, 0x1D169, LBP_CM },
+       { 0x1D16A, 0x1D16C, LBP_AL },
+       { 0x1D16D, 0x1D182, LBP_CM },
+       { 0x1D183, 0x1D184, LBP_AL },
+       { 0x1D185, 0x1D18B, LBP_CM },
+       { 0x1D18C, 0x1D1A9, LBP_AL },
+       { 0x1D1AA, 0x1D1AD, LBP_CM },
+       { 0x1D1AE, 0x1D241, LBP_AL },
+       { 0x1D242, 0x1D244, LBP_CM },
+       { 0x1D245, 0x1D7CB, LBP_AL },
+       { 0x1D7CE, 0x1D7FF, LBP_NU },
+       { 0x1E800, 0x1E8CF, LBP_AL },
+       { 0x1E8D0, 0x1E8D6, LBP_CM },
+       { 0x1EE00, 0x1EEF1, LBP_AL },
+       { 0x1F000, 0x1F0F5, LBP_ID },
+       { 0x1F100, 0x1F12D, LBP_AI },
+       { 0x1F12E, 0x1F12E, LBP_AL },
+       { 0x1F130, 0x1F169, LBP_AI },
+       { 0x1F16A, 0x1F16B, LBP_AL },
+       { 0x1F170, 0x1F19A, LBP_AI },
+       { 0x1F1E6, 0x1F1FF, LBP_RI },
+       { 0x1F200, 0x1F39B, LBP_ID },
+       { 0x1F39C, 0x1F39D, LBP_AL },
+       { 0x1F39E, 0x1F3B4, LBP_ID },
+       { 0x1F3B5, 0x1F3B6, LBP_AL },
+       { 0x1F3B7, 0x1F3BB, LBP_ID },
+       { 0x1F3BC, 0x1F3BC, LBP_AL },
+       { 0x1F3BD, 0x1F49F, LBP_ID },
+       { 0x1F4A0, 0x1F4A0, LBP_AL },
+       { 0x1F4A1, 0x1F4A1, LBP_ID },
+       { 0x1F4A2, 0x1F4A2, LBP_AL },
+       { 0x1F4A3, 0x1F4A3, LBP_ID },
+       { 0x1F4A4, 0x1F4A4, LBP_AL },
+       { 0x1F4A5, 0x1F4AE, LBP_ID },
+       { 0x1F4AF, 0x1F4AF, LBP_AL },
+       { 0x1F4B0, 0x1F4B0, LBP_ID },
+       { 0x1F4B1, 0x1F4B2, LBP_AL },
+       { 0x1F4B3, 0x1F4FE, LBP_ID },
+       { 0x1F500, 0x1F506, LBP_AL },
+       { 0x1F507, 0x1F516, LBP_ID },
+       { 0x1F517, 0x1F524, LBP_AL },
+       { 0x1F525, 0x1F531, LBP_ID },
+       { 0x1F532, 0x1F549, LBP_AL },
+       { 0x1F54A, 0x1F5D3, LBP_ID },
+       { 0x1F5D4, 0x1F5DB, LBP_AL },
+       { 0x1F5DC, 0x1F5F3, LBP_ID },
+       { 0x1F5F4, 0x1F5F9, LBP_AL },
+       { 0x1F5FA, 0x1F64F, LBP_ID },
+       { 0x1F650, 0x1F675, LBP_AL },
+       { 0x1F676, 0x1F678, LBP_QU },
+       { 0x1F679, 0x1F67B, LBP_NS },
+       { 0x1F67C, 0x1F67F, LBP_AL },
+       { 0x1F680, 0x1F6F3, LBP_ID },
+       { 0x1F700, 0x1F8AD, LBP_AL },
+       { 0x20000, 0x3FFFD, LBP_ID },
+       { 0xE0001, 0xE01EF, LBP_CM },
+       { 0xF0000, 0x10FFFD, LBP_XX },
+       { 0xFFFFFFFF, 0xFFFFFFFF, LBP_Undefined }
+};
diff --git a/third-party/libunibreak/linebreakdef.c b/third-party/libunibreak/linebreakdef.c
new file mode 100644 (file)
index 0000000..41a7296
--- /dev/null
@@ -0,0 +1,139 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Line breaking in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2008-2015 Wu Yongwei <wuyongwei at gmail dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ * The main reference is Unicode Standard Annex 14 (UAX #14):
+ *      <URL:http://www.unicode.org/reports/tr14/>
+ *
+ * When this library was designed, this annex was at Revision 19, for
+ * Unicode 5.0.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-19.html>
+ *
+ * This library has been updated according to Revision 33, for
+ * Unicode 7.0.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-33.html>
+ *
+ * The Unicode Terms of Use are available at
+ *      <URL:http://www.unicode.org/copyright.html>
+ */
+
+/**
+ * @file    linebreakdef.c
+ *
+ * Definition of language-specific data.
+ *
+ * @version 2.2, 2012/10/06
+ * @author  Wu Yongwei
+ */
+
+#include "linebreak.h"
+#include "linebreakdef.h"
+
+/**
+ * English-specifc data over the default Unicode rules.
+ */
+static struct LineBreakProperties lb_prop_English[] = {
+    { 0x2018, 0x2018, LBP_OP }, /* Left single quotation mark: opening */
+    { 0x201C, 0x201C, LBP_OP }, /* Left double quotation mark: opening */
+    { 0x201D, 0x201D, LBP_CL }, /* Right double quotation mark: closing */
+    { 0, 0, LBP_Undefined }
+};
+
+/**
+ * German-specifc data over the default Unicode rules.
+ */
+static struct LineBreakProperties lb_prop_German[] = {
+    { 0x00AB, 0x00AB, LBP_CL }, /* Left double angle quotation mark: closing */
+    { 0x00BB, 0x00BB, LBP_OP }, /* Right double angle quotation mark: opening */
+    { 0x2018, 0x2018, LBP_CL }, /* Left single quotation mark: closing */
+    { 0x201C, 0x201C, LBP_CL }, /* Left double quotation mark: closing */
+    { 0x2039, 0x2039, LBP_CL }, /* Left single angle quotation mark: closing */
+    { 0x203A, 0x203A, LBP_OP }, /* Right single angle quotation mark: opening */
+    { 0, 0, LBP_Undefined }
+};
+
+/**
+ * Spanish-specifc data over the default Unicode rules.
+ */
+static struct LineBreakProperties lb_prop_Spanish[] = {
+    { 0x00AB, 0x00AB, LBP_OP }, /* Left double angle quotation mark: opening */
+    { 0x00BB, 0x00BB, LBP_CL }, /* Right double angle quotation mark: closing */
+    { 0x2018, 0x2018, LBP_OP }, /* Left single quotation mark: opening */
+    { 0x201C, 0x201C, LBP_OP }, /* Left double quotation mark: opening */
+    { 0x201D, 0x201D, LBP_CL }, /* Right double quotation mark: closing */
+    { 0x2039, 0x2039, LBP_OP }, /* Left single angle quotation mark: opening */
+    { 0x203A, 0x203A, LBP_CL }, /* Right single angle quotation mark: closing */
+    { 0, 0, LBP_Undefined }
+};
+
+/**
+ * French-specifc data over the default Unicode rules.
+ */
+static struct LineBreakProperties lb_prop_French[] = {
+    { 0x00AB, 0x00AB, LBP_OP }, /* Left double angle quotation mark: opening */
+    { 0x00BB, 0x00BB, LBP_CL }, /* Right double angle quotation mark: closing */
+    { 0x2018, 0x2018, LBP_OP }, /* Left single quotation mark: opening */
+    { 0x201C, 0x201C, LBP_OP }, /* Left double quotation mark: opening */
+    { 0x201D, 0x201D, LBP_CL }, /* Right double quotation mark: closing */
+    { 0x2039, 0x2039, LBP_OP }, /* Left single angle quotation mark: opening */
+    { 0x203A, 0x203A, LBP_CL }, /* Right single angle quotation mark: closing */
+    { 0, 0, LBP_Undefined }
+};
+
+/**
+ * Russian-specifc data over the default Unicode rules.
+ */
+static struct LineBreakProperties lb_prop_Russian[] = {
+    { 0x00AB, 0x00AB, LBP_OP }, /* Left double angle quotation mark: opening */
+    { 0x00BB, 0x00BB, LBP_CL }, /* Right double angle quotation mark: closing */
+    { 0x201C, 0x201C, LBP_CL }, /* Left double quotation mark: closing */
+    { 0, 0, LBP_Undefined }
+};
+
+/**
+ * Chinese-specifc data over the default Unicode rules.
+ */
+static struct LineBreakProperties lb_prop_Chinese[] = {
+    { 0x2018, 0x2018, LBP_OP }, /* Left single quotation mark: opening */
+    { 0x2019, 0x2019, LBP_CL }, /* Right single quotation mark: closing */
+    { 0x201C, 0x201C, LBP_OP }, /* Left double quotation mark: opening */
+    { 0x201D, 0x201D, LBP_CL }, /* Right double quotation mark: closing */
+    { 0, 0, LBP_Undefined }
+};
+
+/**
+ * Association data of language-specific line breaking properties with
+ * language names.  This is the definition for the static data in this
+ * file.  If you want more flexibility, or do not need the data here,
+ * you may want to redefine \e lb_prop_lang_map in your C source file.
+ */
+struct LineBreakPropertiesLang lb_prop_lang_map[] = {
+    { "en", 2, lb_prop_English },
+    { "de", 2, lb_prop_German },
+    { "es", 2, lb_prop_Spanish },
+    { "fr", 2, lb_prop_French },
+    { "ru", 2, lb_prop_Russian },
+    { "zh", 2, lb_prop_Chinese },
+    { NULL, 0, NULL }
+};
diff --git a/third-party/libunibreak/linebreakdef.h b/third-party/libunibreak/linebreakdef.h
new file mode 100644 (file)
index 0000000..7600d0a
--- /dev/null
@@ -0,0 +1,162 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Line breaking in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2008-2015 Wu Yongwei <wuyongwei at gmail dot com>
+ * Copyright (C) 2013 Petr Filipsky <philodej at gmail dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ * The main reference is Unicode Standard Annex 14 (UAX #14):
+ *      <URL:http://www.unicode.org/reports/tr14/>
+ *
+ * When this library was designed, this annex was at Revision 19, for
+ * Unicode 5.0.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-19.html>
+ *
+ * This library has been updated according to Revision 33, for
+ * Unicode 7.0.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-33.html>
+ *
+ * The Unicode Terms of Use are available at
+ *      <URL:http://www.unicode.org/copyright.html>
+ */
+
+/**
+ * @file    linebreakdef.h
+ *
+ * Definitions of internal data structures, declarations of global
+ * variables, and function prototypes for the line breaking algorithm.
+ *
+ * @version 2.6, 2015/04/18
+ * @author  Wu Yongwei
+ * @author  Petr Filipsky
+ */
+
+#include "unibreakdef.h"
+
+/**
+ * Line break classes.  This is a direct mapping of Table 1 of Unicode
+ * Standard Annex 14, Revision 26.
+ */
+enum LineBreakClass
+{
+    /* This is used to signal an error condition. */
+    LBP_Undefined,  /**< Undefined */
+
+    /* The following break classes are treated in the pair table. */
+    LBP_OP,         /**< Opening punctuation */
+    LBP_CL,         /**< Closing punctuation */
+    LBP_CP,         /**< Closing parenthesis */
+    LBP_QU,         /**< Ambiguous quotation */
+    LBP_GL,         /**< Glue */
+    LBP_NS,         /**< Non-starters */
+    LBP_EX,         /**< Exclamation/Interrogation */
+    LBP_SY,         /**< Symbols allowing break after */
+    LBP_IS,         /**< Infix separator */
+    LBP_PR,         /**< Prefix */
+    LBP_PO,         /**< Postfix */
+    LBP_NU,         /**< Numeric */
+    LBP_AL,         /**< Alphabetic */
+    LBP_HL,         /**< Hebrew letter */
+    LBP_ID,         /**< Ideographic */
+    LBP_IN,         /**< Inseparable characters */
+    LBP_HY,         /**< Hyphen */
+    LBP_BA,         /**< Break after */
+    LBP_BB,         /**< Break before */
+    LBP_B2,         /**< Break on either side (but not pair) */
+    LBP_ZW,         /**< Zero-width space */
+    LBP_CM,         /**< Combining marks */
+    LBP_WJ,         /**< Word joiner */
+    LBP_H2,         /**< Hangul LV */
+    LBP_H3,         /**< Hangul LVT */
+    LBP_JL,         /**< Hangul L Jamo */
+    LBP_JV,         /**< Hangul V Jamo */
+    LBP_JT,         /**< Hangul T Jamo */
+    LBP_RI,         /**< Regional indicator */
+
+    /* The following break classes are not treated in the pair table */
+    LBP_AI,         /**< Ambiguous (alphabetic or ideograph) */
+    LBP_BK,         /**< Break (mandatory) */
+    LBP_CB,         /**< Contingent break */
+    LBP_CJ,         /**< Conditional Japanese starter */
+    LBP_CR,         /**< Carriage return */
+    LBP_LF,         /**< Line feed */
+    LBP_NL,         /**< Next line */
+    LBP_SA,         /**< South-East Asian */
+    LBP_SG,         /**< Surrogates */
+    LBP_SP,         /**< Space */
+    LBP_XX          /**< Unknown */
+};
+
+/**
+ * Struct for entries of line break properties.  The array of the
+ * entries \e must be sorted.
+ */
+struct LineBreakProperties
+{
+    utf32_t start;              /**< Starting coding point */
+    utf32_t end;                /**< End coding point */
+    enum LineBreakClass prop;   /**< The line breaking property */
+};
+
+/**
+ * Struct for association of language-specific line breaking properties
+ * with language names.
+ */
+struct LineBreakPropertiesLang
+{
+    const char *lang;                   /**< Language name */
+    size_t namelen;                     /**< Length of name to match */
+    struct LineBreakProperties *lbp;    /**< Pointer to associated data */
+};
+
+/**
+ * Context representing internal state of the line breaking algorithm.
+ * This is useful to callers if incremental analysis is wanted.
+ */
+struct LineBreakContext
+{
+    const char *lang;               /**< Language name */
+    struct LineBreakProperties *lbpLang;/**< Pointer to LineBreakProperties */
+    enum LineBreakClass lbcCur;     /**< Breaking class of current codepoint */
+    enum LineBreakClass lbcNew;     /**< Breaking class of next codepoint */
+    enum LineBreakClass lbcLast;    /**< Breaking class of last codepoint */
+    int fLb21aHebrew;               /**< Flag for Hebrew letters (LB21a) */
+};
+
+/* Declarations */
+extern struct LineBreakProperties lb_prop_default[];
+extern struct LineBreakPropertiesLang lb_prop_lang_map[];
+
+/* Function Prototype */
+void lb_init_break_context(
+        struct LineBreakContext *lbpCtx,
+        utf32_t ch,
+        const char *lang);
+int lb_process_next_char(
+        struct LineBreakContext *lbpCtx,
+        utf32_t ch);
+void set_linebreaks(
+        const void *s,
+        size_t len,
+        const char *lang,
+        char *brks,
+        get_next_char_t get_next_char);
diff --git a/third-party/libunibreak/unibreakbase.c b/third-party/libunibreak/unibreakbase.c
new file mode 100755 (executable)
index 0000000..dbe3a38
--- /dev/null
@@ -0,0 +1,41 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Break processing in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2015 Wu Yongwei <wuyongwei at gmail dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ */
+
+/**
+ * @file    unibreakbase.c
+ *
+ * Definition of basic libunibreak information.
+ *
+ * @version 1.0, 2015/04/18
+ * @author  Wu Yongwei
+ */
+
+#include "unibreakbase.h"
+
+/**
+ * Version number of the library.
+ */
+const int unibreak_version = UNIBREAK_VERSION;
diff --git a/third-party/libunibreak/unibreakbase.h b/third-party/libunibreak/unibreakbase.h
new file mode 100755 (executable)
index 0000000..76b35e6
--- /dev/null
@@ -0,0 +1,73 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Break processing in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2015 Wu Yongwei <wuyongwei at gmail dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ * The main reference is Unicode Standard Annex 14 (UAX #14):
+ *      <URL:http://www.unicode.org/reports/tr14/>
+ *
+ * When this library was designed, this annex was at Revision 19, for
+ * Unicode 5.0.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-19.html>
+ *
+ * This library has been updated according to Revision 33, for
+ * Unicode 7.0.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-33.html>
+ *
+ * The Unicode Terms of Use are available at
+ *      <URL:http://www.unicode.org/copyright.html>
+ */
+
+/**
+ * @file    unibreakbase.h
+ *
+ * Header file for common definitions in the libunibreak library.
+ *
+ * @version 1.0, 2015/04/18
+ * @author  Wu Yongwei
+ */
+
+#ifndef UNIBREAKBASE_H
+#define UNIBREAKBASE_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define UNIBREAK_VERSION   0x0300      /**< Version of the library linebreak */
+extern const int unibreak_version;
+
+#ifndef UNIBREAK_UTF_TYPES_DEFINED
+#define UNIBREAK_UTF_TYPES_DEFINED
+typedef unsigned char   utf8_t;     /**< Type for UTF-8 data points */
+typedef unsigned short  utf16_t;    /**< Type for UTF-16 data points */
+typedef unsigned int    utf32_t;    /**< Type for UTF-32 data points */
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UNIBREAKBASE_H */
diff --git a/third-party/libunibreak/unibreakdef.c b/third-party/libunibreak/unibreakdef.c
new file mode 100755 (executable)
index 0000000..2647b61
--- /dev/null
@@ -0,0 +1,159 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Break processing in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2015 Wu Yongwei <wuyongwei at gmail dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ */
+
+/**
+ * @file    unibreakdef.c
+ *
+ * Definition of utility functions used by the libunibreak library.
+ *
+ * @version 1.0, 2015/04/18
+ * @author  Wu Yongwei
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include "unibreakdef.h"
+
+/**
+ * Gets the next Unicode character in a UTF-8 sequence.  The index will
+ * be advanced to the next complete character, unless the end of string
+ * is reached in the middle of a UTF-8 sequence.
+ *
+ * @param[in]     s    input UTF-8 string
+ * @param[in]     len  length of the string in bytes
+ * @param[in,out] ip   pointer to the index
+ * @return             the Unicode character beginning at the index; or
+ *                     #EOS if end of input is encountered
+ */
+utf32_t ub_get_next_char_utf8(
+        const utf8_t *s,
+        size_t len,
+        size_t *ip)
+{
+    utf8_t ch;
+    utf32_t res;
+
+    assert(*ip <= len);
+    if (*ip == len)
+        return EOS;
+    ch = s[*ip];
+
+    if (ch < 0xC2 || ch > 0xF4)
+    {   /* One-byte sequence, tail (should not occur), or invalid */
+        *ip += 1;
+        return ch;
+    }
+    else if (ch < 0xE0)
+    {   /* Two-byte sequence */
+        if (*ip + 2 > len)
+            return EOS;
+        res = ((ch & 0x1F) << 6) + (s[*ip + 1] & 0x3F);
+        *ip += 2;
+        return res;
+    }
+    else if (ch < 0xF0)
+    {   /* Three-byte sequence */
+        if (*ip + 3 > len)
+            return EOS;
+        res = ((ch & 0x0F) << 12) +
+              ((s[*ip + 1] & 0x3F) << 6) +
+              ((s[*ip + 2] & 0x3F));
+        *ip += 3;
+        return res;
+    }
+    else
+    {   /* Four-byte sequence */
+        if (*ip + 4 > len)
+            return EOS;
+        res = ((ch & 0x07) << 18) +
+              ((s[*ip + 1] & 0x3F) << 12) +
+              ((s[*ip + 2] & 0x3F) << 6) +
+              ((s[*ip + 3] & 0x3F));
+        *ip += 4;
+        return res;
+    }
+}
+
+/**
+ * Gets the next Unicode character in a UTF-16 sequence.  The index will
+ * be advanced to the next complete character, unless the end of string
+ * is reached in the middle of a UTF-16 surrogate pair.
+ *
+ * @param[in]     s    input UTF-16 string
+ * @param[in]     len  length of the string in words
+ * @param[in,out] ip   pointer to the index
+ * @return             the Unicode character beginning at the index; or
+ *                     #EOS if end of input is encountered
+ */
+utf32_t ub_get_next_char_utf16(
+        const utf16_t *s,
+        size_t len,
+        size_t *ip)
+{
+    utf16_t ch;
+
+    assert(*ip <= len);
+    if (*ip == len)
+        return EOS;
+    ch = s[(*ip)++];
+
+    if (ch < 0xD800 || ch > 0xDBFF)
+    {   /* If the character is not a high surrogate */
+        return ch;
+    }
+    if (*ip == len)
+    {   /* If the input ends here (an error) */
+        --(*ip);
+        return EOS;
+    }
+    if (s[*ip] < 0xDC00 || s[*ip] > 0xDFFF)
+    {   /* If the next character is not the low surrogate (an error) */
+        return ch;
+    }
+    /* Return the constructed character and advance the index again */
+    return (((utf32_t)ch & 0x3FF) << 10) + (s[(*ip)++] & 0x3FF) + 0x10000;
+}
+
+/**
+ * Gets the next Unicode character in a UTF-32 sequence.  The index will
+ * be advanced to the next character.
+ *
+ * @param[in]     s    input UTF-32 string
+ * @param[in]     len  length of the string in dwords
+ * @param[in,out] ip   pointer to the index
+ * @return             the Unicode character beginning at the index; or
+ *                     #EOS if end of input is encountered
+ */
+utf32_t ub_get_next_char_utf32(
+        const utf32_t *s,
+        size_t len,
+        size_t *ip)
+{
+    assert(*ip <= len);
+    if (*ip == len)
+        return EOS;
+    return s[(*ip)++];
+}
diff --git a/third-party/libunibreak/unibreakdef.h b/third-party/libunibreak/unibreakdef.h
new file mode 100755 (executable)
index 0000000..b823e50
--- /dev/null
@@ -0,0 +1,80 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Break processing in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2015 Wu Yongwei <wuyongwei at gmail dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ * The main reference is Unicode Standard Annex 14 (UAX #14):
+ *      <URL:http://www.unicode.org/reports/tr14/>
+ *
+ * When this library was designed, this annex was at Revision 19, for
+ * Unicode 5.0.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-19.html>
+ *
+ * This library has been updated according to Revision 33, for
+ * Unicode 7.0.0:
+ *      <URL:http://www.unicode.org/reports/tr14/tr14-33.html>
+ *
+ * The Unicode Terms of Use are available at
+ *      <URL:http://www.unicode.org/copyright.html>
+ */
+
+/**
+ * @file    unibreakdef.h
+ *
+ * Header file for private definitions in the libunibreak library.
+ *
+ * @version 1.1, 2015/04/19
+ * @author  Wu Yongwei
+ */
+
+#ifndef UNIBREAKDEF_H
+#define UNIBREAKDEF_H
+
+#include "unibreakbase.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Constant value to mark the end of string.  It is not a valid Unicode
+ * character.
+ */
+#define EOS 0xFFFFFFFF
+
+/**
+ * Abstract function interface for #ub_get_next_char_utf8,
+ * #ub_get_next_char_utf16, and #ub_get_next_char_utf32.
+ */
+typedef utf32_t (*get_next_char_t)(const void *, size_t, size_t *);
+
+/* Function Prototype */
+utf32_t ub_get_next_char_utf8(const utf8_t *s, size_t len, size_t *ip);
+utf32_t ub_get_next_char_utf16(const utf16_t *s, size_t len, size_t *ip);
+utf32_t ub_get_next_char_utf32(const utf32_t *s, size_t len, size_t *ip);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* UNIBREAKDEF_H */
diff --git a/third-party/libunibreak/wordbreak.c b/third-party/libunibreak/wordbreak.c
new file mode 100644 (file)
index 0000000..d7d5a42
--- /dev/null
@@ -0,0 +1,493 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Word breaking in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2013-2015 Tom Hacohen <tom at stosb dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ * The main reference is Unicode Standard Annex 29 (UAX #29):
+ *      <URL:http://unicode.org/reports/tr29>
+ *
+ * When this library was designed, this annex was at Revision 17, for
+ * Unicode 6.0.0:
+ *      <URL:http://www.unicode.org/reports/tr29/tr29-17.html>
+ *
+ * This library has been updated according to Revision 25, for
+ * Unicode 7.0.0:
+ *      <URL:http://www.unicode.org/reports/tr29/tr29-25.html>
+ *
+ * The Unicode Terms of Use are available at
+ *      <URL:http://www.unicode.org/copyright.html>
+ */
+
+/**
+ * @file    wordbreak.c
+ *
+ * Implementation of the word breaking algorithm as described in Unicode
+ * Standard Annex 29.
+ *
+ * @version 2.6, 2015/04/18
+ * @author  Tom Hacohen
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <string.h>
+#include "unibreakdef.h"
+#include "wordbreak.h"
+#include "wordbreakdata.c"
+
+#define ARRAY_LEN(x) (sizeof(x) / sizeof(x[0]))
+
+/**
+ * Initializes the wordbreak internals.  It currently does nothing, but
+ * it may in the future.
+ */
+void init_wordbreak(void)
+{
+}
+
+/**
+ * Gets the word breaking class of a character.
+ *
+ * @param ch   character to check
+ * @param wbp  pointer to the wbp breaking properties array
+ * @param len  size of the wbp array in number of items
+ * @return     the word breaking class if found; \c WBP_Any otherwise
+ */
+static enum WordBreakClass get_char_wb_class(
+        utf32_t ch,
+        struct WordBreakProperties *wbp,
+        size_t len)
+{
+    int min = 0;
+    int max = len - 1;
+    int mid;
+
+    do
+    {
+        mid = (min + max) / 2;
+
+        if (ch < wbp[mid].start)
+            max = mid - 1;
+        else if (ch > wbp[mid].end)
+            min = mid + 1;
+        else
+            return wbp[mid].prop;
+    }
+    while (min <= max);
+
+    return WBP_Any;
+}
+
+/**
+ * Sets the word break types to a specific value in a range.
+ *
+ * It sets the inside chars to #WORDBREAK_INSIDEACHAR and the rest to brkType.
+ * Assumes \a brks is initialized - all the cells with #WORDBREAK_NOBREAK are
+ * cells that we really don't want to break after.
+ *
+ * @param[in]  s             input string
+ * @param[out] brks          breaks array to fill
+ * @param[in]  posStart      start position
+ * @param[in]  posEnd        end position (exclusive)
+ * @param[in]  len           length of the string
+ * @param[in]  brkType       breaks type to use
+ * @param[in] get_next_char  function to get the next UTF-32 character
+ */
+static void set_brks_to(
+        const void *s,
+        char *brks,
+        size_t posStart,
+        size_t posEnd,
+        size_t len,
+        char brkType,
+        get_next_char_t get_next_char)
+{
+    size_t posNext = posStart;
+    while (posNext < posEnd)
+    {
+        utf32_t ch;
+        ch = get_next_char(s, len, &posNext);
+        assert(ch != EOS);
+        for (; posStart < posNext - 1; ++posStart)
+            brks[posStart] = WORDBREAK_INSIDEACHAR;
+        assert(posStart == posNext - 1);
+
+        /* Only set it if we haven't set it not to break before. */
+        if (brks[posStart] != WORDBREAK_NOBREAK)
+            brks[posStart] = brkType;
+        posStart = posNext;
+    }
+}
+
+/* Checks to see if the class is newline, CR, or LF (rules WB3a and b). */
+#define IS_WB3ab(cls) ((cls == WBP_Newline) || (cls == WBP_CR) || \
+                       (cls == WBP_LF))
+
+/**
+ * Sets the word breaking information for a generic input string.
+ *
+ * @param[in]  s             input string
+ * @param[in]  len           length of the input
+ * @param[in]  lang          language of the input
+ * @param[out] brks          pointer to the output breaking data, containing
+ *                           #WORDBREAK_BREAK, #WORDBREAK_NOBREAK, or
+ *                           #WORDBREAK_INSIDEACHAR
+ * @param[in] get_next_char  function to get the next UTF-32 character
+ */
+static void set_wordbreaks(
+        const void *s,
+        size_t len,
+        const char *lang,
+        char *brks,
+        get_next_char_t get_next_char)
+{
+    enum WordBreakClass wbcLast = WBP_Undefined;
+    /* wbcSeqStart is the class that started the current sequence.
+     * WBP_Undefined is a special case that means "sot".
+     * This value is the class that is at the start of the current rule
+     * matching sequence. For example, in case of Numeric+MidNum+Numeric
+     * it'll be Numeric all the way.
+     */
+    enum WordBreakClass wbcSeqStart = WBP_Undefined;
+    utf32_t ch;
+    size_t posNext = 0;
+    size_t posCur = 0;
+    size_t posLast = 0;
+
+    /* TODO: Language-specific specialization. */
+    (void) lang;
+
+    /* Init brks. */
+    memset(brks, WORDBREAK_BREAK, len);
+
+    ch = get_next_char(s, len, &posNext);
+
+    while (ch != EOS)
+    {
+        enum WordBreakClass wbcCur;
+        wbcCur = get_char_wb_class(ch, wb_prop_default,
+                                   ARRAY_LEN(wb_prop_default));
+
+        switch (wbcCur)
+        {
+        case WBP_CR:
+            /* WB3b */
+            set_brks_to(s, brks, posLast, posCur, len,
+                        WORDBREAK_BREAK, get_next_char);
+            wbcSeqStart = wbcCur;
+            posLast = posCur;
+            break;
+
+        case WBP_LF:
+            if (wbcSeqStart == WBP_CR) /* WB3 */
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_NOBREAK, get_next_char);
+                wbcSeqStart = wbcCur;
+                posLast = posCur;
+                break;
+            }
+            /* Fall off */
+
+        case WBP_Newline:
+            /* WB3a,3b */
+            set_brks_to(s, brks, posLast, posCur, len,
+                        WORDBREAK_BREAK, get_next_char);
+            wbcSeqStart = wbcCur;
+            posLast = posCur;
+            break;
+
+        case WBP_Extend:
+        case WBP_Format:
+            /* WB4 - If not the first char/after a newline (WB3a,3b), skip
+             * this class, set it to be the same as the prev, and mark
+             * brks not to break before them. */
+            if ((wbcSeqStart == WBP_Undefined) || IS_WB3ab(wbcSeqStart))
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_BREAK, get_next_char);
+                wbcSeqStart = wbcCur;
+            }
+            else
+            {
+                /* It's surely not the first */
+                brks[posCur - 1] = WORDBREAK_NOBREAK;
+                /* "inherit" the previous class. */
+                wbcCur = wbcLast;
+            }
+            break;
+
+        case WBP_Katakana:
+            if ((wbcSeqStart == WBP_Katakana) || /* WB13 */
+                    (wbcSeqStart == WBP_ExtendNumLet)) /* WB13b */
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_NOBREAK, get_next_char);
+            }
+            /* No rule found, reset */
+            else
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_BREAK, get_next_char);
+            }
+            wbcSeqStart = wbcCur;
+            posLast = posCur;
+            break;
+
+        case WBP_Hebrew_Letter:
+        case WBP_ALetter:
+            if ((wbcSeqStart == WBP_Hebrew_Letter) &&
+                    (wbcLast == WBP_Double_Quote)) /* WB7b,c */
+            {
+               if (wbcCur == WBP_Hebrew_Letter)
+                 {
+                     set_brks_to(s, brks, posLast, posCur, len,
+                             WORDBREAK_NOBREAK, get_next_char);
+                 }
+               else
+                 {
+                     set_brks_to(s, brks, posLast, posCur, len,
+                             WORDBREAK_BREAK, get_next_char);
+                 }
+            }
+            else if (((wbcSeqStart == WBP_ALetter) ||
+                        (wbcSeqStart == WBP_Hebrew_Letter)) || /* WB5,6,7 */
+                    (wbcLast == WBP_Numeric) || /* WB10 */
+                    (wbcSeqStart == WBP_ExtendNumLet)) /* WB13b */
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_NOBREAK, get_next_char);
+            }
+            /* No rule found, reset */
+            else
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_BREAK, get_next_char);
+            }
+            wbcSeqStart = wbcCur;
+            posLast = posCur;
+            break;
+
+        case WBP_Single_Quote:
+            if (wbcLast == WBP_Hebrew_Letter) /* WB7a */
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_NOBREAK, get_next_char);
+                wbcSeqStart = wbcCur;
+                posLast = posCur;
+            }
+            /* No break on purpose */
+        case WBP_MidNumLet:
+            if (((wbcLast == WBP_ALetter) ||
+                        (wbcLast == WBP_Hebrew_Letter)) || /* WB6,7 */
+                    (wbcLast == WBP_Numeric)) /* WB11,12 */
+            {
+                /* Go on */
+            }
+            else
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_BREAK, get_next_char);
+                wbcSeqStart = wbcCur;
+                posLast = posCur;
+            }
+            break;
+
+        case WBP_MidLetter:
+            if ((wbcLast == WBP_ALetter) ||
+                    (wbcLast == WBP_Hebrew_Letter)) /* WB6,7 */
+            {
+                /* Go on */
+            }
+            else
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_BREAK, get_next_char);
+                wbcSeqStart = wbcCur;
+                posLast = posCur;
+            }
+            break;
+
+        case WBP_MidNum:
+            if (wbcLast == WBP_Numeric) /* WB11,12 */
+            {
+                /* Go on */
+            }
+            else
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_BREAK, get_next_char);
+                wbcSeqStart = wbcCur;
+                posLast = posCur;
+            }
+            break;
+
+        case WBP_Numeric:
+            if ((wbcSeqStart == WBP_Numeric) || /* WB8,11,12 */
+                    ((wbcLast == WBP_ALetter) ||
+                     (wbcLast == WBP_Hebrew_Letter)) || /* WB9 */
+                    (wbcSeqStart == WBP_ExtendNumLet)) /* WB13b */
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_NOBREAK, get_next_char);
+            }
+            /* No rule found, reset */
+            else
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_BREAK, get_next_char);
+            }
+            wbcSeqStart = wbcCur;
+            posLast = posCur;
+            break;
+
+        case WBP_ExtendNumLet:
+            /* WB13a,13b */
+            if ((wbcSeqStart == wbcLast) &&
+                ((wbcLast == WBP_ALetter) ||
+                 (wbcLast == WBP_Hebrew_Letter) ||
+                 (wbcLast == WBP_Numeric) ||
+                 (wbcLast == WBP_Katakana) ||
+                 (wbcLast == WBP_ExtendNumLet)))
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_NOBREAK, get_next_char);
+            }
+            /* No rule found, reset */
+            else
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_BREAK, get_next_char);
+            }
+            wbcSeqStart = wbcCur;
+            posLast = posCur;
+            break;
+
+        case WBP_Regional_Indicator:
+            /* WB13c */
+            if (wbcSeqStart == WBP_Regional_Indicator)
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_NOBREAK, get_next_char);
+            }
+            wbcSeqStart = wbcCur;
+            posLast = posCur;
+            break;
+
+        case WBP_Double_Quote:
+            if (wbcLast == WBP_Hebrew_Letter) /* WB7b,c */
+            {
+               /* Go on */
+            }
+            else
+            {
+                set_brks_to(s, brks, posLast, posCur, len,
+                            WORDBREAK_BREAK, get_next_char);
+                wbcSeqStart = wbcCur;
+                posLast = posCur;
+            }
+            break;
+
+        case WBP_Any:
+            /* Allow breaks and reset */
+            set_brks_to(s, brks, posLast, posCur, len,
+                        WORDBREAK_BREAK, get_next_char);
+            wbcSeqStart = wbcCur;
+            posLast = posCur;
+            break;
+
+        default:
+            /* Error, should never get here! */
+            assert(0);
+            break;
+        }
+
+        wbcLast = wbcCur;
+        posCur = posNext;
+        ch = get_next_char(s, len, &posNext);
+    }
+
+    /* WB2 */
+    set_brks_to(s, brks, posLast, posNext, len,
+                WORDBREAK_BREAK, get_next_char);
+}
+
+/**
+ * Sets the word breaking information for a UTF-8 input string.
+ *
+ * @param[in]  s     input UTF-8 string
+ * @param[in]  len   length of the input
+ * @param[in]  lang  language of the input
+ * @param[out] brks  pointer to the output breaking data, containing
+ *                   #WORDBREAK_BREAK, #WORDBREAK_NOBREAK, or
+ *                   #WORDBREAK_INSIDEACHAR
+ */
+void set_wordbreaks_utf8(
+        const utf8_t *s,
+        size_t len,
+        const char *lang,
+        char *brks)
+{
+    set_wordbreaks(s, len, lang, brks,
+                   (get_next_char_t)ub_get_next_char_utf8);
+}
+
+/**
+ * Sets the word breaking information for a UTF-16 input string.
+ *
+ * @param[in]  s     input UTF-16 string
+ * @param[in]  len   length of the input
+ * @param[in]  lang  language of the input
+ * @param[out] brks  pointer to the output breaking data, containing
+ *                   #WORDBREAK_BREAK, #WORDBREAK_NOBREAK, or
+ *                   #WORDBREAK_INSIDEACHAR
+ */
+void set_wordbreaks_utf16(
+        const utf16_t *s,
+        size_t len,
+        const char *lang,
+        char *brks)
+{
+    set_wordbreaks(s, len, lang, brks,
+                   (get_next_char_t)ub_get_next_char_utf16);
+}
+
+/**
+ * Sets the word breaking information for a UTF-32 input string.
+ *
+ * @param[in]  s     input UTF-32 string
+ * @param[in]  len   length of the input
+ * @param[in]  lang  language of the input
+ * @param[out] brks  pointer to the output breaking data, containing
+ *                   #WORDBREAK_BREAK, #WORDBREAK_NOBREAK, or
+ *                   #WORDBREAK_INSIDEACHAR
+ */
+void set_wordbreaks_utf32(
+        const utf32_t *s,
+        size_t len,
+        const char *lang,
+        char *brks)
+{
+    set_wordbreaks(s, len, lang, brks,
+                   (get_next_char_t)ub_get_next_char_utf32);
+}
diff --git a/third-party/libunibreak/wordbreak.h b/third-party/libunibreak/wordbreak.h
new file mode 100644 (file)
index 0000000..360953f
--- /dev/null
@@ -0,0 +1,76 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Word breaking in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2013-2015 Tom Hacohen <tom at stosb dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ * The main reference is Unicode Standard Annex 29 (UAX #29):
+ *      <URL:http://unicode.org/reports/tr29>
+ *
+ * When this library was designed, this annex was at Revision 17, for
+ * Unicode 6.0.0:
+ *      <URL:http://www.unicode.org/reports/tr29/tr29-17.html>
+ *
+ * This library has been updated according to Revision 25, for
+ * Unicode 7.0.0:
+ *      <URL:http://www.unicode.org/reports/tr29/tr29-25.html>
+ *
+ * The Unicode Terms of Use are available at
+ *      <URL:http://www.unicode.org/copyright.html>
+ */
+
+/**
+ * @file    wordbreak.h
+ *
+ * Header file for the word breaking (segmentation) algorithm.
+ *
+ * @version 2.5, 2015/04/18
+ * @author  Tom Hacohen
+ */
+
+#ifndef WORDBREAK_H
+#define WORDBREAK_H
+
+#include <stddef.h>
+#include "unibreakbase.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define WORDBREAK_BREAK         0   /**< Break is allowed */
+#define WORDBREAK_NOBREAK       1   /**< No break is allowed */
+#define WORDBREAK_INSIDEACHAR   2   /**< A UTF-8/16 sequence is unfinished */
+
+void init_wordbreak(void);
+void set_wordbreaks_utf8(
+        const utf8_t *s, size_t len, const char* lang, char *brks);
+void set_wordbreaks_utf16(
+        const utf16_t *s, size_t len, const char* lang, char *brks);
+void set_wordbreaks_utf32(
+        const utf32_t *s, size_t len, const char* lang, char *brks);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/third-party/libunibreak/wordbreakdata.c b/third-party/libunibreak/wordbreakdata.c
new file mode 100644 (file)
index 0000000..c6d5694
--- /dev/null
@@ -0,0 +1,1072 @@
+/* The content of this file is generated from:
+# WordBreakProperty-7.0.0.txt
+# Date: 2014-02-19, 15:51:39 GMT [MD]
+*/
+
+#include "wordbreakdef.h"
+
+static struct WordBreakProperties wb_prop_default[] = {
+       {0x000A, 0x000A, WBP_LF},
+       {0x000B, 0x000C, WBP_Newline},
+       {0x000D, 0x000D, WBP_CR},
+       {0x0022, 0x0022, WBP_Double_Quote},
+       {0x0027, 0x0027, WBP_Single_Quote},
+       {0x002C, 0x002C, WBP_MidNum},
+       {0x002E, 0x002E, WBP_MidNumLet},
+       {0x0030, 0x0039, WBP_Numeric},
+       {0x003A, 0x003A, WBP_MidLetter},
+       {0x003B, 0x003B, WBP_MidNum},
+       {0x0041, 0x005A, WBP_ALetter},
+       {0x005F, 0x005F, WBP_ExtendNumLet},
+       {0x0061, 0x007A, WBP_ALetter},
+       {0x0085, 0x0085, WBP_Newline},
+       {0x00AA, 0x00AA, WBP_ALetter},
+       {0x00AD, 0x00AD, WBP_Format},
+       {0x00B5, 0x00B5, WBP_ALetter},
+       {0x00B7, 0x00B7, WBP_MidLetter},
+       {0x00BA, 0x00BA, WBP_ALetter},
+       {0x00C0, 0x00D6, WBP_ALetter},
+       {0x00D8, 0x00F6, WBP_ALetter},
+       {0x00F8, 0x01BA, WBP_ALetter},
+       {0x01BB, 0x01BB, WBP_ALetter},
+       {0x01BC, 0x01BF, WBP_ALetter},
+       {0x01C0, 0x01C3, WBP_ALetter},
+       {0x01C4, 0x0293, WBP_ALetter},
+       {0x0294, 0x0294, WBP_ALetter},
+       {0x0295, 0x02AF, WBP_ALetter},
+       {0x02B0, 0x02C1, WBP_ALetter},
+       {0x02C6, 0x02D1, WBP_ALetter},
+       {0x02D7, 0x02D7, WBP_MidLetter},
+       {0x02E0, 0x02E4, WBP_ALetter},
+       {0x02EC, 0x02EC, WBP_ALetter},
+       {0x02EE, 0x02EE, WBP_ALetter},
+       {0x0300, 0x036F, WBP_Extend},
+       {0x0370, 0x0373, WBP_ALetter},
+       {0x0374, 0x0374, WBP_ALetter},
+       {0x0376, 0x0377, WBP_ALetter},
+       {0x037A, 0x037A, WBP_ALetter},
+       {0x037B, 0x037D, WBP_ALetter},
+       {0x037E, 0x037E, WBP_MidNum},
+       {0x037F, 0x037F, WBP_ALetter},
+       {0x0386, 0x0386, WBP_ALetter},
+       {0x0387, 0x0387, WBP_MidLetter},
+       {0x0388, 0x038A, WBP_ALetter},
+       {0x038C, 0x038C, WBP_ALetter},
+       {0x038E, 0x03A1, WBP_ALetter},
+       {0x03A3, 0x03F5, WBP_ALetter},
+       {0x03F7, 0x0481, WBP_ALetter},
+       {0x0483, 0x0487, WBP_Extend},
+       {0x0488, 0x0489, WBP_Extend},
+       {0x048A, 0x052F, WBP_ALetter},
+       {0x0531, 0x0556, WBP_ALetter},
+       {0x0559, 0x0559, WBP_ALetter},
+       {0x0561, 0x0587, WBP_ALetter},
+       {0x0589, 0x0589, WBP_MidNum},
+       {0x0591, 0x05BD, WBP_Extend},
+       {0x05BF, 0x05BF, WBP_Extend},
+       {0x05C1, 0x05C2, WBP_Extend},
+       {0x05C4, 0x05C5, WBP_Extend},
+       {0x05C7, 0x05C7, WBP_Extend},
+       {0x05D0, 0x05EA, WBP_Hebrew_Letter},
+       {0x05F0, 0x05F2, WBP_Hebrew_Letter},
+       {0x05F3, 0x05F3, WBP_ALetter},
+       {0x05F4, 0x05F4, WBP_MidLetter},
+       {0x0600, 0x0605, WBP_Format},
+       {0x060C, 0x060D, WBP_MidNum},
+       {0x0610, 0x061A, WBP_Extend},
+       {0x061C, 0x061C, WBP_Format},
+       {0x0620, 0x063F, WBP_ALetter},
+       {0x0640, 0x0640, WBP_ALetter},
+       {0x0641, 0x064A, WBP_ALetter},
+       {0x064B, 0x065F, WBP_Extend},
+       {0x0660, 0x0669, WBP_Numeric},
+       {0x066B, 0x066B, WBP_Numeric},
+       {0x066C, 0x066C, WBP_MidNum},
+       {0x066E, 0x066F, WBP_ALetter},
+       {0x0670, 0x0670, WBP_Extend},
+       {0x0671, 0x06D3, WBP_ALetter},
+       {0x06D5, 0x06D5, WBP_ALetter},
+       {0x06D6, 0x06DC, WBP_Extend},
+       {0x06DD, 0x06DD, WBP_Format},
+       {0x06DF, 0x06E4, WBP_Extend},
+       {0x06E5, 0x06E6, WBP_ALetter},
+       {0x06E7, 0x06E8, WBP_Extend},
+       {0x06EA, 0x06ED, WBP_Extend},
+       {0x06EE, 0x06EF, WBP_ALetter},
+       {0x06F0, 0x06F9, WBP_Numeric},
+       {0x06FA, 0x06FC, WBP_ALetter},
+       {0x06FF, 0x06FF, WBP_ALetter},
+       {0x070F, 0x070F, WBP_Format},
+       {0x0710, 0x0710, WBP_ALetter},
+       {0x0711, 0x0711, WBP_Extend},
+       {0x0712, 0x072F, WBP_ALetter},
+       {0x0730, 0x074A, WBP_Extend},
+       {0x074D, 0x07A5, WBP_ALetter},
+       {0x07A6, 0x07B0, WBP_Extend},
+       {0x07B1, 0x07B1, WBP_ALetter},
+       {0x07C0, 0x07C9, WBP_Numeric},
+       {0x07CA, 0x07EA, WBP_ALetter},
+       {0x07EB, 0x07F3, WBP_Extend},
+       {0x07F4, 0x07F5, WBP_ALetter},
+       {0x07F8, 0x07F8, WBP_MidNum},
+       {0x07FA, 0x07FA, WBP_ALetter},
+       {0x0800, 0x0815, WBP_ALetter},
+       {0x0816, 0x0819, WBP_Extend},
+       {0x081A, 0x081A, WBP_ALetter},
+       {0x081B, 0x0823, WBP_Extend},
+       {0x0824, 0x0824, WBP_ALetter},
+       {0x0825, 0x0827, WBP_Extend},
+       {0x0828, 0x0828, WBP_ALetter},
+       {0x0829, 0x082D, WBP_Extend},
+       {0x0840, 0x0858, WBP_ALetter},
+       {0x0859, 0x085B, WBP_Extend},
+       {0x08A0, 0x08B2, WBP_ALetter},
+       {0x08E4, 0x0902, WBP_Extend},
+       {0x0903, 0x0903, WBP_Extend},
+       {0x0904, 0x0939, WBP_ALetter},
+       {0x093A, 0x093A, WBP_Extend},
+       {0x093B, 0x093B, WBP_Extend},
+       {0x093C, 0x093C, WBP_Extend},
+       {0x093D, 0x093D, WBP_ALetter},
+       {0x093E, 0x0940, WBP_Extend},
+       {0x0941, 0x0948, WBP_Extend},
+       {0x0949, 0x094C, WBP_Extend},
+       {0x094D, 0x094D, WBP_Extend},
+       {0x094E, 0x094F, WBP_Extend},
+       {0x0950, 0x0950, WBP_ALetter},
+       {0x0951, 0x0957, WBP_Extend},
+       {0x0958, 0x0961, WBP_ALetter},
+       {0x0962, 0x0963, WBP_Extend},
+       {0x0966, 0x096F, WBP_Numeric},
+       {0x0971, 0x0971, WBP_ALetter},
+       {0x0972, 0x0980, WBP_ALetter},
+       {0x0981, 0x0981, WBP_Extend},
+       {0x0982, 0x0983, WBP_Extend},
+       {0x0985, 0x098C, WBP_ALetter},
+       {0x098F, 0x0990, WBP_ALetter},
+       {0x0993, 0x09A8, WBP_ALetter},
+       {0x09AA, 0x09B0, WBP_ALetter},
+       {0x09B2, 0x09B2, WBP_ALetter},
+       {0x09B6, 0x09B9, WBP_ALetter},
+       {0x09BC, 0x09BC, WBP_Extend},
+       {0x09BD, 0x09BD, WBP_ALetter},
+       {0x09BE, 0x09C0, WBP_Extend},
+       {0x09C1, 0x09C4, WBP_Extend},
+       {0x09C7, 0x09C8, WBP_Extend},
+       {0x09CB, 0x09CC, WBP_Extend},
+       {0x09CD, 0x09CD, WBP_Extend},
+       {0x09CE, 0x09CE, WBP_ALetter},
+       {0x09D7, 0x09D7, WBP_Extend},
+       {0x09DC, 0x09DD, WBP_ALetter},
+       {0x09DF, 0x09E1, WBP_ALetter},
+       {0x09E2, 0x09E3, WBP_Extend},
+       {0x09E6, 0x09EF, WBP_Numeric},
+       {0x09F0, 0x09F1, WBP_ALetter},
+       {0x0A01, 0x0A02, WBP_Extend},
+       {0x0A03, 0x0A03, WBP_Extend},
+       {0x0A05, 0x0A0A, WBP_ALetter},
+       {0x0A0F, 0x0A10, WBP_ALetter},
+       {0x0A13, 0x0A28, WBP_ALetter},
+       {0x0A2A, 0x0A30, WBP_ALetter},
+       {0x0A32, 0x0A33, WBP_ALetter},
+       {0x0A35, 0x0A36, WBP_ALetter},
+       {0x0A38, 0x0A39, WBP_ALetter},
+       {0x0A3C, 0x0A3C, WBP_Extend},
+       {0x0A3E, 0x0A40, WBP_Extend},
+       {0x0A41, 0x0A42, WBP_Extend},
+       {0x0A47, 0x0A48, WBP_Extend},
+       {0x0A4B, 0x0A4D, WBP_Extend},
+       {0x0A51, 0x0A51, WBP_Extend},
+       {0x0A59, 0x0A5C, WBP_ALetter},
+       {0x0A5E, 0x0A5E, WBP_ALetter},
+       {0x0A66, 0x0A6F, WBP_Numeric},
+       {0x0A70, 0x0A71, WBP_Extend},
+       {0x0A72, 0x0A74, WBP_ALetter},
+       {0x0A75, 0x0A75, WBP_Extend},
+       {0x0A81, 0x0A82, WBP_Extend},
+       {0x0A83, 0x0A83, WBP_Extend},
+       {0x0A85, 0x0A8D, WBP_ALetter},
+       {0x0A8F, 0x0A91, WBP_ALetter},
+       {0x0A93, 0x0AA8, WBP_ALetter},
+       {0x0AAA, 0x0AB0, WBP_ALetter},
+       {0x0AB2, 0x0AB3, WBP_ALetter},
+       {0x0AB5, 0x0AB9, WBP_ALetter},
+       {0x0ABC, 0x0ABC, WBP_Extend},
+       {0x0ABD, 0x0ABD, WBP_ALetter},
+       {0x0ABE, 0x0AC0, WBP_Extend},
+       {0x0AC1, 0x0AC5, WBP_Extend},
+       {0x0AC7, 0x0AC8, WBP_Extend},
+       {0x0AC9, 0x0AC9, WBP_Extend},
+       {0x0ACB, 0x0ACC, WBP_Extend},
+       {0x0ACD, 0x0ACD, WBP_Extend},
+       {0x0AD0, 0x0AD0, WBP_ALetter},
+       {0x0AE0, 0x0AE1, WBP_ALetter},
+       {0x0AE2, 0x0AE3, WBP_Extend},
+       {0x0AE6, 0x0AEF, WBP_Numeric},
+       {0x0B01, 0x0B01, WBP_Extend},
+       {0x0B02, 0x0B03, WBP_Extend},
+       {0x0B05, 0x0B0C, WBP_ALetter},
+       {0x0B0F, 0x0B10, WBP_ALetter},
+       {0x0B13, 0x0B28, WBP_ALetter},
+       {0x0B2A, 0x0B30, WBP_ALetter},
+       {0x0B32, 0x0B33, WBP_ALetter},
+       {0x0B35, 0x0B39, WBP_ALetter},
+       {0x0B3C, 0x0B3C, WBP_Extend},
+       {0x0B3D, 0x0B3D, WBP_ALetter},
+       {0x0B3E, 0x0B3E, WBP_Extend},
+       {0x0B3F, 0x0B3F, WBP_Extend},
+       {0x0B40, 0x0B40, WBP_Extend},
+       {0x0B41, 0x0B44, WBP_Extend},
+       {0x0B47, 0x0B48, WBP_Extend},
+       {0x0B4B, 0x0B4C, WBP_Extend},
+       {0x0B4D, 0x0B4D, WBP_Extend},
+       {0x0B56, 0x0B56, WBP_Extend},
+       {0x0B57, 0x0B57, WBP_Extend},
+       {0x0B5C, 0x0B5D, WBP_ALetter},
+       {0x0B5F, 0x0B61, WBP_ALetter},
+       {0x0B62, 0x0B63, WBP_Extend},
+       {0x0B66, 0x0B6F, WBP_Numeric},
+       {0x0B71, 0x0B71, WBP_ALetter},
+       {0x0B82, 0x0B82, WBP_Extend},
+       {0x0B83, 0x0B83, WBP_ALetter},
+       {0x0B85, 0x0B8A, WBP_ALetter},
+       {0x0B8E, 0x0B90, WBP_ALetter},
+       {0x0B92, 0x0B95, WBP_ALetter},
+       {0x0B99, 0x0B9A, WBP_ALetter},
+       {0x0B9C, 0x0B9C, WBP_ALetter},
+       {0x0B9E, 0x0B9F, WBP_ALetter},
+       {0x0BA3, 0x0BA4, WBP_ALetter},
+       {0x0BA8, 0x0BAA, WBP_ALetter},
+       {0x0BAE, 0x0BB9, WBP_ALetter},
+       {0x0BBE, 0x0BBF, WBP_Extend},
+       {0x0BC0, 0x0BC0, WBP_Extend},
+       {0x0BC1, 0x0BC2, WBP_Extend},
+       {0x0BC6, 0x0BC8, WBP_Extend},
+       {0x0BCA, 0x0BCC, WBP_Extend},
+       {0x0BCD, 0x0BCD, WBP_Extend},
+       {0x0BD0, 0x0BD0, WBP_ALetter},
+       {0x0BD7, 0x0BD7, WBP_Extend},
+       {0x0BE6, 0x0BEF, WBP_Numeric},
+       {0x0C00, 0x0C00, WBP_Extend},
+       {0x0C01, 0x0C03, WBP_Extend},
+       {0x0C05, 0x0C0C, WBP_ALetter},
+       {0x0C0E, 0x0C10, WBP_ALetter},
+       {0x0C12, 0x0C28, WBP_ALetter},
+       {0x0C2A, 0x0C39, WBP_ALetter},
+       {0x0C3D, 0x0C3D, WBP_ALetter},
+       {0x0C3E, 0x0C40, WBP_Extend},
+       {0x0C41, 0x0C44, WBP_Extend},
+       {0x0C46, 0x0C48, WBP_Extend},
+       {0x0C4A, 0x0C4D, WBP_Extend},
+       {0x0C55, 0x0C56, WBP_Extend},
+       {0x0C58, 0x0C59, WBP_ALetter},
+       {0x0C60, 0x0C61, WBP_ALetter},
+       {0x0C62, 0x0C63, WBP_Extend},
+       {0x0C66, 0x0C6F, WBP_Numeric},
+       {0x0C81, 0x0C81, WBP_Extend},
+       {0x0C82, 0x0C83, WBP_Extend},
+       {0x0C85, 0x0C8C, WBP_ALetter},
+       {0x0C8E, 0x0C90, WBP_ALetter},
+       {0x0C92, 0x0CA8, WBP_ALetter},
+       {0x0CAA, 0x0CB3, WBP_ALetter},
+       {0x0CB5, 0x0CB9, WBP_ALetter},
+       {0x0CBC, 0x0CBC, WBP_Extend},
+       {0x0CBD, 0x0CBD, WBP_ALetter},
+       {0x0CBE, 0x0CBE, WBP_Extend},
+       {0x0CBF, 0x0CBF, WBP_Extend},
+       {0x0CC0, 0x0CC4, WBP_Extend},
+       {0x0CC6, 0x0CC6, WBP_Extend},
+       {0x0CC7, 0x0CC8, WBP_Extend},
+       {0x0CCA, 0x0CCB, WBP_Extend},
+       {0x0CCC, 0x0CCD, WBP_Extend},
+       {0x0CD5, 0x0CD6, WBP_Extend},
+       {0x0CDE, 0x0CDE, WBP_ALetter},
+       {0x0CE0, 0x0CE1, WBP_ALetter},
+       {0x0CE2, 0x0CE3, WBP_Extend},
+       {0x0CE6, 0x0CEF, WBP_Numeric},
+       {0x0CF1, 0x0CF2, WBP_ALetter},
+       {0x0D01, 0x0D01, WBP_Extend},
+       {0x0D02, 0x0D03, WBP_Extend},
+       {0x0D05, 0x0D0C, WBP_ALetter},
+       {0x0D0E, 0x0D10, WBP_ALetter},
+       {0x0D12, 0x0D3A, WBP_ALetter},
+       {0x0D3D, 0x0D3D, WBP_ALetter},
+       {0x0D3E, 0x0D40, WBP_Extend},
+       {0x0D41, 0x0D44, WBP_Extend},
+       {0x0D46, 0x0D48, WBP_Extend},
+       {0x0D4A, 0x0D4C, WBP_Extend},
+       {0x0D4D, 0x0D4D, WBP_Extend},
+       {0x0D4E, 0x0D4E, WBP_ALetter},
+       {0x0D57, 0x0D57, WBP_Extend},
+       {0x0D60, 0x0D61, WBP_ALetter},
+       {0x0D62, 0x0D63, WBP_Extend},
+       {0x0D66, 0x0D6F, WBP_Numeric},
+       {0x0D7A, 0x0D7F, WBP_ALetter},
+       {0x0D82, 0x0D83, WBP_Extend},
+       {0x0D85, 0x0D96, WBP_ALetter},
+       {0x0D9A, 0x0DB1, WBP_ALetter},
+       {0x0DB3, 0x0DBB, WBP_ALetter},
+       {0x0DBD, 0x0DBD, WBP_ALetter},
+       {0x0DC0, 0x0DC6, WBP_ALetter},
+       {0x0DCA, 0x0DCA, WBP_Extend},
+       {0x0DCF, 0x0DD1, WBP_Extend},
+       {0x0DD2, 0x0DD4, WBP_Extend},
+       {0x0DD6, 0x0DD6, WBP_Extend},
+       {0x0DD8, 0x0DDF, WBP_Extend},
+       {0x0DE6, 0x0DEF, WBP_Numeric},
+       {0x0DF2, 0x0DF3, WBP_Extend},
+       {0x0E31, 0x0E31, WBP_Extend},
+       {0x0E34, 0x0E3A, WBP_Extend},
+       {0x0E47, 0x0E4E, WBP_Extend},
+       {0x0E50, 0x0E59, WBP_Numeric},
+       {0x0EB1, 0x0EB1, WBP_Extend},
+       {0x0EB4, 0x0EB9, WBP_Extend},
+       {0x0EBB, 0x0EBC, WBP_Extend},
+       {0x0EC8, 0x0ECD, WBP_Extend},
+       {0x0ED0, 0x0ED9, WBP_Numeric},
+       {0x0F00, 0x0F00, WBP_ALetter},
+       {0x0F18, 0x0F19, WBP_Extend},
+       {0x0F20, 0x0F29, WBP_Numeric},
+       {0x0F35, 0x0F35, WBP_Extend},
+       {0x0F37, 0x0F37, WBP_Extend},
+       {0x0F39, 0x0F39, WBP_Extend},
+       {0x0F3E, 0x0F3F, WBP_Extend},
+       {0x0F40, 0x0F47, WBP_ALetter},
+       {0x0F49, 0x0F6C, WBP_ALetter},
+       {0x0F71, 0x0F7E, WBP_Extend},
+       {0x0F7F, 0x0F7F, WBP_Extend},
+       {0x0F80, 0x0F84, WBP_Extend},
+       {0x0F86, 0x0F87, WBP_Extend},
+       {0x0F88, 0x0F8C, WBP_ALetter},
+       {0x0F8D, 0x0F97, WBP_Extend},
+       {0x0F99, 0x0FBC, WBP_Extend},
+       {0x0FC6, 0x0FC6, WBP_Extend},
+       {0x102B, 0x102C, WBP_Extend},
+       {0x102D, 0x1030, WBP_Extend},
+       {0x1031, 0x1031, WBP_Extend},
+       {0x1032, 0x1037, WBP_Extend},
+       {0x1038, 0x1038, WBP_Extend},
+       {0x1039, 0x103A, WBP_Extend},
+       {0x103B, 0x103C, WBP_Extend},
+       {0x103D, 0x103E, WBP_Extend},
+       {0x1040, 0x1049, WBP_Numeric},
+       {0x1056, 0x1057, WBP_Extend},
+       {0x1058, 0x1059, WBP_Extend},
+       {0x105E, 0x1060, WBP_Extend},
+       {0x1062, 0x1064, WBP_Extend},
+       {0x1067, 0x106D, WBP_Extend},
+       {0x1071, 0x1074, WBP_Extend},
+       {0x1082, 0x1082, WBP_Extend},
+       {0x1083, 0x1084, WBP_Extend},
+       {0x1085, 0x1086, WBP_Extend},
+       {0x1087, 0x108C, WBP_Extend},
+       {0x108D, 0x108D, WBP_Extend},
+       {0x108F, 0x108F, WBP_Extend},
+       {0x1090, 0x1099, WBP_Numeric},
+       {0x109A, 0x109C, WBP_Extend},
+       {0x109D, 0x109D, WBP_Extend},
+       {0x10A0, 0x10C5, WBP_ALetter},
+       {0x10C7, 0x10C7, WBP_ALetter},
+       {0x10CD, 0x10CD, WBP_ALetter},
+       {0x10D0, 0x10FA, WBP_ALetter},
+       {0x10FC, 0x10FC, WBP_ALetter},
+       {0x10FD, 0x1248, WBP_ALetter},
+       {0x124A, 0x124D, WBP_ALetter},
+       {0x1250, 0x1256, WBP_ALetter},
+       {0x1258, 0x1258, WBP_ALetter},
+       {0x125A, 0x125D, WBP_ALetter},
+       {0x1260, 0x1288, WBP_ALetter},
+       {0x128A, 0x128D, WBP_ALetter},
+       {0x1290, 0x12B0, WBP_ALetter},
+       {0x12B2, 0x12B5, WBP_ALetter},
+       {0x12B8, 0x12BE, WBP_ALetter},
+       {0x12C0, 0x12C0, WBP_ALetter},
+       {0x12C2, 0x12C5, WBP_ALetter},
+       {0x12C8, 0x12D6, WBP_ALetter},
+       {0x12D8, 0x1310, WBP_ALetter},
+       {0x1312, 0x1315, WBP_ALetter},
+       {0x1318, 0x135A, WBP_ALetter},
+       {0x135D, 0x135F, WBP_Extend},
+       {0x1380, 0x138F, WBP_ALetter},
+       {0x13A0, 0x13F4, WBP_ALetter},
+       {0x1401, 0x166C, WBP_ALetter},
+       {0x166F, 0x167F, WBP_ALetter},
+       {0x1681, 0x169A, WBP_ALetter},
+       {0x16A0, 0x16EA, WBP_ALetter},
+       {0x16EE, 0x16F0, WBP_ALetter},
+       {0x16F1, 0x16F8, WBP_ALetter},
+       {0x1700, 0x170C, WBP_ALetter},
+       {0x170E, 0x1711, WBP_ALetter},
+       {0x1712, 0x1714, WBP_Extend},
+       {0x1720, 0x1731, WBP_ALetter},
+       {0x1732, 0x1734, WBP_Extend},
+       {0x1740, 0x1751, WBP_ALetter},
+       {0x1752, 0x1753, WBP_Extend},
+       {0x1760, 0x176C, WBP_ALetter},
+       {0x176E, 0x1770, WBP_ALetter},
+       {0x1772, 0x1773, WBP_Extend},
+       {0x17B4, 0x17B5, WBP_Extend},
+       {0x17B6, 0x17B6, WBP_Extend},
+       {0x17B7, 0x17BD, WBP_Extend},
+       {0x17BE, 0x17C5, WBP_Extend},
+       {0x17C6, 0x17C6, WBP_Extend},
+       {0x17C7, 0x17C8, WBP_Extend},
+       {0x17C9, 0x17D3, WBP_Extend},
+       {0x17DD, 0x17DD, WBP_Extend},
+       {0x17E0, 0x17E9, WBP_Numeric},
+       {0x180B, 0x180D, WBP_Extend},
+       {0x180E, 0x180E, WBP_Format},
+       {0x1810, 0x1819, WBP_Numeric},
+       {0x1820, 0x1842, WBP_ALetter},
+       {0x1843, 0x1843, WBP_ALetter},
+       {0x1844, 0x1877, WBP_ALetter},
+       {0x1880, 0x18A8, WBP_ALetter},
+       {0x18A9, 0x18A9, WBP_Extend},
+       {0x18AA, 0x18AA, WBP_ALetter},
+       {0x18B0, 0x18F5, WBP_ALetter},
+       {0x1900, 0x191E, WBP_ALetter},
+       {0x1920, 0x1922, WBP_Extend},
+       {0x1923, 0x1926, WBP_Extend},
+       {0x1927, 0x1928, WBP_Extend},
+       {0x1929, 0x192B, WBP_Extend},
+       {0x1930, 0x1931, WBP_Extend},
+       {0x1932, 0x1932, WBP_Extend},
+       {0x1933, 0x1938, WBP_Extend},
+       {0x1939, 0x193B, WBP_Extend},
+       {0x1946, 0x194F, WBP_Numeric},
+       {0x19B0, 0x19C0, WBP_Extend},
+       {0x19C8, 0x19C9, WBP_Extend},
+       {0x19D0, 0x19D9, WBP_Numeric},
+       {0x1A00, 0x1A16, WBP_ALetter},
+       {0x1A17, 0x1A18, WBP_Extend},
+       {0x1A19, 0x1A1A, WBP_Extend},
+       {0x1A1B, 0x1A1B, WBP_Extend},
+       {0x1A55, 0x1A55, WBP_Extend},
+       {0x1A56, 0x1A56, WBP_Extend},
+       {0x1A57, 0x1A57, WBP_Extend},
+       {0x1A58, 0x1A5E, WBP_Extend},
+       {0x1A60, 0x1A60, WBP_Extend},
+       {0x1A61, 0x1A61, WBP_Extend},
+       {0x1A62, 0x1A62, WBP_Extend},
+       {0x1A63, 0x1A64, WBP_Extend},
+       {0x1A65, 0x1A6C, WBP_Extend},
+       {0x1A6D, 0x1A72, WBP_Extend},
+       {0x1A73, 0x1A7C, WBP_Extend},
+       {0x1A7F, 0x1A7F, WBP_Extend},
+       {0x1A80, 0x1A89, WBP_Numeric},
+       {0x1A90, 0x1A99, WBP_Numeric},
+       {0x1AB0, 0x1ABD, WBP_Extend},
+       {0x1ABE, 0x1ABE, WBP_Extend},
+       {0x1B00, 0x1B03, WBP_Extend},
+       {0x1B04, 0x1B04, WBP_Extend},
+       {0x1B05, 0x1B33, WBP_ALetter},
+       {0x1B34, 0x1B34, WBP_Extend},
+       {0x1B35, 0x1B35, WBP_Extend},
+       {0x1B36, 0x1B3A, WBP_Extend},
+       {0x1B3B, 0x1B3B, WBP_Extend},
+       {0x1B3C, 0x1B3C, WBP_Extend},
+       {0x1B3D, 0x1B41, WBP_Extend},
+       {0x1B42, 0x1B42, WBP_Extend},
+       {0x1B43, 0x1B44, WBP_Extend},
+       {0x1B45, 0x1B4B, WBP_ALetter},
+       {0x1B50, 0x1B59, WBP_Numeric},
+       {0x1B6B, 0x1B73, WBP_Extend},
+       {0x1B80, 0x1B81, WBP_Extend},
+       {0x1B82, 0x1B82, WBP_Extend},
+       {0x1B83, 0x1BA0, WBP_ALetter},
+       {0x1BA1, 0x1BA1, WBP_Extend},
+       {0x1BA2, 0x1BA5, WBP_Extend},
+       {0x1BA6, 0x1BA7, WBP_Extend},
+       {0x1BA8, 0x1BA9, WBP_Extend},
+       {0x1BAA, 0x1BAA, WBP_Extend},
+       {0x1BAB, 0x1BAD, WBP_Extend},
+       {0x1BAE, 0x1BAF, WBP_ALetter},
+       {0x1BB0, 0x1BB9, WBP_Numeric},
+       {0x1BBA, 0x1BE5, WBP_ALetter},
+       {0x1BE6, 0x1BE6, WBP_Extend},
+       {0x1BE7, 0x1BE7, WBP_Extend},
+       {0x1BE8, 0x1BE9, WBP_Extend},
+       {0x1BEA, 0x1BEC, WBP_Extend},
+       {0x1BED, 0x1BED, WBP_Extend},
+       {0x1BEE, 0x1BEE, WBP_Extend},
+       {0x1BEF, 0x1BF1, WBP_Extend},
+       {0x1BF2, 0x1BF3, WBP_Extend},
+       {0x1C00, 0x1C23, WBP_ALetter},
+       {0x1C24, 0x1C2B, WBP_Extend},
+       {0x1C2C, 0x1C33, WBP_Extend},
+       {0x1C34, 0x1C35, WBP_Extend},
+       {0x1C36, 0x1C37, WBP_Extend},
+       {0x1C40, 0x1C49, WBP_Numeric},
+       {0x1C4D, 0x1C4F, WBP_ALetter},
+       {0x1C50, 0x1C59, WBP_Numeric},
+       {0x1C5A, 0x1C77, WBP_ALetter},
+       {0x1C78, 0x1C7D, WBP_ALetter},
+       {0x1CD0, 0x1CD2, WBP_Extend},
+       {0x1CD4, 0x1CE0, WBP_Extend},
+       {0x1CE1, 0x1CE1, WBP_Extend},
+       {0x1CE2, 0x1CE8, WBP_Extend},
+       {0x1CE9, 0x1CEC, WBP_ALetter},
+       {0x1CED, 0x1CED, WBP_Extend},
+       {0x1CEE, 0x1CF1, WBP_ALetter},
+       {0x1CF2, 0x1CF3, WBP_Extend},
+       {0x1CF4, 0x1CF4, WBP_Extend},
+       {0x1CF5, 0x1CF6, WBP_ALetter},
+       {0x1CF8, 0x1CF9, WBP_Extend},
+       {0x1D00, 0x1D2B, WBP_ALetter},
+       {0x1D2C, 0x1D6A, WBP_ALetter},
+       {0x1D6B, 0x1D77, WBP_ALetter},
+       {0x1D78, 0x1D78, WBP_ALetter},
+       {0x1D79, 0x1D9A, WBP_ALetter},
+       {0x1D9B, 0x1DBF, WBP_ALetter},
+       {0x1DC0, 0x1DF5, WBP_Extend},
+       {0x1DFC, 0x1DFF, WBP_Extend},
+       {0x1E00, 0x1F15, WBP_ALetter},
+       {0x1F18, 0x1F1D, WBP_ALetter},
+       {0x1F20, 0x1F45, WBP_ALetter},
+       {0x1F48, 0x1F4D, WBP_ALetter},
+       {0x1F50, 0x1F57, WBP_ALetter},
+       {0x1F59, 0x1F59, WBP_ALetter},
+       {0x1F5B, 0x1F5B, WBP_ALetter},
+       {0x1F5D, 0x1F5D, WBP_ALetter},
+       {0x1F5F, 0x1F7D, WBP_ALetter},
+       {0x1F80, 0x1FB4, WBP_ALetter},
+       {0x1FB6, 0x1FBC, WBP_ALetter},
+       {0x1FBE, 0x1FBE, WBP_ALetter},
+       {0x1FC2, 0x1FC4, WBP_ALetter},
+       {0x1FC6, 0x1FCC, WBP_ALetter},
+       {0x1FD0, 0x1FD3, WBP_ALetter},
+       {0x1FD6, 0x1FDB, WBP_ALetter},
+       {0x1FE0, 0x1FEC, WBP_ALetter},
+       {0x1FF2, 0x1FF4, WBP_ALetter},
+       {0x1FF6, 0x1FFC, WBP_ALetter},
+       {0x200C, 0x200D, WBP_Extend},
+       {0x200E, 0x200F, WBP_Format},
+       {0x2018, 0x2018, WBP_MidNumLet},
+       {0x2019, 0x2019, WBP_MidNumLet},
+       {0x2024, 0x2024, WBP_MidNumLet},
+       {0x2027, 0x2027, WBP_MidLetter},
+       {0x2028, 0x2028, WBP_Newline},
+       {0x2029, 0x2029, WBP_Newline},
+       {0x202A, 0x202E, WBP_Format},
+       {0x203F, 0x2040, WBP_ExtendNumLet},
+       {0x2044, 0x2044, WBP_MidNum},
+       {0x2054, 0x2054, WBP_ExtendNumLet},
+       {0x2060, 0x2064, WBP_Format},
+       {0x2066, 0x206F, WBP_Format},
+       {0x2071, 0x2071, WBP_ALetter},
+       {0x207F, 0x207F, WBP_ALetter},
+       {0x2090, 0x209C, WBP_ALetter},
+       {0x20D0, 0x20DC, WBP_Extend},
+       {0x20DD, 0x20E0, WBP_Extend},
+       {0x20E1, 0x20E1, WBP_Extend},
+       {0x20E2, 0x20E4, WBP_Extend},
+       {0x20E5, 0x20F0, WBP_Extend},
+       {0x2102, 0x2102, WBP_ALetter},
+       {0x2107, 0x2107, WBP_ALetter},
+       {0x210A, 0x2113, WBP_ALetter},
+       {0x2115, 0x2115, WBP_ALetter},
+       {0x2119, 0x211D, WBP_ALetter},
+       {0x2124, 0x2124, WBP_ALetter},
+       {0x2126, 0x2126, WBP_ALetter},
+       {0x2128, 0x2128, WBP_ALetter},
+       {0x212A, 0x212D, WBP_ALetter},
+       {0x212F, 0x2134, WBP_ALetter},
+       {0x2135, 0x2138, WBP_ALetter},
+       {0x2139, 0x2139, WBP_ALetter},
+       {0x213C, 0x213F, WBP_ALetter},
+       {0x2145, 0x2149, WBP_ALetter},
+       {0x214E, 0x214E, WBP_ALetter},
+       {0x2160, 0x2182, WBP_ALetter},
+       {0x2183, 0x2184, WBP_ALetter},
+       {0x2185, 0x2188, WBP_ALetter},
+       {0x24B6, 0x24E9, WBP_ALetter},
+       {0x2C00, 0x2C2E, WBP_ALetter},
+       {0x2C30, 0x2C5E, WBP_ALetter},
+       {0x2C60, 0x2C7B, WBP_ALetter},
+       {0x2C7C, 0x2C7D, WBP_ALetter},
+       {0x2C7E, 0x2CE4, WBP_ALetter},
+       {0x2CEB, 0x2CEE, WBP_ALetter},
+       {0x2CEF, 0x2CF1, WBP_Extend},
+       {0x2CF2, 0x2CF3, WBP_ALetter},
+       {0x2D00, 0x2D25, WBP_ALetter},
+       {0x2D27, 0x2D27, WBP_ALetter},
+       {0x2D2D, 0x2D2D, WBP_ALetter},
+       {0x2D30, 0x2D67, WBP_ALetter},
+       {0x2D6F, 0x2D6F, WBP_ALetter},
+       {0x2D7F, 0x2D7F, WBP_Extend},
+       {0x2D80, 0x2D96, WBP_ALetter},
+       {0x2DA0, 0x2DA6, WBP_ALetter},
+       {0x2DA8, 0x2DAE, WBP_ALetter},
+       {0x2DB0, 0x2DB6, WBP_ALetter},
+       {0x2DB8, 0x2DBE, WBP_ALetter},
+       {0x2DC0, 0x2DC6, WBP_ALetter},
+       {0x2DC8, 0x2DCE, WBP_ALetter},
+       {0x2DD0, 0x2DD6, WBP_ALetter},
+       {0x2DD8, 0x2DDE, WBP_ALetter},
+       {0x2DE0, 0x2DFF, WBP_Extend},
+       {0x2E2F, 0x2E2F, WBP_ALetter},
+       {0x3005, 0x3005, WBP_ALetter},
+       {0x302A, 0x302D, WBP_Extend},
+       {0x302E, 0x302F, WBP_Extend},
+       {0x3031, 0x3035, WBP_Katakana},
+       {0x303B, 0x303B, WBP_ALetter},
+       {0x303C, 0x303C, WBP_ALetter},
+       {0x3099, 0x309A, WBP_Extend},
+       {0x309B, 0x309C, WBP_Katakana},
+       {0x30A0, 0x30A0, WBP_Katakana},
+       {0x30A1, 0x30FA, WBP_Katakana},
+       {0x30FC, 0x30FE, WBP_Katakana},
+       {0x30FF, 0x30FF, WBP_Katakana},
+       {0x3105, 0x312D, WBP_ALetter},
+       {0x3131, 0x318E, WBP_ALetter},
+       {0x31A0, 0x31BA, WBP_ALetter},
+       {0x31F0, 0x31FF, WBP_Katakana},
+       {0x32D0, 0x32FE, WBP_Katakana},
+       {0x3300, 0x3357, WBP_Katakana},
+       {0xA000, 0xA014, WBP_ALetter},
+       {0xA015, 0xA015, WBP_ALetter},
+       {0xA016, 0xA48C, WBP_ALetter},
+       {0xA4D0, 0xA4F7, WBP_ALetter},
+       {0xA4F8, 0xA4FD, WBP_ALetter},
+       {0xA500, 0xA60B, WBP_ALetter},
+       {0xA60C, 0xA60C, WBP_ALetter},
+       {0xA610, 0xA61F, WBP_ALetter},
+       {0xA620, 0xA629, WBP_Numeric},
+       {0xA62A, 0xA62B, WBP_ALetter},
+       {0xA640, 0xA66D, WBP_ALetter},
+       {0xA66E, 0xA66E, WBP_ALetter},
+       {0xA66F, 0xA66F, WBP_Extend},
+       {0xA670, 0xA672, WBP_Extend},
+       {0xA674, 0xA67D, WBP_Extend},
+       {0xA67F, 0xA67F, WBP_ALetter},
+       {0xA680, 0xA69B, WBP_ALetter},
+       {0xA69C, 0xA69D, WBP_ALetter},
+       {0xA69F, 0xA69F, WBP_Extend},
+       {0xA6A0, 0xA6E5, WBP_ALetter},
+       {0xA6E6, 0xA6EF, WBP_ALetter},
+       {0xA6F0, 0xA6F1, WBP_Extend},
+       {0xA717, 0xA71F, WBP_ALetter},
+       {0xA722, 0xA76F, WBP_ALetter},
+       {0xA770, 0xA770, WBP_ALetter},
+       {0xA771, 0xA787, WBP_ALetter},
+       {0xA788, 0xA788, WBP_ALetter},
+       {0xA78B, 0xA78E, WBP_ALetter},
+       {0xA790, 0xA7AD, WBP_ALetter},
+       {0xA7B0, 0xA7B1, WBP_ALetter},
+       {0xA7F7, 0xA7F7, WBP_ALetter},
+       {0xA7F8, 0xA7F9, WBP_ALetter},
+       {0xA7FA, 0xA7FA, WBP_ALetter},
+       {0xA7FB, 0xA801, WBP_ALetter},
+       {0xA802, 0xA802, WBP_Extend},
+       {0xA803, 0xA805, WBP_ALetter},
+       {0xA806, 0xA806, WBP_Extend},
+       {0xA807, 0xA80A, WBP_ALetter},
+       {0xA80B, 0xA80B, WBP_Extend},
+       {0xA80C, 0xA822, WBP_ALetter},
+       {0xA823, 0xA824, WBP_Extend},
+       {0xA825, 0xA826, WBP_Extend},
+       {0xA827, 0xA827, WBP_Extend},
+       {0xA840, 0xA873, WBP_ALetter},
+       {0xA880, 0xA881, WBP_Extend},
+       {0xA882, 0xA8B3, WBP_ALetter},
+       {0xA8B4, 0xA8C3, WBP_Extend},
+       {0xA8C4, 0xA8C4, WBP_Extend},
+       {0xA8D0, 0xA8D9, WBP_Numeric},
+       {0xA8E0, 0xA8F1, WBP_Extend},
+       {0xA8F2, 0xA8F7, WBP_ALetter},
+       {0xA8FB, 0xA8FB, WBP_ALetter},
+       {0xA900, 0xA909, WBP_Numeric},
+       {0xA90A, 0xA925, WBP_ALetter},
+       {0xA926, 0xA92D, WBP_Extend},
+       {0xA930, 0xA946, WBP_ALetter},
+       {0xA947, 0xA951, WBP_Extend},
+       {0xA952, 0xA953, WBP_Extend},
+       {0xA960, 0xA97C, WBP_ALetter},
+       {0xA980, 0xA982, WBP_Extend},
+       {0xA983, 0xA983, WBP_Extend},
+       {0xA984, 0xA9B2, WBP_ALetter},
+       {0xA9B3, 0xA9B3, WBP_Extend},
+       {0xA9B4, 0xA9B5, WBP_Extend},
+       {0xA9B6, 0xA9B9, WBP_Extend},
+       {0xA9BA, 0xA9BB, WBP_Extend},
+       {0xA9BC, 0xA9BC, WBP_Extend},
+       {0xA9BD, 0xA9C0, WBP_Extend},
+       {0xA9CF, 0xA9CF, WBP_ALetter},
+       {0xA9D0, 0xA9D9, WBP_Numeric},
+       {0xA9E5, 0xA9E5, WBP_Extend},
+       {0xA9F0, 0xA9F9, WBP_Numeric},
+       {0xAA00, 0xAA28, WBP_ALetter},
+       {0xAA29, 0xAA2E, WBP_Extend},
+       {0xAA2F, 0xAA30, WBP_Extend},
+       {0xAA31, 0xAA32, WBP_Extend},
+       {0xAA33, 0xAA34, WBP_Extend},
+       {0xAA35, 0xAA36, WBP_Extend},
+       {0xAA40, 0xAA42, WBP_ALetter},
+       {0xAA43, 0xAA43, WBP_Extend},
+       {0xAA44, 0xAA4B, WBP_ALetter},
+       {0xAA4C, 0xAA4C, WBP_Extend},
+       {0xAA4D, 0xAA4D, WBP_Extend},
+       {0xAA50, 0xAA59, WBP_Numeric},
+       {0xAA7B, 0xAA7B, WBP_Extend},
+       {0xAA7C, 0xAA7C, WBP_Extend},
+       {0xAA7D, 0xAA7D, WBP_Extend},
+       {0xAAB0, 0xAAB0, WBP_Extend},
+       {0xAAB2, 0xAAB4, WBP_Extend},
+       {0xAAB7, 0xAAB8, WBP_Extend},
+       {0xAABE, 0xAABF, WBP_Extend},
+       {0xAAC1, 0xAAC1, WBP_Extend},
+       {0xAAE0, 0xAAEA, WBP_ALetter},
+       {0xAAEB, 0xAAEB, WBP_Extend},
+       {0xAAEC, 0xAAED, WBP_Extend},
+       {0xAAEE, 0xAAEF, WBP_Extend},
+       {0xAAF2, 0xAAF2, WBP_ALetter},
+       {0xAAF3, 0xAAF4, WBP_ALetter},
+       {0xAAF5, 0xAAF5, WBP_Extend},
+       {0xAAF6, 0xAAF6, WBP_Extend},
+       {0xAB01, 0xAB06, WBP_ALetter},
+       {0xAB09, 0xAB0E, WBP_ALetter},
+       {0xAB11, 0xAB16, WBP_ALetter},
+       {0xAB20, 0xAB26, WBP_ALetter},
+       {0xAB28, 0xAB2E, WBP_ALetter},
+       {0xAB30, 0xAB5A, WBP_ALetter},
+       {0xAB5C, 0xAB5F, WBP_ALetter},
+       {0xAB64, 0xAB65, WBP_ALetter},
+       {0xABC0, 0xABE2, WBP_ALetter},
+       {0xABE3, 0xABE4, WBP_Extend},
+       {0xABE5, 0xABE5, WBP_Extend},
+       {0xABE6, 0xABE7, WBP_Extend},
+       {0xABE8, 0xABE8, WBP_Extend},
+       {0xABE9, 0xABEA, WBP_Extend},
+       {0xABEC, 0xABEC, WBP_Extend},
+       {0xABED, 0xABED, WBP_Extend},
+       {0xABF0, 0xABF9, WBP_Numeric},
+       {0xAC00, 0xD7A3, WBP_ALetter},
+       {0xD7B0, 0xD7C6, WBP_ALetter},
+       {0xD7CB, 0xD7FB, WBP_ALetter},
+       {0xFB00, 0xFB06, WBP_ALetter},
+       {0xFB13, 0xFB17, WBP_ALetter},
+       {0xFB1D, 0xFB1D, WBP_Hebrew_Letter},
+       {0xFB1E, 0xFB1E, WBP_Extend},
+       {0xFB1F, 0xFB28, WBP_Hebrew_Letter},
+       {0xFB2A, 0xFB36, WBP_Hebrew_Letter},
+       {0xFB38, 0xFB3C, WBP_Hebrew_Letter},
+       {0xFB3E, 0xFB3E, WBP_Hebrew_Letter},
+       {0xFB40, 0xFB41, WBP_Hebrew_Letter},
+       {0xFB43, 0xFB44, WBP_Hebrew_Letter},
+       {0xFB46, 0xFB4F, WBP_Hebrew_Letter},
+       {0xFB50, 0xFBB1, WBP_ALetter},
+       {0xFBD3, 0xFD3D, WBP_ALetter},
+       {0xFD50, 0xFD8F, WBP_ALetter},
+       {0xFD92, 0xFDC7, WBP_ALetter},
+       {0xFDF0, 0xFDFB, WBP_ALetter},
+       {0xFE00, 0xFE0F, WBP_Extend},
+       {0xFE10, 0xFE10, WBP_MidNum},
+       {0xFE13, 0xFE13, WBP_MidLetter},
+       {0xFE14, 0xFE14, WBP_MidNum},
+       {0xFE20, 0xFE2D, WBP_Extend},
+       {0xFE33, 0xFE34, WBP_ExtendNumLet},
+       {0xFE4D, 0xFE4F, WBP_ExtendNumLet},
+       {0xFE50, 0xFE50, WBP_MidNum},
+       {0xFE52, 0xFE52, WBP_MidNumLet},
+       {0xFE54, 0xFE54, WBP_MidNum},
+       {0xFE55, 0xFE55, WBP_MidLetter},
+       {0xFE70, 0xFE74, WBP_ALetter},
+       {0xFE76, 0xFEFC, WBP_ALetter},
+       {0xFEFF, 0xFEFF, WBP_Format},
+       {0xFF07, 0xFF07, WBP_MidNumLet},
+       {0xFF0C, 0xFF0C, WBP_MidNum},
+       {0xFF0E, 0xFF0E, WBP_MidNumLet},
+       {0xFF1A, 0xFF1A, WBP_MidLetter},
+       {0xFF1B, 0xFF1B, WBP_MidNum},
+       {0xFF21, 0xFF3A, WBP_ALetter},
+       {0xFF3F, 0xFF3F, WBP_ExtendNumLet},
+       {0xFF41, 0xFF5A, WBP_ALetter},
+       {0xFF66, 0xFF6F, WBP_Katakana},
+       {0xFF70, 0xFF70, WBP_Katakana},
+       {0xFF71, 0xFF9D, WBP_Katakana},
+       {0xFF9E, 0xFF9F, WBP_Extend},
+       {0xFFA0, 0xFFBE, WBP_ALetter},
+       {0xFFC2, 0xFFC7, WBP_ALetter},
+       {0xFFCA, 0xFFCF, WBP_ALetter},
+       {0xFFD2, 0xFFD7, WBP_ALetter},
+       {0xFFDA, 0xFFDC, WBP_ALetter},
+       {0xFFF9, 0xFFFB, WBP_Format},
+       {0x10000, 0x1000B, WBP_ALetter},
+       {0x1000D, 0x10026, WBP_ALetter},
+       {0x10028, 0x1003A, WBP_ALetter},
+       {0x1003C, 0x1003D, WBP_ALetter},
+       {0x1003F, 0x1004D, WBP_ALetter},
+       {0x10050, 0x1005D, WBP_ALetter},
+       {0x10080, 0x100FA, WBP_ALetter},
+       {0x10140, 0x10174, WBP_ALetter},
+       {0x101FD, 0x101FD, WBP_Extend},
+       {0x10280, 0x1029C, WBP_ALetter},
+       {0x102A0, 0x102D0, WBP_ALetter},
+       {0x102E0, 0x102E0, WBP_Extend},
+       {0x10300, 0x1031F, WBP_ALetter},
+       {0x10330, 0x10340, WBP_ALetter},
+       {0x10341, 0x10341, WBP_ALetter},
+       {0x10342, 0x10349, WBP_ALetter},
+       {0x1034A, 0x1034A, WBP_ALetter},
+       {0x10350, 0x10375, WBP_ALetter},
+       {0x10376, 0x1037A, WBP_Extend},
+       {0x10380, 0x1039D, WBP_ALetter},
+       {0x103A0, 0x103C3, WBP_ALetter},
+       {0x103C8, 0x103CF, WBP_ALetter},
+       {0x103D1, 0x103D5, WBP_ALetter},
+       {0x10400, 0x1044F, WBP_ALetter},
+       {0x10450, 0x1049D, WBP_ALetter},
+       {0x104A0, 0x104A9, WBP_Numeric},
+       {0x10500, 0x10527, WBP_ALetter},
+       {0x10530, 0x10563, WBP_ALetter},
+       {0x10600, 0x10736, WBP_ALetter},
+       {0x10740, 0x10755, WBP_ALetter},
+       {0x10760, 0x10767, WBP_ALetter},
+       {0x10800, 0x10805, WBP_ALetter},
+       {0x10808, 0x10808, WBP_ALetter},
+       {0x1080A, 0x10835, WBP_ALetter},
+       {0x10837, 0x10838, WBP_ALetter},
+       {0x1083C, 0x1083C, WBP_ALetter},
+       {0x1083F, 0x10855, WBP_ALetter},
+       {0x10860, 0x10876, WBP_ALetter},
+       {0x10880, 0x1089E, WBP_ALetter},
+       {0x10900, 0x10915, WBP_ALetter},
+       {0x10920, 0x10939, WBP_ALetter},
+       {0x10980, 0x109B7, WBP_ALetter},
+       {0x109BE, 0x109BF, WBP_ALetter},
+       {0x10A00, 0x10A00, WBP_ALetter},
+       {0x10A01, 0x10A03, WBP_Extend},
+       {0x10A05, 0x10A06, WBP_Extend},
+       {0x10A0C, 0x10A0F, WBP_Extend},
+       {0x10A10, 0x10A13, WBP_ALetter},
+       {0x10A15, 0x10A17, WBP_ALetter},
+       {0x10A19, 0x10A33, WBP_ALetter},
+       {0x10A38, 0x10A3A, WBP_Extend},
+       {0x10A3F, 0x10A3F, WBP_Extend},
+       {0x10A60, 0x10A7C, WBP_ALetter},
+       {0x10A80, 0x10A9C, WBP_ALetter},
+       {0x10AC0, 0x10AC7, WBP_ALetter},
+       {0x10AC9, 0x10AE4, WBP_ALetter},
+       {0x10AE5, 0x10AE6, WBP_Extend},
+       {0x10B00, 0x10B35, WBP_ALetter},
+       {0x10B40, 0x10B55, WBP_ALetter},
+       {0x10B60, 0x10B72, WBP_ALetter},
+       {0x10B80, 0x10B91, WBP_ALetter},
+       {0x10C00, 0x10C48, WBP_ALetter},
+       {0x11000, 0x11000, WBP_Extend},
+       {0x11001, 0x11001, WBP_Extend},
+       {0x11002, 0x11002, WBP_Extend},
+       {0x11003, 0x11037, WBP_ALetter},
+       {0x11038, 0x11046, WBP_Extend},
+       {0x11066, 0x1106F, WBP_Numeric},
+       {0x1107F, 0x11081, WBP_Extend},
+       {0x11082, 0x11082, WBP_Extend},
+       {0x11083, 0x110AF, WBP_ALetter},
+       {0x110B0, 0x110B2, WBP_Extend},
+       {0x110B3, 0x110B6, WBP_Extend},
+       {0x110B7, 0x110B8, WBP_Extend},
+       {0x110B9, 0x110BA, WBP_Extend},
+       {0x110BD, 0x110BD, WBP_Format},
+       {0x110D0, 0x110E8, WBP_ALetter},
+       {0x110F0, 0x110F9, WBP_Numeric},
+       {0x11100, 0x11102, WBP_Extend},
+       {0x11103, 0x11126, WBP_ALetter},
+       {0x11127, 0x1112B, WBP_Extend},
+       {0x1112C, 0x1112C, WBP_Extend},
+       {0x1112D, 0x11134, WBP_Extend},
+       {0x11136, 0x1113F, WBP_Numeric},
+       {0x11150, 0x11172, WBP_ALetter},
+       {0x11173, 0x11173, WBP_Extend},
+       {0x11176, 0x11176, WBP_ALetter},
+       {0x11180, 0x11181, WBP_Extend},
+       {0x11182, 0x11182, WBP_Extend},
+       {0x11183, 0x111B2, WBP_ALetter},
+       {0x111B3, 0x111B5, WBP_Extend},
+       {0x111B6, 0x111BE, WBP_Extend},
+       {0x111BF, 0x111C0, WBP_Extend},
+       {0x111C1, 0x111C4, WBP_ALetter},
+       {0x111D0, 0x111D9, WBP_Numeric},
+       {0x111DA, 0x111DA, WBP_ALetter},
+       {0x11200, 0x11211, WBP_ALetter},
+       {0x11213, 0x1122B, WBP_ALetter},
+       {0x1122C, 0x1122E, WBP_Extend},
+       {0x1122F, 0x11231, WBP_Extend},
+       {0x11232, 0x11233, WBP_Extend},
+       {0x11234, 0x11234, WBP_Extend},
+       {0x11235, 0x11235, WBP_Extend},
+       {0x11236, 0x11237, WBP_Extend},
+       {0x112B0, 0x112DE, WBP_ALetter},
+       {0x112DF, 0x112DF, WBP_Extend},
+       {0x112E0, 0x112E2, WBP_Extend},
+       {0x112E3, 0x112EA, WBP_Extend},
+       {0x112F0, 0x112F9, WBP_Numeric},
+       {0x11301, 0x11301, WBP_Extend},
+       {0x11302, 0x11303, WBP_Extend},
+       {0x11305, 0x1130C, WBP_ALetter},
+       {0x1130F, 0x11310, WBP_ALetter},
+       {0x11313, 0x11328, WBP_ALetter},
+       {0x1132A, 0x11330, WBP_ALetter},
+       {0x11332, 0x11333, WBP_ALetter},
+       {0x11335, 0x11339, WBP_ALetter},
+       {0x1133C, 0x1133C, WBP_Extend},
+       {0x1133D, 0x1133D, WBP_ALetter},
+       {0x1133E, 0x1133F, WBP_Extend},
+       {0x11340, 0x11340, WBP_Extend},
+       {0x11341, 0x11344, WBP_Extend},
+       {0x11347, 0x11348, WBP_Extend},
+       {0x1134B, 0x1134D, WBP_Extend},
+       {0x11357, 0x11357, WBP_Extend},
+       {0x1135D, 0x11361, WBP_ALetter},
+       {0x11362, 0x11363, WBP_Extend},
+       {0x11366, 0x1136C, WBP_Extend},
+       {0x11370, 0x11374, WBP_Extend},
+       {0x11480, 0x114AF, WBP_ALetter},
+       {0x114B0, 0x114B2, WBP_Extend},
+       {0x114B3, 0x114B8, WBP_Extend},
+       {0x114B9, 0x114B9, WBP_Extend},
+       {0x114BA, 0x114BA, WBP_Extend},
+       {0x114BB, 0x114BE, WBP_Extend},
+       {0x114BF, 0x114C0, WBP_Extend},
+       {0x114C1, 0x114C1, WBP_Extend},
+       {0x114C2, 0x114C3, WBP_Extend},
+       {0x114C4, 0x114C5, WBP_ALetter},
+       {0x114C7, 0x114C7, WBP_ALetter},
+       {0x114D0, 0x114D9, WBP_Numeric},
+       {0x11580, 0x115AE, WBP_ALetter},
+       {0x115AF, 0x115B1, WBP_Extend},
+       {0x115B2, 0x115B5, WBP_Extend},
+       {0x115B8, 0x115BB, WBP_Extend},
+       {0x115BC, 0x115BD, WBP_Extend},
+       {0x115BE, 0x115BE, WBP_Extend},
+       {0x115BF, 0x115C0, WBP_Extend},
+       {0x11600, 0x1162F, WBP_ALetter},
+       {0x11630, 0x11632, WBP_Extend},
+       {0x11633, 0x1163A, WBP_Extend},
+       {0x1163B, 0x1163C, WBP_Extend},
+       {0x1163D, 0x1163D, WBP_Extend},
+       {0x1163E, 0x1163E, WBP_Extend},
+       {0x1163F, 0x11640, WBP_Extend},
+       {0x11644, 0x11644, WBP_ALetter},
+       {0x11650, 0x11659, WBP_Numeric},
+       {0x11680, 0x116AA, WBP_ALetter},
+       {0x116AB, 0x116AB, WBP_Extend},
+       {0x116AC, 0x116AC, WBP_Extend},
+       {0x116AD, 0x116AD, WBP_Extend},
+       {0x116AE, 0x116AF, WBP_Extend},
+       {0x116B0, 0x116B5, WBP_Extend},
+       {0x116B6, 0x116B6, WBP_Extend},
+       {0x116B7, 0x116B7, WBP_Extend},
+       {0x116C0, 0x116C9, WBP_Numeric},
+       {0x118A0, 0x118DF, WBP_ALetter},
+       {0x118E0, 0x118E9, WBP_Numeric},
+       {0x118FF, 0x118FF, WBP_ALetter},
+       {0x11AC0, 0x11AF8, WBP_ALetter},
+       {0x12000, 0x12398, WBP_ALetter},
+       {0x12400, 0x1246E, WBP_ALetter},
+       {0x13000, 0x1342E, WBP_ALetter},
+       {0x16800, 0x16A38, WBP_ALetter},
+       {0x16A40, 0x16A5E, WBP_ALetter},
+       {0x16A60, 0x16A69, WBP_Numeric},
+       {0x16AD0, 0x16AED, WBP_ALetter},
+       {0x16AF0, 0x16AF4, WBP_Extend},
+       {0x16B00, 0x16B2F, WBP_ALetter},
+       {0x16B30, 0x16B36, WBP_Extend},
+       {0x16B40, 0x16B43, WBP_ALetter},
+       {0x16B50, 0x16B59, WBP_Numeric},
+       {0x16B63, 0x16B77, WBP_ALetter},
+       {0x16B7D, 0x16B8F, WBP_ALetter},
+       {0x16F00, 0x16F44, WBP_ALetter},
+       {0x16F50, 0x16F50, WBP_ALetter},
+       {0x16F51, 0x16F7E, WBP_Extend},
+       {0x16F8F, 0x16F92, WBP_Extend},
+       {0x16F93, 0x16F9F, WBP_ALetter},
+       {0x1B000, 0x1B000, WBP_Katakana},
+       {0x1BC00, 0x1BC6A, WBP_ALetter},
+       {0x1BC70, 0x1BC7C, WBP_ALetter},
+       {0x1BC80, 0x1BC88, WBP_ALetter},
+       {0x1BC90, 0x1BC99, WBP_ALetter},
+       {0x1BC9D, 0x1BC9E, WBP_Extend},
+       {0x1BCA0, 0x1BCA3, WBP_Format},
+       {0x1D165, 0x1D166, WBP_Extend},
+       {0x1D167, 0x1D169, WBP_Extend},
+       {0x1D16D, 0x1D172, WBP_Extend},
+       {0x1D173, 0x1D17A, WBP_Format},
+       {0x1D17B, 0x1D182, WBP_Extend},
+       {0x1D185, 0x1D18B, WBP_Extend},
+       {0x1D1AA, 0x1D1AD, WBP_Extend},
+       {0x1D242, 0x1D244, WBP_Extend},
+       {0x1D400, 0x1D454, WBP_ALetter},
+       {0x1D456, 0x1D49C, WBP_ALetter},
+       {0x1D49E, 0x1D49F, WBP_ALetter},
+       {0x1D4A2, 0x1D4A2, WBP_ALetter},
+       {0x1D4A5, 0x1D4A6, WBP_ALetter},
+       {0x1D4A9, 0x1D4AC, WBP_ALetter},
+       {0x1D4AE, 0x1D4B9, WBP_ALetter},
+       {0x1D4BB, 0x1D4BB, WBP_ALetter},
+       {0x1D4BD, 0x1D4C3, WBP_ALetter},
+       {0x1D4C5, 0x1D505, WBP_ALetter},
+       {0x1D507, 0x1D50A, WBP_ALetter},
+       {0x1D50D, 0x1D514, WBP_ALetter},
+       {0x1D516, 0x1D51C, WBP_ALetter},
+       {0x1D51E, 0x1D539, WBP_ALetter},
+       {0x1D53B, 0x1D53E, WBP_ALetter},
+       {0x1D540, 0x1D544, WBP_ALetter},
+       {0x1D546, 0x1D546, WBP_ALetter},
+       {0x1D54A, 0x1D550, WBP_ALetter},
+       {0x1D552, 0x1D6A5, WBP_ALetter},
+       {0x1D6A8, 0x1D6C0, WBP_ALetter},
+       {0x1D6C2, 0x1D6DA, WBP_ALetter},
+       {0x1D6DC, 0x1D6FA, WBP_ALetter},
+       {0x1D6FC, 0x1D714, WBP_ALetter},
+       {0x1D716, 0x1D734, WBP_ALetter},
+       {0x1D736, 0x1D74E, WBP_ALetter},
+       {0x1D750, 0x1D76E, WBP_ALetter},
+       {0x1D770, 0x1D788, WBP_ALetter},
+       {0x1D78A, 0x1D7A8, WBP_ALetter},
+       {0x1D7AA, 0x1D7C2, WBP_ALetter},
+       {0x1D7C4, 0x1D7CB, WBP_ALetter},
+       {0x1D7CE, 0x1D7FF, WBP_Numeric},
+       {0x1E800, 0x1E8C4, WBP_ALetter},
+       {0x1E8D0, 0x1E8D6, WBP_Extend},
+       {0x1EE00, 0x1EE03, WBP_ALetter},
+       {0x1EE05, 0x1EE1F, WBP_ALetter},
+       {0x1EE21, 0x1EE22, WBP_ALetter},
+       {0x1EE24, 0x1EE24, WBP_ALetter},
+       {0x1EE27, 0x1EE27, WBP_ALetter},
+       {0x1EE29, 0x1EE32, WBP_ALetter},
+       {0x1EE34, 0x1EE37, WBP_ALetter},
+       {0x1EE39, 0x1EE39, WBP_ALetter},
+       {0x1EE3B, 0x1EE3B, WBP_ALetter},
+       {0x1EE42, 0x1EE42, WBP_ALetter},
+       {0x1EE47, 0x1EE47, WBP_ALetter},
+       {0x1EE49, 0x1EE49, WBP_ALetter},
+       {0x1EE4B, 0x1EE4B, WBP_ALetter},
+       {0x1EE4D, 0x1EE4F, WBP_ALetter},
+       {0x1EE51, 0x1EE52, WBP_ALetter},
+       {0x1EE54, 0x1EE54, WBP_ALetter},
+       {0x1EE57, 0x1EE57, WBP_ALetter},
+       {0x1EE59, 0x1EE59, WBP_ALetter},
+       {0x1EE5B, 0x1EE5B, WBP_ALetter},
+       {0x1EE5D, 0x1EE5D, WBP_ALetter},
+       {0x1EE5F, 0x1EE5F, WBP_ALetter},
+       {0x1EE61, 0x1EE62, WBP_ALetter},
+       {0x1EE64, 0x1EE64, WBP_ALetter},
+       {0x1EE67, 0x1EE6A, WBP_ALetter},
+       {0x1EE6C, 0x1EE72, WBP_ALetter},
+       {0x1EE74, 0x1EE77, WBP_ALetter},
+       {0x1EE79, 0x1EE7C, WBP_ALetter},
+       {0x1EE7E, 0x1EE7E, WBP_ALetter},
+       {0x1EE80, 0x1EE89, WBP_ALetter},
+       {0x1EE8B, 0x1EE9B, WBP_ALetter},
+       {0x1EEA1, 0x1EEA3, WBP_ALetter},
+       {0x1EEA5, 0x1EEA9, WBP_ALetter},
+       {0x1EEAB, 0x1EEBB, WBP_ALetter},
+       {0x1F130, 0x1F149, WBP_ALetter},
+       {0x1F150, 0x1F169, WBP_ALetter},
+       {0x1F170, 0x1F189, WBP_ALetter},
+       {0x1F1E6, 0x1F1FF, WBP_Regional_Indicator},
+       {0xE0001, 0xE0001, WBP_Format},
+       {0xE0020, 0xE007F, WBP_Format},
+       {0xE0100, 0xE01EF, WBP_Extend},
+       {0xFFFFFFFF, 0xFFFFFFFF, WBP_Undefined}
+};
diff --git a/third-party/libunibreak/wordbreakdef.h b/third-party/libunibreak/wordbreakdef.h
new file mode 100644 (file)
index 0000000..7130a13
--- /dev/null
@@ -0,0 +1,87 @@
+/* vim: set expandtab tabstop=4 softtabstop=4 shiftwidth=4: */
+
+/*
+ * Word breaking in a Unicode sequence.  Designed to be used in a
+ * generic text renderer.
+ *
+ * Copyright (C) 2013-15 Tom Hacohen <tom at stosb dot com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must
+ *    not claim that you wrote the original software.  If you use this
+ *    software in a product, an acknowledgement in the product
+ *    documentation would be appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must
+ *    not be misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source
+ *    distribution.
+ *
+ * The main reference is Unicode Standard Annex 29 (UAX #29):
+ *      <URL:http://unicode.org/reports/tr29>
+ *
+ * When this library was designed, this annex was at Revision 17, for
+ * Unicode 6.0.0:
+ *      <URL:http://www.unicode.org/reports/tr29/tr29-17.html>
+ *
+ * This library has been updated according to Revision 25, for
+ * Unicode 7.0.0:
+ *
+ * The Unicode Terms of Use are available at
+ *      <URL:http://www.unicode.org/copyright.html>
+ */
+
+/**
+ * @file    wordbreakdef.h
+ *
+ * Definitions of internal data structures, declarations of global
+ * variables, and function prototypes for the word breaking algorithm.
+ *
+ * @version 2.6, 2015/04/19
+ * @author  Tom Hacohen
+ */
+
+#include "unibreakdef.h"
+
+/**
+ * Word break classes.  This is a direct mapping of Table 3 of Unicode
+ * Standard Annex 29, Revision 23.
+ */
+enum WordBreakClass
+{
+    WBP_Undefined,
+    WBP_CR,
+    WBP_LF,
+    WBP_Newline,
+    WBP_Extend,
+    WBP_Regional_Indicator,
+    WBP_Format,
+    WBP_Katakana,
+    WBP_Hebrew_Letter,
+    WBP_ALetter,
+    WBP_Single_Quote,
+    WBP_Double_Quote,
+    WBP_MidNumLet,
+    WBP_MidLetter,
+    WBP_MidNum,
+    WBP_Numeric,
+    WBP_ExtendNumLet,
+    WBP_Any
+};
+
+/**
+ * Struct for entries of word break properties.  The array of the
+ * entries \e must be sorted.
+ */
+struct WordBreakProperties
+{
+    utf32_t start;              /**< Starting coding point */
+    utf32_t end;                /**< End coding point */
+    enum WordBreakClass prop;   /**< The word breaking property */
+};
diff --git a/third-party/resampler/resampler.cpp b/third-party/resampler/resampler.cpp
new file mode 100644 (file)
index 0000000..c602466
--- /dev/null
@@ -0,0 +1,1204 @@
+// resampler.cpp, Separable filtering image rescaler v2.21, Rich Geldreich - richgel99@gmail.com
+// See unlicense at the bottom of resampler.h, or at http://unlicense.org/
+//
+// Feb. 1996: Creation, losely based on a heavily bugfixed version of Schumacher's resampler in Graphics Gems 3.
+// Oct. 2000: Ported to C++, tweaks.
+// May 2001: Continous to discrete mapping, box filter tweaks.
+// March 9, 2002: Kaiser filter grabbed from Jonathan Blow's GD magazine mipmap sample code.
+// Sept. 8, 2002: Comments cleaned up a bit.
+// Dec. 31, 2008: v2.2: Bit more cleanup, released as public domain.
+// June 4, 2012: v2.21: Switched to unlicense.org, integrated GCC fixes supplied by Peter Nagy <petern@crytek.com>, Anteru at anteru.net, and clay@coge.net,
+// added Codeblocks project (for testing with MinGW and GCC), VS2008 static code analysis pass.
+#include <stdlib.h>
+#include <math.h>
+#include <float.h>
+#include <assert.h>
+#include <string.h>
+
+// resampler is written using C style casts
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+
+#include "resampler.h"
+
+#define resampler_assert assert
+
+static inline int resampler_range_check(int v, int h) { (void)h; resampler_assert((v >= 0) && (v < h)); return v; }
+
+#ifndef max
+   #define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef min
+   #define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef TRUE
+   #define TRUE (1)
+#endif
+
+#ifndef FALSE
+   #define FALSE (0)
+#endif
+
+#define RESAMPLER_DEBUG 0
+
+#define M_PI 3.14159265358979323846
+
+// Float to int cast with truncation.
+static inline int cast_to_int(Resample_Real i)
+{
+   return (int)i;
+}
+
+// (x mod y) with special handling for negative x values.
+static inline int posmod(int x, int y)
+{
+   if (x >= 0)
+      return (x % y);
+   else
+   {
+      int m = (-x) % y;
+
+      if (m != 0)
+         m = y - m;
+
+      return (m);
+   }
+}
+
+// To add your own filter, insert the new function below and update the filter table.
+// There is no need to make the filter function particularly fast, because it's
+// only called during initializing to create the X and Y axis contributor tables.
+
+#define BOX_FILTER_SUPPORT (0.5f)
+static Resample_Real box_filter(Resample_Real t)    /* pulse/Fourier window */
+{
+   // make_clist() calls the filter function with t inverted (pos = left, neg = right)
+   if ((t >= -0.5f) && (t < 0.5f))
+      return 1.0f;
+   else
+      return 0.0f;
+}
+
+#define TENT_FILTER_SUPPORT (1.0f)
+static Resample_Real tent_filter(Resample_Real t)   /* box (*) box, bilinear/triangle */
+{
+   if (t < 0.0f)
+      t = -t;
+
+   if (t < 1.0f)
+      return 1.0f - t;
+   else
+      return 0.0f;
+}
+
+#define BELL_SUPPORT (1.5f)
+static Resample_Real bell_filter(Resample_Real t)    /* box (*) box (*) box */
+{
+   if (t < 0.0f)
+      t = -t;
+
+   if (t < .5f)
+      return (.75f - (t * t));
+
+   if (t < 1.5f)
+   {
+      t = (t - 1.5f);
+      return (.5f * (t * t));
+   }
+
+   return (0.0f);
+}
+
+#define B_SPLINE_SUPPORT (2.0f)
+static Resample_Real B_spline_filter(Resample_Real t)  /* box (*) box (*) box (*) box */
+{
+   Resample_Real tt;
+
+   if (t < 0.0f)
+      t = -t;
+
+   if (t < 1.0f)
+   {
+      tt = t * t;
+      return ((.5f * tt * t) - tt + (2.0f / 3.0f));
+   }
+   else if (t < 2.0f)
+   {
+      t = 2.0f - t;
+      return ((1.0f / 6.0f) * (t * t * t));
+   }
+
+   return (0.0f);
+}
+
+// Dodgson, N., "Quadratic Interpolation for Image Resampling"
+#define QUADRATIC_SUPPORT 1.5f
+static Resample_Real quadratic(Resample_Real t, const Resample_Real R)
+{
+   if (t < 0.0f)
+      t = -t;
+   if (t < QUADRATIC_SUPPORT)
+   {
+      Resample_Real tt = t * t;
+      if (t <= .5f)
+         return (-2.0f * R) * tt + .5f * (R + 1.0f);
+      else
+         return (R * tt) + (-2.0f * R - .5f) * t + (3.0f / 4.0f) * (R + 1.0f);
+   }
+   else
+      return 0.0f;
+}
+
+static Resample_Real quadratic_interp_filter(Resample_Real t)
+{
+   return quadratic(t, 1.0f);
+}
+
+static Resample_Real quadratic_approx_filter(Resample_Real t)
+{
+   return quadratic(t, .5f);
+}
+
+static Resample_Real quadratic_mix_filter(Resample_Real t)
+{
+   return quadratic(t, .8f);
+}
+
+// Mitchell, D. and A. Netravali, "Reconstruction Filters in Computer Graphics."
+// Computer Graphics, Vol. 22, No. 4, pp. 221-228.
+// (B, C)
+// (1/3, 1/3) - Defaults recommended by Mitchell and Netravali
+// (1, 0)     - Equivalent to the Cubic B-Spline
+// (0, 0.5)   - Equivalent to the Catmull-Rom Spline
+// (0, C)     - The family of Cardinal Cubic Splines
+// (B, 0)     - Duff's tensioned B-Splines.
+static Resample_Real mitchell(Resample_Real t, const Resample_Real B, const Resample_Real C)
+{
+   Resample_Real tt;
+
+   tt = t * t;
+
+   if(t < 0.0f)
+      t = -t;
+
+   if(t < 1.0f)
+   {
+      t = (((12.0f - 9.0f * B - 6.0f * C) * (t * tt))
+         + ((-18.0f + 12.0f * B + 6.0f * C) * tt)
+         + (6.0f - 2.0f * B));
+
+      return (t / 6.0f);
+   }
+   else if (t < 2.0f)
+   {
+      t = (((-1.0f * B - 6.0f * C) * (t * tt))
+         + ((6.0f * B + 30.0f * C) * tt)
+         + ((-12.0f * B - 48.0f * C) * t)
+         + (8.0f * B + 24.0f * C));
+
+      return (t / 6.0f);
+   }
+
+   return (0.0f);
+}
+
+#define MITCHELL_SUPPORT (2.0f)
+static Resample_Real mitchell_filter(Resample_Real t)
+{
+   return mitchell(t, 1.0f / 3.0f, 1.0f / 3.0f);
+}
+
+#define CATMULL_ROM_SUPPORT (2.0f)
+static Resample_Real catmull_rom_filter(Resample_Real t)
+{
+   return mitchell(t, 0.0f, .5f);
+}
+
+static double sinc(double x)
+{
+   x = (x * M_PI);
+
+   if ((x < 0.01f) && (x > -0.01f))
+      return 1.0f + x*x*(-1.0f/6.0f + x*x*1.0f/120.0f);
+
+   return sin(x) / x;
+}
+
+static Resample_Real clean(double t)
+{
+   const Resample_Real EPSILON = .0000125f;
+   if (fabs(t) < EPSILON)
+      return 0.0f;
+   return (Resample_Real)t;
+}
+
+static double blackman_exact_window(double x)
+{
+   return 0.42659071f + 0.49656062f * cos(M_PI*x) + 0.07684867f * cos(2.0f*M_PI*x);
+}
+
+#define BLACKMAN_SUPPORT (3.0f)
+static Resample_Real blackman_filter(Resample_Real t)
+{
+   if (t < 0.0f)
+      t = -t;
+
+   if (t < 3.0f)
+      //return clean(sinc(t) * blackman_window(t / 3.0f));
+      return clean(sinc(t) * blackman_exact_window(t / 3.0f));
+   else
+      return (0.0f);
+}
+
+#define GAUSSIAN_SUPPORT (1.25f)
+static Resample_Real gaussian_filter(Resample_Real t) // with blackman window
+{
+   if (t < 0)
+      t = -t;
+   if (t < GAUSSIAN_SUPPORT)
+      return clean(exp(-2.0f * t * t) * sqrt(2.0f / M_PI) * blackman_exact_window(t / GAUSSIAN_SUPPORT));
+   else
+      return 0.0f;
+}
+
+// Windowed sinc -- see "Jimm Blinn's Corner: Dirty Pixels" pg. 26.
+#define LANCZOS3_SUPPORT (3.0f)
+static Resample_Real lanczos3_filter(Resample_Real t)
+{
+   if (t < 0.0f)
+      t = -t;
+
+   if (t < 3.0f)
+      return clean(sinc(t) * sinc(t / 3.0f));
+   else
+      return (0.0f);
+}
+
+#define LANCZOS4_SUPPORT (4.0f)
+static Resample_Real lanczos4_filter(Resample_Real t)
+{
+   if (t < 0.0f)
+      t = -t;
+
+   if (t < 4.0f)
+      return clean(sinc(t) * sinc(t / 4.0f));
+   else
+      return (0.0f);
+}
+
+#define LANCZOS6_SUPPORT (6.0f)
+static Resample_Real lanczos6_filter(Resample_Real t)
+{
+   if (t < 0.0f)
+      t = -t;
+
+   if (t < 6.0f)
+      return clean(sinc(t) * sinc(t / 6.0f));
+   else
+      return (0.0f);
+}
+
+#define LANCZOS12_SUPPORT (12.0f)
+static Resample_Real lanczos12_filter(Resample_Real t)
+{
+   if (t < 0.0f)
+      t = -t;
+
+   if (t < 12.0f)
+      return clean(sinc(t) * sinc(t / 12.0f));
+   else
+      return (0.0f);
+}
+
+static double bessel0(double x)
+{
+   const double EPSILON_RATIO = 1E-16;
+   double xh, sum, pow, ds;
+   int k;
+
+   xh = 0.5 * x;
+   sum = 1.0;
+   pow = 1.0;
+   k = 0;
+   ds = 1.0;
+   while (ds > sum * EPSILON_RATIO) // FIXME: Shouldn't this stop after X iterations for max. safety?
+   {
+      ++k;
+      pow = pow * (xh / k);
+      ds = pow * pow;
+      sum = sum + ds;
+   }
+
+   return sum;
+}
+
+static const Resample_Real KAISER_ALPHA = 4.0;
+static double kaiser(double alpha, double half_width, double x)
+{
+   const double ratio = (x / half_width);
+   return bessel0(alpha * sqrt(1 - ratio * ratio)) / bessel0(alpha);
+}
+
+#define KAISER_SUPPORT 3
+static Resample_Real kaiser_filter(Resample_Real t)
+{
+   if (t < 0.0f)
+      t = -t;
+
+   if (t < KAISER_SUPPORT)
+   {
+      // db atten
+      const Resample_Real att = 40.0f;
+      const Resample_Real alpha = (Resample_Real)(exp(log((double)0.58417 * (att - 20.96)) * 0.4) + 0.07886 * (att - 20.96));
+      //const Resample_Real alpha = KAISER_ALPHA;
+      return (Resample_Real)clean(sinc(t) * kaiser(alpha, KAISER_SUPPORT, t));
+   }
+
+   return 0.0f;
+}
+
+// filters[] is a list of all the available filter functions.
+static struct
+{
+   Resampler::Filter name;
+   Resample_Real (*func)(Resample_Real t);
+   Resample_Real support;
+} g_filters[] =
+{
+   { 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]);
+
+/* Ensure that the contributing source sample is
+* within bounds. If not, reflect, clamp, or wrap.
+*/
+int Resampler::reflect(const int j, const int src_x, const Boundary_Op boundary_op)
+{
+   int n;
+
+   if (j < 0)
+   {
+      if (boundary_op == BOUNDARY_REFLECT)
+      {
+         n = -j;
+
+         if (n >= src_x)
+            n = src_x - 1;
+      }
+      else if (boundary_op == BOUNDARY_WRAP)
+         n = posmod(j, src_x);
+      else
+         n = 0;
+   }
+   else if (j >= src_x)
+   {
+      if (boundary_op == BOUNDARY_REFLECT)
+      {
+         n = (src_x - j) + (src_x - 1);
+
+         if (n < 0)
+            n = 0;
+      }
+      else if (boundary_op == BOUNDARY_WRAP)
+         n = posmod(j, src_x);
+      else
+         n = src_x - 1;
+   }
+   else
+      n = j;
+
+   return n;
+}
+
+// The make_clist() method generates, for all destination samples,
+// the list of all source samples with non-zero weighted contributions.
+Resampler::Contrib_List* Resampler::make_clist(
+   int src_x, int dst_x, Boundary_Op boundary_op,
+   Resample_Real (*Pfilter)(Resample_Real),
+   Resample_Real filter_support,
+   Resample_Real filter_scale,
+   Resample_Real src_ofs)
+{
+   typedef struct
+   {
+      // The center of the range in DISCRETE coordinates (pixel center = 0.0f).
+      Resample_Real center;
+      int left, right;
+   } Contrib_Bounds;
+
+   int i, j, k, n, left, right;
+   Resample_Real total_weight;
+   Resample_Real xscale, center, half_width, weight;
+   Contrib_List* Pcontrib;
+   Contrib* Pcpool;
+   Contrib* Pcpool_next;
+   Contrib_Bounds* Pcontrib_bounds;
+
+   if ((Pcontrib = (Contrib_List*)calloc(dst_x, sizeof(Contrib_List))) == NULL)
+      return NULL;
+
+   Pcontrib_bounds = (Contrib_Bounds*)calloc(dst_x, sizeof(Contrib_Bounds));
+   if (!Pcontrib_bounds)
+   {
+      free(Pcontrib);
+      return (NULL);
+   }
+
+   const Resample_Real oo_filter_scale = 1.0f / filter_scale;
+
+   const Resample_Real NUDGE = 0.5f;
+   xscale = dst_x / (Resample_Real)src_x;
+
+   if (xscale < 1.0f)
+   {
+      int total; (void)total;
+
+      /* Handle case when there are fewer destination
+      * samples than source samples (downsampling/minification).
+      */
+
+      // stretched half width of filter
+      half_width = (filter_support / xscale) * filter_scale;
+
+      // Find the range of source sample(s) that will contribute to each destination sample.
+
+      for (i = 0, n = 0; i < dst_x; i++)
+      {
+         // Convert from discrete to continuous coordinates, scale, then convert back to discrete.
+         center = ((Resample_Real)i + NUDGE) / xscale;
+         center -= NUDGE;
+         center += src_ofs;
+
+         left   = cast_to_int((Resample_Real)floor(center - half_width));
+         right  = cast_to_int((Resample_Real)ceil(center + half_width));
+
+         Pcontrib_bounds[i].center = center;
+         Pcontrib_bounds[i].left = left;
+         Pcontrib_bounds[i].right = right;
+
+         n += (right - left + 1);
+      }
+
+      /* Allocate memory for contributors. */
+
+      if ((n == 0) || ((Pcpool = (Contrib*)calloc(n, sizeof(Contrib))) == NULL))
+      {
+         free(Pcontrib);
+         free(Pcontrib_bounds);
+         return NULL;
+      }
+      total = n;
+
+      Pcpool_next = Pcpool;
+
+      /* Create the list of source samples which
+      * contribute to each destination sample.
+      */
+
+      for (i = 0; i < dst_x; i++)
+      {
+         int max_k = -1;
+         Resample_Real max_w = -1e+20f;
+
+         center = Pcontrib_bounds[i].center;
+         left   = Pcontrib_bounds[i].left;
+         right  = Pcontrib_bounds[i].right;
+
+         Pcontrib[i].n = 0;
+         Pcontrib[i].p = Pcpool_next;
+         Pcpool_next += (right - left + 1);
+         resampler_assert ((Pcpool_next - Pcpool) <= total);
+
+         total_weight = 0;
+
+         for (j = left; j <= right; j++)
+            total_weight += (*Pfilter)((center - (Resample_Real)j) * xscale * oo_filter_scale);
+         const Resample_Real norm = static_cast<Resample_Real>(1.0f / total_weight);
+
+         total_weight = 0;
+
+#if RESAMPLER_DEBUG
+         printf("%i: ", i);
+#endif
+
+         for (j = left; j <= right; j++)
+         {
+            weight = (*Pfilter)((center - (Resample_Real)j) * xscale * oo_filter_scale) * norm;
+            if (weight == 0.0f)
+               continue;
+
+            n = reflect(j, src_x, boundary_op);
+
+#if RESAMPLER_DEBUG
+            printf("%i(%f), ", n, weight);
+#endif
+
+            /* Increment the number of source
+            * samples which contribute to the
+            * current destination sample.
+            */
+
+            k = Pcontrib[i].n++;
+
+            Pcontrib[i].p[k].pixel  = (unsigned short)(n);       /* store src sample number */
+            Pcontrib[i].p[k].weight = weight; /* store src sample weight */
+
+            total_weight += weight;          /* total weight of all contributors */
+
+            if (weight > max_w)
+            {
+               max_w = weight;
+               max_k = k;
+            }
+         }
+
+#if RESAMPLER_DEBUG
+         printf("\n\n");
+#endif
+
+         //resampler_assert(Pcontrib[i].n);
+         //resampler_assert(max_k != -1);
+         if ((max_k == -1) || (Pcontrib[i].n == 0))
+         {
+            free(Pcpool);
+            free(Pcontrib);
+            free(Pcontrib_bounds);
+            return NULL;
+         }
+
+         if (total_weight != 1.0f)
+            Pcontrib[i].p[max_k].weight += 1.0f - total_weight;
+      }
+   }
+   else
+   {
+      /* Handle case when there are more
+      * destination samples than source
+      * samples (upsampling).
+      */
+
+      half_width = filter_support * filter_scale;
+
+      // Find the source sample(s) that contribute to each destination sample.
+
+      for (i = 0, n = 0; i < dst_x; i++)
+      {
+         // Convert from discrete to continuous coordinates, scale, then convert back to discrete.
+         center = ((Resample_Real)i + NUDGE) / xscale;
+         center -= NUDGE;
+         center += src_ofs;
+
+         left   = cast_to_int((Resample_Real)floor(center - half_width));
+         right  = cast_to_int((Resample_Real)ceil(center + half_width));
+
+         Pcontrib_bounds[i].center = center;
+         Pcontrib_bounds[i].left = left;
+         Pcontrib_bounds[i].right = right;
+
+         n += (right - left + 1);
+      }
+
+      /* Allocate memory for contributors. */
+
+      int total = n;
+      if ((total == 0) || ((Pcpool = (Contrib*)calloc(total, sizeof(Contrib))) == NULL))
+      {
+         free(Pcontrib);
+         free(Pcontrib_bounds);
+         return NULL;
+      }
+
+      Pcpool_next = Pcpool;
+
+      /* Create the list of source samples which
+      * contribute to each destination sample.
+      */
+
+      for (i = 0; i < dst_x; i++)
+      {
+         int max_k = -1;
+         Resample_Real max_w = -1e+20f;
+
+         center = Pcontrib_bounds[i].center;
+         left   = Pcontrib_bounds[i].left;
+         right  = Pcontrib_bounds[i].right;
+
+         Pcontrib[i].n = 0;
+         Pcontrib[i].p = Pcpool_next;
+         Pcpool_next += (right - left + 1);
+         resampler_assert((Pcpool_next - Pcpool) <= total);
+
+         total_weight = 0;
+         for (j = left; j <= right; j++)
+            total_weight += (*Pfilter)((center - (Resample_Real)j) * oo_filter_scale);
+
+         const Resample_Real norm = static_cast<Resample_Real>(1.0f / total_weight);
+
+         total_weight = 0;
+
+#if RESAMPLER_DEBUG
+         printf("%i: ", i);
+#endif
+
+         for (j = left; j <= right; j++)
+         {
+            weight = (*Pfilter)((center - (Resample_Real)j) * oo_filter_scale) * norm;
+            if (weight == 0.0f)
+               continue;
+
+            n = reflect(j, src_x, boundary_op);
+
+#if RESAMPLER_DEBUG
+            printf("%i(%f), ", n, weight);
+#endif
+
+            /* Increment the number of source
+            * samples which contribute to the
+            * current destination sample.
+            */
+
+            k = Pcontrib[i].n++;
+
+            Pcontrib[i].p[k].pixel  = (unsigned short)(n);       /* store src sample number */
+            Pcontrib[i].p[k].weight = weight; /* store src sample weight */
+
+            total_weight += weight;          /* total weight of all contributors */
+
+            if (weight > max_w)
+            {
+               max_w = weight;
+               max_k = k;
+            }
+         }
+
+#if RESAMPLER_DEBUG
+         printf("\n\n");
+#endif
+
+         //resampler_assert(Pcontrib[i].n);
+         //resampler_assert(max_k != -1);
+
+         if ((max_k == -1) || (Pcontrib[i].n == 0))
+         {
+            free(Pcpool);
+            free(Pcontrib);
+            free(Pcontrib_bounds);
+            return NULL;
+         }
+
+         if (total_weight != 1.0f)
+            Pcontrib[i].p[max_k].weight += 1.0f - total_weight;
+      }
+   }
+
+#if RESAMPLER_DEBUG
+   printf("*******\n");
+#endif
+
+   free(Pcontrib_bounds);
+
+   return Pcontrib;
+}
+
+void Resampler::resample_x(Sample* Pdst, const Sample* Psrc)
+{
+   resampler_assert(Pdst);
+   resampler_assert(Psrc);
+
+   int i, j;
+   Sample total;
+   Contrib_List *Pclist = m_Pclist_x;
+   Contrib *p;
+
+   for (i = m_resample_dst_x; i > 0; i--, Pclist++)
+   {
+#if RESAMPLER_DEBUG_OPS
+      total_ops += Pclist->n;
+#endif
+
+      for (j = Pclist->n, p = Pclist->p, total = 0; j > 0; j--, p++)
+         total += Psrc[p->pixel] * p->weight;
+
+      *Pdst++ = total;
+   }
+}
+
+void Resampler::scale_y_mov(Sample* Ptmp, const Sample* Psrc, Resample_Real weight, int dst_x)
+{
+   int i;
+
+#if RESAMPLER_DEBUG_OPS
+   total_ops += dst_x;
+#endif
+
+   // Not += because temp buf wasn't cleared.
+   for (i = dst_x; i > 0; i--)
+      *Ptmp++ = *Psrc++ * weight;
+}
+
+void Resampler::scale_y_add(Sample* Ptmp, const Sample* Psrc, Resample_Real weight, int dst_x)
+{
+#if RESAMPLER_DEBUG_OPS
+   total_ops += dst_x;
+#endif
+
+   for (int i = dst_x; i > 0; i--)
+      (*Ptmp++) += *Psrc++ * weight;
+}
+
+void Resampler::clamp(Sample* Pdst, int n)
+{
+   while (n > 0)
+   {
+      *Pdst = clamp_sample(*Pdst);
+      ++Pdst;
+      n--;
+   }
+}
+
+void Resampler::resample_y(Sample* Pdst)
+{
+   int i, j;
+   Sample* Psrc;
+   Contrib_List* Pclist = &m_Pclist_y[m_cur_dst_y];
+
+   Sample* Ptmp = m_delay_x_resample ? m_Ptmp_buf : Pdst;
+   resampler_assert(Ptmp);
+
+   /* Process each contributor. */
+
+   for (i = 0; i < Pclist->n; i++)
+   {
+      /* locate the contributor's location in the scan
+      * buffer -- the contributor must always be found!
+      */
+
+      for (j = 0; j < MAX_SCAN_BUF_SIZE; j++)
+         if (m_Pscan_buf->scan_buf_y[j] == Pclist->p[i].pixel)
+            break;
+
+      resampler_assert(j < MAX_SCAN_BUF_SIZE);
+
+      Psrc = m_Pscan_buf->scan_buf_l[j];
+
+      if (!i)
+         scale_y_mov(Ptmp, Psrc, Pclist->p[i].weight, m_intermediate_x);
+      else
+         scale_y_add(Ptmp, Psrc, Pclist->p[i].weight, m_intermediate_x);
+
+      /* If this source line doesn't contribute to any
+      * more destination lines then mark the scanline buffer slot
+      * which holds this source line as free.
+      * (The max. number of slots used depends on the Y
+      * axis sampling factor and the scaled filter width.)
+      */
+
+      if (--m_Psrc_y_count[resampler_range_check(Pclist->p[i].pixel, m_resample_src_y)] == 0)
+      {
+         m_Psrc_y_flag[resampler_range_check(Pclist->p[i].pixel, m_resample_src_y)] = FALSE;
+         m_Pscan_buf->scan_buf_y[j] = -1;
+      }
+   }
+
+   /* Now generate the destination line */
+
+   if (m_delay_x_resample) // Was X resampling delayed until after Y resampling?
+   {
+      resampler_assert(Pdst != Ptmp);
+      resample_x(Pdst, Ptmp);
+   }
+   else
+   {
+      resampler_assert(Pdst == Ptmp);
+   }
+
+   if (m_lo < m_hi)
+      clamp(Pdst, m_resample_dst_x);
+}
+
+bool Resampler::put_line(const Sample* Psrc)
+{
+   int i;
+
+   if (m_cur_src_y >= m_resample_src_y)
+      return false;
+
+   /* Does this source line contribute
+   * to any destination line? if not,
+   * exit now.
+   */
+
+   if (!m_Psrc_y_count[resampler_range_check(m_cur_src_y, m_resample_src_y)])
+   {
+      m_cur_src_y++;
+      return true;
+   }
+
+   /* Find an empty slot in the scanline buffer. (FIXME: Perf. is terrible here with extreme scaling ratios.) */
+
+   for (i = 0; i < MAX_SCAN_BUF_SIZE; i++)
+      if (m_Pscan_buf->scan_buf_y[i] == -1)
+         break;
+
+   /* If the buffer is full, exit with an error. */
+
+   if (i == MAX_SCAN_BUF_SIZE)
+   {
+      m_status = STATUS_SCAN_BUFFER_FULL;
+      return false;
+   }
+
+   m_Psrc_y_flag[resampler_range_check(m_cur_src_y, m_resample_src_y)] = TRUE;
+   m_Pscan_buf->scan_buf_y[i]  = m_cur_src_y;
+
+   /* Does this slot have any memory allocated to it? */
+
+   if (!m_Pscan_buf->scan_buf_l[i])
+   {
+      if ((m_Pscan_buf->scan_buf_l[i] = (Sample*)malloc(m_intermediate_x * sizeof(Sample))) == NULL)
+      {
+         m_status = STATUS_OUT_OF_MEMORY;
+         return false;
+      }
+   }
+
+   // Resampling on the X axis first?
+   if (m_delay_x_resample)
+   {
+      resampler_assert(m_intermediate_x == m_resample_src_x);
+
+      // Y-X resampling order
+      memcpy(m_Pscan_buf->scan_buf_l[i], Psrc, m_intermediate_x * sizeof(Sample));
+   }
+   else
+   {
+      resampler_assert(m_intermediate_x == m_resample_dst_x);
+
+      // X-Y resampling order
+      resample_x(m_Pscan_buf->scan_buf_l[i], Psrc);
+   }
+
+   m_cur_src_y++;
+
+   return true;
+}
+
+const Resampler::Sample* Resampler::get_line()
+{
+   int i;
+
+   /* If all the destination lines have been
+   * generated, then always return NULL.
+   */
+
+   if (m_cur_dst_y == m_resample_dst_y)
+      return NULL;
+
+   /* Check to see if all the required
+   * contributors are present, if not,
+   * return NULL.
+   */
+
+   for (i = 0; i < m_Pclist_y[m_cur_dst_y].n; i++)
+      if (!m_Psrc_y_flag[resampler_range_check(m_Pclist_y[m_cur_dst_y].p[i].pixel, m_resample_src_y)])
+         return NULL;
+
+   resample_y(m_Pdst_buf);
+
+   m_cur_dst_y++;
+
+   return m_Pdst_buf;
+}
+
+Resampler::~Resampler()
+{
+   int i;
+
+#if RESAMPLER_DEBUG_OPS
+   printf("actual ops: %i\n", total_ops);
+#endif
+
+   free(m_Pdst_buf);
+   m_Pdst_buf = NULL;
+
+   if (m_Ptmp_buf)
+   {
+      free(m_Ptmp_buf);
+      m_Ptmp_buf = NULL;
+   }
+
+   /* Don't deallocate a contibutor list
+   * if the user passed us one of their own.
+   */
+
+   if ((m_Pclist_x) && (!m_clist_x_forced))
+   {
+      free(m_Pclist_x->p);
+      free(m_Pclist_x);
+      m_Pclist_x = NULL;
+   }
+
+   if ((m_Pclist_y) && (!m_clist_y_forced))
+   {
+      free(m_Pclist_y->p);
+      free(m_Pclist_y);
+      m_Pclist_y = NULL;
+   }
+
+   free(m_Psrc_y_count);
+   m_Psrc_y_count = NULL;
+
+   free(m_Psrc_y_flag);
+   m_Psrc_y_flag = NULL;
+
+   if (m_Pscan_buf)
+   {
+      for (i = 0; i < MAX_SCAN_BUF_SIZE; i++)
+         free(m_Pscan_buf->scan_buf_l[i]);
+
+      free(m_Pscan_buf);
+      m_Pscan_buf = NULL;
+   }
+}
+
+void Resampler::restart()
+{
+   if (STATUS_OKAY != m_status)
+      return;
+
+   m_cur_src_y = m_cur_dst_y = 0;
+
+   int i, j;
+   for (i = 0; i < m_resample_src_y; i++)
+   {
+      m_Psrc_y_count[i] = 0;
+      m_Psrc_y_flag[i] = FALSE;
+   }
+
+   for (i = 0; i < m_resample_dst_y; i++)
+   {
+      for (j = 0; j < m_Pclist_y[i].n; j++)
+         m_Psrc_y_count[resampler_range_check(m_Pclist_y[i].p[j].pixel, m_resample_src_y)]++;
+   }
+
+   for (i = 0; i < MAX_SCAN_BUF_SIZE; i++)
+   {
+      m_Pscan_buf->scan_buf_y[i] = -1;
+
+      free(m_Pscan_buf->scan_buf_l[i]);
+      m_Pscan_buf->scan_buf_l[i] = NULL;
+   }
+}
+
+Resampler::Resampler(int src_x, int src_y,
+                     int dst_x, int dst_y,
+                     Boundary_Op boundary_op,
+                     Resample_Real sample_low, Resample_Real sample_high,
+                     Resampler::Filter filter,
+                     Contrib_List* Pclist_x,
+                     Contrib_List* Pclist_y,
+                     Resample_Real filter_x_scale,
+                     Resample_Real filter_y_scale,
+                     Resample_Real src_x_ofs,
+                     Resample_Real src_y_ofs)
+{
+   int i, j;
+   Resample_Real support, (*func)(Resample_Real);
+
+   resampler_assert(src_x > 0);
+   resampler_assert(src_y > 0);
+   resampler_assert(dst_x > 0);
+   resampler_assert(dst_y > 0);
+
+#if RESAMPLER_DEBUG_OPS
+   total_ops = 0;
+#endif
+
+   m_lo = sample_low;
+   m_hi = sample_high;
+
+   m_delay_x_resample = false;
+   m_intermediate_x = 0;
+   m_Pdst_buf = NULL;
+   m_Ptmp_buf = NULL;
+   m_clist_x_forced = false;
+   m_Pclist_x = NULL;
+   m_clist_y_forced = false;
+   m_Pclist_y = NULL;
+   m_Psrc_y_count = NULL;
+   m_Psrc_y_flag = NULL;
+   m_Pscan_buf = NULL;
+   m_status = STATUS_OKAY;
+
+   m_resample_src_x = src_x;
+   m_resample_src_y = src_y;
+   m_resample_dst_x = dst_x;
+   m_resample_dst_y = dst_y;
+
+   m_boundary_op = boundary_op;
+
+   if ((m_Pdst_buf = (Sample*)malloc(m_resample_dst_x * sizeof(Sample))) == NULL)
+   {
+      m_status = STATUS_OUT_OF_MEMORY;
+      return;
+   }
+
+   // Find the specified filter.
+   for (i = 0; i < NUM_FILTERS; i++)
+      if ( filter ==  g_filters[i].name )
+         break;
+
+   if (i == NUM_FILTERS)
+   {
+      m_status = STATUS_BAD_FILTER_TYPE;
+      return;
+   }
+
+   func = g_filters[i].func;
+   support = g_filters[i].support;
+
+   /* Create contributor lists, unless the user supplied custom lists. */
+
+   if (!Pclist_x)
+   {
+      m_Pclist_x = make_clist(m_resample_src_x, m_resample_dst_x, m_boundary_op, func, support, filter_x_scale, src_x_ofs);
+      if (!m_Pclist_x)
+      {
+         m_status = STATUS_OUT_OF_MEMORY;
+         return;
+      }
+   }
+   else
+   {
+      m_Pclist_x = Pclist_x;
+      m_clist_x_forced = true;
+   }
+
+   if (!Pclist_y)
+   {
+      m_Pclist_y = make_clist(m_resample_src_y, m_resample_dst_y, m_boundary_op, func, support, filter_y_scale, src_y_ofs);
+      if (!m_Pclist_y)
+      {
+         m_status = STATUS_OUT_OF_MEMORY;
+         return;
+      }
+   }
+   else
+   {
+      m_Pclist_y = Pclist_y;
+      m_clist_y_forced = true;
+   }
+
+   if ((m_Psrc_y_count = (int*)calloc(m_resample_src_y, sizeof(int))) == NULL)
+   {
+      m_status = STATUS_OUT_OF_MEMORY;
+      return;
+   }
+
+   if ((m_Psrc_y_flag = (unsigned char*)calloc(m_resample_src_y, sizeof(unsigned char))) == NULL)
+   {
+      m_status = STATUS_OUT_OF_MEMORY;
+      return;
+   }
+
+   /* Count how many times each source line
+   * contributes to a destination line.
+   */
+
+   for (i = 0; i < m_resample_dst_y; i++)
+      for (j = 0; j < m_Pclist_y[i].n; j++)
+         m_Psrc_y_count[resampler_range_check(m_Pclist_y[i].p[j].pixel, m_resample_src_y)]++;
+
+   if ((m_Pscan_buf = (Scan_Buf*)malloc(sizeof(Scan_Buf))) == NULL)
+   {
+      m_status = STATUS_OUT_OF_MEMORY;
+      return;
+   }
+
+   for (i = 0; i < MAX_SCAN_BUF_SIZE; i++)
+   {
+      m_Pscan_buf->scan_buf_y[i] = -1;
+      m_Pscan_buf->scan_buf_l[i] = NULL;
+   }
+
+   m_cur_src_y = m_cur_dst_y = 0;
+   {
+      // Determine which axis to resample first by comparing the number of multiplies required
+      // for each possibility.
+      int x_ops = count_ops(m_Pclist_x, m_resample_dst_x);
+      int y_ops = count_ops(m_Pclist_y, m_resample_dst_y);
+
+      // Hack 10/2000: Weight Y axis ops a little more than X axis ops.
+      // (Y axis ops use more cache resources.)
+      int xy_ops = x_ops * m_resample_src_y +
+         (4 * y_ops * m_resample_dst_x)/3;
+
+      int yx_ops = (4 * y_ops * m_resample_src_x)/3 +
+         x_ops * m_resample_dst_y;
+
+#if RESAMPLER_DEBUG_OPS
+      printf("src: %i %i\n", m_resample_src_x, m_resample_src_y);
+      printf("dst: %i %i\n", m_resample_dst_x, m_resample_dst_y);
+      printf("x_ops: %i\n", x_ops);
+      printf("y_ops: %i\n", y_ops);
+      printf("xy_ops: %i\n", xy_ops);
+      printf("yx_ops: %i\n", yx_ops);
+#endif
+
+      // Now check which resample order is better. In case of a tie, choose the order
+      // which buffers the least amount of data.
+      if ((xy_ops > yx_ops) ||
+         ((xy_ops == yx_ops) && (m_resample_src_x < m_resample_dst_x))
+         )
+      {
+         m_delay_x_resample = true;
+         m_intermediate_x = m_resample_src_x;
+      }
+      else
+      {
+         m_delay_x_resample = false;
+         m_intermediate_x = m_resample_dst_x;
+      }
+#if RESAMPLER_DEBUG_OPS
+      printf("delaying: %i\n", m_delay_x_resample);
+#endif
+   }
+
+   if (m_delay_x_resample)
+   {
+      if ((m_Ptmp_buf = (Sample*)malloc(m_intermediate_x * sizeof(Sample))) == NULL)
+      {
+         m_status = STATUS_OUT_OF_MEMORY;
+         return;
+      }
+   }
+}
+
+void Resampler::get_clists(Contrib_List** ptr_clist_x, Contrib_List** ptr_clist_y)
+{
+   if (ptr_clist_x)
+      *ptr_clist_x = m_Pclist_x;
+
+   if (ptr_clist_y)
+      *ptr_clist_y = m_Pclist_y;
+}
+
+#pragma GCC diagnostic pop
diff --git a/third-party/resampler/resampler.h b/third-party/resampler/resampler.h
new file mode 100644 (file)
index 0000000..5db3a1d
--- /dev/null
@@ -0,0 +1,215 @@
+// 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_MAX_DIMENSION 16384
+
+// float or double
+typedef float Resample_Real;
+
+class Resampler
+{
+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;
+      unsigned short pixel;
+   };
+
+   struct Contrib_List
+   {
+      unsigned short n;
+      Contrib* p;
+   };
+
+   enum Boundary_Op
+   {
+      BOUNDARY_WRAP = 0,
+      BOUNDARY_REFLECT = 1,
+      BOUNDARY_CLAMP = 2
+   };
+
+   enum Status
+   {
+      STATUS_OKAY = 0,
+      STATUS_OUT_OF_MEMORY = 1,
+      STATUS_BAD_FILTER_TYPE = 2,
+      STATUS_SCAN_BUFFER_FULL = 3
+   };
+
+   // src_x/src_y - Input dimensions
+   // dst_x/dst_y - Output dimensions
+   // boundary_op - How to sample pixels near the image boundaries
+   // sample_low/sample_high - Clamp output samples to specified range, or disable clamping if sample_low >= sample_high
+   // Pclist_x/Pclist_y - Optional pointers to contributor lists from another instance of a Resampler
+   // src_x_ofs/src_y_ofs - Offset input image by specified amount (fractional values okay)
+   Resampler(
+      int src_x, int src_y,
+      int dst_x, int dst_y,
+      Boundary_Op boundary_op = BOUNDARY_CLAMP,
+      Resample_Real sample_low = 0.0f, Resample_Real sample_high = 0.0f,
+      Resampler::Filter = Resampler::LANCZOS3,
+      Contrib_List* Pclist_x = NULL,
+      Contrib_List* Pclist_y = NULL,
+      Resample_Real filter_x_scale = 1.0f,
+      Resample_Real filter_y_scale = 1.0f,
+      Resample_Real src_x_ofs = 0.0f,
+      Resample_Real src_y_ofs = 0.0f);
+
+   ~Resampler();
+
+   // Reinits resampler so it can handle another frame.
+   void restart();
+
+   // false on out of memory.
+   bool put_line(const Sample* Psrc);
+
+   // NULL if no scanlines are currently available (give the resampler more scanlines!)
+   const Sample* get_line();
+
+   Status status() const { return m_status; }
+
+   // Returned contributor lists can be shared with another Resampler.
+   void get_clists(Contrib_List** ptr_clist_x, Contrib_List** ptr_clist_y);
+   Contrib_List* get_clist_x() const { return m_Pclist_x; }
+   Contrib_List* get_clist_y() const { return m_Pclist_y; }
+
+private:
+   Resampler();
+   Resampler(const Resampler& o);
+   Resampler& operator= (const Resampler& o);
+
+#ifdef RESAMPLER_DEBUG_OPS
+   int total_ops;
+#endif
+
+   int m_intermediate_x;
+
+   int m_resample_src_x;
+   int m_resample_src_y;
+   int m_resample_dst_x;
+   int m_resample_dst_y;
+
+   Boundary_Op m_boundary_op;
+
+   Sample* m_Pdst_buf;
+   Sample* m_Ptmp_buf;
+
+   Contrib_List* m_Pclist_x;
+   Contrib_List* m_Pclist_y;
+
+   bool m_clist_x_forced;
+   bool m_clist_y_forced;
+
+   bool m_delay_x_resample;
+
+   int* m_Psrc_y_count;
+   unsigned char* m_Psrc_y_flag;
+
+   // The maximum number of scanlines that can be buffered at one time.
+   enum { MAX_SCAN_BUF_SIZE = RESAMPLER_MAX_DIMENSION };
+
+   struct Scan_Buf
+   {
+      int scan_buf_y[MAX_SCAN_BUF_SIZE];
+      Sample* scan_buf_l[MAX_SCAN_BUF_SIZE];
+   };
+
+   Scan_Buf* m_Pscan_buf;
+
+   int m_cur_src_y;
+   int m_cur_dst_y;
+
+   Status m_status;
+
+   void resample_x(Sample* Pdst, const Sample* Psrc);
+   void scale_y_mov(Sample* Ptmp, const Sample* Psrc, Resample_Real weight, int dst_x);
+   void scale_y_add(Sample* Ptmp, const Sample* Psrc, Resample_Real weight, int dst_x);
+   void clamp(Sample* Pdst, int n);
+   void resample_y(Sample* Pdst);
+
+   int reflect(const int j, const int src_x, const Boundary_Op boundary_op);
+
+   Contrib_List* make_clist(
+      int src_x, int dst_x, Boundary_Op boundary_op,
+      Resample_Real (*Pfilter)(Resample_Real),
+      Resample_Real filter_support,
+      Resample_Real filter_scale,
+      Resample_Real src_ofs);
+
+   inline int count_ops(Contrib_List* Pclist, int k)
+   {
+      int i, t = 0;
+      for (i = 0; i < k; i++)
+         t += Pclist[i].n;
+      return (t);
+   }
+
+   Resample_Real m_lo;
+   Resample_Real m_hi;
+
+   inline Resample_Real clamp_sample(Resample_Real f) const
+   {
+      if (f < m_lo)
+         f = m_lo;
+      else if (f > m_hi)
+         f = m_hi;
+      return f;
+   }
+};
+
+#endif // RESAMPLER_H
+
+// This is free and unencumbered software released into the public domain.
+//
+// Anyone is free to copy, modify, publish, use, compile, sell, or
+// distribute this software, either in source code form or as a compiled
+// binary, for any purpose, commercial or non-commercial, and by any
+// means.
+//
+// In jurisdictions that recognize copyright laws, the author or authors
+// of this software dedicate any and all copyright interest in the
+// software to the public domain. We make this dedication for the benefit
+// of the public at large and to the detriment of our heirs and
+// successors. We intend this dedication to be an overt act of
+// relinquishment in perpetuity of all present and future rights to this
+// software under copyright law.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+// For more information, please refer to <http://unlicense.org/>
diff --git a/third-party/windows-platform/Win32File/CustomFile.cpp b/third-party/windows-platform/Win32File/CustomFile.cpp
new file mode 100644 (file)
index 0000000..1cfb627
--- /dev/null
@@ -0,0 +1,178 @@
+#include "CustomFile.h"
+
+extern void* MemFOpen( uint8_t* buffer, size_t dataSize, const char * const mode );
+extern void MemFClose( const void *fp );
+extern int MemFRead( void* buf, int eleSize, int count, const void *fp );
+extern void MemFWrite( void *buf, int size, const void *fp );
+extern int MemFSeek( const void *fp, int offset, int origin );
+extern int MemFTell( const void *fp );
+extern bool MemFEof( const void *fp );
+
+extern void* OriginalFOpen( const char *name, const char *mode );
+extern int OriginalFClose( const void *fp );
+extern int OriginalFRead( void* buf, int eleSize, int count, const void *fp );
+extern void OriginalFWrite( void *buf, int size, const void *fp );
+extern void OriginalFWrite( void *buf, int eleSize, int count, const void *fp );
+extern int OriginalFSeek( const void *fp, int offset, int origin );
+extern int OriginalFTell( const void *fp );
+extern bool OriginalFEof( const void *fp );
+
+namespace
+{
+std::string GetRealName(const char* name)
+{
+  if (nullptr != name && '*' == name[0])
+  {
+    std::string envName;
+
+    const char *p = name + 1;
+
+    while (0 != *p && '*' != *p)
+    {
+      envName.push_back(*p);
+      p++;
+    }
+
+    p++;
+
+    char *envValue = std::getenv(envName.c_str());
+
+    std::string realName;
+    realName = "";
+    realName += envValue;
+    realName += p;
+
+    return realName;
+  }
+  else
+  {
+    return std::string(name);
+  }
+}
+} // namespace
+
+namespace CustomFile
+{
+FILE* FOpen( const char *name, const char *mode )
+{
+  if( NULL != name && '*' == name[0] )
+  {
+    std::string realName = GetRealName( name );
+    FILE* ret = (FILE*)OriginalFOpen( realName.c_str(), mode );
+    if (NULL == ret)
+    {
+      int temp = 0;
+    }
+    return ret;
+  }
+  else
+  {
+    return (FILE*)OriginalFOpen( name, mode );
+  }
+}
+
+int FClose( const void* fp )
+{
+  if( -1 == *( (char*)fp + 4 ) )
+  {
+    MemFClose( fp );
+    return 0;
+  }
+  else
+  {
+    return OriginalFClose( fp );
+  }
+}
+
+FILE* FMemopen( void* buffer, size_t dataSize, const char * mode )
+{
+  return (FILE*)MemFOpen( ( uint8_t*)buffer, dataSize, mode );
+}
+
+int FRead( void* buf, int eleSize, int count, const void *fp )
+{
+  if( -1 == *( (char*)fp + 4 ) )
+  {
+    return MemFRead( buf, eleSize, count, fp );
+  }
+  else
+  {
+    return OriginalFRead( buf, eleSize, count, fp );
+  }
+}
+
+void FWrite( void *buf, int size, const void *fp )
+{
+  if( -1 == *( (char*)fp + 4 ) )
+  {
+    MemFWrite( buf, size, fp );
+  }
+  else
+  {
+    OriginalFWrite( buf, size, fp );
+  }
+}
+
+unsigned int FWrite( const char  *buf, unsigned int eleSize, unsigned int count, void *fp )
+{
+  if( -1 == *( (char*)fp + 4 ) )
+  {
+    MemFWrite( (void*)buf, eleSize * count, fp );
+  }
+  else
+  {
+    OriginalFWrite((void*)buf, eleSize, count, fp );
+  }
+
+  return eleSize * count;
+}
+
+int FSeek( const void *fp, int offset, int origin )
+{
+  if( -1 == *( (char*)fp + 4 ) )
+  {
+    return MemFSeek( fp, offset, origin );
+  }
+  else
+  {
+    return OriginalFSeek( fp, offset, origin );
+  }
+}
+
+int FTell( const void *fp )
+{
+  if( -1 == *( (char*)fp + 4 ) )
+  {
+    return MemFTell( fp );
+  }
+  else
+  {
+    return OriginalFTell( fp );
+  }
+}
+
+bool FEof( const void *fp )
+{
+  if( -1 == *( (char*)fp + 4 ) )
+  {
+    return MemFEof( fp );
+  }
+  else
+  {
+    return OriginalFEof( fp );
+  }
+}
+}
+
+extern "C"
+{
+size_t __cdecl fread_for_c( void*  _Buffer, size_t _ElementSize, size_t _ElementCount, void*  _Stream )
+{
+  return CustomFile::FRead( _Buffer, _ElementSize, _ElementCount, _Stream );
+}
+
+void __cdecl fwrite_for_c( void *buf, int size, const void *fp )
+{
+  CustomFile::FWrite( buf, size, fp );
+}
+}
diff --git a/third-party/windows-platform/Win32File/CustomFile.h b/third-party/windows-platform/Win32File/CustomFile.h
new file mode 100644 (file)
index 0000000..4a33531
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _CUSTOMFILE_INCLUDE_
+#define _CUSTOMFILE_INCLUDE_
+
+#include <stdint.h>
+#include <string>
+
+namespace CustomFile
+{
+FILE* FOpen( const char *name, const char *mode );
+
+int FClose( const void* fp );
+
+FILE* FMemopen( void* buffer, size_t dataSize, const char * mode );
+
+int FRead( void* buf, int eleSize, int count, const void *fp );
+
+void FWrite( void *buf, int size, const void *fp );
+
+unsigned int FWrite( const char *buf, unsigned int eleSize, unsigned int count, void *fp );
+
+int FSeek( const void *fp, int offset, int origin );
+
+int FTell( const void *fp );
+
+bool FEof( const void *fp );
+}
+
+#endif
diff --git a/third-party/windows-platform/Win32File/MemFile.cpp b/third-party/windows-platform/Win32File/MemFile.cpp
new file mode 100644 (file)
index 0000000..922fc84
--- /dev/null
@@ -0,0 +1,159 @@
+#include <string>
+
+using namespace std;
+
+typedef unsigned char BYTE;
+typedef unsigned int UINT;
+
+#define SEEK_CUR    1
+#define SEEK_END    2
+#define SEEK_SET    0
+
+class CBufferFile
+{
+public:
+  CBufferFile( BYTE* lpBuffer, UINT nBufferSize )
+  {
+    mFlag = 0xFF;
+    mCurIndex = 0;
+    mLength = nBufferSize;
+
+    mBuffer = lpBuffer;
+  }
+
+  virtual ~CBufferFile()
+  {
+    Close();
+  }
+
+  int Read( void *buf, int size )
+  {
+    int realReadSize = mLength - mCurIndex;
+
+    if( realReadSize > size )
+    {
+      realReadSize = size;
+    }
+
+    if( 0 < realReadSize )
+    {
+      memcpy( buf, mBuffer + mCurIndex, realReadSize );
+      mCurIndex += realReadSize;
+    }
+
+    return realReadSize;
+  }
+
+  void Write( void *buf, int size )
+  {
+    memcpy( mBuffer + mCurIndex, buf, size );
+    mCurIndex += size;
+  }
+
+  int Seek( long offset, int origin )
+  {
+    int nextIndex = -1;
+
+    switch( origin )
+    {
+    case SEEK_SET:
+      nextIndex = offset;
+      break;
+
+    case SEEK_CUR:
+      nextIndex = mCurIndex + offset;
+      break;
+
+    case SEEK_END:
+      nextIndex = mLength - 1 - offset;
+      break;
+    }
+
+    if( nextIndex >= mLength )
+    {
+      nextIndex = -1;
+    }
+
+    if( 0 > nextIndex )
+    {
+      return 1;
+    }
+    else
+    {
+      mCurIndex = nextIndex;
+      return 0;
+    }
+  }
+
+  int GetPosition()
+  {
+    return mCurIndex;
+  }
+
+  bool IsEnd()
+  {
+    return ( mLength - 1 == mCurIndex );
+  }
+
+  void Close()
+  {
+    mBuffer = NULL;
+
+    mCurIndex = 0;
+    mLength = -1;
+    mFlag = 0;
+  }
+
+protected:
+
+private:
+  char mFlag;
+  BYTE *mBuffer;
+
+  UINT mLength;
+  UINT mCurIndex;
+};
+
+void* MemFOpen( uint8_t* buffer, size_t dataSize, const char * const mode )
+{
+  CBufferFile *pBufferFile = new CBufferFile( buffer, dataSize );
+  return pBufferFile;
+}
+
+void MemFClose( const void *fp )
+{
+  CBufferFile *file = (CBufferFile*)fp;
+  printf("MemFClose file 0x%x\n", file);
+  file->Close();
+  delete file;
+}
+
+int MemFRead( void* buf, int eleSize, int count, const void *fp )
+{
+  CBufferFile *file = (CBufferFile*)fp;
+  return file->Read( buf, eleSize * count );
+}
+
+void MemFWrite( void *buf, int size, const void *fp )
+{
+  CBufferFile *file = (CBufferFile*)fp;
+  file->Write( buf, size );
+}
+
+int MemFSeek( const void *fp, int offset, int origin )
+{
+  CBufferFile *file = (CBufferFile*)fp;
+  return file->Seek( offset, origin );
+}
+
+int MemFTell( const void *fp )
+{
+  CBufferFile *file = (CBufferFile*)fp;
+  return file->GetPosition();
+}
+
+bool MemFEof( const void *fp )
+{
+  CBufferFile *file = (CBufferFile*)fp;
+  return file->IsEnd();
+}
diff --git a/third-party/windows-platform/Win32File/OriginalFile.cpp b/third-party/windows-platform/Win32File/OriginalFile.cpp
new file mode 100644 (file)
index 0000000..5048176
--- /dev/null
@@ -0,0 +1,41 @@
+#include "stdio.h"
+
+void* OriginalFOpen( const char *name, const char *mode )
+{
+  return fopen( name, mode );
+}
+
+int OriginalFClose( const void *fp )
+{
+  return fclose( (FILE*)fp );
+}
+
+int OriginalFRead( void* buf, int eleSize, int count, const void *fp )
+{
+  return fread( buf, eleSize, count, (FILE*)fp );
+}
+
+void OriginalFWrite( void *buf, int size, const void *fp )
+{
+  fwrite( buf, size, 1, (FILE*)fp );
+}
+
+void OriginalFWrite( void *buf, int eleSize, int count, const void *fp )
+{
+  fwrite( buf, eleSize, count, (FILE*)fp );
+}
+
+int OriginalFSeek( const void *fp, int offset, int origin )
+{
+  return fseek( (FILE*)fp, offset, origin );
+}
+
+int OriginalFTell( const void *fp )
+{
+  return ftell( (FILE*)fp );
+}
+
+bool OriginalFEof( const void *fp )
+{
+  return (bool)feof( (FILE*)fp );
+}
\ No newline at end of file
diff --git a/third-party/windows-platform/dirent.h b/third-party/windows-platform/dirent.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/third-party/windows-platform/dlfcn.cpp b/third-party/windows-platform/dlfcn.cpp
new file mode 100644 (file)
index 0000000..5140ec1
--- /dev/null
@@ -0,0 +1,29 @@
+#include <dlfcn.h>
+#include <windows.h>
+
+namespace
+{
+  char DL_ERROR[2] = "";
+}
+
+bool dlclose( void* handle )
+{
+  return true;
+}
+
+char* dlerror()
+{
+  return DL_ERROR;
+}
+
+void* dlopen( const char *name, int mode )
+{
+  const char* szStr = name;
+
+  return LoadLibrary( szStr );
+}
+
+void* dlsym( void *handle, const char *name )
+{
+  return GetProcAddress( (HMODULE)handle, "CreateFeedbackPlugin" );
+}
diff --git a/third-party/windows-platform/dlfcn.h b/third-party/windows-platform/dlfcn.h
new file mode 100644 (file)
index 0000000..1e4e408
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _DLFCN_INCLUDE_
+#define _DLFCN_INCLUDE_
+
+#undef PlaySound
+
+#define RTLD_NOW      0
+#define RTLD_GLOBAL   1
+#define RTLD_LAZY     2
+
+bool dlclose( void* handle );
+
+char* dlerror();
+
+void* dlopen( const char *name, int mode );
+
+void* dlsym( void *handle, const char *name );
+
+#endif
\ No newline at end of file
diff --git a/third-party/windows-platform/environment.cpp b/third-party/windows-platform/environment.cpp
new file mode 100644 (file)
index 0000000..d6dab55
--- /dev/null
@@ -0,0 +1,26 @@
+#include <cstdlib>
+#include <string>
+
+using namespace std;
+
+int setenv( const char *__name, const char *__value, int __replace )
+{
+  string value = __name;
+  value += "=";
+  value += __value;
+
+  return putenv( value.c_str() );
+}
+
+const char* app_get_data_path()
+{
+  static std::string envValue = "";
+
+  if( true == envValue.empty() )
+  {
+    envValue = std::getenv( "DemoData" );
+    envValue += "/";
+  }
+
+  return envValue.c_str();
+}
diff --git a/third-party/windows-platform/extern-definitions.h b/third-party/windows-platform/extern-definitions.h
new file mode 100644 (file)
index 0000000..814b1e4
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#ifndef DALI_ADAPTOR_EXTERN_DEFINITIONS_H
+#define DALI_ADAPTOR_EXTERN_DEFINITIONS_H
+
+#include <xlocale>
+
+int setenv( const char* __name, const char* __value, int __replace );
+const char* app_get_data_path();
+
+static int strncasecmp(const char *s1, const char *s2, register int n)
+{
+  while (--n >= 0 && toupper((unsigned char)*s1) == toupper((unsigned char)*s2++))
+      if (*s1++ == 0)  return 0;
+  return(n < 0 ? 0 : toupper((unsigned char)*s1) - toupper((unsigned char)*--s2));
+}
+
+int __cdecl setsockopt( int s, int level, int optname, unsigned int * optval, unsigned int optlen );
+
+int __cdecl setsockopt( int s, int level, int optname, int * optval, unsigned int optlen );
+
+
+#define fmemopen CustomFile::FMemopen
+
+namespace CustomFile
+{
+  FILE* FMemopen( void* __s, size_t __len, const char* __modes );
+}
+
+#endif // DALI_ADAPTOR_EXTERN_DEFINITIONS_H
diff --git a/third-party/windows-platform/netinet/in.h b/third-party/windows-platform/netinet/in.h
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/third-party/windows-platform/network.cpp b/third-party/windows-platform/network.cpp
new file mode 100644 (file)
index 0000000..910831f
--- /dev/null
@@ -0,0 +1,11 @@
+#include <winsock2.h>
+
+int __cdecl setsockopt( int s, int level, int optname, unsigned int * optval, unsigned int optlen )
+{
+  return setsockopt( (SOCKET)s, level, optname, (const char*)optval, optlen );
+}
+
+int __cdecl setsockopt( int s, int level, int optname, int * optval, unsigned int optlen )
+{
+  return setsockopt( (SOCKET)s, level, optname, (const char*)optval, optlen );
+}
\ No newline at end of file
diff --git a/third-party/windows-platform/preprocessor-definitions.h b/third-party/windows-platform/preprocessor-definitions.h
new file mode 100644 (file)
index 0000000..b8af587
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019 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.
+ *
+ */
+
+#ifndef DALI_ADAPTOR_PREPROCESSOR_DEFINITIONS_H
+#define DALI_ADAPTOR_PREPROCESSOR_DEFINITIONS_H
+
+#define WIN_CALLBACK_EVENT 9999
+#define LC_MESSAGES 0
+
+#endif // DALI_ADAPTOR_PREPROCESSOR_DEFINITIONS_H
diff --git a/third-party/windows-platform/sys/mman.h b/third-party/windows-platform/sys/mman.h
new file mode 100644 (file)
index 0000000..8e2e2d9
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _MMAN_INCLUDE_
+#define _MMAN_INCLUDE_
+
+#define PROT_READ   0
+#define MAP_SHARED  1
+
+static void* mmap( void*, long long length, int, int, int handle, int )
+{
+  char *buffer = new char[length];
+  read( handle, buffer, length );
+  return buffer;
+}
+
+static void munmap( void* buffer, long long )
+{
+  delete[] buffer;
+}
+
+#endif
\ No newline at end of file
diff --git a/third-party/windows-platform/sys/prctl.h b/third-party/windows-platform/sys/prctl.h
new file mode 100644 (file)
index 0000000..5cea4e3
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _PRCTL_INCLUDE_H_
+#define _PRCTL_INCLUDE_H_
+
+#define PR_SET_NAME 0
+
+int prctl(int type, const char *str);
+
+#endif
\ No newline at end of file
diff --git a/third-party/windows-platform/sys/socket.h b/third-party/windows-platform/sys/socket.h
new file mode 100644 (file)
index 0000000..97ed344
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef _SOCKET_INCLUDE_
+#define _SOCKET_INCLUDE_
+
+#include <winsock2.h>
+
+#ifdef ERROR
+#undef ERROR
+#endif
+
+#ifdef CopyMemory
+#undef CopyMemory
+#endif
+
+#ifdef TRANSPARENT
+#undef TRANSPARENT
+#endif
+
+typedef int socklen_t;
+char DALI_SOCKET_ERROR[2] = "";
+
+char* strerror_r(int, char *, int)
+{
+  return DALI_SOCKET_ERROR;
+}
+
+int pipe( int* )
+{
+  return 1;
+}
+
+#endif
\ No newline at end of file
diff --git a/third-party/windows-platform/sys/time.h b/third-party/windows-platform/sys/time.h
new file mode 100644 (file)
index 0000000..928b2c0
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef TIME_INCLUDE
+#define TIME_INCLUDE
+
+#include <time.h>
+#include <windows.h>
+#include <winsock.h>
+
+#undef OPAQUE
+#undef TRANSPARENT
+
+#undef ERROR
+
+#undef TRUE
+#undef FALSE
+
+static int gettimeofday( struct timeval *tp, void *tzp )
+{
+  time_t clock;
+  struct tm tm;
+  SYSTEMTIME wtm;
+  GetLocalTime( &wtm );
+  tm.tm_year = wtm.wYear - 1900;
+  tm.tm_mon = wtm.wMonth - 1;
+  tm.tm_mday = wtm.wDay;
+  tm.tm_hour = wtm.wHour;
+  tm.tm_min = wtm.wMinute;
+  tm.tm_sec = wtm.wSecond;
+  tm.tm_isdst = -1;
+  clock = mktime( &tm );
+  tp->tv_sec = clock;
+  tp->tv_usec = wtm.wMilliseconds * 1000;
+  return ( 0 );
+}
+
+#endif
\ No newline at end of file
diff --git a/third-party/windows-platform/thread.cpp b/third-party/windows-platform/thread.cpp
new file mode 100644 (file)
index 0000000..69f1414
--- /dev/null
@@ -0,0 +1,4 @@
+int prctl( int type, const char *str )
+{
+  return 0;
+}
\ No newline at end of file
diff --git a/third-party/windows-platform/unistd.h b/third-party/windows-platform/unistd.h
new file mode 100644 (file)
index 0000000..35ee57e
--- /dev/null
@@ -0,0 +1,9 @@
+
+/** This file is part of the Mingw32 package.
+*  unistd.h maps     (roughly) to io.h
+*/
+#ifndef _UNISTD_H
+#define _UNISTD_H
+#include <io.h>
+#include <process.h>
+#endif /* _UNISTD_H */