From 4360626c48c90b4d1928398b964679b3acde8cc4 Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Tue, 23 Jun 2009 09:54:49 +1000 Subject: Integrate the OpenVG graphics system into Qt 4.6 This change also moves the EGL support classes from QtOpenGL to QtGui so they can be shared between OpenGL and OpenVG. --- bin/syncqt | 2 + config.tests/unix/egl/egl.cpp | 10 + config.tests/unix/egl/egl.pro | 10 + config.tests/unix/egl4gles1/egl4gles1.cpp | 10 + config.tests/unix/egl4gles1/egl4gles1.pro | 10 + config.tests/unix/opengles1/opengles1.cpp | 2 - config.tests/unix/opengles1cl/opengles1cl.cpp | 2 - config.tests/unix/opengles2/opengles2.cpp | 2 - config.tests/unix/openvg/openvg.cpp | 16 + config.tests/unix/openvg/openvg.pro | 11 + config.tests/unix/shivavg/shivavg.cpp | 10 + config.tests/unix/shivavg/shivavg.pro | 7 + configure | 131 +- doc/src/modules.qdoc | 1 + doc/src/qtopengl.qdoc | 2 +- doc/src/qtopenvg.qdoc | 73 + mkspecs/common/linux.conf | 3 + mkspecs/features/egl.prf | 3 + mkspecs/features/qt.prf | 3 +- mkspecs/features/unix/openvg.prf | 3 + mkspecs/features/win32/openvg.prf | 3 + src/corelib/global/qglobal.h | 12 + src/gui/egl/egl.pri | 28 + src/gui/egl/qegl.cpp | 403 +++ src/gui/egl/qegl_p.h | 140 + src/gui/egl/qegl_qws.cpp | 111 + src/gui/egl/qegl_symbian.cpp | 109 + src/gui/egl/qegl_wince.cpp | 116 + src/gui/egl/qegl_x11.cpp | 144 + src/gui/egl/qeglproperties.cpp | 496 +++ src/gui/egl/qeglproperties_p.h | 138 + src/gui/gui.pro | 2 + src/opengl/opengl.pro | 17 +- src/opengl/qegl.cpp | 842 ----- src/opengl/qegl_p.h | 188 -- src/opengl/qegl_qws.cpp | 125 - src/opengl/qegl_wince.cpp | 105 - src/opengl/qegl_x11egl.cpp | 133 - src/opengl/qgl_egl_p.h | 2 +- src/opengl/qgl_qws.cpp | 61 +- src/opengl/qgl_wince.cpp | 4 +- src/opengl/qgl_x11egl.cpp | 6 +- src/opengl/qglpixelbuffer_egl.cpp | 10 +- src/openvg/openvg.pro | 48 + src/openvg/qpaintengine_vg.cpp | 3231 ++++++++++++++++++++ src/openvg/qpaintengine_vg_p.h | 163 + src/openvg/qpixmapdata_vg.cpp | 344 +++ src/openvg/qpixmapdata_vg_p.h | 113 + src/openvg/qpixmapfilter_vg.cpp | 340 ++ src/openvg/qpixmapfilter_vg_p.h | 108 + src/openvg/qvg.h | 65 + src/openvg/qvg_p.h | 110 + src/openvg/qvgcompositionhelper_p.h | 91 + src/openvg/qwindowsurface_vg.cpp | 120 + src/openvg/qwindowsurface_vg_p.h | 92 + src/openvg/qwindowsurface_vgegl.cpp | 751 +++++ src/openvg/qwindowsurface_vgegl_p.h | 163 + src/plugins/graphicssystems/graphicssystems.pro | 6 + src/plugins/graphicssystems/openvg/main.cpp | 71 + src/plugins/graphicssystems/openvg/openvg.pro | 20 + .../graphicssystems/openvg/qgraphicssystem_vg.cpp | 70 + .../graphicssystems/openvg/qgraphicssystem_vg_p.h | 71 + src/plugins/graphicssystems/shivavg/README | 8 + src/plugins/graphicssystems/shivavg/main.cpp | 71 + src/plugins/graphicssystems/shivavg/shivavg.pro | 16 + .../shivavg/shivavggraphicssystem.cpp | 62 + .../shivavg/shivavggraphicssystem.h | 60 + .../shivavg/shivavgwindowsurface.cpp | 370 +++ .../graphicssystems/shivavg/shivavgwindowsurface.h | 76 + src/src.pro | 4 + tests/arthur/common/qengines.cpp | 1 + tools/qdoc3/test/qt-cpp-ignore.qdocconf | 2 + 72 files changed, 8715 insertions(+), 1438 deletions(-) create mode 100644 config.tests/unix/egl/egl.cpp create mode 100644 config.tests/unix/egl/egl.pro create mode 100644 config.tests/unix/egl4gles1/egl4gles1.cpp create mode 100644 config.tests/unix/egl4gles1/egl4gles1.pro create mode 100644 config.tests/unix/openvg/openvg.cpp create mode 100644 config.tests/unix/openvg/openvg.pro create mode 100644 config.tests/unix/shivavg/shivavg.cpp create mode 100644 config.tests/unix/shivavg/shivavg.pro create mode 100644 doc/src/qtopenvg.qdoc create mode 100644 mkspecs/features/egl.prf create mode 100644 mkspecs/features/unix/openvg.prf create mode 100644 mkspecs/features/win32/openvg.prf create mode 100644 src/gui/egl/egl.pri create mode 100644 src/gui/egl/qegl.cpp create mode 100644 src/gui/egl/qegl_p.h create mode 100644 src/gui/egl/qegl_qws.cpp create mode 100644 src/gui/egl/qegl_symbian.cpp create mode 100644 src/gui/egl/qegl_wince.cpp create mode 100644 src/gui/egl/qegl_x11.cpp create mode 100644 src/gui/egl/qeglproperties.cpp create mode 100644 src/gui/egl/qeglproperties_p.h delete mode 100644 src/opengl/qegl.cpp delete mode 100644 src/opengl/qegl_p.h delete mode 100644 src/opengl/qegl_qws.cpp delete mode 100644 src/opengl/qegl_wince.cpp delete mode 100644 src/opengl/qegl_x11egl.cpp create mode 100644 src/openvg/openvg.pro create mode 100644 src/openvg/qpaintengine_vg.cpp create mode 100644 src/openvg/qpaintengine_vg_p.h create mode 100644 src/openvg/qpixmapdata_vg.cpp create mode 100644 src/openvg/qpixmapdata_vg_p.h create mode 100644 src/openvg/qpixmapfilter_vg.cpp create mode 100644 src/openvg/qpixmapfilter_vg_p.h create mode 100644 src/openvg/qvg.h create mode 100644 src/openvg/qvg_p.h create mode 100644 src/openvg/qvgcompositionhelper_p.h create mode 100644 src/openvg/qwindowsurface_vg.cpp create mode 100644 src/openvg/qwindowsurface_vg_p.h create mode 100644 src/openvg/qwindowsurface_vgegl.cpp create mode 100644 src/openvg/qwindowsurface_vgegl_p.h create mode 100644 src/plugins/graphicssystems/openvg/main.cpp create mode 100644 src/plugins/graphicssystems/openvg/openvg.pro create mode 100644 src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp create mode 100644 src/plugins/graphicssystems/openvg/qgraphicssystem_vg_p.h create mode 100644 src/plugins/graphicssystems/shivavg/README create mode 100644 src/plugins/graphicssystems/shivavg/main.cpp create mode 100644 src/plugins/graphicssystems/shivavg/shivavg.pro create mode 100644 src/plugins/graphicssystems/shivavg/shivavggraphicssystem.cpp create mode 100644 src/plugins/graphicssystems/shivavg/shivavggraphicssystem.h create mode 100644 src/plugins/graphicssystems/shivavg/shivavgwindowsurface.cpp create mode 100644 src/plugins/graphicssystems/shivavg/shivavgwindowsurface.h diff --git a/bin/syncqt b/bin/syncqt index f58a4d1..2fe5329 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -24,6 +24,7 @@ $basedir =~ s=\\=/=g; my %modules = ( # path to module name map "QtGui" => "$basedir/src/gui", "QtOpenGL" => "$basedir/src/opengl", + "QtOpenVG" => "$basedir/src/openvg", "QtCore" => "$basedir/src/corelib", "QtXml" => "$basedir/src/xml", "QtXmlPatterns" => "$basedir/src/xmlpatterns", @@ -689,6 +690,7 @@ foreach (@modules_to_sync) { $master_contents .= "#include \n" if("$_" eq "xml"); $master_contents .= "#include \n" if("$_" eq "xmlpatterns"); $master_contents .= "#include \n" if("$_" eq "opengl"); + $master_contents .= "#include \n" if("$_" eq "openvg"); } } } diff --git a/config.tests/unix/egl/egl.cpp b/config.tests/unix/egl/egl.cpp new file mode 100644 index 0000000..0c7f32c --- /dev/null +++ b/config.tests/unix/egl/egl.cpp @@ -0,0 +1,10 @@ +#include + +int main(int, char **) +{ + EGLint x = 0; + EGLDisplay dpy = 0; + EGLContext ctx = 0; + eglDestroyContext(dpy, ctx); + return 0; +} diff --git a/config.tests/unix/egl/egl.pro b/config.tests/unix/egl/egl.pro new file mode 100644 index 0000000..f04d053 --- /dev/null +++ b/config.tests/unix/egl/egl.pro @@ -0,0 +1,10 @@ +SOURCES = egl.cpp + +for(p, QMAKE_LIBDIR_EGL) { + exists($$p):LIBS += -L$$p +} + +!isEmpty(QMAKE_INCDIR_EGL): INCLUDEPATH += $$QMAKE_INCDIR_EGL +!isEmpty(QMAKE_LIBS_EGL): LIBS += $$QMAKE_LIBS_EGL + +CONFIG -= qt diff --git a/config.tests/unix/egl4gles1/egl4gles1.cpp b/config.tests/unix/egl4gles1/egl4gles1.cpp new file mode 100644 index 0000000..c1acb90 --- /dev/null +++ b/config.tests/unix/egl4gles1/egl4gles1.cpp @@ -0,0 +1,10 @@ +#include + +int main(int, char **) +{ + EGLint x = 0; + EGLDisplay dpy = 0; + EGLContext ctx = 0; + eglDestroyContext(dpy, ctx); + return 0; +} diff --git a/config.tests/unix/egl4gles1/egl4gles1.pro b/config.tests/unix/egl4gles1/egl4gles1.pro new file mode 100644 index 0000000..667ea8e --- /dev/null +++ b/config.tests/unix/egl4gles1/egl4gles1.pro @@ -0,0 +1,10 @@ +SOURCES = egl4gles1.cpp + +for(p, QMAKE_LIBDIR_EGL) { + exists($$p):LIBS += -L$$p +} + +!isEmpty(QMAKE_INCDIR_EGL): INCLUDEPATH += $$QMAKE_INCDIR_EGL +!isEmpty(QMAKE_LIBS_EGL): LIBS += $$QMAKE_LIBS_EGL + +CONFIG -= qt diff --git a/config.tests/unix/opengles1/opengles1.cpp b/config.tests/unix/opengles1/opengles1.cpp index a0060b4..de690c9 100644 --- a/config.tests/unix/opengles1/opengles1.cpp +++ b/config.tests/unix/opengles1/opengles1.cpp @@ -1,10 +1,8 @@ #include -#include int main(int, char **) { GLfloat a = 1.0f; - eglInitialize(0, 0, 0); glColor4f(a, a, a, a); glClear(GL_COLOR_BUFFER_BIT); diff --git a/config.tests/unix/opengles1cl/opengles1cl.cpp b/config.tests/unix/opengles1cl/opengles1cl.cpp index f864276..23ae710 100644 --- a/config.tests/unix/opengles1cl/opengles1cl.cpp +++ b/config.tests/unix/opengles1cl/opengles1cl.cpp @@ -1,10 +1,8 @@ #include -#include int main(int, char **) { GLfixed a = 0; - eglInitialize(0, 0, 0); glColor4x(a, a, a, a); glClear(GL_COLOR_BUFFER_BIT); diff --git a/config.tests/unix/opengles2/opengles2.cpp b/config.tests/unix/opengles2/opengles2.cpp index 493530d..63c7b35 100644 --- a/config.tests/unix/opengles2/opengles2.cpp +++ b/config.tests/unix/opengles2/opengles2.cpp @@ -1,9 +1,7 @@ -#include #include int main(int, char **) { - eglInitialize(0, 0, 0); glUniform1f(1, GLfloat(1.0)); glClear(GL_COLOR_BUFFER_BIT); diff --git a/config.tests/unix/openvg/openvg.cpp b/config.tests/unix/openvg/openvg.cpp new file mode 100644 index 0000000..8f763cd --- /dev/null +++ b/config.tests/unix/openvg/openvg.cpp @@ -0,0 +1,16 @@ +// There is some variation in OpenVG engines as to what case +// the VG includes use. The Khronos reference implementation +// for OpenVG 1.1 uses upper case, so we treat that as canonical. +#if defined(QT_LOWER_CASE_VG_INCLUDES) +#include +#else +#include +#endif + +int main(int, char **) +{ + VGint i; + i = 2; + vgFlush(); + return 0; +} diff --git a/config.tests/unix/openvg/openvg.pro b/config.tests/unix/openvg/openvg.pro new file mode 100644 index 0000000..8dd227b --- /dev/null +++ b/config.tests/unix/openvg/openvg.pro @@ -0,0 +1,11 @@ +SOURCES += openvg.cpp + +!isEmpty(QMAKE_INCDIR_OPENVG): INCLUDEPATH += $$QMAKE_INCDIR_OPENVG +!isEmpty(QMAKE_LIBDIR_OPENVG): LIBS += -L$$QMAKE_LIBDIR_OPENVG +!isEmpty(QMAKE_LIBS_OPENVG): LIBS += $$QMAKE_LIBS_OPENVG + +lower_case_includes { + DEFINES += QT_LOWER_CASE_VG_INCLUDES +} + +CONFIG -= qt diff --git a/config.tests/unix/shivavg/shivavg.cpp b/config.tests/unix/shivavg/shivavg.cpp new file mode 100644 index 0000000..b5d3291 --- /dev/null +++ b/config.tests/unix/shivavg/shivavg.cpp @@ -0,0 +1,10 @@ +#include + +int main(int, char **) +{ + VGint i; + i = 2; + vgFlush(); + vgDestroyContextSH(); + return 0; +} diff --git a/config.tests/unix/shivavg/shivavg.pro b/config.tests/unix/shivavg/shivavg.pro new file mode 100644 index 0000000..0c1bd07 --- /dev/null +++ b/config.tests/unix/shivavg/shivavg.pro @@ -0,0 +1,7 @@ +SOURCES += shivavg.cpp + +!isEmpty(QMAKE_INCDIR_OPENVG): INCLUDEPATH += $$QMAKE_INCDIR_OPENVG +!isEmpty(QMAKE_LIBDIR_OPENVG): LIBS += -L$$QMAKE_LIBDIR_OPENVG +!isEmpty(QMAKE_LIBS_OPENVG): LIBS += $$QMAKE_LIBS_OPENVG + +CONFIG -= qt diff --git a/configure b/configure index e0b8b3e..a146175 100755 --- a/configure +++ b/configure @@ -588,6 +588,11 @@ CFG_XRANDR=runtime CFG_XRENDER=auto CFG_MITSHM=auto CFG_OPENGL=auto +CFG_OPENVG=no +CFG_OPENVG_LC_INCLUDES=no +CFG_OPENVG_SHIVA=no +CFG_EGL=no +CFG_EGL_GLES_INCLUDES=no CFG_SSE=auto CFG_FONTCONFIG=auto CFG_QWS_FREETYPE=auto @@ -888,6 +893,16 @@ while [ "$#" -gt 0 ]; do VAL=$1 fi ;; + -openvg) + VAR=openvg + # this option may or may not be followed by an argument + if [ -z "$2" ] || echo "$2" | grep '^-' >/dev/null 2>&1; then + VAL=yes + else + shift; + VAL=$1 + fi + ;; -hostprefix) VAR=`echo $1 | sed "s,^-\(.*\),\1,"` # this option may or may not be followed by an argument @@ -1132,6 +1147,13 @@ while [ "$#" -gt 0 ]; do UNKNOWN_OPT=yes fi ;; + openvg) + if [ "$VAL" = "auto" ] || [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then + CFG_OPENVG="$VAL" + else + UNKNOWN_OPT=yes + fi + ;; graphicssystem) if [ "$PLATFORM_QWS" = "yes" ]; then echo "Error: Graphics System plugins are not supported on QWS." @@ -3480,7 +3502,12 @@ Qt/X11 only: to force the use of the Desktop (OpenGL 1.x or 2.x), OpenGL ES 1.x Common profile, 1.x Common Lite profile or 2.x APIs instead. On X11, the EGL API will be used - to manage GL contexts in the case of OpenGL ES. + to manage GL contexts in the case of OpenGL ES + + -no-openvg ........ Do not support OpenVG. + + -openvg ........... Enable OpenVG support. + Requires EGL support, typically supplied by an OpenGL + or other graphics implementation. $SMN -no-sm ............. Do not support X Session Management. $SMY -sm ................ Support X Session Management, links in -lSM -lICE. @@ -4685,6 +4712,27 @@ if [ "$PLATFORM_MAC" = "yes" -a ! -z "$QT_NAMESPACE" ]; then fi if [ "$PLATFORM_X11" = "yes" -o "$PLATFORM_QWS" = "yes" ]; then + + # detect EGL support + if "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" "config.tests/unix/egl" "EGL (EGL/egl.h)" $L_FLAGS $I_FLAGS $l_FLAGS; then + # EGL specified by QMAKE_*_EGL, included with + CFG_EGL=yes + CFG_EGL_GLES_INCLUDES=no + elif "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" "config.tests/unix/egl4gles1" "EGL (GLES/egl.h)" $L_FLAGS $I_FLAGS $l_FLAGS; then + # EGL specified by QMAKE_*_EGL, included with + CFG_EGL=yes + CFG_EGL_GLES_INCLUDES=yes + fi + if ( [ "$CFG_OPENGL" = "es1" ] || [ "$CFG_OPENGL" = "es1cl" ] || [ "$CFG_OPENGL" = "es2" ] ) && [ "$CFG_EGL" != "yes" ] && [ "$PLATFORM_X11" = "yes" ]; then + echo "The EGL functionality test failed!" + echo " EGL is required for OpenGL ES on X11 to manage contexts & surfaces." + echo " You might need to modify the include and library search paths by editing" + echo " QMAKE_INCDIR_EGL, QMAKE_LIBDIR_EGL and QMAKE_LIBS_EGL in" + echo " ${XQMAKESPEC}." + exit 1 + fi + + # auto-detect Glib support if [ "$CFG_GLIB" != "no" ]; then if [ -n "$PKG_CONFIG" ]; then @@ -4814,8 +4862,8 @@ if [ "$PLATFORM_X11" = "yes" ]; then if [ $? != "0" ]; then echo "The OpenGL ES 1.x Common Lite Profile functionality test failed!" echo " You might need to modify the include and library search paths by editing" - echo " QMAKE_INCDIR_OPENGL, QMAKE_LIBDIR_OPENGL and QMAKE_LIBS_OPENGL in" - echo " ${XQMAKESPEC}." + echo " QMAKE_INCDIR_OPENGL, QMAKE_LIBDIR_OPENGL and QMAKE_LIBS_OPENGL in" + echo " ${XQMAKESPEC}." exit 1 fi elif [ "$CFG_OPENGL" = "es1" ]; then @@ -4824,8 +4872,8 @@ if [ "$PLATFORM_X11" = "yes" ]; then if [ $? != "0" ]; then echo "The OpenGL ES 1.x functionality test failed!" echo " You might need to modify the include and library search paths by editing" - echo " QMAKE_INCDIR_OPENGL, QMAKE_LIBDIR_OPENGL and QMAKE_LIBS_OPENGL in" - echo " ${XQMAKESPEC}." + echo " QMAKE_INCDIR_OPENGL, QMAKE_LIBDIR_OPENGL and QMAKE_LIBS_OPENGL in" + echo " ${XQMAKESPEC}." exit 1 fi elif [ "$CFG_OPENGL" = "es2" ]; then @@ -4834,8 +4882,8 @@ if [ "$PLATFORM_X11" = "yes" ]; then if [ $? != "0" ]; then echo "The OpenGL ES 2.0 functionality test failed!" echo " You might need to modify the include and library search paths by editing" - echo " QMAKE_INCDIR_OPENGL, QMAKE_LIBDIR_OPENGL and QMAKE_LIBS_OPENGL in" - echo " ${XQMAKESPEC}." + echo " QMAKE_INCDIR_OPENGL, QMAKE_LIBDIR_OPENGL and QMAKE_LIBS_OPENGL in" + echo " ${XQMAKESPEC}." exit 1 fi elif [ "$CFG_OPENGL" = "desktop" ]; then @@ -4844,8 +4892,8 @@ if [ "$PLATFORM_X11" = "yes" ]; then if [ $? != "0" ]; then echo "The OpenGL functionality test failed!" echo " You might need to modify the include and library search paths by editing" - echo " QMAKE_INCDIR_OPENGL, QMAKE_LIBDIR_OPENGL and QMAKE_LIBS_OPENGL in" - echo " ${XQMAKESPEC}." + echo " QMAKE_INCDIR_OPENGL, QMAKE_LIBDIR_OPENGL and QMAKE_LIBS_OPENGL in" + echo " ${XQMAKESPEC}." exit 1 fi case "$PLATFORM" in @@ -5500,6 +5548,33 @@ if [ "$CFG_OPENSSL" != "no" ]; then fi fi +# detect OpenVG support +if [ "$CFG_OPENVG" != "no" ]; then + if "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" "config.tests/unix/openvg" "OpenVG" $L_FLAGS $I_FLAGS $l_FLAGS $CONFIG_ARG; then + if [ "$CFG_OPENVG" = "auto" ]; then + CFG_OPENVG=yes + fi + elif "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG lower_case_includes" $OPT_VERBOSE "$relpath" "$outpath" "config.tests/unix/openvg" "OpenVG (lc includes)" $L_FLAGS $I_FLAGS $l_FLAGS $CONFIG_ARG; then + if [ "$CFG_OPENVG" = "auto" ]; then + CFG_OPENVG=yes + fi + CFG_OPENVG_LC_INCLUDES=yes + else + if [ "$CFG_OPENVG" != "auto" ] && [ "$CFG_CONFIGURE_EXIT_ON_ERROR" = "yes" ]; then + echo "$CFG_OPENVG was specified for OpenVG but cannot be enabled due to functionality tests!" + echo " Turn on verbose messaging (-v) to $0 to see the final report." + echo " If you believe this message is in error you may use the continue" + echo " switch (-continue) to $0 to continue." + exit 101 + else + CFG_OPENVG=no + fi + fi + if [ "$CFG_OPENVG" == "yes" ] && "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" "config.tests/unix/shivavg" "ShivaVG" $L_FLAGS $I_FLAGS $l_FLAGS $CONFIG_ARG; then + CFG_OPENVG_SHIVA=yes + fi +fi + if [ "$CFG_PTMALLOC" != "no" ]; then # build ptmalloc, copy .a file to lib/ echo "Building ptmalloc. Please wait..." @@ -5629,6 +5704,30 @@ else QT_CONFIG="$QT_CONFIG accessibility" fi +# enable egl +if [ "$CFG_EGL" = "no" ]; then + QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_EGL" +else + QT_CONFIG="$QT_CONFIG egl" + if [ "$CFG_EGL_GLES_INCLUDES" = "yes" ]; then + QCONFIG_FLAGS="$QCONFIG_FLAGS QT_GLES_EGL" + fi +fi + +# enable openvg +if [ "$CFG_OPENVG" = "no" ]; then + QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_OPENVG" +else + QT_CONFIG="$QT_CONFIG openvg" + if [ "$CFG_OPENVG_LC_INCLUDES" = "yes" ]; then + QCONFIG_FLAGS="$QCONFIG_FLAGS QT_LOWER_CASE_VG_INCLUDES" + fi + if [ "$CFG_OPENVG_SHIVA" = "yes" ]; then + QT_CONFIG="$QT_CONFIG shivavg" + QCONFIG_FLAGS="$QCONFIG_FLAGS QT_SHIVAVG" + fi +fi + # enable opengl if [ "$CFG_OPENGL" = "no" ]; then QCONFIG_FLAGS="$QCONFIG_FLAGS QT_NO_OPENGL" @@ -6971,6 +7070,20 @@ elif [ "$CFG_OPENGL" = "es2" ]; then else echo "OpenGL support ...... no" fi +if [ "$CFG_EGL" != "no" ]; then + if [ "$CFG_EGL_GLES_INCLUDES" != "no" ]; then + echo "EGL support ......... yes " + else + echo "EGL support ......... yes " + fi +fi +if [ "$CFG_OPENVG" ]; then + if [ "$CFG_OPENVG_SHIVA" = "yes" ]; then + echo "OpenVG support ...... ShivaVG" + else + echo "OpenVG support ...... $CFG_OPENVG" + fi +fi if [ "$PLATFORM_X11" = "yes" ]; then echo "NAS sound support ... $CFG_NAS" echo "XShape support ...... $CFG_XSHAPE" diff --git a/doc/src/modules.qdoc b/doc/src/modules.qdoc index 145b361..5f0f868 100644 --- a/doc/src/modules.qdoc +++ b/doc/src/modules.qdoc @@ -55,6 +55,7 @@ \row \o \l{QtGui} \o Graphical user interface (GUI) components \row \o \l{QtNetwork} \o Classes for network programming \row \o \l{QtOpenGL} \o OpenGL support classes + \row \o \l{QtOpenVG} \o OpenVG support classes \row \o \l{QtScript} \o Classes for evaluating Qt Scripts \row \o \l{QtScriptTools} \o Additional Qt Script components \row \o \l{QtSql} \o Classes for database integration using SQL diff --git a/doc/src/qtopengl.qdoc b/doc/src/qtopengl.qdoc index 69d33bb..f60ef89 100644 --- a/doc/src/qtopengl.qdoc +++ b/doc/src/qtopengl.qdoc @@ -44,7 +44,7 @@ \title QtOpenGL Module \contentspage Qt's Modules \previouspage QtNetwork - \nextpage QtSql + \nextpage QtOpenVG \ingroup modules \brief The QtOpenGL module offers classes that make it easy to diff --git a/doc/src/qtopenvg.qdoc b/doc/src/qtopenvg.qdoc new file mode 100644 index 0000000..ad036ef --- /dev/null +++ b/doc/src/qtopenvg.qdoc @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \module QtOpenVG + \title QtOpenVG Module + \contentspage Qt's Modules + \previouspage QtOpenGL + \nextpage QtSql + \ingroup modules + + \brief The QtOpenVG module offers classes that make it easy to + use OpenVG in Qt applications. + + From the OpenVG 1.1 Specification: + + \quotation + + OpenVG is an application programming interface (API) for hardware-accelerated two- + dimensional vector and raster graphics developed under the auspices of the Khronos + Group (www.khronos.org). It provides a device-independent and vendor-neutral interface + for sophisticated 2D graphical applications, while allowing device manufacturers to + provide hardware acceleration where appropriate. + + \endquotation + + The specification, and a reference implementation of it are available from the + \l{http://www.khronos.org/registry/vg/}{Khronos Group}. + + \bold{Note:} Khronos and OpenVG are trademarks of The Khronos Group Inc. OpenGL is a + registered trademark, and OpenGL ES is a trademark, of Silicon Graphics, Inc. + + + The Qt OpenVG module makes it easy to use OpenVG in Qt applications. + */ diff --git a/mkspecs/common/linux.conf b/mkspecs/common/linux.conf index ff87c74..fa84841 100644 --- a/mkspecs/common/linux.conf +++ b/mkspecs/common/linux.conf @@ -13,12 +13,15 @@ QMAKE_INCDIR_QT = $$[QT_INSTALL_HEADERS] QMAKE_LIBDIR_QT = $$[QT_INSTALL_LIBS] QMAKE_INCDIR_OPENGL = /usr/X11R6/include QMAKE_LIBDIR_OPENGL = /usr/X11R6/lib +QMAKE_INCDIR_EGL = +QMAKE_LIBDIR_EGL = QMAKE_LIBS = QMAKE_LIBS_DYNLOAD = -ldl QMAKE_LIBS_X11 = -lXext -lX11 -lm QMAKE_LIBS_X11SM = -lSM -lICE QMAKE_LIBS_NIS = -lnsl +QMAKE_LIBS_EGL = -lEGL QMAKE_LIBS_OPENGL = -lGLU -lGL QMAKE_LIBS_OPENGL_QT = -lGL QMAKE_LIBS_THREAD = -lpthread diff --git a/mkspecs/features/egl.prf b/mkspecs/features/egl.prf new file mode 100644 index 0000000..22002c3 --- /dev/null +++ b/mkspecs/features/egl.prf @@ -0,0 +1,3 @@ +!isEmpty(QMAKE_INCDIR_EGL): INCLUDEPATH += $$QMAKE_INCDIR_EGL +!isEmpty(QMAKE_LIBDIR_EGL): LIBS += -L$$QMAKE_LIBDIR_EGL +!isEmpty(QMAKE_LIBS_EGL): LIBS += $$QMAKE_LIBS_EGL diff --git a/mkspecs/features/qt.prf b/mkspecs/features/qt.prf index 0c6e09a..332eaca 100644 --- a/mkspecs/features/qt.prf +++ b/mkspecs/features/qt.prf @@ -36,7 +36,7 @@ INCLUDEPATH = $$QMAKE_INCDIR_QT $$INCLUDEPATH #prepending prevents us from picki win32:INCLUDEPATH += $$QMAKE_INCDIR_QT/ActiveQt # As order does matter for static libs, we reorder the QT variable here -TMPLIBS = webkit phonon dbus testlib script scripttools svg qt3support sql xmlpatterns xml opengl gui network core +TMPLIBS = webkit phonon dbus testlib script scripttools svg qt3support sql xmlpatterns xml egl opengl openvg gui network core for(QTLIB, $$list($$TMPLIBS)) { contains(QT, $$QTLIB): QT_ORDERED += $$QTLIB } @@ -140,6 +140,7 @@ for(QTLIB, $$list($$lower($$unique(QT)))) { else:isEqual(QTLIB, xml):qlib = QtXml else:isEqual(QTLIB, xmlpatterns):qlib = QtXmlPatterns else:isEqual(QTLIB, opengl):qlib = QtOpenGL + else:isEqual(QTLIB, openvg):qlib = QtOpenVG else:isEqual(QTLIB, sql):qlib = QtSql else:isEqual(QTLIB, core):qlib = QtCore else:isEqual(QTLIB, canvas):qlib = QtCanvas diff --git a/mkspecs/features/unix/openvg.prf b/mkspecs/features/unix/openvg.prf new file mode 100644 index 0000000..7bd7fbe --- /dev/null +++ b/mkspecs/features/unix/openvg.prf @@ -0,0 +1,3 @@ +!isEmpty(QMAKE_INCDIR_OPENVG): INCLUDEPATH += $$QMAKE_INCDIR_OPENVG +!isEmpty(QMAKE_LIBDIR_OPENVG): QMAKE_LIBDIR += -L$$QMAKE_LIBDIR_OPENVG +!isEmpty(QMAKE_LIBS_OPENVG): LIBS += $QMAKE_LIBS_OPENVG diff --git a/mkspecs/features/win32/openvg.prf b/mkspecs/features/win32/openvg.prf new file mode 100644 index 0000000..d4aa296 --- /dev/null +++ b/mkspecs/features/win32/openvg.prf @@ -0,0 +1,3 @@ +QMAKE_LIBS += $$QMAKE_LIBS_OPENVG +QMAKE_LFLAGS += $$QMAKE_LFLAGS_OPENVG + diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 3e6771c..0721c39 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -1143,6 +1143,11 @@ class QDataStream; # else # define Q_OPENGL_EXPORT Q_DECL_IMPORT # endif +# if defined(QT_BUILD_OPENVG_LIB) +# define Q_OPENVG_EXPORT Q_DECL_EXPORT +# else +# define Q_OPENVG_EXPORT Q_DECL_IMPORT +# endif # if defined(QT_BUILD_XML_LIB) # define Q_XML_EXPORT Q_DECL_EXPORT # else @@ -1182,6 +1187,7 @@ class QDataStream; # define Q_SVG_EXPORT Q_DECL_IMPORT # define Q_CANVAS_EXPORT Q_DECL_IMPORT # define Q_OPENGL_EXPORT Q_DECL_IMPORT +# define Q_OPENVG_EXPORT Q_DECL_IMPORT # define Q_XML_EXPORT Q_DECL_IMPORT # define Q_XMLPATTERNS_EXPORT Q_DECL_IMPORT # define Q_SCRIPT_EXPORT Q_DECL_IMPORT @@ -1207,6 +1213,7 @@ class QDataStream; # define Q_NETWORK_EXPORT Q_DECL_EXPORT # define Q_SVG_EXPORT Q_DECL_EXPORT # define Q_OPENGL_EXPORT Q_DECL_EXPORT +# define Q_OPENVG_EXPORT Q_DECL_EXPORT # define Q_XML_EXPORT Q_DECL_EXPORT # define Q_XMLPATTERNS_EXPORT Q_DECL_EXPORT # define Q_SCRIPT_EXPORT Q_DECL_EXPORT @@ -2252,6 +2259,7 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf(); #define QT_MODULE_TEST 0x04000 #define QT_MODULE_DBUS 0x08000 #define QT_MODULE_SCRIPTTOOLS 0x10000 +#define QT_MODULE_OPENVG 0x20000 /* Qt editions */ #define QT_EDITION_CONSOLE (QT_MODULE_CORE \ @@ -2271,6 +2279,7 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf(); | QT_MODULE_GUI \ | QT_MODULE_NETWORK \ | QT_MODULE_OPENGL \ + | QT_MODULE_OPENVG \ | QT_MODULE_SQL \ | QT_MODULE_XML \ | QT_MODULE_XMLPATTERNS \ @@ -2314,6 +2323,9 @@ QT_LICENSED_MODULE(Network) #if (QT_EDITION & QT_MODULE_OPENGL) QT_LICENSED_MODULE(OpenGL) #endif +#if (QT_EDITION & QT_MODULE_OPENVG) +QT_LICENSED_MODULE(OpenVG) +#endif #if (QT_EDITION & QT_MODULE_SQL) QT_LICENSED_MODULE(Sql) #endif diff --git a/src/gui/egl/egl.pri b/src/gui/egl/egl.pri new file mode 100644 index 0000000..651507f --- /dev/null +++ b/src/gui/egl/egl.pri @@ -0,0 +1,28 @@ +HEADERS += \ + egl/qegl_p.h \ + egl/qeglproperties_p.h + +SOURCES += \ + egl/qegl.cpp \ + egl/qeglproperties.cpp + +contains(QT_CONFIG, wince*): SOURCES += egl/qegl_wince.cpp + +unix { + embedded { + SOURCES += egl/qegl_qws.cpp + } else { + symbian { + SOURCES += egl/qegl_symbian.cpp + } else { + SOURCES += egl/qegl_x11.cpp + } + } +} + +for(p, QMAKE_LIBDIR_EGL) { + exists($$p):LIBS += -L$$p +} + +!isEmpty(QMAKE_INCDIR_EGL): INCLUDEPATH += $$QMAKE_INCDIR_EGL +!isEmpty(QMAKE_LIBS_EGL): LIBS += $$QMAKE_LIBS_EGL diff --git a/src/gui/egl/qegl.cpp b/src/gui/egl/qegl.cpp new file mode 100644 index 0000000..89d9d1b --- /dev/null +++ b/src/gui/egl/qegl.cpp @@ -0,0 +1,403 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include "qegl_p.h" + +QT_BEGIN_NAMESPACE + +QEglContext::QEglContext() + : apiType(QEgl::OpenGL) + , dpy(EGL_NO_DISPLAY) + , ctx(EGL_NO_CONTEXT) + , surf(EGL_NO_SURFACE) + , cfg(0) + , share(false) + , current(false) + , reserved(0) +{ +} + +QEglContext::~QEglContext() +{ + destroy(); +} + +bool QEglContext::isValid() const +{ + return (ctx != EGL_NO_CONTEXT); +} + +bool QEglContext::isSharing() const +{ + return share; +} + +bool QEglContext::isCurrent() const +{ + return current; +} + +// Open the EGL display associated with "device". +bool QEglContext::openDisplay(QPaintDevice *device) +{ + if (dpy == EGL_NO_DISPLAY) + dpy = defaultDisplay(device); + return (dpy != EGL_NO_DISPLAY); +} + +// Choose a configuration that matches "properties". +bool QEglContext::chooseConfig + (const QEglProperties& properties, QEgl::PixelFormatMatch match) +{ + QEglProperties props(properties); + do { + // Get the number of matching configurations for this set of properties. + EGLint matching = 0; + if (!eglChooseConfig(dpy, props.properties(), 0, 256, &matching) || !matching) + continue; + + // If we want the best pixel format, then return the first + // matching configuration. + if (match == QEgl::BestPixelFormat) { + eglChooseConfig(dpy, props.properties(), &cfg, 1, &matching); + if (matching < 1) + continue; + return true; + } + + // Fetch all of the matching configurations and find the + // first that matches the pixel format we wanted. + EGLint size = matching; + EGLConfig *configs = new EGLConfig [size]; + eglChooseConfig(dpy, props.properties(), configs, size, &matching); + for (EGLint index = 0; index < size; ++index) { + EGLint red, green, blue, alpha; + eglGetConfigAttrib(dpy, configs[index], EGL_RED_SIZE, &red); + eglGetConfigAttrib(dpy, configs[index], EGL_GREEN_SIZE, &green); + eglGetConfigAttrib(dpy, configs[index], EGL_BLUE_SIZE, &blue); + eglGetConfigAttrib(dpy, configs[index], EGL_ALPHA_SIZE, &alpha); + if (red == props.value(EGL_RED_SIZE) && + green == props.value(EGL_GREEN_SIZE) && + blue == props.value(EGL_BLUE_SIZE) && + (props.value(EGL_ALPHA_SIZE) == 0 || + alpha == props.value(EGL_ALPHA_SIZE))) { + cfg = configs[index]; + delete [] configs; + return true; + } + } + delete [] configs; + } while (props.reduceConfiguration()); + +#ifdef EGL_BIND_TO_TEXTURE_RGBA + // Don't report an error just yet if we failed to get a pbuffer + // configuration with texture rendering. Only report failure if + // we cannot get any pbuffer configurations at all. + if (props.value(EGL_BIND_TO_TEXTURE_RGBA) == EGL_DONT_CARE && + props.value(EGL_BIND_TO_TEXTURE_RGB) == EGL_DONT_CARE) +#endif + { + qWarning() << "QEglContext::chooseConfig(): Could not find a suitable EGL configuration"; + qWarning() << "Requested:" << props.toString(); + qWarning() << "Available:"; + dumpAllConfigs(); + } + return false; +} + +// Create the EGLContext. +bool QEglContext::createContext(QEglContext *shareContext) +{ + // We need to select the correct API before calling eglCreateContext(). +#ifdef EGL_OPENGL_ES_API + if (apiType == QEgl::OpenGL) + eglBindAPI(EGL_OPENGL_ES_API); +#endif +#ifdef EGL_OPENVG_API + if (apiType == QEgl::OpenVG) + eglBindAPI(EGL_OPENVG_API); +#endif + + // Create a new context for the configuration. + QEglProperties contextProps; +#if defined(QT_OPENGL_ES_2) + if (apiType == QEgl::OpenGL) + contextProps.setValue(EGL_CONTEXT_CLIENT_VERSION, 2); +#endif + if (shareContext && shareContext->ctx == EGL_NO_CONTEXT) + shareContext = 0; + if (shareContext) { + ctx = eglCreateContext(dpy, cfg, shareContext->ctx, contextProps.properties()); + if (ctx == EGL_NO_CONTEXT) { + qWarning() << "QEglContext::createContext(): Could not share context:" << errorString(eglGetError()); + shareContext = 0; + } + } + if (ctx == EGL_NO_CONTEXT) { + ctx = eglCreateContext(dpy, cfg, 0, contextProps.properties()); + if (ctx == EGL_NO_CONTEXT) { + qWarning() << "QEglContext::createContext(): Unable to create EGL context:" << errorString(eglGetError()); + return false; + } + } + share = (shareContext != 0); + return true; +} + +// Recreate the surface for a paint device because the native id has changed. +bool QEglContext::recreateSurface(QPaintDevice *device) +{ + // Bail out if the surface has not been created for the first time yet. + if (surf == EGL_NO_SURFACE) + return true; + + // Destroy the old surface. + eglDestroySurface(dpy, surf); + surf = EGL_NO_SURFACE; + + // Create a new one. + return createSurface(device); +} + +// Destroy the EGL surface object. +void QEglContext::destroySurface() +{ + if (surf != EGL_NO_SURFACE) { + eglDestroySurface(dpy, surf); + surf = EGL_NO_SURFACE; + } +} + +// Destroy the context. Note: this does not destroy the surface. +void QEglContext::destroy() +{ + if (ctx != EGL_NO_CONTEXT) + eglDestroyContext(dpy, ctx); + dpy = EGL_NO_DISPLAY; + ctx = EGL_NO_CONTEXT; + surf = EGL_NO_SURFACE; + cfg = 0; + share = false; +} + +bool QEglContext::makeCurrent() +{ + if (ctx == EGL_NO_CONTEXT) { + qWarning() << "QEglContext::makeCurrent(): Cannot make invalid context current"; + return false; + } + + current = true; + + bool ok = eglMakeCurrent(dpy, surf, surf, ctx); + if (!ok) + qWarning() << "QEglContext::makeCurrent():" << errorString(eglGetError()); + return ok; +} + +bool QEglContext::doneCurrent() +{ + // If the context is invalid, we assume that an error was reported + // when makeCurrent() was called. + if (ctx == EGL_NO_CONTEXT) + return false; + + current = false; + + // We need to select the correct API before calling eglMakeCurrent() + // with EGL_NO_CONTEXT because threads can have both OpenGL and OpenVG + // contexts active at the same time. +#ifdef EGL_OPENGL_ES_API + if (apiType == QEgl::OpenGL) + eglBindAPI(EGL_OPENGL_ES_API); +#endif +#ifdef EGL_OPENVG_API + if (apiType == QEgl::OpenVG) + eglBindAPI(EGL_OPENVG_API); +#endif + + bool ok = eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + if (!ok) + qWarning() << "QEglContext::doneCurrent():" << errorString(eglGetError()); + return ok; +} + +bool QEglContext::swapBuffers() +{ + if(ctx == EGL_NO_CONTEXT) + return false; + + bool ok = eglSwapBuffers(dpy, surf); + if (!ok) + qWarning() << "QEglContext::swapBuffers():" << errorString(eglGetError()); + return ok; +} + +// Wait for native rendering operations to complete before starting +// to use OpenGL/OpenVG operations. +void QEglContext::waitNative() +{ +#ifdef EGL_CORE_NATIVE_ENGINE + eglWaitNative(EGL_CORE_NATIVE_ENGINE); +#endif +} + +// Wait for client OpenGL/OpenVG operations to complete before +// using native rendering operations. +void QEglContext::waitClient() +{ +#ifdef EGL_OPENGL_ES_API + if (apiType == QEgl::OpenGL) { + eglBindAPI(EGL_OPENGL_ES_API); + eglWaitClient(); + } +#else + if (apiType == QEgl::OpenGL) + eglWaitGL(); +#endif +#ifdef EGL_OPENVG_API + if (apiType == QEgl::OpenVG) { + eglBindAPI(EGL_OPENVG_API); + eglWaitClient(); + } +#endif +} + +// Query the actual size of the EGL surface. +QSize QEglContext::surfaceSize() const +{ + int w, h; + eglQuerySurface(dpy, surf, EGL_WIDTH, &w); + eglQuerySurface(dpy, surf, EGL_HEIGHT, &h); + return QSize(w, h); +} + +// Query the value of a configuration attribute. +bool QEglContext::configAttrib(int name, EGLint *value) const +{ + return eglGetConfigAttrib(dpy, cfg, name, value); +} + +// Retrieve all of the properties on "cfg". If zero, return +// the context's configuration. +QEglProperties QEglContext::configProperties(EGLConfig cfg) const +{ + if (!cfg) + cfg = config(); + QEglProperties props; + for (int name = 0x3020; name <= 0x304F; ++name) { + EGLint value; + if (name != EGL_NONE && eglGetConfigAttrib(dpy, cfg, name, &value)) + props.setValue(name, value); + } + eglGetError(); // Clear the error state. + return props; +} + +// Initialize and return the default display. +EGLDisplay QEglContext::defaultDisplay(QPaintDevice *device) +{ + static EGLDisplay dpy = EGL_NO_DISPLAY; + if (dpy == EGL_NO_DISPLAY) { + dpy = getDisplay(device); + if (dpy == EGL_NO_DISPLAY) { + qWarning() << "QEglContext::defaultDisplay(): Cannot open EGL display"; + return EGL_NO_DISPLAY; + } + if (!eglInitialize(dpy, NULL, NULL)) { + qWarning() << "QEglContext::defaultDisplay(): Cannot initialize EGL display:" << errorString(eglGetError()); + return EGL_NO_DISPLAY; + } +#ifdef EGL_OPENGL_ES_API + eglBindAPI(EGL_OPENGL_ES_API); +#endif + } + return dpy; +} + +// Return the error string associated with a specific code. +QString QEglContext::errorString(EGLint code) +{ + static const char * const errors[] = { + "Success (0x3000)", // No tr + "Not initialized (0x3001)", // No tr + "Bad access (0x3002)", // No tr + "Bad alloc (0x3003)", // No tr + "Bad attribute (0x3004)", // No tr + "Bad config (0x3005)", // No tr + "Bad context (0x3006)", // No tr + "Bad current surface (0x3007)", // No tr + "Bad display (0x3008)", // No tr + "Bad match (0x3009)", // No tr + "Bad native pixmap (0x300A)", // No tr + "Bad native window (0x300B)", // No tr + "Bad parameter (0x300C)", // No tr + "Bad surface (0x300D)", // No tr + "Context lost (0x300E)" // No tr + }; + if (code >= 0x3000 && code <= 0x300E) { + return QString::fromLatin1(errors[code - 0x3000]); + } else { + return QLatin1String("0x") + QString::number(int(code), 16); + } +} + +// Dump all of the EGL configurations supported by the system. +void QEglContext::dumpAllConfigs() +{ + QEglProperties props; + EGLint count = 0; + if (!eglGetConfigs(dpy, 0, 0, &count) || count < 1) + return; + EGLConfig *configs = new EGLConfig [count]; + eglGetConfigs(dpy, configs, count, &count); + for (EGLint index = 0; index < count; ++index) { + props = configProperties(configs[index]); + qWarning() << props.toString(); + } + delete [] configs; +} + +QT_END_NAMESPACE diff --git a/src/gui/egl/qegl_p.h b/src/gui/egl/qegl_p.h new file mode 100644 index 0000000..89949e2 --- /dev/null +++ b/src/gui/egl/qegl_p.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEGL_P_H +#define QEGL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience of +// the QGLWidget and QVGWidget classes. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +#include "qeglproperties_p.h" + +QT_BEGIN_INCLUDE_NAMESPACE + +#if !defined(EGL_VERSION_1_3) && !defined(QEGL_NATIVE_TYPES_DEFINED) +#undef EGLNativeWindowType +#undef EGLNativePixmapType +#undef EGLNativeDisplayType +typedef NativeWindowType EGLNativeWindowType; +typedef NativePixmapType EGLNativePixmapType; +typedef NativeDisplayType EGLNativeDisplayType; +#define QEGL_NATIVE_TYPES_DEFINED 1 +#endif +QT_END_INCLUDE_NAMESPACE + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QEglContext +{ +public: + QEglContext(); + ~QEglContext(); + + bool isValid() const; + bool isSharing() const; + bool isCurrent() const; + + QEgl::API api() const { return apiType; } + void setApi(QEgl::API api) { apiType = api; } + + bool openDisplay(QPaintDevice *device); + bool chooseConfig(const QEglProperties& properties, QEgl::PixelFormatMatch match = QEgl::ExactPixelFormat); + bool createContext(QEglContext *shareContext = 0); + bool createSurface(QPaintDevice *device, const QEglProperties *properties = 0); + bool recreateSurface(QPaintDevice *device); + void destroySurface(); + + void destroy(); + + bool makeCurrent(); + bool doneCurrent(); + bool swapBuffers(); + + void waitNative(); + void waitClient(); + + QSize surfaceSize() const; + + bool configAttrib(int name, EGLint *value) const; + + static void clearError() { eglGetError(); } + static EGLint error() { return eglGetError(); } + static QString errorString(EGLint code); + + EGLDisplay display() const { return dpy; } + EGLContext context() const { return ctx; } + EGLSurface surface() const { return surf; } + void setSurface(EGLSurface surface) { surf = surface; } + EGLConfig config() const { return cfg; } + + QEglProperties configProperties(EGLConfig cfg = 0) const; + + static EGLDisplay defaultDisplay(QPaintDevice *device); + + void dumpAllConfigs(); + +private: + QEgl::API apiType; + EGLDisplay dpy; + EGLContext ctx; + EGLSurface surf; + EGLConfig cfg; + bool share; + bool current; + void *reserved; // For extension data in future versions. + + static EGLDisplay getDisplay(QPaintDevice *device); +}; + +QT_END_NAMESPACE + +#endif // QEGL_P_H diff --git a/src/gui/egl/qegl_qws.cpp b/src/gui/egl/qegl_qws.cpp new file mode 100644 index 0000000..69eaf1b --- /dev/null +++ b/src/gui/egl/qegl_qws.cpp @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include "qegl_p.h" + +#if !defined(QT_NO_EGL) + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +// Create the surface for a QPixmap, QImage, or QWidget. +// We don't have QGLScreen to create EGL surfaces for us, +// so surface creation needs to be done in QtOpenGL or +// QtOpenVG for Qt/Embedded. +bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties) +{ + Q_UNUSED(device); + Q_UNUSED(properties); + return false; +} + +EGLDisplay QEglContext::getDisplay(QPaintDevice *device) +{ + Q_UNUSED(device); + return eglGetDisplay(EGLNativeDisplayType(EGL_DEFAULT_DISPLAY)); +} + +static QScreen *screenForDevice(QPaintDevice *device) +{ + QScreen *screen = qt_screen; + if (!screen) + return 0; + if (screen->classId() == QScreen::MultiClass) { + int screenNumber; + if (device && device->devType() == QInternal::Widget) + screenNumber = qApp->desktop()->screenNumber(static_cast(device)); + else + screenNumber = 0; + screen = screen->subScreens()[screenNumber]; + } + while (screen->classId() == QScreen::ProxyClass) { + screen = static_cast(screen)->screen(); + } + return screen; +} + +// Set pixel format and other properties based on a paint device. +void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev) +{ + if (!dev) + return; + + // Find the QGLScreen for this paint device. + QScreen *screen = screenForDevice(dev); + if (!screen) + return; + int devType = dev->devType(); + if (devType == QInternal::Image) + setPixelFormat(static_cast(dev)->format()); + else + setPixelFormat(screen->pixelFormat()); +} + +QT_END_NAMESPACE + +#endif // !QT_NO_EGL diff --git a/src/gui/egl/qegl_symbian.cpp b/src/gui/egl/qegl_symbian.cpp new file mode 100644 index 0000000..16a72a1 --- /dev/null +++ b/src/gui/egl/qegl_symbian.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include "qegl_p.h" + +#include + +QT_BEGIN_NAMESPACE + +bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties) +{ + // Create the native drawable for the paint device. + int devType = device->devType(); + EGLNativePixmapType pixmapDrawable = 0; + EGLNativeWindowType windowDrawable = 0; + bool ok; + if (devType == QInternal::Pixmap) { + pixmapDrawable = 0; + ok = (pixmapDrawable != 0); + } else if (devType == QInternal::Widget) { + QWidget *w = static_cast(device); + windowDrawable = (EGLNativeWindowType)(w->winId()->DrawableWindow()); + ok = (windowDrawable != 0); + } else { + ok = false; + } + if (!ok) { + qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); + return false; + } + + // Create the EGL surface to draw into, based on the native drawable. + const int *props; + if (properties) + props = properties->properties(); + else + props = 0; + if (devType == QInternal::Widget) + surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, 0); + else + surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, 0); + if (surf == EGL_NO_SURFACE) { + qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); + return false; + } + return true; +} + +EGLDisplay QEglContext::getDisplay(QPaintDevice *device) +{ + EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + if (dpy == EGL_NO_DISPLAY) + qWarning("QEglContext::defaultDisplay(): Falling back to EGL_DEFAULT_DISPLAY"); + return dpy; +} + +// Set pixel format and other properties based on a paint device. +void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev) +{ + int devType = dev->devType(); + if (devType == QInternal::Image) + setPixelFormat(static_cast(dev)->format()); + else + setPixelFormat(QImage::Format_RGB32); +} + + +QT_END_NAMESPACE diff --git a/src/gui/egl/qegl_wince.cpp b/src/gui/egl/qegl_wince.cpp new file mode 100644 index 0000000..7bcbcf8 --- /dev/null +++ b/src/gui/egl/qegl_wince.cpp @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include "qegl_p.h" + +#include + + +QT_BEGIN_NAMESPACE + +bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties) +{ + // Create the native drawable for the paint device. + int devType = device->devType(); + EGLNativePixmapType pixmapDrawable = 0; + EGLNativeWindowType windowDrawable = 0; + bool ok; + if (devType == QInternal::Pixmap) { + pixmapDrawable = 0; + ok = (pixmapDrawable != 0); + } else if (devType == QInternal::Widget) { + windowDrawable = (EGLNativeWindowType)(static_cast(device))->winId(); + ok = (windowDrawable != 0); + } else { + ok = false; + } + if (!ok) { + qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); + return false; + } + + // Create the EGL surface to draw into, based on the native drawable. + const int *props; + if (properties) + props = properties->properties(); + else + props = 0; + if (devType == QInternal::Widget) + surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, props); + else + surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, props); + if (surf == EGL_NO_SURFACE) { + qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); + return false; + } + return true; +} + +EGLDisplay QEglContext::getDisplay(QPaintDevice *device) +{ + EGLDisplay dpy = 0; + HWND win = (static_cast(device))->winId(); + HDC myDc = GetDC(win); + if (!myDc) { + qWarning("QEglContext::defaultDisplay(): WinCE display is not open"); + } + dpy = eglGetDisplay(EGLNativeDisplayType(myDc)); + if (dpy == EGL_NO_DISPLAY) { + qWarning("QEglContext::defaultDisplay(): Falling back to EGL_DEFAULT_DISPLAY"); + dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + } + return dpy; +} + +// Set pixel format and other properties based on a paint device. +void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev) +{ + int devType = dev->devType(); + if (devType == QInternal::Image) + setPixelFormat(static_cast(dev)->format()); + else + setPixelFormat(QImage::Format_RGB16); // XXX +} + +QT_END_NAMESPACE diff --git a/src/gui/egl/qegl_x11.cpp b/src/gui/egl/qegl_x11.cpp new file mode 100644 index 0000000..be89efe --- /dev/null +++ b/src/gui/egl/qegl_x11.cpp @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include "qegl_p.h" + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +bool QEglContext::createSurface(QPaintDevice *device, const QEglProperties *properties) +{ + // Create the native drawable for the paint device. + int devType = device->devType(); + EGLNativePixmapType pixmapDrawable = 0; + EGLNativeWindowType windowDrawable = 0; + bool ok; + if (devType == QInternal::Pixmap) { + pixmapDrawable = (EGLNativePixmapType)(static_cast(device))->handle(); + ok = (pixmapDrawable != 0); + } else if (devType == QInternal::Widget) { + windowDrawable = (EGLNativeWindowType)(static_cast(device))->winId(); + ok = (windowDrawable != 0); + } else { + ok = false; + } + if (!ok) { + qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); + return false; + } + + // Create the EGL surface to draw into, based on the native drawable. + const int *props; + if (properties) + props = properties->properties(); + else + props = 0; + if (devType == QInternal::Widget) + surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, props); + else + surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, props); + if (surf == EGL_NO_SURFACE) { + qWarning() << "QEglContext::createSurface(): Unable to create EGL surface:" + << errorString(eglGetError()); + return false; + } + return true; +} + +EGLDisplay QEglContext::getDisplay(QPaintDevice *device) +{ + Q_UNUSED(device); + Display *xdpy = QX11Info::display(); + if (!xdpy) { + qWarning("QEglContext::getDisplay(): X11 display is not open"); + return EGL_NO_DISPLAY; + } + return eglGetDisplay(EGLNativeDisplayType(xdpy)); +} + +static int countBits(unsigned long mask) +{ + int count = 0; + while (mask != 0) { + if (mask & 1) + ++count; + mask >>= 1; + } + return count; +} + +// Set the pixel format parameters from the visual in "xinfo". +void QEglProperties::setVisualFormat(const QX11Info *xinfo) +{ + if (!xinfo) + return; + Visual *visual = (Visual*)xinfo->visual(); + if (!visual) + return; + if (visual->c_class != TrueColor && visual->c_class != DirectColor) + return; + setValue(EGL_RED_SIZE, countBits(visual->red_mask)); + setValue(EGL_GREEN_SIZE, countBits(visual->green_mask)); + setValue(EGL_BLUE_SIZE, countBits(visual->blue_mask)); + setValue(EGL_ALPHA_SIZE, 0); // XXX +} + +extern const QX11Info *qt_x11Info(const QPaintDevice *pd); + +// Set pixel format and other properties based on a paint device. +void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev) +{ + if (!dev) + return; + if (dev->devType() == QInternal::Image) + setPixelFormat(static_cast(dev)->format()); + else + setVisualFormat(qt_x11Info(dev)); +} + +QT_END_NAMESPACE diff --git a/src/gui/egl/qeglproperties.cpp b/src/gui/egl/qeglproperties.cpp new file mode 100644 index 0000000..e0ae8a6 --- /dev/null +++ b/src/gui/egl/qeglproperties.cpp @@ -0,0 +1,496 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qeglproperties_p.h" + +QT_BEGIN_NAMESPACE + +#include +#include + +// Initialize a property block. +QEglProperties::QEglProperties() +{ + props.append(EGL_NONE); +} + +// Fetch the current value associated with a property. +int QEglProperties::value(int name) const +{ + for (int index = 0; index < (props.size() - 1); index += 2) { + if (props[index] == name) + return props[index + 1]; + } + + // If the attribute has not been explicitly set, return the EGL default + // The following defaults were taken from the EGL 1.4 spec: + switch(name) { + case EGL_BUFFER_SIZE: return 0; + case EGL_RED_SIZE: return 0; + case EGL_GREEN_SIZE: return 0; + case EGL_BLUE_SIZE: return 0; + case EGL_ALPHA_SIZE: return 0; +#if defined(EGL_LUMINANCE_SIZE) + case EGL_LUMINANCE_SIZE: return 0; +#endif +#if defined(EGL_ALPHA_MASK_SIZE) + case EGL_ALPHA_MASK_SIZE: return 0; +#endif + case EGL_BIND_TO_TEXTURE_RGB: return EGL_DONT_CARE; + case EGL_BIND_TO_TEXTURE_RGBA: return EGL_DONT_CARE; +#if defined(EGL_COLOR_BUFFER_TYPE) + case EGL_COLOR_BUFFER_TYPE: return EGL_RGB_BUFFER; +#endif + case EGL_CONFIG_CAVEAT: return EGL_DONT_CARE; + case EGL_CONFIG_ID: return EGL_DONT_CARE; + case EGL_DEPTH_SIZE: return 0; + case EGL_LEVEL: return 0; + case EGL_NATIVE_RENDERABLE: return EGL_DONT_CARE; + case EGL_NATIVE_VISUAL_TYPE: return EGL_DONT_CARE; + case EGL_MAX_SWAP_INTERVAL: return EGL_DONT_CARE; + case EGL_MIN_SWAP_INTERVAL: return EGL_DONT_CARE; +#if defined(EGL_RENDERABLE_TYPE) + case EGL_RENDERABLE_TYPE: return EGL_OPENGL_ES_BIT; +#endif + case EGL_SAMPLE_BUFFERS: return 0; + case EGL_SAMPLES: return 0; + case EGL_STENCIL_SIZE: return 0; + case EGL_SURFACE_TYPE: return EGL_WINDOW_BIT; + case EGL_TRANSPARENT_TYPE: return EGL_NONE; + case EGL_TRANSPARENT_RED_VALUE: return EGL_DONT_CARE; + case EGL_TRANSPARENT_GREEN_VALUE: return EGL_DONT_CARE; + case EGL_TRANSPARENT_BLUE_VALUE: return EGL_DONT_CARE; + +#if defined(EGL_VERSION_1_3) + case EGL_CONFORMANT: return 0; + case EGL_MATCH_NATIVE_PIXMAP: return EGL_NONE; +#endif + + case EGL_MAX_PBUFFER_HEIGHT: + case EGL_MAX_PBUFFER_WIDTH: + case EGL_MAX_PBUFFER_PIXELS: + case EGL_NATIVE_VISUAL_ID: + case EGL_NONE: + // Attribute does not affect config selection. + return EGL_DONT_CARE; + default: + // Attribute is unknown in EGL <= 1.4. + return EGL_DONT_CARE; + } +} + +// Set the value associated with a property, replacing an existing +// value if there is one. +void QEglProperties::setValue(int name, int value) +{ + for (int index = 0; index < (props.size() - 1); index += 2) { + if (props[index] == name) { + props[index + 1] = value; + return; + } + } + props[props.size() - 1] = name; + props.append(value); + props.append(EGL_NONE); +} + +// Remove a property value. Returns false if the property is not present. +bool QEglProperties::removeValue(int name) +{ + for (int index = 0; index < (props.size() - 1); index += 2) { + if (props[index] == name) { + while ((index + 2) < props.size()) { + props[index] = props[index + 2]; + ++index; + } + props.resize(props.size() - 2); + return true; + } + } + return false; +} + +// Sets the red, green, blue, and alpha sizes based on a pixel format. +// Normally used to match a configuration request to the screen format. +void QEglProperties::setPixelFormat(QImage::Format pixelFormat) +{ + int red, green, blue, alpha; + switch (pixelFormat) { + case QImage::Format_RGB32: + case QImage::Format_RGB888: + red = green = blue = 8; alpha = 0; break; + case QImage::Format_ARGB32: + case QImage::Format_ARGB32_Premultiplied: + red = green = blue = alpha = 8; break; + case QImage::Format_RGB16: + red = 5; green = 6; blue = 5; alpha = 0; break; + case QImage::Format_ARGB8565_Premultiplied: + red = 5; green = 6; blue = 5; alpha = 8; break; + case QImage::Format_RGB666: + red = green = blue = 6; alpha = 0; break; + case QImage::Format_ARGB6666_Premultiplied: + red = green = blue = alpha = 6; break; + case QImage::Format_RGB555: + red = green = blue = 5; alpha = 0; break; + case QImage::Format_ARGB8555_Premultiplied: + red = green = blue = 5; alpha = 8; break; + case QImage::Format_RGB444: + red = green = blue = 4; alpha = 0; break; + case QImage::Format_ARGB4444_Premultiplied: + red = green = blue = alpha = 4; break; + default: + qWarning() << "QEglProperties::setPixelFormat(): Unsupported pixel format"; + red = green = blue = alpha = 1; break; + } + setValue(EGL_RED_SIZE, red); + setValue(EGL_GREEN_SIZE, green); + setValue(EGL_BLUE_SIZE, blue); + setValue(EGL_ALPHA_SIZE, alpha); +} + +void QEglProperties::setRenderableType(QEgl::API api) +{ +#if defined(EGL_RENDERABLE_TYPE) +#if defined(QT_OPENGL_ES_2) + if (api == QEgl::OpenGL) + setValue(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT); +#elif defined(QT_OPENGL_ES) + if (api == QEgl::OpenGL) + setValue(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT); +#endif +#if defined(EGL_OPENVG_BIT) + if (api == QEgl::OpenVG) + setValue(EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT); +#endif +#else + Q_UNUSED(api); +#endif +} + +// Reduce the complexity of a configuration request to ask for less +// because the previous request did not result in success. Returns +// true if the complexity was reduced, or false if no further +// reductions in complexity are possible. +bool QEglProperties::reduceConfiguration() +{ + if (removeValue(EGL_SAMPLE_BUFFERS)) { + removeValue(EGL_SAMPLES); + return true; + } + if (removeValue(EGL_ALPHA_SIZE)) + return true; + if (removeValue(EGL_STENCIL_SIZE)) + return true; + if (removeValue(EGL_DEPTH_SIZE)) + return true; + return false; +} + +static void addTag(QString& str, const QString& tag) +{ + int lastnl = str.lastIndexOf(QLatin1String("\n")); + if (lastnl == -1) + lastnl = 0; + if ((str.length() - lastnl) >= 50) + str += QLatin1String("\n "); + str += tag; +} + +// Convert a property list to a string suitable for debug output. +QString QEglProperties::toString() const +{ + QString str; + int val; + + val = value(EGL_CONFIG_ID); + if (val != EGL_DONT_CARE) { + str += QLatin1String("id="); + str += QString::number(val); + str += QLatin1Char(' '); + } + +#ifdef EGL_RENDERABLE_TYPE + val = value(EGL_RENDERABLE_TYPE); + if (val != EGL_DONT_CARE) { + str += QLatin1String("type="); + QStringList types; + if ((val & EGL_OPENGL_ES_BIT) != 0) + types += QLatin1String("es1"); +#ifdef EGL_OPENGL_ES2_BIT + if ((val & EGL_OPENGL_ES2_BIT) != 0) + types += QLatin1String("es2"); +#endif + if ((val & EGL_OPENVG_BIT) != 0) + types += QLatin1String("vg"); + if ((val & ~7) != 0) + types += QString::number(val); + str += types.join(QLatin1String(",")); + } else { + str += QLatin1String("type=any"); + } +#else + str += QLatin1String("type=es1"); +#endif + + int red = value(EGL_RED_SIZE); + int green = value(EGL_GREEN_SIZE); + int blue = value(EGL_BLUE_SIZE); + int alpha = value(EGL_ALPHA_SIZE); + int bufferSize = value(EGL_BUFFER_SIZE); + if (bufferSize == (red + green + blue + alpha)) + bufferSize = EGL_DONT_CARE; + str += QLatin1String(" rgba="); + str += QString::number(red); + str += QLatin1Char(','); + str += QString::number(green); + str += QLatin1Char(','); + str += QString::number(blue); + str += QLatin1Char(','); + str += QString::number(alpha); + if (bufferSize != EGL_DONT_CARE) { + // Only report buffer size if different than r+g+b+a. + str += QLatin1String(" buffer-size="); + str += QString::number(bufferSize); + } + +#ifdef EGL_COLOR_BUFFER_TYPE + val = value(EGL_COLOR_BUFFER_TYPE); + if (val == EGL_LUMINANCE_BUFFER) { + addTag(str, QLatin1String(" color-buffer-type=luminance")); + } else if (val != EGL_DONT_CARE && val != EGL_RGB_BUFFER) { + addTag(str, QLatin1String(" color-buffer-type=")); + str += QString::number(val, 16); + } +#endif + + val = value(EGL_DEPTH_SIZE); + if (val != 0) { + addTag(str, QLatin1String(" depth=")); + str += QString::number(val); + } + + val = value(EGL_STENCIL_SIZE); + if (val != 0) { + addTag(str, QLatin1String(" stencil=")); + str += QString::number(val); + } + + val = value(EGL_SURFACE_TYPE); + if (val != EGL_DONT_CARE) { + addTag(str, QLatin1String(" surface-type=")); + QStringList types; + if ((val & EGL_WINDOW_BIT) != 0) + types += QLatin1String("window"); + if ((val & EGL_PIXMAP_BIT) != 0) + types += QLatin1String("pixmap"); + if ((val & EGL_PBUFFER_BIT) != 0) + types += QLatin1String("pbuffer"); +#ifdef EGL_VG_COLORSPACE_LINEAR_BIT + if ((val & EGL_VG_COLORSPACE_LINEAR_BIT) != 0) + types += QLatin1String("vg-colorspace-linear"); +#endif +#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT + if ((val & EGL_VG_ALPHA_FORMAT_PRE_BIT) != 0) + types += QLatin1String("vg-alpha-format-pre"); +#endif + if ((val & ~(EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT +#ifdef EGL_VG_COLORSPACE_LINEAR_BIT + | EGL_VG_COLORSPACE_LINEAR_BIT +#endif +#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT + | EGL_VG_ALPHA_FORMAT_PRE_BIT +#endif + )) != 0) { + types += QString::number(val); + } + str += types.join(QLatin1String(",")); + } + + val = value(EGL_CONFIG_CAVEAT); + if (val != EGL_DONT_CARE) { + addTag(str, QLatin1String(" caveat=")); + if (val == EGL_NONE) + str += QLatin1String("none"); + else if (val == EGL_SLOW_CONFIG) + str += QLatin1String("slow"); + else if (val == EGL_NON_CONFORMANT_CONFIG) + str += QLatin1String("non-conformant"); + else + str += QString::number(val, 16); + } + + val = value(EGL_LEVEL); + if (val != 0) { + addTag(str, QLatin1String(" level=")); + str += QString::number(val); + } + + int width, height, pixels; + width = value(EGL_MAX_PBUFFER_WIDTH); + height = value(EGL_MAX_PBUFFER_HEIGHT); + pixels = value(EGL_MAX_PBUFFER_PIXELS); + if (height != EGL_DONT_CARE || width != EGL_DONT_CARE) { + addTag(str, QLatin1String(" max-pbuffer-size=")); + str += QString::number(width); + str += QLatin1Char('x'); + str += QString::number(height); + if (pixels != (width * height)) { + addTag(str, QLatin1String(" max-pbuffer-pixels=")); + str += QString::number(pixels); + } + } + + val = value(EGL_NATIVE_RENDERABLE); + if (val != EGL_DONT_CARE) { + if (val) + addTag(str, QLatin1String(" native-renderable=true")); + else + addTag(str, QLatin1String(" native-renderable=false")); + } + + val = value(EGL_NATIVE_VISUAL_ID); + if (val != EGL_DONT_CARE) { + addTag(str, QLatin1String(" visual-id=")); + str += QString::number(val); + } + + val = value(EGL_NATIVE_VISUAL_TYPE); + if (val != EGL_DONT_CARE) { + addTag(str, QLatin1String(" visual-type=")); + str += QString::number(val); + } + +#ifdef EGL_PRESERVED_RESOURCES + val = value(EGL_PRESERVED_RESOURCES); + if (val != EGL_DONT_CARE) { + if (val) + addTag(str, QLatin1String(" preserved-resources=true")); + else + addTag(str, QLatin1String(" preserved-resources=false")); + } +#endif + + val = value(EGL_SAMPLES); + if (val != 0) { + addTag(str, QLatin1String(" samples=")); + str += QString::number(val); + } + + val = value(EGL_SAMPLE_BUFFERS); + if (val != 0) { + addTag(str, QLatin1String(" sample-buffers=")); + str += QString::number(val); + } + + val = value(EGL_TRANSPARENT_TYPE); + if (val == EGL_TRANSPARENT_RGB) { + addTag(str, QLatin1String(" transparent-rgb=")); + str += QString::number(value(EGL_TRANSPARENT_RED_VALUE)); + str += QLatin1Char(','); + str += QString::number(value(EGL_TRANSPARENT_GREEN_VALUE)); + str += QLatin1Char(','); + str += QString::number(value(EGL_TRANSPARENT_BLUE_VALUE)); + } + +#if defined(EGL_BIND_TO_TEXTURE_RGB) && defined(EGL_BIND_TO_TEXTURE_RGBA) + val = value(EGL_BIND_TO_TEXTURE_RGB); + int val2 = value(EGL_BIND_TO_TEXTURE_RGBA); + if (val != EGL_DONT_CARE || val2 != EGL_DONT_CARE) { + addTag(str, QLatin1String(" bind-texture=")); + if (val == EGL_TRUE) + str += QLatin1String("rgb"); + else + str += QLatin1String("no-rgb"); + if (val2 == EGL_TRUE) + str += QLatin1String(",rgba"); + else + str += QLatin1String(",no-rgba"); + } +#endif + +#ifdef EGL_MIN_SWAP_INTERVAL + val = value(EGL_MIN_SWAP_INTERVAL); + if (val != EGL_DONT_CARE) { + addTag(str, QLatin1String(" min-swap-interval=")); + str += QString::number(val); + } +#endif + +#ifdef EGL_MIN_SWAP_INTERVAL + val = value(EGL_MAX_SWAP_INTERVAL); + if (val != EGL_DONT_CARE) { + addTag(str, QLatin1String(" max-swap-interval=")); + str += QString::number(val); + } +#endif + +#ifdef EGL_LUMINANCE_SIZE + val = value(EGL_LUMINANCE_SIZE); + if (val != 0) { + addTag(str, QLatin1String(" luminance=")); + str += QString::number(val); + } +#endif + +#ifdef EGL_ALPHA_MASK_SIZE + val = value(EGL_ALPHA_MASK_SIZE); + if (val != 0) { + addTag(str, QLatin1String(" alpha-mask=")); + str += QString::number(val); + } +#endif + +#ifdef EGL_CONFORMANT + val = value(EGL_CONFORMANT); + if (val != 0) { + if (val) + addTag(str, QLatin1String(" conformant=true")); + else + addTag(str, QLatin1String(" conformant=false")); + } +#endif + + return str; +} + +QT_END_NAMESPACE + + diff --git a/src/gui/egl/qeglproperties_p.h b/src/gui/egl/qeglproperties_p.h new file mode 100644 index 0000000..3570f80 --- /dev/null +++ b/src/gui/egl/qeglproperties_p.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QEGLPROPERTIES_P_H +#define QEGLPROPERTIES_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QGLWidget class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_INCLUDE_NAMESPACE + +#if defined(QT_GLES_EGL) +#include +#else +#include +#endif + +#if defined(Q_WS_X11) +// If included , then the global namespace +// may have been polluted with X #define's. The following makes sure +// the X11 headers were included properly and then cleans things up. +#include +#include +#undef Bool +#undef Status +#undef None +#undef KeyPress +#undef KeyRelease +#undef FocusIn +#undef FocusOut +#undef Type +#undef FontChange +#undef CursorShape +#endif + +QT_END_INCLUDE_NAMESPACE + +QT_BEGIN_NAMESPACE + +namespace QEgl { + enum API + { + OpenGL, + OpenVG + }; + + enum PixelFormatMatch + { + ExactPixelFormat, + BestPixelFormat + }; +}; + +class QX11Info; +class QPaintDevice; + +class Q_GUI_EXPORT QEglProperties +{ +public: + QEglProperties(); + QEglProperties(const QEglProperties& other) : props(other.props) {} + ~QEglProperties() {} + + int value(int name) const; + void setValue(int name, int value); + bool removeValue(int name); + bool isEmpty() const { return props[0] == EGL_NONE; } + + const int *properties() const { return props.constData(); } + + void setPixelFormat(QImage::Format pixelFormat); +#ifdef Q_WS_X11 + void setVisualFormat(const QX11Info *xinfo); +#endif + void setRenderableType(QEgl::API api); + + void setPaintDeviceFormat(QPaintDevice *dev); + + bool reduceConfiguration(); + + QString toString() const; + +private: + QVarLengthArray props; +}; + +QT_END_NAMESPACE + +#endif // QEGLPROPERTIES_P_H diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 329fb01..b77bfdc 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -35,6 +35,8 @@ include(util/util.pri) include(statemachine/statemachine.pri) include(math3d/math3d.pri) +contains(QT_CONFIG, egl): include(egl/egl.pri) + embedded: QT += network QMAKE_LIBS += $$QMAKE_LIBS_GUI diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index 73af174..c92b8cf 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -62,12 +62,9 @@ x11 { contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles1cl)|contains(QT_CONFIG, opengles2) { SOURCES += qgl_x11egl.cpp \ qglpixelbuffer_egl.cpp \ - qgl_egl.cpp \ - qegl.cpp \ - qegl_x11egl.cpp + qgl_egl.cpp - HEADERS += qegl_p.h \ - qgl_egl_p.h + HEADERS += qgl_egl_p.h } else { SOURCES += qgl_x11.cpp \ @@ -93,13 +90,10 @@ win32:!wince*: { wince*: { SOURCES += qgl_wince.cpp \ qglpixelbuffer_egl.cpp \ - qgl_egl.cpp \ - qegl.cpp \ - qegl_wince.cpp + qgl_egl.cpp HEADERS += qgl_cl_p.h \ qgl_egl_p.h \ - qegl_p.h } embedded { @@ -108,15 +102,12 @@ embedded { qglpixelbuffer_egl.cpp \ qglscreen_qws.cpp \ qglwindowsurface_qws.cpp \ - qegl.cpp \ - qegl_qws.cpp \ qgl_egl.cpp HEADERS += qglpaintdevice_qws_p.h \ qglscreen_qws.h \ qglwindowsurface_qws_p.h \ - qgl_egl_p.h \ - qegl_p.h + qgl_egl_p.h contains(QT_CONFIG, fontconfig) { include($$QT_SOURCE_TREE/config.tests/unix/freetype/freetype.pri) diff --git a/src/opengl/qegl.cpp b/src/opengl/qegl.cpp deleted file mode 100644 index 61c7427..0000000 --- a/src/opengl/qegl.cpp +++ /dev/null @@ -1,842 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include -#include "qegl_p.h" - -#if defined(QT_OPENGL_ES) || defined(QT_OPENVG) - -QT_BEGIN_NAMESPACE - -QEglContext::QEglContext() -{ - apiType = OpenGL; - dpy = EGL_NO_DISPLAY; - ctx = EGL_NO_CONTEXT; - surf = EGL_NO_SURFACE; - cfg = 0; - share = false; - reserved = 0; -} - -QEglContext::~QEglContext() -{ - destroy(); -} - -bool QEglContext::isValid() const -{ - return (ctx != EGL_NO_CONTEXT); -} - -bool QEglContext::isSharing() const -{ - return share; -} - -// Open the EGL display associated with "device". -bool QEglContext::openDisplay(QPaintDevice *device) -{ - if (dpy == EGL_NO_DISPLAY) - dpy = defaultDisplay(device); - return (dpy != EGL_NO_DISPLAY); -} - -// Choose a configuration that matches "properties". -bool QEglContext::chooseConfig - (const QEglProperties& properties, PixelFormatMatch match) -{ - QEglProperties props(properties); - EGLConfig *configs; - EGLint matching, size; - do { - // Get the number of matching configurations for this set of properties. - matching = 0; - if (!eglChooseConfig(dpy, props.properties(), 0, 256, &matching) || !matching) - continue; - - // If we want the best pixel format, then return the first - // matching configuration. - if (match == BestPixelFormat) { - eglChooseConfig(dpy, props.properties(), &cfg, 1, &matching); - if (matching < 1) - continue; - return true; - } - - // Fetch all of the matching configurations and find the - // first that matches the pixel format we wanted. - size = matching; - configs = new EGLConfig [size]; - eglChooseConfig(dpy, props.properties(), configs, size, &matching); - for (EGLint index = 0; index < size; ++index) { - EGLint red, green, blue, alpha; - eglGetConfigAttrib(dpy, configs[index], EGL_RED_SIZE, &red); - eglGetConfigAttrib(dpy, configs[index], EGL_GREEN_SIZE, &green); - eglGetConfigAttrib(dpy, configs[index], EGL_BLUE_SIZE, &blue); - eglGetConfigAttrib(dpy, configs[index], EGL_ALPHA_SIZE, &alpha); - if (red == props.value(EGL_RED_SIZE) && - green == props.value(EGL_GREEN_SIZE) && - blue == props.value(EGL_BLUE_SIZE) && - (props.value(EGL_ALPHA_SIZE) == 0 || - alpha == props.value(EGL_ALPHA_SIZE))) { - cfg = configs[index]; - delete [] configs; - return true; - } - } - delete [] configs; - } while (props.reduceConfiguration()); - -#ifdef EGL_BIND_TO_TEXTURE_RGBA - // Don't report an error just yet if we failed to get a pbuffer - // configuration with texture rendering. Only report failure if - // we cannot get any pbuffer configurations at all. - if (props.value(EGL_BIND_TO_TEXTURE_RGBA) == EGL_DONT_CARE && - props.value(EGL_BIND_TO_TEXTURE_RGB) == EGL_DONT_CARE) -#endif - { - qWarning() << "QEglContext::chooseConfig(): Could not find a suitable EGL configuration"; - qWarning() << "Requested:" << props.toString(); - qWarning() << "Available:"; - dumpAllConfigs(); - } - return false; -} - -// Create the EGLContext. -bool QEglContext::createContext(QEglContext *shareContext) -{ - // We need to select the correct API before calling eglCreateContext(). -#ifdef EGL_OPENGL_ES_API - if (apiType == OpenGL) - eglBindAPI(EGL_OPENGL_ES_API); -#endif -#ifdef EGL_OPENVG_API - if (apiType == OpenVG) - eglBindAPI(EGL_OPENVG_API); -#endif - - // Create a new context for the configuration. - QEglProperties contextProps; -#if defined(QT_OPENGL_ES_2) - if (apiType == OpenGL) - contextProps.setValue(EGL_CONTEXT_CLIENT_VERSION, 2); -#endif - if (shareContext && shareContext->ctx == EGL_NO_CONTEXT) - shareContext = 0; - if (shareContext) { - ctx = eglCreateContext(dpy, cfg, shareContext->ctx, contextProps.properties()); - if (ctx == EGL_NO_CONTEXT) { - qWarning() << "QEglContext::createContext(): Could not share context:" << errorString(eglGetError()); - shareContext = 0; - } - } - if (ctx == EGL_NO_CONTEXT) { - ctx = eglCreateContext(dpy, cfg, 0, contextProps.properties()); - if (ctx == EGL_NO_CONTEXT) { - qWarning() << "QEglContext::createContext(): Unable to create EGL context:" << errorString(eglGetError()); - return false; - } - } - share = (shareContext != 0); - return true; -} - -// Recreate the surface for a paint device because the native id has changed. -bool QEglContext::recreateSurface(QPaintDevice *device) -{ - // Bail out if the surface has not been created for the first time yet. - if (surf == EGL_NO_SURFACE) - return true; - - // Destroy the old surface. - eglDestroySurface(dpy, surf); - - // Create a new one. - return createSurface(device); -} - -void QEglContext::destroy() -{ - if (ctx != EGL_NO_CONTEXT) - eglDestroyContext(dpy, ctx); - dpy = EGL_NO_DISPLAY; - ctx = EGL_NO_CONTEXT; - surf = EGL_NO_SURFACE; - cfg = 0; - share = false; -} - -bool QEglContext::makeCurrent() -{ - if(ctx == EGL_NO_CONTEXT) { - qWarning() << "QEglContext::makeCurrent(): Cannot make invalid context current"; - return false; - } - - bool ok = eglMakeCurrent(dpy, surf, surf, ctx); - if (!ok) { - EGLint err = eglGetError(); - qWarning() << "QEglContext::makeCurrent():" << errorString(err); - } - return ok; -} - -bool QEglContext::doneCurrent() -{ - // If the context is invalid, we assume that an error was reported - // when makeCurrent() was called. - if (ctx == EGL_NO_CONTEXT) - return false; - - // We need to select the correct API before calling eglMakeCurrent() - // with EGL_NO_CONTEXT because threads can have both OpenGL and OpenVG - // contexts active at the same time. -#ifdef EGL_OPENGL_ES_API - if (apiType == OpenGL) - eglBindAPI(EGL_OPENGL_ES_API); -#endif -#ifdef EGL_OPENVG_API - if (apiType == OpenVG) - eglBindAPI(EGL_OPENVG_API); -#endif - - bool ok = eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - if (!ok) { - EGLint err = eglGetError(); - qWarning() << "QEglContext::doneCurrent():" << errorString(err); - } - return ok; -} - -bool QEglContext::swapBuffers() -{ - if(ctx == EGL_NO_CONTEXT) - return false; - - bool ok = eglSwapBuffers(dpy, surf); - if (!ok) { - EGLint err = eglGetError(); - qWarning() << "QEglContext::swapBuffers():" << errorString(err); - } - return ok; -} - -// Wait for native rendering operations to complete before starting -// to use OpenGL/OpenVG operations. -void QEglContext::waitNative() -{ -#ifdef EGL_CORE_NATIVE_ENGINE - eglWaitNative(EGL_CORE_NATIVE_ENGINE); -#endif -} - -// Wait for client OpenGL/OpenVG operations to complete before -// using native rendering operations. -void QEglContext::waitClient() -{ -#ifdef EGL_OPENGL_ES_API - if (apiType == OpenGL) { - eglBindAPI(EGL_OPENGL_ES_API); - eglWaitClient(); - } -#else - if (apiType == OpenGL) - eglWaitGL(); -#endif -#ifdef EGL_OPENVG_API - if (apiType == OpenVG) { - eglBindAPI(EGL_OPENVG_API); - eglWaitClient(); - } -#endif -} - -// Query the actual size of the EGL surface. -QSize QEglContext::surfaceSize() const -{ - int w, h; - eglQuerySurface(dpy, surf, EGL_WIDTH, &w); - eglQuerySurface(dpy, surf, EGL_HEIGHT, &h); - return QSize(w, h); -} - -// Query the value of a configuration attribute. -bool QEglContext::configAttrib(int name, EGLint *value) const -{ - return eglGetConfigAttrib(dpy, cfg, name, value); -} - -// Retrieve all of the properties on "cfg". If zero, return -// the context's configuration. -QEglProperties QEglContext::configProperties(EGLConfig cfg) const -{ - if (!cfg) - cfg = config(); - QEglProperties props; - for (int name = 0x3020; name <= 0x304F; ++name) { - EGLint value; - if (name != EGL_NONE && eglGetConfigAttrib(dpy, cfg, name, &value)) - props.setValue(name, value); - } - eglGetError(); // Clear the error state. - return props; -} - -// Initialize and return the default display. -EGLDisplay QEglContext::defaultDisplay(QPaintDevice *device) -{ - static EGLDisplay dpy = EGL_NO_DISPLAY; - if (dpy == EGL_NO_DISPLAY) { - dpy = getDisplay(device); - if (dpy == EGL_NO_DISPLAY) { - qWarning() << "QEglContext::defaultDisplay(): Cannot open EGL display"; - return EGL_NO_DISPLAY; - } - if (!eglInitialize(dpy, NULL, NULL)) { - EGLint err = eglGetError(); - qWarning() << "QEglContext::defaultDisplay(): Cannot initialize EGL display:" << errorString(err); - return EGL_NO_DISPLAY; - } -#ifdef EGL_OPENGL_ES_API - eglBindAPI(EGL_OPENGL_ES_API); -#endif - } - return dpy; -} - -// Return the error string associated with a specific code. -QString QEglContext::errorString(int code) -{ - static const char * const errors[] = { - "Success (0x3000)", // No tr - "Not initialized (0x3001)", // No tr - "Bad access (0x3002)", // No tr - "Bad alloc (0x3003)", // No tr - "Bad attribute (0x3004)", // No tr - "Bad config (0x3005)", // No tr - "Bad context (0x3006)", // No tr - "Bad current surface (0x3007)", // No tr - "Bad display (0x3008)", // No tr - "Bad match (0x3009)", // No tr - "Bad native pixmap (0x300A)", // No tr - "Bad native window (0x300B)", // No tr - "Bad parameter (0x300C)", // No tr - "Bad surface (0x300D)", // No tr - "Context lost (0x300E)" // No tr - }; - if (code >= 0x3000 && code <= 0x300E) { - return QString::fromLatin1(errors[code - 0x3000]); - } else { - return QLatin1String("0x") + QString::number(code, 16); - } -} - -// Dump all of the EGL configurations supported by the system. -void QEglContext::dumpAllConfigs() -{ - QEglProperties props; - EGLint count = 0; - if (!eglGetConfigs(dpy, 0, 0, &count)) - return; - if (count < 1) - return; - EGLConfig *configs = new EGLConfig [count]; - eglGetConfigs(dpy, configs, count, &count); - for (EGLint index = 0; index < count; ++index) { - props = configProperties(configs[index]); - qWarning() << props.toString(); - } - delete [] configs; -} - -// Initialize a property block. -QEglProperties::QEglProperties() -{ - props.append(EGL_NONE); -} - -// Fetch the current value associated with a property. -int QEglProperties::value(int name) const -{ - for (int index = 0; index < (props.size() - 1); index += 2) { - if (props[index] == name) - return props[index + 1]; - } - - // If the attribute has not been explicitly set, return the EGL default - // The following defaults were taken from the EGL 1.4 spec: - switch(name) { - case EGL_BUFFER_SIZE: return 0; - case EGL_RED_SIZE: return 0; - case EGL_GREEN_SIZE: return 0; - case EGL_BLUE_SIZE: return 0; - case EGL_ALPHA_SIZE: return 0; -#if defined(EGL_LUMINANCE_SIZE) - case EGL_LUMINANCE_SIZE: return 0; -#endif -#if defined(EGL_ALPHA_MASK_SIZE) - case EGL_ALPHA_MASK_SIZE: return 0; -#endif - case EGL_BIND_TO_TEXTURE_RGB: return EGL_DONT_CARE; - case EGL_BIND_TO_TEXTURE_RGBA: return EGL_DONT_CARE; -#if defined(EGL_COLOR_BUFFER_TYPE) - case EGL_COLOR_BUFFER_TYPE: return EGL_RGB_BUFFER; -#endif - case EGL_CONFIG_CAVEAT: return EGL_DONT_CARE; - case EGL_CONFIG_ID: return EGL_DONT_CARE; - case EGL_DEPTH_SIZE: return 0; - case EGL_LEVEL: return 0; - case EGL_NATIVE_RENDERABLE: return EGL_DONT_CARE; - case EGL_NATIVE_VISUAL_TYPE: return EGL_DONT_CARE; - case EGL_MAX_SWAP_INTERVAL: return EGL_DONT_CARE; - case EGL_MIN_SWAP_INTERVAL: return EGL_DONT_CARE; -#if defined(EGL_RENDERABLE_TYPE) - case EGL_RENDERABLE_TYPE: return EGL_OPENGL_ES_BIT; -#endif - case EGL_SAMPLE_BUFFERS: return 0; - case EGL_SAMPLES: return 0; - case EGL_STENCIL_SIZE: return 0; - case EGL_SURFACE_TYPE: return EGL_WINDOW_BIT; - case EGL_TRANSPARENT_TYPE: return EGL_NONE; - case EGL_TRANSPARENT_RED_VALUE: return EGL_DONT_CARE; - case EGL_TRANSPARENT_GREEN_VALUE: return EGL_DONT_CARE; - case EGL_TRANSPARENT_BLUE_VALUE: return EGL_DONT_CARE; - -#if defined(EGL_VERSION_1_3) - case EGL_CONFORMANT: return 0; - case EGL_MATCH_NATIVE_PIXMAP: return EGL_NONE; -#endif - - case EGL_MAX_PBUFFER_HEIGHT: - case EGL_MAX_PBUFFER_WIDTH: - case EGL_MAX_PBUFFER_PIXELS: - case EGL_NATIVE_VISUAL_ID: - case EGL_NONE: - qWarning("QEglProperties::value() - Attibute %d does not affect config selection", name); - return EGL_DONT_CARE; - default: - qWarning("QEglProperties::value() - Attibute %d is unknown in EGL <=1.4", name); - return EGL_DONT_CARE; - } -} - -// Set the value associated with a property, replacing an existing -// value if there is one. -void QEglProperties::setValue(int name, int value) -{ - for (int index = 0; index < (props.size() - 1); index += 2) { - if (props[index] == name) { - props[index + 1] = value; - return; - } - } - props[props.size() - 1] = name; - props.append(value); - props.append(EGL_NONE); -} - -// Remove a property value. Returns false if the property is not present. -bool QEglProperties::removeValue(int name) -{ - for (int index = 0; index < (props.size() - 1); index += 2) { - if (props[index] == name) { - while ((index + 2) < props.size()) { - props[index] = props[index + 2]; - ++index; - } - props.resize(props.size() - 2); - return true; - } - } - return false; -} - -// Sets the red, green, blue, and alpha sizes based on a pixel format. -// Normally used to match a configuration request to the screen format. -void QEglProperties::setPixelFormat(QImage::Format pixelFormat) -{ - int red, green, blue, alpha; - switch (pixelFormat) { - case QImage::Format_RGB32: - case QImage::Format_RGB888: - red = green = blue = 8; alpha = 0; break; - case QImage::Format_ARGB32: - case QImage::Format_ARGB32_Premultiplied: - red = green = blue = alpha = 8; break; - case QImage::Format_RGB16: - red = 5; green = 6; blue = 5; alpha = 0; break; - case QImage::Format_ARGB8565_Premultiplied: - red = 5; green = 6; blue = 5; alpha = 8; break; - case QImage::Format_RGB666: - red = green = blue = 6; alpha = 0; break; - case QImage::Format_ARGB6666_Premultiplied: - red = green = blue = alpha = 6; break; - case QImage::Format_RGB555: - red = green = blue = 5; alpha = 0; break; - case QImage::Format_ARGB8555_Premultiplied: - red = green = blue = 5; alpha = 8; break; - case QImage::Format_RGB444: - red = green = blue = 4; alpha = 0; break; - case QImage::Format_ARGB4444_Premultiplied: - red = green = blue = alpha = 4; break; - default: - qWarning() << "QEglProperties::setPixelFormat(): Unsupported pixel format"; - red = green = blue = alpha = 1; break; - } - setValue(EGL_RED_SIZE, red); - setValue(EGL_GREEN_SIZE, green); - setValue(EGL_BLUE_SIZE, blue); - setValue(EGL_ALPHA_SIZE, alpha); -} - -void QEglProperties::setRenderableType(int api) -{ -#if defined(EGL_RENDERABLE_TYPE) -#if defined(QT_OPENGL_ES_2) - if (api == QEglContext::OpenGL) - setValue(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT); -#elif defined(QT_OPENGL_ES) - if (api == QEglContext::OpenGL) - setValue(EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT); -#endif -#if defined(EGL_OPENVG_BIT) - if (api == QEglContext::OpenVG) - setValue(EGL_RENDERABLE_TYPE, EGL_OPENVG_BIT); -#endif -#else - Q_UNUSED(api); -#endif -} - -// Reduce the complexity of a configuration request to ask for less -// because the previous request did not result in success. Returns -// true if the complexity was reduced, or false if no further -// reductions in complexity are possible. -bool QEglProperties::reduceConfiguration() -{ - if (removeValue(EGL_SAMPLE_BUFFERS)) { - removeValue(EGL_SAMPLES); - return true; - } - if (removeValue(EGL_ALPHA_SIZE)) - return true; - if (removeValue(EGL_STENCIL_SIZE)) - return true; - if (removeValue(EGL_DEPTH_SIZE)) - return true; - return false; -} - -static void addTag(QString& str, const QString& tag) -{ - int lastnl = str.lastIndexOf(QLatin1String("\n")); - if (lastnl == -1) - lastnl = 0; - if ((str.length() - lastnl) >= 50) - str += QLatin1String("\n "); - str += tag; -} - -// Convert a property list to a string suitable for debug output. -QString QEglProperties::toString() const -{ - QString str; - int val; - - val = value(EGL_CONFIG_ID); - if (val != EGL_DONT_CARE) { - str += QLatin1String("id="); - str += QString::number(val); - str += QLatin1Char(' '); - } - -#ifdef EGL_RENDERABLE_TYPE - val = value(EGL_RENDERABLE_TYPE); - if (val != EGL_DONT_CARE) { - str += QLatin1String("type="); - QStringList types; - if ((val & EGL_OPENGL_ES_BIT) != 0) - types += QLatin1String("es1"); -#ifdef EGL_OPENGL_ES2_BIT - if ((val & EGL_OPENGL_ES2_BIT) != 0) - types += QLatin1String("es2"); -#endif - if ((val & EGL_OPENVG_BIT) != 0) - types += QLatin1String("vg"); - if ((val & ~7) != 0) - types += QString::number(val); - str += types.join(QLatin1String(",")); - } else { - str += QLatin1String("type=any"); - } -#else - str += QLatin1String("type=es1"); -#endif - - int red = value(EGL_RED_SIZE); - int green = value(EGL_GREEN_SIZE); - int blue = value(EGL_BLUE_SIZE); - int alpha = value(EGL_ALPHA_SIZE); - int bufferSize = value(EGL_BUFFER_SIZE); - if (bufferSize == (red + green + blue + alpha)) - bufferSize = EGL_DONT_CARE; - str += QLatin1String(" rgba="); - str += QString::number(red); - str += QLatin1Char(','); - str += QString::number(green); - str += QLatin1Char(','); - str += QString::number(blue); - str += QLatin1Char(','); - str += QString::number(alpha); - if (bufferSize != EGL_DONT_CARE) { - // Only report buffer size if different than r+g+b+a. - str += QLatin1String(" buffer-size="); - str += QString::number(bufferSize); - } - -#ifdef EGL_COLOR_BUFFER_TYPE - val = value(EGL_COLOR_BUFFER_TYPE); - if (val == EGL_LUMINANCE_BUFFER) { - addTag(str, QLatin1String(" color-buffer-type=luminance")); - } else if (val != EGL_DONT_CARE && val != EGL_RGB_BUFFER) { - addTag(str, QLatin1String(" color-buffer-type=")); - str += QString::number(val, 16); - } -#endif - - val = value(EGL_DEPTH_SIZE); - if (val != 0) { - addTag(str, QLatin1String(" depth=")); - str += QString::number(val); - } - - val = value(EGL_STENCIL_SIZE); - if (val != 0) { - addTag(str, QLatin1String(" stencil=")); - str += QString::number(val); - } - - val = value(EGL_SURFACE_TYPE); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" surface-type=")); - QStringList types; - if ((val & EGL_WINDOW_BIT) != 0) - types += QLatin1String("window"); - if ((val & EGL_PIXMAP_BIT) != 0) - types += QLatin1String("pixmap"); - if ((val & EGL_PBUFFER_BIT) != 0) - types += QLatin1String("pbuffer"); -#ifdef EGL_VG_COLORSPACE_LINEAR_BIT - if ((val & EGL_VG_COLORSPACE_LINEAR_BIT) != 0) - types += QLatin1String("vg-colorspace-linear"); -#endif -#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT - if ((val & EGL_VG_ALPHA_FORMAT_PRE_BIT) != 0) - types += QLatin1String("vg-alpha-format-pre"); -#endif - if ((val & ~(EGL_WINDOW_BIT | EGL_PIXMAP_BIT | EGL_PBUFFER_BIT -#ifdef EGL_VG_COLORSPACE_LINEAR_BIT - | EGL_VG_COLORSPACE_LINEAR_BIT -#endif -#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT - | EGL_VG_ALPHA_FORMAT_PRE_BIT -#endif - )) != 0) { - types += QString::number(val); - } - str += types.join(QLatin1String(",")); - } - - val = value(EGL_CONFIG_CAVEAT); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" caveat=")); - if (val == EGL_NONE) - str += QLatin1String("none"); - else if (val == EGL_SLOW_CONFIG) - str += QLatin1String("slow"); - else if (val == EGL_NON_CONFORMANT_CONFIG) - str += QLatin1String("non-conformant"); - else - str += QString::number(val, 16); - } - - val = value(EGL_LEVEL); - if (val != 0) { - addTag(str, QLatin1String(" level=")); - str += QString::number(val); - } - - int width, height, pixels; - width = value(EGL_MAX_PBUFFER_WIDTH); - height = value(EGL_MAX_PBUFFER_HEIGHT); - pixels = value(EGL_MAX_PBUFFER_PIXELS); - if (height != EGL_DONT_CARE || width != EGL_DONT_CARE) { - addTag(str, QLatin1String(" max-pbuffer-size=")); - str += QString::number(width); - str += QLatin1Char('x'); - str += QString::number(height); - if (pixels != (width * height)) { - addTag(str, QLatin1String(" max-pbuffer-pixels=")); - str += QString::number(pixels); - } - } - - val = value(EGL_NATIVE_RENDERABLE); - if (val != EGL_DONT_CARE) { - if (val) - addTag(str, QLatin1String(" native-renderable=true")); - else - addTag(str, QLatin1String(" native-renderable=false")); - } - - val = value(EGL_NATIVE_VISUAL_ID); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" visual-id=")); - str += QString::number(val); - } - - val = value(EGL_NATIVE_VISUAL_TYPE); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" visual-type=")); - str += QString::number(val); - } - -#ifdef EGL_PRESERVED_RESOURCES - val = value(EGL_PRESERVED_RESOURCES); - if (val != EGL_DONT_CARE) { - if (val) - addTag(str, QLatin1String(" preserved-resources=true")); - else - addTag(str, QLatin1String(" preserved-resources=false")); - } -#endif - - val = value(EGL_SAMPLES); - if (val != 0) { - addTag(str, QLatin1String(" samples=")); - str += QString::number(val); - } - - val = value(EGL_SAMPLE_BUFFERS); - if (val != 0) { - addTag(str, QLatin1String(" sample-buffers=")); - str += QString::number(val); - } - - val = value(EGL_TRANSPARENT_TYPE); - if (val == EGL_TRANSPARENT_RGB) { - addTag(str, QLatin1String(" transparent-rgb=")); - str += QString::number(value(EGL_TRANSPARENT_RED_VALUE)); - str += QLatin1Char(','); - str += QString::number(value(EGL_TRANSPARENT_GREEN_VALUE)); - str += QLatin1Char(','); - str += QString::number(value(EGL_TRANSPARENT_BLUE_VALUE)); - } - -#if defined(EGL_BIND_TO_TEXTURE_RGB) && defined(EGL_BIND_TO_TEXTURE_RGBA) - val = value(EGL_BIND_TO_TEXTURE_RGB); - int val2 = value(EGL_BIND_TO_TEXTURE_RGBA); - if (val != EGL_DONT_CARE || val2 != EGL_DONT_CARE) { - addTag(str, QLatin1String(" bind-texture=")); - if (val == EGL_TRUE) - str += QLatin1String("rgb"); - else - str += QLatin1String("no-rgb"); - if (val2 == EGL_TRUE) - str += QLatin1String(",rgba"); - else - str += QLatin1String(",no-rgba"); - } -#endif - -#ifdef EGL_MIN_SWAP_INTERVAL - val = value(EGL_MIN_SWAP_INTERVAL); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" min-swap-interval=")); - str += QString::number(val); - } -#endif - -#ifdef EGL_MIN_SWAP_INTERVAL - val = value(EGL_MAX_SWAP_INTERVAL); - if (val != EGL_DONT_CARE) { - addTag(str, QLatin1String(" max-swap-interval=")); - str += QString::number(val); - } -#endif - -#ifdef EGL_LUMINANCE_SIZE - val = value(EGL_LUMINANCE_SIZE); - if (val != 0) { - addTag(str, QLatin1String(" luminance=")); - str += QString::number(val); - } -#endif - -#ifdef EGL_ALPHA_MASK_SIZE - val = value(EGL_ALPHA_MASK_SIZE); - if (val != 0) { - addTag(str, QLatin1String(" alpha-mask=")); - str += QString::number(val); - } -#endif - -#ifdef EGL_CONFORMANT - val = value(EGL_CONFORMANT); - if (val != 0) { - if (val) - addTag(str, QLatin1String(" conformant=true")); - else - addTag(str, QLatin1String(" conformant=false")); - } -#endif - - return str; -} - -QT_END_NAMESPACE - -#endif // QT_OPENGL_ES || QT_OPENVG diff --git a/src/opengl/qegl_p.h b/src/opengl/qegl_p.h deleted file mode 100644 index 4e46965..0000000 --- a/src/opengl/qegl_p.h +++ /dev/null @@ -1,188 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QEGL_P_H -#define QEGL_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of the QGLWidget class. This header file may change from -// version to version without notice, or even be removed. -// -// We mean it. -// - -#include "QtCore/qvarlengtharray.h" -#include "QtCore/qsize.h" -#include "QtGui/qimage.h" - -#if defined(QT_OPENGL_ES) || defined(QT_OPENVG) - -QT_BEGIN_INCLUDE_NAMESPACE -#if defined(QT_OPENGL_ES_2) || defined(QT_OPENVG) -#include -#else -#include -#endif -#if !defined(EGL_VERSION_1_3) && !defined(QEGL_NATIVE_TYPES_DEFINED) -#undef EGLNativeWindowType -#undef EGLNativePixmapType -#undef EGLNativeDisplayType -typedef NativeWindowType EGLNativeWindowType; -typedef NativePixmapType EGLNativePixmapType; -typedef NativeDisplayType EGLNativeDisplayType; -#define QEGL_NATIVE_TYPES_DEFINED 1 -#endif -QT_END_INCLUDE_NAMESPACE - -class QX11Info; -class QPaintDevice; -class QImage; -class QPixmap; -class QWidget; - -QT_BEGIN_NAMESPACE - -class Q_OPENGL_EXPORT QEglProperties -{ -public: - QEglProperties(); - QEglProperties(const QEglProperties& other) : props(other.props) {} - ~QEglProperties() {} - - int value(int name) const; - void setValue(int name, int value); - bool removeValue(int name); - - const int *properties() const { return props.constData(); } - - void setPixelFormat(QImage::Format pixelFormat); -#ifdef Q_WS_X11 - void setVisualFormat(const QX11Info *xinfo); -#endif - void setRenderableType(int api); - - bool reduceConfiguration(); - - QString toString() const; - -private: - QVarLengthArray props; -}; - -class Q_OPENGL_EXPORT QEglContext -{ -public: - QEglContext(); - ~QEglContext(); - - enum API - { - OpenGL, - OpenVG - }; - - enum PixelFormatMatch - { - ExactPixelFormat, - BestPixelFormat - }; - - bool isValid() const; - bool isSharing() const; - - void setApi(QEglContext::API api) { apiType = api; } - bool openDisplay(QPaintDevice *device); - bool chooseConfig(const QEglProperties& properties, PixelFormatMatch match = ExactPixelFormat); - bool createContext(QEglContext *shareContext = 0); - bool createSurface(QPaintDevice *device); - bool recreateSurface(QPaintDevice *device); - void setSurface(EGLSurface surface) { surf = surface; } - - void destroy(); - - bool makeCurrent(); - bool doneCurrent(); - bool swapBuffers(); - - void waitNative(); - void waitClient(); - - QSize surfaceSize() const; - - bool configAttrib(int name, EGLint *value) const; - - void clearError() const { eglGetError(); } - - QEglContext::API api() const { return apiType; } - - EGLDisplay display() const { return dpy; } - EGLContext context() const { return ctx; } - EGLSurface surface() const { return surf; } - EGLConfig config() const { return cfg; } - - QEglProperties configProperties(EGLConfig cfg = 0) const; - - static EGLDisplay defaultDisplay(QPaintDevice *device); - static QString errorString(int code); - - void dumpAllConfigs(); - -private: - QEglContext::API apiType; - EGLDisplay dpy; - EGLContext ctx; - EGLSurface surf; - EGLConfig cfg; - bool share; - void *reserved; // For extension data in future versions. - - static EGLDisplay getDisplay(QPaintDevice *device); -}; - -QT_END_NAMESPACE - -#endif // QT_OPENGL_ES || QT_OPENVG - -#endif // QEGL_P_H diff --git a/src/opengl/qegl_qws.cpp b/src/opengl/qegl_qws.cpp deleted file mode 100644 index 89bee09..0000000 --- a/src/opengl/qegl_qws.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include "qegl_p.h" - -#if defined(QT_OPENGL_ES) || defined(QT_OPENVG) - -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -static QGLScreen *glScreenForDevice(QPaintDevice *device) -{ - QScreen *screen = qt_screen; - if (screen->classId() == QScreen::MultiClass) { - int screenNumber; - if (device && device->devType() == QInternal::Widget) - screenNumber = qApp->desktop()->screenNumber(static_cast(device)); - else - screenNumber = 0; - screen = screen->subScreens()[screenNumber]; - } - while (screen->classId() == QScreen::ProxyClass) { - screen = static_cast(screen)->screen(); - } - if (screen->classId() == QScreen::GLClass) - return static_cast(screen); - else - return 0; -} - -// Create the surface for a QPixmap, QImage, or QWidget. -bool QEglContext::createSurface(QPaintDevice *device) -{ - // Get the screen surface functions, which are used to create native ids. - QGLScreen *glScreen = glScreenForDevice(device); - if (!glScreen) - return false; - QGLScreenSurfaceFunctions *funcs = glScreen->surfaceFunctions(); - if (!funcs) - return false; - - // Create the native drawable for the paint device. - int devType = device->devType(); - EGLNativePixmapType pixmapDrawable = 0; - EGLNativeWindowType windowDrawable = 0; - bool ok; - if (devType == QInternal::Pixmap) { - ok = funcs->createNativePixmap(static_cast(device), &pixmapDrawable); - } else if (devType == QInternal::Image) { - ok = funcs->createNativeImage(static_cast(device), &pixmapDrawable); - } else { - ok = funcs->createNativeWindow(static_cast(device), &windowDrawable); - } - if (!ok) { - qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); - return false; - } - - // Create the EGL surface to draw into, based on the native drawable. - if (devType == QInternal::Widget) - surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, 0); - else - surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, 0); - if (surf == EGL_NO_SURFACE) { - qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); - return false; - } - return true; -} - -EGLDisplay QEglContext::getDisplay(QPaintDevice *device) -{ - Q_UNUSED(device); - return eglGetDisplay(EGLNativeDisplayType(EGL_DEFAULT_DISPLAY)); -} - -QT_END_NAMESPACE - -#endif // QT_OPENGL_ES || QT_OPENVG diff --git a/src/opengl/qegl_wince.cpp b/src/opengl/qegl_wince.cpp deleted file mode 100644 index b978bc6..0000000 --- a/src/opengl/qegl_wince.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include "qegl_p.h" - -#if defined(QT_OPENGL_ES) || defined(QT_OPENVG) - -#include - - -QT_BEGIN_NAMESPACE - -bool QEglContext::createSurface(QPaintDevice *device) -{ - // Create the native drawable for the paint device. - int devType = device->devType(); - EGLNativePixmapType pixmapDrawable = 0; - EGLNativeWindowType windowDrawable = 0; - bool ok; - if (devType == QInternal::Pixmap) { - pixmapDrawable = 0; - ok = (pixmapDrawable != 0); - } else if (devType == QInternal::Widget) { - windowDrawable = (EGLNativeWindowType)(static_cast(device))->winId(); - ok = (windowDrawable != 0); - } else { - ok = false; - } - if (!ok) { - qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); - return false; - } - - // Create the EGL surface to draw into, based on the native drawable. - if (devType == QInternal::Widget) - surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, 0); - else - surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, 0); - if (surf == EGL_NO_SURFACE) { - qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); - return false; - } - return true; -} - -EGLDisplay QEglContext::getDisplay(QPaintDevice *device) -{ - EGLDisplay dpy = 0; - HWND win = ((QWidget*)device)->winId(); - HDC myDc = GetDC(win); - if (!myDc) { - qWarning("QEglContext::defaultDisplay(): WinCE display is not open"); - } - dpy = eglGetDisplay(EGLNativeDisplayType(myDc)); - if (dpy == EGL_NO_DISPLAY) { - qWarning("QEglContext::defaultDisplay(): Falling back to EGL_DEFAULT_DISPLAY"); - dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); - } - return dpy; -} - -QT_END_NAMESPACE - -#endif // QT_OPENGL_ES || QT_OPENVG diff --git a/src/opengl/qegl_x11egl.cpp b/src/opengl/qegl_x11egl.cpp deleted file mode 100644 index 23d1ac6..0000000 --- a/src/opengl/qegl_x11egl.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtOpenGL module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain -** additional rights. These rights are described in the Nokia Qt LGPL -** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://www.qtsoftware.com/contact. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include -#include -#include -#include -#include "qegl_p.h" - -#if defined(QT_OPENGL_ES) || defined(QT_OPENVG) - -#if defined(Q_WS_X11) -#include -#include -#include -#endif - -QT_BEGIN_NAMESPACE - -bool QEglContext::createSurface(QPaintDevice *device) -{ - // Create the native drawable for the paint device. - int devType = device->devType(); - EGLNativePixmapType pixmapDrawable = 0; - EGLNativeWindowType windowDrawable = 0; - bool ok; - if (devType == QInternal::Pixmap) { - pixmapDrawable = (EGLNativePixmapType)(static_cast(device))->handle(); - ok = (pixmapDrawable != 0); - } else if (devType == QInternal::Widget) { - windowDrawable = (EGLNativeWindowType)(static_cast(device))->winId(); - ok = (windowDrawable != 0); - } else { - ok = false; - } - if (!ok) { - qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); - return false; - } - - // Create the EGL surface to draw into, based on the native drawable. - if (devType == QInternal::Widget) - surf = eglCreateWindowSurface(dpy, cfg, windowDrawable, 0); - else - surf = eglCreatePixmapSurface(dpy, cfg, pixmapDrawable, 0); - - if (surf == EGL_NO_SURFACE) { - qWarning() << "QEglContext::createSurface(): Unable to create EGL surface:" - << errorString(eglGetError()); - return false; - } - return true; -} - -EGLDisplay QEglContext::getDisplay(QPaintDevice *device) -{ - Q_UNUSED(device); - Display *xdpy = QX11Info::display(); - if (!xdpy) { - qWarning("QEglContext::getDisplay(): X11 display is not open"); - return EGL_NO_DISPLAY; - } - return eglGetDisplay(EGLNativeDisplayType(xdpy)); -} - -static int countBits(unsigned long mask) -{ - int count = 0; - while (mask != 0) { - if (mask & 1) - ++count; - mask >>= 1; - } - return count; -} - -// Set the pixel format parameters from the visual in "xinfo". -void QEglProperties::setVisualFormat(const QX11Info *xinfo) -{ - if (!xinfo) - return; - Visual *visual = (Visual*)xinfo->visual(); - if (!visual) - return; - if (visual->c_class != TrueColor && visual->c_class != DirectColor) - return; - setValue(EGL_RED_SIZE, countBits(visual->red_mask)); - setValue(EGL_GREEN_SIZE, countBits(visual->green_mask)); - setValue(EGL_BLUE_SIZE, countBits(visual->blue_mask)); - setValue(EGL_ALPHA_SIZE, 0); // XXX -} - -QT_END_NAMESPACE - -#endif // QT_OPENGL_ES || QT_OPENVG diff --git a/src/opengl/qgl_egl_p.h b/src/opengl/qgl_egl_p.h index 2fb2e8f..d54036d 100644 --- a/src/opengl/qgl_egl_p.h +++ b/src/opengl/qgl_egl_p.h @@ -53,7 +53,7 @@ // We mean it. // -#include "qegl_p.h" +#include QT_BEGIN_NAMESPACE diff --git a/src/opengl/qgl_qws.cpp b/src/opengl/qgl_qws.cpp index 3b6ad63..a71a734 100644 --- a/src/opengl/qgl_qws.cpp +++ b/src/opengl/qgl_qws.cpp @@ -116,6 +116,57 @@ void qt_egl_add_platform_config(QEglProperties& props, QPaintDevice *device) props.setPixelFormat(glScreen->pixelFormat()); } +static bool qt_egl_create_surface + (QEglContext *context, QPaintDevice *device, + const QEglProperties *properties = 0) +{ + // Get the screen surface functions, which are used to create native ids. + QGLScreen *glScreen = glScreenForDevice(device); + if (!glScreen) + return false; + QGLScreenSurfaceFunctions *funcs = glScreen->surfaceFunctions(); + if (!funcs) + return false; + + // Create the native drawable for the paint device. + int devType = device->devType(); + EGLNativePixmapType pixmapDrawable = 0; + EGLNativeWindowType windowDrawable = 0; + bool ok; + if (devType == QInternal::Pixmap) { + ok = funcs->createNativePixmap(static_cast(device), &pixmapDrawable); + } else if (devType == QInternal::Image) { + ok = funcs->createNativeImage(static_cast(device), &pixmapDrawable); + } else { + ok = funcs->createNativeWindow(static_cast(device), &windowDrawable); + } + if (!ok) { + qWarning("QEglContext::createSurface(): Cannot create the native EGL drawable"); + return false; + } + + // Create the EGL surface to draw into, based on the native drawable. + const int *props; + if (properties) + props = properties->properties(); + else + props = 0; + EGLSurface surf; + if (devType == QInternal::Widget) { + surf = eglCreateWindowSurface + (context->display(), context->config(), windowDrawable, props); + } else { + surf = eglCreatePixmapSurface + (context->display(), context->config(), pixmapDrawable, props); + } + if (surf == EGL_NO_SURFACE) { + qWarning("QEglContext::createSurface(): Unable to create EGL surface, error = 0x%x", eglGetError()); + return false; + } + context->setSurface(surf); + return true; +} + bool QGLContext::chooseContext(const QGLContext* shareContext) { Q_D(QGLContext); @@ -131,7 +182,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) // Get the display and initialize it. d->eglContext = new QEglContext(); - d->eglContext->setApi(QEglContext::OpenGL); + d->eglContext->setApi(QEgl::OpenGL); if (!d->eglContext->openDisplay(device())) { delete d->eglContext; d->eglContext = 0; @@ -142,7 +193,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) QEglProperties configProps; qt_egl_add_platform_config(configProps, device()); qt_egl_set_format(configProps, devType, d->glFormat); - configProps.setRenderableType(QEglContext::OpenGL); + configProps.setRenderableType(QEgl::OpenGL); // Search for a matching configuration, reducing the complexity // each time until we get something that matches. @@ -168,8 +219,10 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) eglSwapInterval(d->eglContext->display(), d->glFormat.swapInterval()); #endif - // Create the EGL surface to draw into. - if (!d->eglContext->createSurface(device())) { + // Create the EGL surface to draw into. We cannot use + // QEglContext::createSurface() because it does not have + // access to the QGLScreen. + if (!qt_egl_create_surface(d->eglContext, device())) { delete d->eglContext; d->eglContext = 0; return false; diff --git a/src/opengl/qgl_wince.cpp b/src/opengl/qgl_wince.cpp index 47dc2d4..afe26ab 100644 --- a/src/opengl/qgl_wince.cpp +++ b/src/opengl/qgl_wince.cpp @@ -140,7 +140,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) // Get the display and initialize it. d->eglContext = new QEglContext(); - d->eglContext->setApi(QEglContext::OpenGL); + d->eglContext->setApi(QEgl::OpenGL); if (!d->eglContext->openDisplay(device())) { delete d->eglContext; d->eglContext = 0; @@ -151,7 +151,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) QEglProperties configProps; qt_egl_add_platform_config(configProps, device()); qt_egl_set_format(configProps, devType, d->glFormat); - configProps.setRenderableType(QEglContext::OpenGL); + configProps.setRenderableType(QEgl::OpenGL); // Search for a matching configuration, reducing the complexity // each time until we get something that matches. diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp index 7fdbfbd..9db3a30 100644 --- a/src/opengl/qgl_x11egl.cpp +++ b/src/opengl/qgl_x11egl.cpp @@ -77,7 +77,7 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) // Get the display and initialize it. d->eglContext = new QEglContext(); - d->eglContext->setApi(QEglContext::OpenGL); + d->eglContext->setApi(QEgl::OpenGL); if (!d->eglContext->openDisplay(device())) { delete d->eglContext; d->eglContext = 0; @@ -88,11 +88,11 @@ bool QGLContext::chooseContext(const QGLContext* shareContext) QEglProperties configProps; qt_egl_set_format(configProps, devType, d->glFormat); qt_egl_add_platform_config(configProps, device()); - configProps.setRenderableType(QEglContext::OpenGL); + configProps.setRenderableType(QEgl::OpenGL); // Search for a matching configuration, reducing the complexity // each time until we get something that matches. - if (!d->eglContext->chooseConfig(configProps, QEglContext::BestPixelFormat)) { + if (!d->eglContext->chooseConfig(configProps, QEgl::BestPixelFormat)) { delete d->eglContext; d->eglContext = 0; return false; diff --git a/src/opengl/qglpixelbuffer_egl.cpp b/src/opengl/qglpixelbuffer_egl.cpp index fca1a31..38e4f74 100644 --- a/src/opengl/qglpixelbuffer_egl.cpp +++ b/src/opengl/qglpixelbuffer_egl.cpp @@ -63,7 +63,7 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge { // Create the EGL context. ctx = new QEglContext(); - ctx->setApi(QEglContext::OpenGL); + ctx->setApi(QEgl::OpenGL); // Open the EGL display. if (!ctx->openDisplay(0)) { @@ -82,13 +82,13 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge #if QGL_RENDER_TEXTURE textureFormat = EGL_TEXTURE_RGBA; configProps.setValue(EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE); - ok = ctx->chooseConfig(configProps, QEglContext::BestPixelFormat); + ok = ctx->chooseConfig(configProps, QEgl::BestPixelFormat); if (!ok) { // Try again with RGB texture rendering. textureFormat = EGL_TEXTURE_RGB; configProps.removeValue(EGL_BIND_TO_TEXTURE_RGBA); configProps.setValue(EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE); - ok = ctx->chooseConfig(configProps, QEglContext::BestPixelFormat); + ok = ctx->chooseConfig(configProps, QEgl::BestPixelFormat); if (!ok) { // One last try for a pbuffer with no texture rendering. configProps.removeValue(EGL_BIND_TO_TEXTURE_RGB); @@ -99,7 +99,7 @@ bool QGLPixelBufferPrivate::init(const QSize &size, const QGLFormat &f, QGLWidge textureFormat = EGL_NONE; #endif if (!ok) { - if (!ctx->chooseConfig(configProps, QEglContext::BestPixelFormat)) { + if (!ctx->chooseConfig(configProps, QEgl::BestPixelFormat)) { delete ctx; ctx = 0; return false; @@ -208,7 +208,7 @@ bool QGLPixelBuffer::hasOpenGLPbuffers() return false; QEglProperties configProps; qt_egl_set_format(configProps, QInternal::Pbuffer, QGLFormat::defaultFormat()); - configProps.setRenderableType(QEglContext::OpenGL); + configProps.setRenderableType(QEgl::OpenGL); return ctx.chooseConfig(configProps); } diff --git a/src/openvg/openvg.pro b/src/openvg/openvg.pro new file mode 100644 index 0000000..4d499ef --- /dev/null +++ b/src/openvg/openvg.pro @@ -0,0 +1,48 @@ +TARGET = QtOpenVG +QT += core \ + gui + +DEFINES+=QT_BUILD_OPENVG_LIB + +contains(QT_CONFIG, shivavg) { + DEFINES += QVG_NO_DRAW_GLYPHS + DEFINES += QVG_NO_RENDER_TO_MASK + DEFINES += QVG_SCISSOR_CLIP +} + +HEADERS += \ + qvg.h \ + qvg_p.h \ + qpaintengine_vg_p.h \ + qpixmapdata_vg_p.h \ + qpixmapfilter_vg_p.h \ + qvgcompositionhelper_p.h +SOURCES += \ + qpaintengine_vg.cpp \ + qpixmapdata_vg.cpp \ + qpixmapfilter_vg.cpp + +contains(QT_CONFIG, egl) { + HEADERS += \ + qwindowsurface_vgegl_p.h \ + qwindowsurface_vg_p.h + SOURCES += \ + qwindowsurface_vg.cpp \ + qwindowsurface_vgegl.cpp +} + +include(../qbase.pri) + +unix:QMAKE_PKGCONFIG_REQUIRES = QtCore QtGui + +!isEmpty(QMAKE_INCDIR_OPENVG): INCLUDEPATH += $$QMAKE_INCDIR_OPENVG +!isEmpty(QMAKE_LIBDIR_OPENVG): LIBS += -L$$QMAKE_LIBDIR_OPENVG +!isEmpty(QMAKE_LIBS_OPENVG): LIBS += $$QMAKE_LIBS_OPENVG + +contains(QT_CONFIG, egl) { + !isEmpty(QMAKE_INCDIR_EGL): INCLUDEPATH += $$QMAKE_INCDIR_EGL + !isEmpty(QMAKE_LIBDIR_EGL): LIBS += -L$$QMAKE_LIBDIR_EGL + !isEmpty(QMAKE_LIBS_EGL): LIBS += $$QMAKE_LIBS_EGL +} + +INCLUDEPATH += ../3rdparty/harfbuzz/src diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp new file mode 100644 index 0000000..37945bf --- /dev/null +++ b/src/openvg/qpaintengine_vg.cpp @@ -0,0 +1,3231 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpaintengine_vg_p.h" +#include "qpixmapdata_vg_p.h" +#include "qpixmapfilter_vg_p.h" +#include "qvgcompositionhelper_p.h" +#if !defined(QT_NO_EGL) +#include +#include "qwindowsurface_vgegl_p.h" +#endif +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +// vgDrawGlyphs() only exists in OpenVG 1.1 and higher. +#if !defined(OPENVG_VERSION_1_1) && !defined(QVG_NO_DRAW_GLYPHS) +#define QVG_NO_DRAW_GLYPHS 1 +#endif + +// vgRenderToMask() only exists in OpenVG 1.1 and higher. +// Also, disable masking completely if we are using the scissor to clip. +#if !defined(OPENVG_VERSION_1_1) && !defined(QVG_NO_RENDER_TO_MASK) +#define QVG_NO_RENDER_TO_MASK 1 +#endif +#if defined(QVG_SCISSOR_CLIP) && !defined(QVG_NO_RENDER_TO_MASK) +#define QVG_NO_RENDER_TO_MASK 1 +#endif + +#if !defined(QVG_NO_DRAW_GLYPHS) + +extern int qt_defaultDpiX(); +extern int qt_defaultDpiY(); + +class QVGPaintEnginePrivate; + +class QVGFontGlyphCache +{ +public: + QVGFontGlyphCache(); + ~QVGFontGlyphCache(); + + void cacheGlyphs(QVGPaintEnginePrivate *d, + const QTextItemInt &ti, + const QVarLengthArray &glyphs); + void setScaleFromText(const QTextItemInt &ti); + + VGFont font; + VGfloat scaleX; + VGfloat scaleY; + + uint cachedGlyphsMask[256 / 32]; + QSet cachedGlyphs; +}; + +typedef QHash QVGFontCache; + +#endif + +class QVGFontEngineCleaner : public QObject +{ + Q_OBJECT +public: + QVGFontEngineCleaner(QVGPaintEnginePrivate *d); + ~QVGFontEngineCleaner(); + +public slots: + void fontEngineDestroyed(); + +private: + QVGPaintEnginePrivate *d_ptr; +}; + +class QVGPaintEnginePrivate : public QPaintEngineExPrivate +{ +public: + QVGPaintEnginePrivate(); + ~QVGPaintEnginePrivate(); + + void init(); + void initObjects(); + void destroy(); + void setTransform(VGMatrixMode mode, const QTransform& transform); + void updateTransform(QPaintDevice *pdev); + void draw(VGPath path, const QPen& pen, const QBrush& brush, VGint rule = VG_EVEN_ODD); + void stroke(VGPath path, const QPen& pen); + void fill(VGPath path, const QBrush& brush, VGint rule = VG_EVEN_ODD); + VGPath vectorPathToVGPath(const QVectorPath& path); + VGPath painterPathToVGPath(const QPainterPath& path); + VGPaintType setBrush + (VGPaint paint, const QBrush& brush, VGMatrixMode mode, + VGPaintType prevPaintType); + void setPenParams(const QPen& pen); + void setBrushTransform(const QBrush& brush, VGMatrixMode mode); + void setupColorRamp(const QGradient *grad, VGPaint paint); + void setImageOptions(); +#if !defined(QVG_SCISSOR_CLIP) + void ensureMask(QVGPaintEngine *engine, int width, int height); + void modifyMask + (QVGPaintEngine *engine, VGMaskOperation op, const QRegion& region); +#endif + + VGint maxScissorRects; // Maximum scissor rectangles for clipping. + + VGPaint penPaint; // Paint for currently active pen. + VGPaint brushPaint; // Paint for currently active brush. + VGPaint opacityPaint; // Paint for drawing images with opacity. + VGPaint fillPaint; // Current fill paint that is active. + + QPen currentPen; // Current pen set in "penPaint". + QBrush currentBrush; // Current brush set in "brushPaint". + + bool forcePenChange; // Force a pen change, even if the same. + bool forceBrushChange; // Force a brush change, even if the same. + + VGPaintType penType; // Type of the last pen that was set. + VGPaintType brushType; // Type of the last brush that was set. + + QPointF brushOrigin; // Current brush origin. + + VGint fillRule; // Last fill rule that was set. + + qreal opacity; // Current drawing opacity. + qreal paintOpacity; // Opacity in opacityPaint. + +#if !defined(QVG_NO_MODIFY_PATH) + VGPath rectPath; // Cached path for quick drawing of rectangles. + VGPath linePath; // Cached path for quick drawing of lines. +#endif + + QTransform transform; // Currently active transform. + bool simpleTransform; // True if the transform is simple (non-projective). + qreal penScale; // Pen scaling factor from "transform". + + QTransform pathTransform; // Calculated VG path transformation. + QTransform imageTransform; // Calculated VG image transformation. + bool pathTransformSet; // True if path transform set in the VG context. + + bool maskValid; // True if vgMask() contains valid data. + bool maskIsSet; // True if mask would be fully set if it was valid. + bool rawVG; // True if processing a raw VG escape. + + QRect maskRect; // Rectangle version of mask if it is simple. + + QTransform penTransform; // Transform for the pen. + QTransform brushTransform; // Transform for the brush. + + VGMatrixMode matrixMode; // Last matrix mode that was set. + VGImageMode imageMode; // Last image mode that was set. + + QRegion scissorRegion; // Currently active scissor region. + bool scissorActive; // True if scissor region is active. + + QPaintEngine::DirtyFlags dirty; + + QColor clearColor; // Last clear color that was set. + VGfloat clearOpacity; // Opacity during the last clear. + + VGBlendMode blendMode; // Active blend mode. + VGRenderingQuality renderingQuality; // Active rendering quality. + VGImageQuality imageQuality; // Active image quality. + +#if !defined(QVG_NO_DRAW_GLYPHS) + QVGFontCache fontCache; + QVGFontEngineCleaner *fontEngineCleaner; +#endif + + // Ensure that the path transform is properly set in the VG context + // before we perform a vgDrawPath() operation. + inline void ensurePathTransform() + { + if (!pathTransformSet) { + setTransform(VG_MATRIX_PATH_USER_TO_SURFACE, pathTransform); + pathTransformSet = true; + } + } + + // Ensure that a specific pen has been set into penPaint. + inline void ensurePen(const QPen& pen) { + if (forcePenChange || pen != currentPen) { + currentPen = pen; + forcePenChange = false; + penType = setBrush + (penPaint, pen.brush(), + VG_MATRIX_STROKE_PAINT_TO_USER, penType); + setPenParams(pen); + } + } + + // Ensure that a specific brush has been set into brushPaint. + inline void ensureBrush(const QBrush& brush) { + if (forceBrushChange || brush != currentBrush) { + currentBrush = brush; + forceBrushChange = false; + brushType = setBrush + (brushPaint, brush, VG_MATRIX_FILL_PAINT_TO_USER, brushType); + } + if (fillPaint != brushPaint) { + vgSetPaint(brushPaint, VG_FILL_PATH); + fillPaint = brushPaint; + } + } + + // Set various modes, but only if different. + inline void setImageMode(VGImageMode mode); + inline void setRenderingQuality(VGRenderingQuality mode); + inline void setImageQuality(VGImageQuality mode); + inline void setBlendMode(VGBlendMode mode); + inline void setFillRule(VGint mode); + + // Clear all lazily-set modes. + void clearModes(); +}; + +inline void QVGPaintEnginePrivate::setImageMode(VGImageMode mode) +{ + if (imageMode != mode) { + imageMode = mode; + vgSeti(VG_IMAGE_MODE, mode); + } +} + +inline void QVGPaintEnginePrivate::setRenderingQuality(VGRenderingQuality mode) +{ + if (renderingQuality != mode) { + vgSeti(VG_RENDERING_QUALITY, mode); + renderingQuality = mode; + } +} + +inline void QVGPaintEnginePrivate::setImageQuality(VGImageQuality mode) +{ + if (imageQuality != mode) { + vgSeti(VG_IMAGE_QUALITY, mode); + imageQuality = mode; + } +} + +inline void QVGPaintEnginePrivate::setBlendMode(VGBlendMode mode) +{ + if (blendMode != mode) { + vgSeti(VG_BLEND_MODE, mode); + blendMode = mode; + } +} + +inline void QVGPaintEnginePrivate::setFillRule(VGint mode) +{ + if (fillRule != mode) { + fillRule = mode; + vgSeti(VG_FILL_RULE, mode); + } +} + +void QVGPaintEnginePrivate::clearModes() +{ + matrixMode = (VGMatrixMode)0; + imageMode = (VGImageMode)0; + blendMode = (VGBlendMode)0; + renderingQuality = (VGRenderingQuality)0; + imageQuality = (VGImageQuality)0; +} + +QVGPaintEnginePrivate::QVGPaintEnginePrivate() +{ + init(); +} + +void QVGPaintEnginePrivate::init() +{ + maxScissorRects = 0; + + penPaint = 0; + brushPaint = 0; + opacityPaint = 0; + fillPaint = 0; + + forcePenChange = true; + forceBrushChange = true; + penType = (VGPaintType)0; + brushType = (VGPaintType)0; + + brushOrigin = QPointF(0.0f, 0.0f); + + fillRule = 0; + + opacity = 1.0; + paintOpacity = 1.0f; + +#if !defined(QVG_NO_MODIFY_PATH) + rectPath = 0; + linePath = 0; +#endif + + simpleTransform = true; + pathTransformSet = false; + penScale = 1.0; + + maskValid = false; + maskIsSet = false; + rawVG = false; + + scissorActive = false; + + dirty = 0; + + clearOpacity = 1.0f; + +#if !defined(QVG_NO_DRAW_GLYPHS) + fontEngineCleaner = 0; +#endif + + clearModes(); +} + +QVGPaintEnginePrivate::~QVGPaintEnginePrivate() +{ + destroy(); +} + +void QVGPaintEnginePrivate::initObjects() +{ + maxScissorRects = vgGeti(VG_MAX_SCISSOR_RECTS); + + penPaint = vgCreatePaint(); + vgSetParameteri(penPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetPaint(penPaint, VG_STROKE_PATH); + + vgSeti(VG_MATRIX_MODE, VG_MATRIX_STROKE_PAINT_TO_USER); + vgLoadIdentity(); + + brushPaint = vgCreatePaint(); + vgSetParameteri(brushPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetPaint(brushPaint, VG_FILL_PATH); + fillPaint = brushPaint; + + vgSeti(VG_MATRIX_MODE, VG_MATRIX_FILL_PAINT_TO_USER); + vgLoadIdentity(); + matrixMode = VG_MATRIX_FILL_PAINT_TO_USER; + + opacityPaint = vgCreatePaint(); + vgSetParameteri(opacityPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + VGfloat values[4]; + values[0] = 1.0f; + values[1] = 1.0f; + values[2] = 1.0f; + values[3] = paintOpacity; + vgSetParameterfv(opacityPaint, VG_PAINT_COLOR, 4, values); + +#if !defined(QVG_NO_MODIFY_PATH) + // Create a dummy path for rectangle drawing, which we can + // modify later with vgModifyPathCoords(). This should be + // faster than constantly creating and destroying paths. + rectPath = vgCreatePath(VG_PATH_FORMAT_STANDARD, + VG_PATH_DATATYPE_F, + 1.0f, // scale + 0.0f, // bias + 5, // segmentCapacityHint + 8, // coordCapacityHint + VG_PATH_CAPABILITY_ALL); + static VGubyte const segments[5] = { + VG_MOVE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_CLOSE_PATH + }; + VGfloat coords[8]; + coords[0] = 0.0f; + coords[1] = 0.0f; + coords[2] = 100.0f; + coords[3] = coords[1]; + coords[4] = coords[2]; + coords[5] = 100.0f; + coords[6] = coords[0]; + coords[7] = coords[5]; + vgAppendPathData(rectPath, 5, segments, coords); + + // Create a dummy line drawing path as well. + linePath = vgCreatePath(VG_PATH_FORMAT_STANDARD, + VG_PATH_DATATYPE_F, + 1.0f, // scale + 0.0f, // bias + 2, // segmentCapacityHint + 4, // coordCapacityHint + VG_PATH_CAPABILITY_ALL); + vgAppendPathData(linePath, 2, segments, coords); +#endif +} + +void QVGPaintEnginePrivate::destroy() +{ + if (penPaint) + vgDestroyPaint(penPaint); + if (brushPaint) + vgDestroyPaint(brushPaint); + if (opacityPaint) + vgDestroyPaint(opacityPaint); + +#if !defined(QVG_NO_MODIFY_PATH) + if (rectPath) + vgDestroyPath(rectPath); + if (linePath) + vgDestroyPath(linePath); +#endif + +#if !defined(QVG_NO_DRAW_GLYPHS) + QVGFontCache::Iterator it; + for (it = fontCache.begin(); it != fontCache.end(); ++it) + delete it.value(); + fontCache.clear(); + delete fontEngineCleaner; +#endif +} + +// Set a specific VG transformation matrix in the current VG context. +void QVGPaintEnginePrivate::setTransform + (VGMatrixMode mode, const QTransform& transform) +{ + VGfloat mat[9]; + if (mode != matrixMode) { + vgSeti(VG_MATRIX_MODE, mode); + matrixMode = mode; + } + mat[0] = transform.m11(); + mat[1] = transform.m12(); + mat[2] = transform.m13(); + mat[3] = transform.m21(); + mat[4] = transform.m22(); + mat[5] = transform.m23(); + mat[6] = transform.m31(); + mat[7] = transform.m32(); + mat[8] = transform.m33(); + vgLoadMatrix(mat); +} + +extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); + +void QVGPaintEnginePrivate::updateTransform(QPaintDevice *pdev) +{ + VGfloat devh = pdev->height() - 1; + + // Construct the VG transform by combining the Qt transform with + // the following viewport transformation: + // | 1 0 0 | | 1 0 0.5 | | 1 0 0.5 | + // | 0 -1 devh | * | 0 1 -0.5 | = | 0 -1 (0.5 + devh) | + // | 0 0 1 | | 0 0 1 | | 0 0 1 | + // The full VG transform is effectively: + // 1. Apply the user's transformation matrix. + // 2. Translate by (0.5, -0.5) to correct for Qt and VG putting + // the centre of the pixel at different positions. + // 3. Flip the co-ordinate system upside down. + QTransform viewport(1.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.5f, devh + 0.5f, 1.0f); + + // The image transform is always the full transformation, + // because it can be projective. + imageTransform = transform * viewport; + + // Determine if the transformation is projective. + bool projective = (imageTransform.m13() != 0.0f || + imageTransform.m23() != 0.0f || + imageTransform.m33() != 1.0f); + if (projective) { + // The engine cannot do projective path transforms for us, + // so we will have to convert the co-ordinates ourselves. + // Change the matrix to just the viewport transformation. + pathTransform = viewport; + simpleTransform = false; + } else { + pathTransform = imageTransform; + simpleTransform = true; + } + pathTransformSet = false; + + // Calculate the scaling factor to use for turning cosmetic pens + // into ordinary non-cosmetic pens. + qt_scaleForTransform(transform, &penScale); +} + +VGPath QVGPaintEnginePrivate::vectorPathToVGPath(const QVectorPath& path) +{ + int count = path.elementCount(); + const qreal *points = path.points(); + const QPainterPath::ElementType *elements = path.elements(); + + VGPath vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD, + VG_PATH_DATATYPE_F, + 1.0f, // scale + 0.0f, // bias + count + 1, // segmentCapacityHint + count * 2, // coordCapacityHint + VG_PATH_CAPABILITY_ALL); + + // Size is sufficient segments for drawRoundedRect() paths. + QVarLengthArray segments; + + if (sizeof(qreal) == sizeof(VGfloat) && elements && simpleTransform) { + // If Qt was compiled with qreal the same size as VGfloat, + // then convert the segment types and use the incoming + // points array directly. + for (int i = 0; i < count; ++i) { + switch (elements[i]) { + + case QPainterPath::MoveToElement: + segments.append(VG_MOVE_TO_ABS); break; + + case QPainterPath::LineToElement: + segments.append(VG_LINE_TO_ABS); break; + + case QPainterPath::CurveToElement: break; + + case QPainterPath::CurveToDataElement: + segments.append(VG_CUBIC_TO_ABS); break; + + } + } + if (path.hasImplicitClose()) + segments.append(VG_CLOSE_PATH); + + vgAppendPathData(vgpath, segments.count(), segments.constData(), + reinterpret_cast(points)); + + return vgpath; + } + + // Sizes chosen so that drawRoundedRect() paths fit in these arrays. + QVarLengthArray coords; + + int curvePos = 0; + QPointF temp; + + if (elements && simpleTransform) { + // Convert the members of the element array. + for (int i = 0; i < count; ++i) { + switch (elements[i]) { + + case QPainterPath::MoveToElement: + { + coords.append(points[0]); + coords.append(points[1]); + segments.append(VG_MOVE_TO_ABS); + } + break; + + case QPainterPath::LineToElement: + { + coords.append(points[0]); + coords.append(points[1]); + segments.append(VG_LINE_TO_ABS); + } + break; + + case QPainterPath::CurveToElement: + { + coords.append(points[0]); + coords.append(points[1]); + curvePos = 2; + } + break; + + case QPainterPath::CurveToDataElement: + { + coords.append(points[0]); + coords.append(points[1]); + curvePos += 2; + if (curvePos == 6) { + curvePos = 0; + segments.append(VG_CUBIC_TO_ABS); + } + } + break; + + } + points += 2; + } + } else if (elements && !simpleTransform) { + // Convert the members of the element array after applying the + // current transform to the path locally. + for (int i = 0; i < count; ++i) { + switch (elements[i]) { + + case QPainterPath::MoveToElement: + { + temp = transform.map(QPointF(points[0], points[1])); + coords.append(temp.x()); + coords.append(temp.y()); + segments.append(VG_MOVE_TO_ABS); + } + break; + + case QPainterPath::LineToElement: + { + temp = transform.map(QPointF(points[0], points[1])); + coords.append(temp.x()); + coords.append(temp.y()); + segments.append(VG_LINE_TO_ABS); + } + break; + + case QPainterPath::CurveToElement: + { + temp = transform.map(QPointF(points[0], points[1])); + coords.append(temp.x()); + coords.append(temp.y()); + curvePos = 2; + } + break; + + case QPainterPath::CurveToDataElement: + { + temp = transform.map(QPointF(points[0], points[1])); + coords.append(temp.x()); + coords.append(temp.y()); + curvePos += 2; + if (curvePos == 6) { + curvePos = 0; + segments.append(VG_CUBIC_TO_ABS); + } + } + break; + + } + points += 2; + } + } else if (count > 0 && simpleTransform) { + // If there is no element array, then the path is assumed + // to be a MoveTo followed by several LineTo's. + coords.append(points[0]); + coords.append(points[1]); + segments.append(VG_MOVE_TO_ABS); + while (count > 1) { + points += 2; + coords.append(points[0]); + coords.append(points[1]); + segments.append(VG_LINE_TO_ABS); + --count; + } + } else if (count > 0 && !simpleTransform) { + // Convert a simple path, and apply the transform locally. + temp = transform.map(QPointF(points[0], points[1])); + coords.append(temp.x()); + coords.append(temp.y()); + segments.append(VG_MOVE_TO_ABS); + while (count > 1) { + points += 2; + temp = transform.map(QPointF(points[0], points[1])); + coords.append(temp.x()); + coords.append(temp.y()); + segments.append(VG_LINE_TO_ABS); + --count; + } + } + + // Close the path if specified. + if (path.hasImplicitClose()) + segments.append(VG_CLOSE_PATH); + + vgAppendPathData(vgpath, segments.count(), + segments.constData(), coords.constData()); + + return vgpath; +} + +VGPath QVGPaintEnginePrivate::painterPathToVGPath(const QPainterPath& path) +{ + int count = path.elementCount(); + + VGPath vgpath = vgCreatePath(VG_PATH_FORMAT_STANDARD, + VG_PATH_DATATYPE_F, + 1.0f, // scale + 0.0f, // bias + count + 1, // segmentCapacityHint + count * 2, // coordCapacityHint + VG_PATH_CAPABILITY_ALL); + + if (count == 0) + return vgpath; + + const QPainterPath::Element *elements = &(path.elementAt(0)); + + // Sizes chosen so that drawRoundedRect() paths fit in these arrays. + QVarLengthArray coords; + QVarLengthArray segments; + + int curvePos = 0; + QPointF temp; + + // Keep track of the start and end of each sub-path. QPainterPath + // does not have an "implicit close" flag like QVectorPath does. + // We therefore have to detect closed paths by looking for a LineTo + // element that connects back to the initial MoveTo element. + qreal startx = 0.0; + qreal starty = 0.0; + qreal endx = 0.0; + qreal endy = 0.0; + bool haveStart = false; + bool haveEnd = false; + + if (simpleTransform) { + // Convert the members of the element array. + for (int i = 0; i < count; ++i) { + switch (elements[i].type) { + + case QPainterPath::MoveToElement: + { + if (haveStart && haveEnd && startx == endx && starty == endy) { + // Implicitly close the previous sub-path. + segments.append(VG_CLOSE_PATH); + } + startx = elements[i].x; + starty = elements[i].y; + coords.append(startx); + coords.append(starty); + haveStart = true; + haveEnd = false; + segments.append(VG_MOVE_TO_ABS); + } + break; + + case QPainterPath::LineToElement: + { + endx = elements[i].x; + endy = elements[i].y; + coords.append(endx); + coords.append(endy); + haveEnd = true; + segments.append(VG_LINE_TO_ABS); + } + break; + + case QPainterPath::CurveToElement: + { + coords.append(elements[i].x); + coords.append(elements[i].y); + haveEnd = false; + curvePos = 2; + } + break; + + case QPainterPath::CurveToDataElement: + { + coords.append(elements[i].x); + coords.append(elements[i].y); + haveEnd = false; + curvePos += 2; + if (curvePos == 6) { + curvePos = 0; + segments.append(VG_CUBIC_TO_ABS); + } + } + break; + + } + } + } else { + // Convert the members of the element array after applying the + // current transform to the path locally. + for (int i = 0; i < count; ++i) { + switch (elements[i].type) { + + case QPainterPath::MoveToElement: + { + if (haveStart && haveEnd && startx == endx && starty == endy) { + // Implicitly close the previous sub-path. + segments.append(VG_CLOSE_PATH); + } + temp = transform.map(QPointF(elements[i].x, elements[i].y)); + startx = temp.x(); + starty = temp.y(); + coords.append(startx); + coords.append(starty); + haveStart = true; + haveEnd = false; + segments.append(VG_MOVE_TO_ABS); + } + break; + + case QPainterPath::LineToElement: + { + temp = transform.map(QPointF(elements[i].x, elements[i].y)); + endx = temp.x(); + endy = temp.y(); + coords.append(endx); + coords.append(endy); + haveEnd = true; + segments.append(VG_LINE_TO_ABS); + } + break; + + case QPainterPath::CurveToElement: + { + temp = transform.map(QPointF(elements[i].x, elements[i].y)); + coords.append(temp.x()); + coords.append(temp.y()); + haveEnd = false; + curvePos = 2; + } + break; + + case QPainterPath::CurveToDataElement: + { + temp = transform.map(QPointF(elements[i].x, elements[i].y)); + coords.append(temp.x()); + coords.append(temp.y()); + haveEnd = false; + curvePos += 2; + if (curvePos == 6) { + curvePos = 0; + segments.append(VG_CUBIC_TO_ABS); + } + } + break; + + } + } + } + + if (haveStart && haveEnd && startx == endx && starty == endy) { + // Implicitly close the last sub-path. + segments.append(VG_CLOSE_PATH); + } + + vgAppendPathData(vgpath, segments.count(), + segments.constData(), coords.constData()); + + return vgpath; +} + +extern QImage qt_imageForBrush(int style, bool invert); + +static QImage colorizeBitmap(const QImage &image, const QColor &color) +{ + QImage sourceImage = image.convertToFormat(QImage::Format_MonoLSB); + QImage dest = QImage(sourceImage.size(), QImage::Format_ARGB32_Premultiplied); + + QRgb fg = PREMUL(color.rgba()); + QRgb bg = 0; + + int height = sourceImage.height(); + int width = sourceImage.width(); + for (int y=0; y(dest.scanLine(y)); + for (int x=0; x < width; ++x) + target[x] = (source[x>>3] >> (x&7)) & 1 ? fg : bg; + } + return dest; +} + +static VGImage toVGImage + (const QImage & image, Qt::ImageConversionFlags flags = Qt::AutoColor) +{ + QImage img(image); + + VGImageFormat format; + switch (img.format()) { + case QImage::Format_Mono: + img = image.convertToFormat(QImage::Format_MonoLSB, flags); + format = VG_BW_1; + break; + case QImage::Format_MonoLSB: + format = VG_BW_1; + break; + case QImage::Format_RGB32: + format = VG_sXRGB_8888; + break; + case QImage::Format_ARGB32: + format = VG_sARGB_8888; + break; + case QImage::Format_ARGB32_Premultiplied: + format = VG_sARGB_8888_PRE; + break; + case QImage::Format_RGB16: + format = VG_sRGB_565; + break; + default: + // Convert everything else into ARGB32_Premultiplied. + img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied, flags); + format = VG_sARGB_8888_PRE; + break; + } + + const uchar *pixels = img.bits(); + + VGImage vgImg = vgCreateImage + (format, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); + vgImageSubData + (vgImg, pixels, img.bytesPerLine(), format, 0, 0, + img.width(), img.height()); + + return vgImg; +} + +static VGImage toVGImageSubRect + (const QImage & image, const QRect& sr, + Qt::ImageConversionFlags flags = Qt::AutoColor) +{ + QImage img(image); + + VGImageFormat format; + int bpp = 4; + + switch (img.format()) { + case QImage::Format_Mono: + case QImage::Format_MonoLSB: + return VG_INVALID_HANDLE; + case QImage::Format_RGB32: + format = VG_sXRGB_8888; + break; + case QImage::Format_ARGB32: + format = VG_sARGB_8888; + break; + case QImage::Format_ARGB32_Premultiplied: + format = VG_sARGB_8888_PRE; + break; + case QImage::Format_RGB16: + format = VG_sRGB_565; + bpp = 2; + break; + default: + // Convert everything else into ARGB32_Premultiplied. + img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied, flags); + format = VG_sARGB_8888_PRE; + break; + } + + const uchar *pixels = img.bits() + bpp * sr.x() + + img.bytesPerLine() * sr.y(); + + VGImage vgImg = vgCreateImage + (format, sr.width(), sr.height(), VG_IMAGE_QUALITY_FASTER); + vgImageSubData + (vgImg, pixels, img.bytesPerLine(), format, 0, 0, + sr.width(), sr.height()); + + return vgImg; +} + +static VGImage toVGImageWithOpacity(const QImage & image, qreal opacity) +{ + QImage img(image.size(), QImage::Format_ARGB32_Premultiplied); + img.fill(0); + QPainter painter; + painter.begin(&img); + painter.setOpacity(opacity); + painter.drawImage(0, 0, image); + painter.end(); + + const uchar *pixels = img.bits(); + + VGImage vgImg = vgCreateImage + (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); + vgImageSubData + (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, + img.width(), img.height()); + + return vgImg; +} + +static VGImage toVGImageWithOpacitySubRect + (const QImage & image, qreal opacity, const QRect& sr) +{ + QImage img(sr.size(), QImage::Format_ARGB32_Premultiplied); + img.fill(0); + QPainter painter; + painter.begin(&img); + painter.setOpacity(opacity); + painter.drawImage(QPoint(0, 0), image, sr); + painter.end(); + + const uchar *pixels = img.bits(); + + VGImage vgImg = vgCreateImage + (VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); + vgImageSubData + (vgImg, pixels, img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, + img.width(), img.height()); + + return vgImg; +} + +VGPaintType QVGPaintEnginePrivate::setBrush + (VGPaint paint, const QBrush& brush, VGMatrixMode mode, + VGPaintType prevType) +{ + VGfloat values[5]; + setBrushTransform(brush, mode); + + // Reset the paint pattern on the brush, which will discard + // the previous VGImage if one was set. + if (prevType == VG_PAINT_TYPE_PATTERN || prevType == (VGPaintType)0) + vgPaintPattern(paint, VG_INVALID_HANDLE); + + switch (brush.style()) { + + case Qt::SolidPattern: { + // The brush is a solid color. + QColor color(brush.color()); + values[0] = color.redF(); + values[1] = color.greenF(); + values[2] = color.blueF(); + values[3] = color.alphaF() * opacity; + if (prevType != VG_PAINT_TYPE_COLOR) + vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(paint, VG_PAINT_COLOR, 4, values); + return VG_PAINT_TYPE_COLOR; + } + + case Qt::LinearGradientPattern: { + // The brush is a linear gradient. + Q_ASSERT(brush.gradient()->type() == QGradient::LinearGradient); + const QLinearGradient *grad = + static_cast(brush.gradient()); + values[0] = grad->start().x(); + values[1] = grad->start().y(); + values[2] = grad->finalStop().x(); + values[3] = grad->finalStop().y(); + if (prevType != VG_PAINT_TYPE_LINEAR_GRADIENT) + vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT); + vgSetParameterfv(paint, VG_PAINT_LINEAR_GRADIENT, 4, values); + setupColorRamp(grad, paint); + return VG_PAINT_TYPE_LINEAR_GRADIENT; + } + + case Qt::RadialGradientPattern: { + // The brush is a radial gradient. + Q_ASSERT(brush.gradient()->type() == QGradient::RadialGradient); + const QRadialGradient *grad = + static_cast(brush.gradient()); + values[0] = grad->center().x(); + values[1] = grad->center().y(); + values[2] = grad->focalPoint().x(); + values[3] = grad->focalPoint().y(); + values[4] = grad->radius(); + if (prevType != VG_PAINT_TYPE_RADIAL_GRADIENT) + vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_RADIAL_GRADIENT); + vgSetParameterfv(paint, VG_PAINT_RADIAL_GRADIENT, 5, values); + setupColorRamp(grad, paint); + return VG_PAINT_TYPE_RADIAL_GRADIENT; + } + + case Qt::TexturePattern: { + // The brush is a texture specified by a QPixmap/QImage. + QPixmapData *pd = brush.texture().pixmapData(); + VGImage vgImg; + if (pd->pixelType() == QPixmapData::BitmapType) { + // Colorize bitmaps using the brush color and opacity. + QColor color = brush.color(); + if (opacity != 1.0) + color.setAlphaF(color.alphaF() * opacity); + QImage image = colorizeBitmap(*(pd->buffer()), color); + vgImg = toVGImage(image); + } else if (opacity == 1.0) { + if (pd->classId() == QPixmapData::OpenVGClass) { + QVGPixmapData *vgpd = static_cast(pd); + vgImg = vgpd->toVGImage(); + } else { + vgImg = toVGImage(*(pd->buffer())); + } + } else { + vgImg = toVGImageWithOpacity(*(pd->buffer()), opacity); + } + if (vgImg == VG_INVALID_HANDLE) + break; + if (prevType != VG_PAINT_TYPE_PATTERN) + vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN); + vgSetParameteri(paint, VG_PAINT_PATTERN_TILING_MODE, VG_TILE_REPEAT); + vgPaintPattern(paint, vgImg); + vgDestroyImage(vgImg); // Will stay valid until pattern is destroyed. + return VG_PAINT_TYPE_PATTERN; + } + + case Qt::ConicalGradientPattern: { + // Convert conical gradients into the first stop color. + qWarning() << "QVGPaintEnginePrivate::setBrush: conical gradients are not supported by OpenVG"; + Q_ASSERT(brush.gradient()->type() == QGradient::ConicalGradient); + const QConicalGradient *grad = + static_cast(brush.gradient()); + const QGradientStops stops = grad->stops(); + QColor color; + if (stops.size() > 0) + color = stops[0].second; + values[0] = color.redF(); + values[1] = color.greenF(); + values[2] = color.blueF(); + values[3] = color.alphaF() * opacity; + if (prevType != VG_PAINT_TYPE_COLOR) + vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); + vgSetParameterfv(paint, VG_PAINT_COLOR, 4, values); + return VG_PAINT_TYPE_COLOR; + } + + case Qt::Dense1Pattern: + case Qt::Dense2Pattern: + case Qt::Dense3Pattern: + case Qt::Dense4Pattern: + case Qt::Dense5Pattern: + case Qt::Dense6Pattern: + case Qt::Dense7Pattern: + case Qt::HorPattern: + case Qt::VerPattern: + case Qt::CrossPattern: + case Qt::BDiagPattern: + case Qt::FDiagPattern: + case Qt::DiagCrossPattern: { + // The brush is a traditional dotted or cross-hatched pattern brush. + QColor color = brush.color(); + if (opacity != 1.0) + color.setAlphaF(color.alphaF() * opacity); + QImage image = colorizeBitmap + (qt_imageForBrush(brush.style(), true), color); + VGImage vgImg = toVGImage(image); + if (prevType != VG_PAINT_TYPE_PATTERN) + vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN); + vgSetParameteri(paint, VG_PAINT_PATTERN_TILING_MODE, VG_TILE_REPEAT); + vgPaintPattern(paint, vgImg); + vgDestroyImage(vgImg); // Will stay valid until pattern is destroyed. + return VG_PAINT_TYPE_PATTERN; + } + + default: break; + } + return (VGPaintType)0; +} + +void QVGPaintEnginePrivate::setPenParams(const QPen& pen) +{ + // Note: OpenVG does not support zero-width or cosmetic pens, + // so we have to simulate cosmetic pens by reversing the scale. + VGfloat width = pen.widthF(); + if (width <= 0.0f) + width = 1.0f; + if (pen.isCosmetic()) { + if (penScale != 1.0 && penScale != 0.0) + width /= penScale; + } + vgSetf(VG_STROKE_LINE_WIDTH, width); + + if (pen.capStyle() == Qt::FlatCap) + vgSetf(VG_STROKE_CAP_STYLE, VG_CAP_BUTT); + else if (pen.capStyle() == Qt::SquareCap) + vgSetf(VG_STROKE_CAP_STYLE, VG_CAP_SQUARE); + else + vgSetf(VG_STROKE_CAP_STYLE, VG_CAP_ROUND); + + if (pen.joinStyle() == Qt::MiterJoin) { + vgSetf(VG_STROKE_JOIN_STYLE, VG_JOIN_MITER); + vgSetf(VG_STROKE_MITER_LIMIT, pen.miterLimit()); + } else if (pen.joinStyle() == Qt::BevelJoin) { + vgSetf(VG_STROKE_JOIN_STYLE, VG_JOIN_BEVEL); + } else { + vgSetf(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND); + } + + if (pen.style() == Qt::SolidLine) { + vgSetfv(VG_STROKE_DASH_PATTERN, 0, NULL); + } else { + const QVector dashPattern = pen.dashPattern(); + QVector currentDashPattern(dashPattern.count()); + for (int i = 0; i < dashPattern.count(); ++i) + currentDashPattern[i] = dashPattern[i] * width; + vgSetfv(VG_STROKE_DASH_PATTERN, currentDashPattern.count(), currentDashPattern.data()); + vgSetf(VG_STROKE_DASH_PHASE, pen.dashOffset()); + vgSetf(VG_STROKE_DASH_PHASE_RESET, VG_FALSE); + } +} + +void QVGPaintEnginePrivate::setBrushTransform + (const QBrush& brush, VGMatrixMode mode) +{ + // Compute the new brush transformation matrix. + QTransform transform(brush.transform()); + if (brushOrigin.x() != 0.0f || brushOrigin.y() != 0.0f) + transform.translate(brushOrigin.x(), brushOrigin.y()); + + // Bail out if the matrix is the same as last time, to avoid + // updating the VG context state unless absolutely necessary. + // Most applications won't have a brush transformation set, + // which will leave the VG setting at its default of identity. + // Always change the transform if coming out of raw VG mode. + if (mode == VG_MATRIX_FILL_PAINT_TO_USER) { + if (!rawVG && transform == brushTransform) + return; + brushTransform = transform; + } else { + if (!rawVG && transform == penTransform) + return; + penTransform = transform; + } + + // Set the brush transformation matrix. + if (mode != matrixMode) { + vgSeti(VG_MATRIX_MODE, mode); + matrixMode = mode; + } + if (transform.isIdentity()) { + vgLoadIdentity(); + } else { + VGfloat mat[9]; + mat[0] = transform.m11(); + mat[1] = transform.m12(); + mat[2] = transform.m13(); + mat[3] = transform.m21(); + mat[4] = transform.m22(); + mat[5] = transform.m23(); + mat[6] = transform.m31(); + mat[7] = transform.m32(); + mat[8] = transform.m33(); + vgLoadMatrix(mat); + } +} + +void QVGPaintEnginePrivate::setupColorRamp(const QGradient *grad, VGPaint paint) +{ + QGradient::Spread spread = grad->spread(); + VGColorRampSpreadMode spreadMode; + if (spread == QGradient::ReflectSpread) + spreadMode = VG_COLOR_RAMP_SPREAD_REFLECT; + else if (spread == QGradient::RepeatSpread) + spreadMode = VG_COLOR_RAMP_SPREAD_REPEAT; + else + spreadMode = VG_COLOR_RAMP_SPREAD_PAD; + + const QGradientStops stops = grad->stops(); + int n = 5*stops.size(); + QVector fill_stops(n); + + for (int i = 0; i < stops.size(); ++i ) { + QColor col = stops[i].second; + fill_stops[i*5] = stops[i].first; + fill_stops[i*5 + 1] = col.redF(); + fill_stops[i*5 + 2] = col.greenF(); + fill_stops[i*5 + 3] = col.blueF(); + fill_stops[i*5 + 4] = col.alphaF() * opacity; + } + + vgSetParameteri(paint, VG_PAINT_COLOR_RAMP_SPREAD_MODE, spreadMode); + vgSetParameteri(paint, VG_PAINT_COLOR_RAMP_PREMULTIPLIED, VG_FALSE); + vgSetParameterfv(paint, VG_PAINT_COLOR_RAMP_STOPS, n, fill_stops.data()); +} + +QVGPainterState::QVGPainterState(QVGPainterState& other) + : QPainterState(other), + isNew(true), clipRegion(other.clipRegion), + savedDirty(0) +{ +} + +QVGPainterState::QVGPainterState() + : isNew(true), savedDirty(0) +{ +} + +QVGPainterState::~QVGPainterState() +{ +} + +QVGPaintEngine::QVGPaintEngine() + : QPaintEngineEx(*new QVGPaintEnginePrivate) +{ +} + +QVGPaintEngine::QVGPaintEngine(QVGPaintEnginePrivate &data) + : QPaintEngineEx(data) +{ +} + +QVGPaintEngine::~QVGPaintEngine() +{ +} + +QPainterState *QVGPaintEngine::createState(QPainterState *orig) const +{ + if (!orig) { + return new QVGPainterState(); + } else { + QVGPaintEnginePrivate *d = + static_cast(d_ptr); + QVGPainterState *origState = static_cast(orig); + origState->savedDirty = d->dirty; + d->dirty = 0; + return new QVGPainterState(*origState); + } +} + +void QVGPaintEnginePrivate::draw + (VGPath path, const QPen& pen, const QBrush& brush, VGint rule) +{ + VGbitfield mode = 0; + if (pen.style() != Qt::NoPen) { + ensurePen(pen); + mode |= VG_STROKE_PATH; + } + if (brush.style() != Qt::NoBrush) { + ensureBrush(brush); + setFillRule(rule); + mode |= VG_FILL_PATH; + } + if (mode != 0) { + ensurePathTransform(); + vgDrawPath(path, mode); + } +} + +void QVGPaintEnginePrivate::stroke(VGPath path, const QPen& pen) +{ + if (pen.style() == Qt::NoPen) + return; + ensurePen(pen); + ensurePathTransform(); + vgDrawPath(path, VG_STROKE_PATH); +} + +void QVGPaintEnginePrivate::fill(VGPath path, const QBrush& brush, VGint rule) +{ + if (brush.style() == Qt::NoBrush) + return; + ensureBrush(brush); + setFillRule(rule); + ensurePathTransform(); + vgDrawPath(path, VG_FILL_PATH); +} + +bool QVGPaintEngine::begin(QPaintDevice *pdev) +{ + Q_UNUSED(pdev); + Q_D(QVGPaintEngine); + + // Initialize the VG painting objects if we haven't done it yet. + if (!d->penPaint) + d->initObjects(); + + // The initial clip region is the entire device area. + QVGPainterState *s = state(); + s->clipRegion = defaultClipRegion(); + + // Initialize the VG state for this paint operation. + restoreState(QPaintEngine::AllDirty); + d->dirty = 0; + d->rawVG = false; + return true; +} + +bool QVGPaintEngine::end() +{ + return true; +} + +void QVGPaintEngine::draw(const QVectorPath &path) +{ + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + VGPath vgpath = d->vectorPathToVGPath(path); + if (!path.hasWindingFill()) + d->draw(vgpath, s->pen, s->brush, VG_EVEN_ODD); + else + d->draw(vgpath, s->pen, s->brush, VG_NON_ZERO); + vgDestroyPath(vgpath); +} + +void QVGPaintEngine::fill(const QVectorPath &path, const QBrush &brush) +{ + Q_D(QVGPaintEngine); + VGPath vgpath = d->vectorPathToVGPath(path); + if (!path.hasWindingFill()) + d->fill(vgpath, brush, VG_EVEN_ODD); + else + d->fill(vgpath, brush, VG_NON_ZERO); + vgDestroyPath(vgpath); +} + +void QVGPaintEngine::stroke(const QVectorPath &path, const QPen &pen) +{ + Q_D(QVGPaintEngine); + VGPath vgpath = d->vectorPathToVGPath(path); + d->stroke(vgpath, pen); + vgDestroyPath(vgpath); +} + +// Determine if a co-ordinate transform is simple enough to allow +// rectangle-based clipping with vgMask(). Simple transforms most +// often result from origin translations. +static inline bool clipTransformIsSimple(const QTransform& transform) +{ + QTransform::TransformationType type = transform.type(); + return (type == QTransform::TxNone || type == QTransform::TxTranslate); +} + +#if defined(QVG_SCISSOR_CLIP) + +void QVGPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) +{ + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + + d->dirty |= QPaintEngine::DirtyClipRegion; + + if (op == Qt::NoClip) { + s->clipRegion = defaultClipRegion(); + updateScissor(); + return; + } + + // We aren't using masking, so handle simple QRectF's only. + if (path.shape() == QVectorPath::RectangleHint && + path.elementCount() == 4 && clipTransformIsSimple(d->transform)) { + // Clipping region that resulted from QPainter::setClipRect(QRectF). + // Convert it into a QRect and apply. + const qreal *points = path.points(); + QRectF rect(points[0], points[1], points[2] - points[0], + points[5] - points[1]); + clip(rect.toRect(), op); + } +} + +void QVGPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) +{ + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + + d->dirty |= QPaintEngine::DirtyClipRegion; + + // If we have a non-simple transform, then use path-based clipping. + if (op != Qt::NoClip && !clipTransformIsSimple(d->transform)) { + QPaintEngineEx::clip(rect, op); + return; + } + + switch (op) { + case Qt::NoClip: + { + s->clipRegion = defaultClipRegion(); + } + break; + + case Qt::ReplaceClip: + { + s->clipRegion = d->transform.map(QRegion(rect)); + } + break; + + case Qt::IntersectClip: + { + s->clipRegion = s->clipRegion.intersect(d->transform.map(QRegion(rect))); + } + break; + + case Qt::UniteClip: + { + s->clipRegion = s->clipRegion.unite(d->transform.map(QRegion(rect))); + } + break; + } + + updateScissor(); +} + +void QVGPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op) +{ + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + + d->dirty |= QPaintEngine::DirtyClipRegion; + + // If we have a non-simple transform, then use path-based clipping. + if (op != Qt::NoClip && !clipTransformIsSimple(d->transform)) { + QPaintEngineEx::clip(region, op); + return; + } + + switch (op) { + case Qt::NoClip: + { + s->clipRegion = defaultClipRegion(); + } + break; + + case Qt::ReplaceClip: + { + s->clipRegion = d->transform.map(region); + } + break; + + case Qt::IntersectClip: + { + s->clipRegion = s->clipRegion.intersect(d->transform.map(region)); + } + break; + + case Qt::UniteClip: + { + s->clipRegion = s->clipRegion.unite(d->transform.map(region)); + } + break; + } + + updateScissor(); +} + +void QVGPaintEngine::clip(const QPainterPath &path, Qt::ClipOperation op) +{ + QPaintEngineEx::clip(path, op); +} + +#else // !QVG_SCISSOR_CLIP + +void QVGPaintEngine::clip(const QVectorPath &path, Qt::ClipOperation op) +{ + Q_D(QVGPaintEngine); + + d->dirty |= QPaintEngine::DirtyClipRegion; + + if (op == Qt::NoClip) { + d->maskValid = false; + d->maskIsSet = true; + d->maskRect = QRect(); + vgSeti(VG_MASKING, VG_FALSE); + return; + } + +#if defined(QVG_NO_RENDER_TO_MASK) + // We don't have vgRenderToMask(), so handle simple QRectF's only. + if (path.shape() == QVectorPath::RectangleHint && + path.elementCount() == 4 && clipTransformIsSimple(d->transform)) { + // Clipping region that resulted from QPainter::setClipRect(QRectF). + // Convert it into a QRect and apply. + const qreal *points = path.points(); + QRectF rect(points[0], points[1], points[2] - points[0], + points[5] - points[1]); + clip(rect.toRect(), op); + } +#else + QPaintDevice *pdev = paintDevice(); + int width = pdev->width(); + int height = pdev->height(); + + if (op == Qt::ReplaceClip) { + vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height); + d->maskRect = QRect(); + } else if (!d->maskValid) { + d->ensureMask(this, width, height); + } + + d->ensurePathTransform(); + VGPath vgpath = d->vectorPathToVGPath(path); + switch (op) { + case Qt::ReplaceClip: + case Qt::UniteClip: + vgRenderToMask(vgpath, VG_FILL_PATH, VG_UNION_MASK); + break; + + case Qt::IntersectClip: + vgRenderToMask(vgpath, VG_FILL_PATH, VG_INTERSECT_MASK); + break; + + default: break; + } + vgDestroyPath(vgpath); + + vgSeti(VG_MASKING, VG_TRUE); + d->maskValid = true; + d->maskIsSet = false; +#endif +} + +void QVGPaintEngine::clip(const QRect &rect, Qt::ClipOperation op) +{ + clip(QRegion(rect), op); +} + +void QVGPaintEngine::clip(const QRegion ®ion, Qt::ClipOperation op) +{ + Q_D(QVGPaintEngine); + + d->dirty |= QPaintEngine::DirtyClipRegion; + + // If we have a non-simple transform, then use path-based clipping. + if (op != Qt::NoClip && !clipTransformIsSimple(d->transform)) { + QPaintEngineEx::clip(region, op); + return; + } + + switch (op) { + case Qt::NoClip: + { + d->maskValid = false; + d->maskIsSet = true; + d->maskRect = QRect(); + vgSeti(VG_MASKING, VG_FALSE); + } + break; + + case Qt::ReplaceClip: + { + QRegion r = d->transform.map(region); + if (isDefaultClipRegion(r)) { + // Replacing the clip with a full-window region is the + // same as turning off clipping. + if (d->maskValid) + vgSeti(VG_MASKING, VG_FALSE); + d->maskValid = false; + d->maskIsSet = true; + d->maskRect = QRect(); + } else { + // Special case: if the intersection of the system + // clip and the region is a single rectangle, then + // use the scissor for clipping. + QRegion clip = d->systemClip; + if (clip.isEmpty()) + clip = r; + else + clip = clip.intersect(r); + if (r.numRects() == 1) { + d->maskValid = false; + d->maskIsSet = false; + d->maskRect = r.boundingRect(); + vgSeti(VG_MASKING, VG_FALSE); + updateScissor(); + } else { + d->maskValid = false; + d->maskIsSet = false; + d->maskRect = QRect(); + d->modifyMask(this, VG_FILL_MASK, r); + } + } + } + break; + + case Qt::IntersectClip: + { + if (region.numRects() != 1) { + // If there is more than one rectangle, then intersecting + // the rectangles one by one in modifyMask() will not give + // the desired result. So fall back to path-based clipping. + QPaintEngineEx::clip(region, op); + return; + } + QRegion r = d->transform.map(region); + if (d->maskIsSet && isDefaultClipRegion(r)) { + // Intersecting a full-window clip with a full-window + // region is the same as turning off clipping. + if (d->maskValid) + vgSeti(VG_MASKING, VG_FALSE); + d->maskValid = false; + d->maskIsSet = true; + d->maskRect = QRect(); + } else { + d->modifyMask(this, VG_INTERSECT_MASK, r); + } + } + break; + + case Qt::UniteClip: + { + // If we already have a full-window clip, then uniting a + // region with it will do nothing. Otherwise union. + if (!(d->maskIsSet)) + d->modifyMask(this, VG_UNION_MASK, d->transform.map(region)); + } + break; + } +} + +void QVGPaintEngine::clip(const QPainterPath &path, Qt::ClipOperation op) +{ +#if !defined(QVG_NO_RENDER_TO_MASK) + Q_D(QVGPaintEngine); + + d->dirty |= QPaintEngine::DirtyClipRegion; + + if (op == Qt::NoClip) { + d->maskValid = false; + d->maskIsSet = true; + d->maskRect = QRect(); + vgSeti(VG_MASKING, VG_FALSE); + return; + } + + QPaintDevice *pdev = paintDevice(); + int width = pdev->width(); + int height = pdev->height(); + + if (op == Qt::ReplaceClip) { + vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height); + d->maskRect = QRect(); + } else if (!d->maskValid) { + d->ensureMask(this, width, height); + } + + d->ensurePathTransform(); + VGPath vgpath = d->painterPathToVGPath(path); + switch (op) { + case Qt::ReplaceClip: + case Qt::UniteClip: + vgRenderToMask(vgpath, VG_FILL_PATH, VG_UNION_MASK); + break; + + case Qt::IntersectClip: + vgRenderToMask(vgpath, VG_FILL_PATH, VG_INTERSECT_MASK); + break; + + default: break; + } + vgDestroyPath(vgpath); + + vgSeti(VG_MASKING, VG_TRUE); + d->maskValid = true; + d->maskIsSet = false; +#else + QPaintEngineEx::clip(path, op); +#endif +} + +void QVGPaintEnginePrivate::ensureMask + (QVGPaintEngine *engine, int width, int height) +{ + if (maskIsSet) { + vgMask(VG_INVALID_HANDLE, VG_FILL_MASK, 0, 0, width, height); + maskRect = QRect(); + } else { + vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, width, height); + if (!maskRect.isNull()) { + vgMask(VG_INVALID_HANDLE, VG_FILL_MASK, + maskRect.x(), height - maskRect.y() - maskRect.height(), + maskRect.width(), maskRect.height()); + maskRect = QRect(); + engine->updateScissor(); + } + } +} + +void QVGPaintEnginePrivate::modifyMask + (QVGPaintEngine *engine, VGMaskOperation op, const QRegion& region) +{ + QPaintDevice *pdev = engine->paintDevice(); + int width = pdev->width(); + int height = pdev->height(); + + if (!maskValid) + ensureMask(engine, width, height); + + QVector rects = region.rects(); + for (int i = 0; i < rects.size(); ++i) { + vgMask(VG_INVALID_HANDLE, op, + rects[i].x(), height - rects[i].y() - rects[i].height(), + rects[i].width(), rects[i].height()); + } + + vgSeti(VG_MASKING, VG_TRUE); + maskValid = true; + maskIsSet = false; +} + +#endif // !QVG_SCISSOR_CLIP + +void QVGPaintEngine::updateScissor() +{ + Q_D(QVGPaintEngine); + + QRegion region = d->systemClip; + +#if defined(QVG_SCISSOR_CLIP) + // Using the scissor to do clipping, so combine the systemClip + // with the current painting clipRegion. + QVGPainterState *s = state(); + if (s->clipEnabled) { + if (region.isEmpty()) + region = s->clipRegion; + else + region = region.intersect(s->clipRegion); + if (isDefaultClipRegion(region)) { + // The scissor region is the entire drawing surface, + // so there is no point doing any scissoring. + vgSeti(VG_SCISSORING, VG_FALSE); + d->scissorActive = false; + return; + } + } else +#endif + { +#if !defined(QVG_SCISSOR_CLIP) + // Combine the system clip with the simple mask rectangle. + if (!d->maskRect.isNull()) { + if (region.isEmpty()) + region = d->maskRect; + else + region.intersect(d->maskRect); + if (isDefaultClipRegion(region)) { + // The scissor region is the entire drawing surface, + // so there is no point doing any scissoring. + vgSeti(VG_SCISSORING, VG_FALSE); + d->scissorActive = false; + return; + } + } else +#endif + + // Disable the scissor completely if the system clip is empty. + if (region.isEmpty()) { + vgSeti(VG_SCISSORING, VG_FALSE); + d->scissorActive = false; + return; + } + } + + if (d->scissorActive && region == d->scissorRegion) + return; + + QVector rects = region.rects(); + int count = rects.count(); + if (count > d->maxScissorRects) + count = d->maxScissorRects; + QVarLengthArray params(count * 4); + int height = paintDevice()->height(); + for (int i = 0; i < count; ++i) { + params[i * 4 + 0] = rects[i].x(); + params[i * 4 + 1] = height - rects[i].y() - rects[i].height(); + params[i * 4 + 2] = rects[i].width(); + params[i * 4 + 3] = rects[i].height(); + } + + vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data()); + vgSeti(VG_SCISSORING, VG_TRUE); + d->scissorActive = true; + d->scissorRegion = region; +} + +QRegion QVGPaintEngine::defaultClipRegion() +{ + // The default clip region for a paint device is the whole drawing area. + QPaintDevice *pdev = paintDevice(); + return QRegion(0, 0, pdev->width(), pdev->height()); +} + +bool QVGPaintEngine::isDefaultClipRegion(const QRegion& region) +{ + if (region.numRects() != 1) + return false; + + QPaintDevice *pdev = paintDevice(); + int width = pdev->width(); + int height = pdev->height(); + + QRect rect = region.boundingRect(); + return (rect.x() == 0 && rect.y() == 0 && + rect.width() == width && rect.height() == height); +} + +void QVGPaintEngine::clipEnabledChanged() +{ +#if defined(QVG_SCISSOR_CLIP) + updateScissor(); +#else + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + d->dirty |= QPaintEngine::DirtyClipEnabled; + if (s->clipEnabled && s->clipOperation != Qt::NoClip) { + // Replay the entire clip stack to put the mask into the right state. + d->maskValid = false; + d->maskIsSet = true; + d->maskRect = QRect(); + s->clipRegion = defaultClipRegion(); + d->replayClipOperations(); + d->transform = s->transform(); + d->updateTransform(paintDevice()); + } else { + vgSeti(VG_MASKING, VG_FALSE); + d->maskValid = false; + d->maskIsSet = false; + d->maskRect = QRect(); + } +#endif +} + +void QVGPaintEngine::penChanged() +{ + Q_D(QVGPaintEngine); + d->dirty |= QPaintEngine::DirtyPen; +} + +void QVGPaintEngine::brushChanged() +{ + Q_D(QVGPaintEngine); + d->dirty |= QPaintEngine::DirtyBrush; +} + +void QVGPaintEngine::brushOriginChanged() +{ + Q_D(QVGPaintEngine); + d->dirty |= QPaintEngine::DirtyBrushOrigin; + d->brushOrigin = state()->brushOrigin; + d->forcePenChange = true; + d->forceBrushChange = true; +} + +void QVGPaintEngine::opacityChanged() +{ + Q_D(QVGPaintEngine); + d->dirty |= QPaintEngine::DirtyOpacity; + d->opacity = state()->opacity; + d->forcePenChange = true; + d->forceBrushChange = true; +} + +void QVGPaintEngine::compositionModeChanged() +{ + Q_D(QVGPaintEngine); + d->dirty |= QPaintEngine::DirtyCompositionMode; + + VGBlendMode vgMode = VG_BLEND_SRC_OVER; + + switch (state()->composition_mode) { + case QPainter::CompositionMode_SourceOver: + vgMode = VG_BLEND_SRC_OVER; + break; + case QPainter::CompositionMode_DestinationOver: + vgMode = VG_BLEND_DST_OVER; + break; + case QPainter::CompositionMode_Source: + vgMode = VG_BLEND_SRC; + break; + case QPainter::CompositionMode_SourceIn: + vgMode = VG_BLEND_SRC_IN; + break; + case QPainter::CompositionMode_DestinationIn: + vgMode = VG_BLEND_DST_IN; + break; + case QPainter::CompositionMode_Plus: + vgMode = VG_BLEND_ADDITIVE; + break; + case QPainter::CompositionMode_Multiply: + vgMode = VG_BLEND_MULTIPLY; + break; + case QPainter::CompositionMode_Screen: + vgMode = VG_BLEND_SCREEN; + break; + case QPainter::CompositionMode_Darken: + vgMode = VG_BLEND_DARKEN; + break; + case QPainter::CompositionMode_Lighten: + vgMode = VG_BLEND_LIGHTEN; + break; + default: + qWarning() << "QVGPaintEngine::compositionModeChanged unsupported mode" << state()->composition_mode; + break; // Fall back to VG_BLEND_SRC_OVER. + } + + d->setBlendMode(vgMode); +} + +void QVGPaintEngine::renderHintsChanged() +{ + Q_D(QVGPaintEngine); + d->dirty |= QPaintEngine::DirtyHints; + + QPainter::RenderHints hints = state()->renderHints; + + VGRenderingQuality rq = + (hints & QPainter::Antialiasing) + ? VG_RENDERING_QUALITY_BETTER + : VG_RENDERING_QUALITY_NONANTIALIASED; + VGImageQuality iq = + (hints & QPainter::SmoothPixmapTransform) + ? VG_IMAGE_QUALITY_BETTER + : VG_IMAGE_QUALITY_NONANTIALIASED; + + d->setRenderingQuality(rq); + d->setImageQuality(iq); +} + +void QVGPaintEngine::transformChanged() +{ + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + d->dirty |= QPaintEngine::DirtyTransform; + d->transform = s->transform(); + qreal oldPenScale = d->penScale; + d->updateTransform(paintDevice()); + if (d->penScale != oldPenScale) + d->forcePenChange = true; +} + +bool QVGPaintEngine::clearRect(const QRectF &rect, const QColor &color) +{ + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + if (!s->clipEnabled || s->clipOperation == Qt::NoClip) { + // The transform will either be identity or a simple translation, + // so do a simpler version of "r = d->transform.map(rect).toRect()". + QRect r = QRect(qRound(rect.x() + d->transform.dx()), + qRound(rect.y() + d->transform.dy()), + qRound(rect.width()), + qRound(rect.height())); + int height = paintDevice()->height(); + if (d->clearColor != color || d->clearOpacity != s->opacity) { + VGfloat values[4]; + values[0] = color.redF(); + values[1] = color.greenF(); + values[2] = color.blueF(); + values[3] = color.alphaF() * s->opacity; + vgSetfv(VG_CLEAR_COLOR, 4, values); + d->clearColor = color; + d->clearOpacity = s->opacity; + } + vgClear(r.x(), height - r.y() - r.height(), + r.width(), r.height()); + return true; + } + return false; +} + +void QVGPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) +{ + Q_D(QVGPaintEngine); + + if (brush.style() == Qt::NoBrush) + return; + + // Check to see if we can use vgClear() for faster filling. + if (brush.style() == Qt::SolidPattern && + clipTransformIsSimple(d->transform) && d->opacity == 1.0f && + clearRect(rect, brush.color())) { + return; + } + +#if !defined(QVG_NO_MODIFY_PATH) + VGfloat coords[8]; + if (d->simpleTransform) { + coords[0] = rect.x(); + coords[1] = rect.y(); + coords[2] = rect.x() + rect.width(); + coords[3] = coords[1]; + coords[4] = coords[2]; + coords[5] = rect.y() + rect.height(); + coords[6] = coords[0]; + coords[7] = coords[5]; + } else { + QPointF tl = d->transform.map(rect.topLeft()); + QPointF tr = d->transform.map(rect.topRight()); + QPointF bl = d->transform.map(rect.bottomLeft()); + QPointF br = d->transform.map(rect.bottomRight()); + coords[0] = tl.x(); + coords[1] = tl.y(); + coords[2] = tr.x(); + coords[3] = tr.y(); + coords[4] = br.x(); + coords[5] = br.y(); + coords[6] = bl.x(); + coords[7] = bl.y(); + } + vgModifyPathCoords(d->rectPath, 0, 4, coords); + d->fill(d->rectPath, brush); +#else + QPaintEngineEx::fillRect(rect, brush); +#endif +} + +void QVGPaintEngine::fillRect(const QRectF &rect, const QColor &color) +{ + Q_D(QVGPaintEngine); + + // Check to see if we can use vgClear() for faster filling. + if (clipTransformIsSimple(d->transform) && d->opacity == 1.0f && + clearRect(rect, color)) { + return; + } + +#if !defined(QVG_NO_MODIFY_PATH) + VGfloat coords[8]; + if (d->simpleTransform) { + coords[0] = rect.x(); + coords[1] = rect.y(); + coords[2] = rect.x() + rect.width(); + coords[3] = coords[1]; + coords[4] = coords[2]; + coords[5] = rect.y() + rect.height(); + coords[6] = coords[0]; + coords[7] = coords[5]; + } else { + QPointF tl = d->transform.map(rect.topLeft()); + QPointF tr = d->transform.map(rect.topRight()); + QPointF bl = d->transform.map(rect.bottomLeft()); + QPointF br = d->transform.map(rect.bottomRight()); + coords[0] = tl.x(); + coords[1] = tl.y(); + coords[2] = tr.x(); + coords[3] = tr.y(); + coords[4] = br.x(); + coords[5] = br.y(); + coords[6] = bl.x(); + coords[7] = bl.y(); + } + vgModifyPathCoords(d->rectPath, 0, 4, coords); + d->fill(d->rectPath, QBrush(color)); +#else + QPaintEngineEx::fillRect(rect, QBrush(color)); +#endif +} + +void QVGPaintEngine::drawRects(const QRect *rects, int rectCount) +{ +#if !defined(QVG_NO_MODIFY_PATH) + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + for (int i = 0; i < rectCount; ++i, ++rects) { + VGfloat coords[8]; + if (d->simpleTransform) { + coords[0] = rects->x(); + coords[1] = rects->y(); + coords[2] = rects->x() + rects->width(); + coords[3] = coords[1]; + coords[4] = coords[2]; + coords[5] = rects->y() + rects->height(); + coords[6] = coords[0]; + coords[7] = coords[5]; + } else { + QPointF tl = d->transform.map(QPointF(rects->x(), rects->y())); + QPointF tr = d->transform.map(QPointF(rects->x() + rects->width(), + rects->y())); + QPointF bl = d->transform.map(QPointF(rects->x(), + rects->y() + rects->height())); + QPointF br = d->transform.map(QPointF(rects->x() + rects->width(), + rects->y() + rects->height())); + coords[0] = tl.x(); + coords[1] = tl.y(); + coords[2] = tr.x(); + coords[3] = tr.y(); + coords[4] = br.x(); + coords[5] = br.y(); + coords[6] = bl.x(); + coords[7] = bl.y(); + } + vgModifyPathCoords(d->rectPath, 0, 4, coords); + d->draw(d->rectPath, s->pen, s->brush); + } +#else + QPaintEngineEx::drawRects(rects, rectCount); +#endif +} + +void QVGPaintEngine::drawRects(const QRectF *rects, int rectCount) +{ +#if !defined(QVG_NO_MODIFY_PATH) + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + for (int i = 0; i < rectCount; ++i, ++rects) { + VGfloat coords[8]; + if (d->simpleTransform) { + coords[0] = rects->x(); + coords[1] = rects->y(); + coords[2] = rects->x() + rects->width(); + coords[3] = coords[1]; + coords[4] = coords[2]; + coords[5] = rects->y() + rects->height(); + coords[6] = coords[0]; + coords[7] = coords[5]; + } else { + QPointF tl = d->transform.map(rects->topLeft()); + QPointF tr = d->transform.map(rects->topRight()); + QPointF bl = d->transform.map(rects->bottomLeft()); + QPointF br = d->transform.map(rects->bottomRight()); + coords[0] = tl.x(); + coords[1] = tl.y(); + coords[2] = tr.x(); + coords[3] = tr.y(); + coords[4] = br.x(); + coords[5] = br.y(); + coords[6] = bl.x(); + coords[7] = bl.y(); + } + vgModifyPathCoords(d->rectPath, 0, 4, coords); + d->draw(d->rectPath, s->pen, s->brush); + } +#else + QPaintEngineEx::drawRects(rects, rectCount); +#endif +} + +void QVGPaintEngine::drawLines(const QLine *lines, int lineCount) +{ +#if !defined(QVG_NO_MODIFY_PATH) + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + for (int i = 0; i < lineCount; ++i, ++lines) { + VGfloat coords[4]; + if (d->simpleTransform) { + coords[0] = lines->x1(); + coords[1] = lines->y1(); + coords[2] = lines->x2(); + coords[3] = lines->y2(); + } else { + QPointF p1 = d->transform.map(QPointF(lines->x1(), lines->y1())); + QPointF p2 = d->transform.map(QPointF(lines->x2(), lines->y2())); + coords[0] = p1.x(); + coords[1] = p1.y(); + coords[2] = p2.x(); + coords[3] = p2.y(); + } + vgModifyPathCoords(d->linePath, 0, 2, coords); + d->stroke(d->linePath, s->pen); + } +#else + QPaintEngineEx::drawLines(lines, lineCount); +#endif +} + +void QVGPaintEngine::drawLines(const QLineF *lines, int lineCount) +{ +#if !defined(QVG_NO_MODIFY_PATH) + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + for (int i = 0; i < lineCount; ++i, ++lines) { + VGfloat coords[4]; + if (d->simpleTransform) { + coords[0] = lines->x1(); + coords[1] = lines->y1(); + coords[2] = lines->x2(); + coords[3] = lines->y2(); + } else { + QPointF p1 = d->transform.map(lines->p1()); + QPointF p2 = d->transform.map(lines->p2()); + coords[0] = p1.x(); + coords[1] = p1.y(); + coords[2] = p2.x(); + coords[3] = p2.y(); + } + vgModifyPathCoords(d->linePath, 0, 2, coords); + d->stroke(d->linePath, s->pen); + } +#else + QPaintEngineEx::drawLines(lines, lineCount); +#endif +} + +void QVGPaintEngine::drawEllipse(const QRectF &r) +{ + // Based on the description of vguEllipse() in the OpenVG specification. + // We don't use vguEllipse(), to avoid unnecessary library dependencies. + Q_D(QVGPaintEngine); + if (d->simpleTransform) { + QVGPainterState *s = state(); + VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, + VG_PATH_DATATYPE_F, + 1.0f, // scale + 0.0f, // bias + 4, // segmentCapacityHint + 12, // coordCapacityHint + VG_PATH_CAPABILITY_ALL); + static VGubyte segments[4] = { + VG_MOVE_TO_ABS, + VG_SCCWARC_TO_REL, + VG_SCCWARC_TO_REL, + VG_CLOSE_PATH + }; + VGfloat coords[12]; + VGfloat halfwid = r.width() / 2; + VGfloat halfht = r.height() / 2; + coords[0] = r.x() + r.width(); + coords[1] = r.y() + halfht; + coords[2] = halfwid; + coords[3] = halfht; + coords[4] = 0.0f; + coords[5] = -r.width(); + coords[6] = 0.0f; + coords[7] = halfwid; + coords[8] = halfht; + coords[9] = 0.0f; + coords[10] = r.width(); + coords[11] = 0.0f; + vgAppendPathData(path, 4, segments, coords); + d->draw(path, s->pen, s->brush); + vgDestroyPath(path); + } else { + // The projective transform version of an ellipse is difficult. + // Generate a QVectorPath containing cubic curves and transform that. + QPaintEngineEx::drawEllipse(r); + } +} + +void QVGPaintEngine::drawEllipse(const QRect &r) +{ + drawEllipse(QRectF(r)); +} + +void QVGPaintEngine::drawPath(const QPainterPath &path) +{ + // Shortcut past the QPainterPath -> QVectorPath conversion, + // converting the QPainterPath directly into a VGPath. + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + VGPath vgpath = d->painterPathToVGPath(path); + if (path.fillRule() == Qt::OddEvenFill) + d->draw(vgpath, s->pen, s->brush, VG_EVEN_ODD); + else + d->draw(vgpath, s->pen, s->brush, VG_NON_ZERO); + vgDestroyPath(vgpath); +} + +void QVGPaintEngine::drawPoints(const QPointF *points, int pointCount) +{ +#if !defined(QVG_NO_MODIFY_PATH) + Q_D(QVGPaintEngine); + + // Set up a new pen if necessary. + QPen pen = state()->pen; + if (pen.style() == Qt::NoPen) + return; + if (pen.capStyle() == Qt::FlatCap) + pen.setCapStyle(Qt::SquareCap); + + for (int i = 0; i < pointCount; ++i, ++points) { + VGfloat coords[4]; + if (d->simpleTransform) { + coords[0] = points->x(); + coords[1] = points->y(); + coords[2] = coords[0]; + coords[3] = coords[1]; + } else { + QPointF p = d->transform.map(*points); + coords[0] = p.x(); + coords[1] = p.y(); + coords[2] = coords[0]; + coords[3] = coords[1]; + } + vgModifyPathCoords(d->linePath, 0, 2, coords); + d->stroke(d->linePath, pen); + } +#else + QPaintEngineEx::drawPoints(points, pointCount); +#endif +} + +void QVGPaintEngine::drawPoints(const QPoint *points, int pointCount) +{ +#if !defined(QVG_NO_MODIFY_PATH) + Q_D(QVGPaintEngine); + + // Set up a new pen if necessary. + QPen pen = state()->pen; + if (pen.style() == Qt::NoPen) + return; + if (pen.capStyle() == Qt::FlatCap) + pen.setCapStyle(Qt::SquareCap); + + for (int i = 0; i < pointCount; ++i, ++points) { + VGfloat coords[4]; + if (d->simpleTransform) { + coords[0] = points->x(); + coords[1] = points->y(); + coords[2] = coords[0]; + coords[3] = coords[1]; + } else { + QPointF p = d->transform.map(QPointF(*points)); + coords[0] = p.x(); + coords[1] = p.y(); + coords[2] = coords[0]; + coords[3] = coords[1]; + } + vgModifyPathCoords(d->linePath, 0, 2, coords); + d->stroke(d->linePath, pen); + } +#else + QPaintEngineEx::drawPoints(points, pointCount); +#endif +} + +void QVGPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode) +{ + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, + VG_PATH_DATATYPE_F, + 1.0f, // scale + 0.0f, // bias + pointCount + 1, // segmentCapacityHint + pointCount * 2, // coordCapacityHint + VG_PATH_CAPABILITY_ALL); + QVarLengthArray coords; + QVarLengthArray segments; + for (int i = 0; i < pointCount; ++i, ++points) { + if (d->simpleTransform) { + coords.append(points->x()); + coords.append(points->y()); + } else { + QPointF temp = d->transform.map(*points); + coords.append(temp.x()); + coords.append(temp.y()); + } + if (i == 0) + segments.append(VG_MOVE_TO_ABS); + else + segments.append(VG_LINE_TO_ABS); + } + if (mode != QPaintEngine::PolylineMode) + segments.append(VG_CLOSE_PATH); + vgAppendPathData(path, segments.count(), + segments.constData(), coords.constData()); + switch (mode) { + case QPaintEngine::WindingMode: + d->draw(path, s->pen, s->brush, VG_NON_ZERO); + break; + + case QPaintEngine::PolylineMode: + d->stroke(path, s->pen); + break; + + default: + d->draw(path, s->pen, s->brush, VG_EVEN_ODD); + break; + } + vgDestroyPath(path); +} + +void QVGPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode) +{ + Q_D(QVGPaintEngine); + QVGPainterState *s = state(); + VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD, + VG_PATH_DATATYPE_F, + 1.0f, // scale + 0.0f, // bias + pointCount + 1, // segmentCapacityHint + pointCount * 2, // coordCapacityHint + VG_PATH_CAPABILITY_ALL); + QVarLengthArray coords; + QVarLengthArray segments; + for (int i = 0; i < pointCount; ++i, ++points) { + if (d->simpleTransform) { + coords.append(points->x()); + coords.append(points->y()); + } else { + QPointF temp = d->transform.map(QPointF(*points)); + coords.append(temp.x()); + coords.append(temp.y()); + } + if (i == 0) + segments.append(VG_MOVE_TO_ABS); + else + segments.append(VG_LINE_TO_ABS); + } + if (mode != QPaintEngine::PolylineMode) + segments.append(VG_CLOSE_PATH); + vgAppendPathData(path, segments.count(), + segments.constData(), coords.constData()); + switch (mode) { + case QPaintEngine::WindingMode: + d->draw(path, s->pen, s->brush, VG_NON_ZERO); + break; + + case QPaintEngine::PolylineMode: + d->stroke(path, s->pen); + break; + + default: + d->draw(path, s->pen, s->brush, VG_EVEN_ODD); + break; + } + vgDestroyPath(path); +} + +void QVGPaintEnginePrivate::setImageOptions() +{ + if (opacity != 1.0f && simpleTransform) { + if (opacity != paintOpacity) { + VGfloat values[4]; + values[0] = 1.0f; + values[1] = 1.0f; + values[2] = 1.0f; + values[3] = opacity; + vgSetParameterfv(opacityPaint, VG_PAINT_COLOR, 4, values); + paintOpacity = opacity; + } + if (fillPaint != opacityPaint) { + vgSetPaint(opacityPaint, VG_FILL_PATH); + fillPaint = opacityPaint; + } + setImageMode(VG_DRAW_IMAGE_MULTIPLY); + } else { + setImageMode(VG_DRAW_IMAGE_NORMAL); + } +} + +static void drawVGImage(QVGPaintEnginePrivate *d, + const QRectF& r, VGImage vgImg, + const QSize& imageSize, const QRectF& sr) +{ + if (vgImg == VG_INVALID_HANDLE) + return; + VGImage child = VG_INVALID_HANDLE; + + if (sr.topLeft().isNull() && sr.size() == imageSize) { + child = vgImg; + } else { + QRect src = sr.toRect(); +#if !defined(QT_SHIVAVG) + child = vgChildImage(vgImg, src.x(), src.y(), src.width(), src.height()); +#else + child = vgImg; // XXX: ShivaVG doesn't have vgChildImage(). +#endif + } + + QTransform transform(d->imageTransform); + VGfloat scaleX = sr.width() == 0.0f ? 0.0f : r.width() / sr.width(); + VGfloat scaleY = sr.height() == 0.0f ? 0.0f : r.height() / sr.height(); + transform.translate(r.x(), r.y()); + transform.scale(scaleX, scaleY); + d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform); + + d->setImageOptions(); + vgDrawImage(child); + + if(child != vgImg) + vgDestroyImage(child); +} + +static void drawVGImage(QVGPaintEnginePrivate *d, + const QPointF& pos, VGImage vgImg) +{ + if (vgImg == VG_INVALID_HANDLE) + return; + + QTransform transform(d->imageTransform); + transform.translate(pos.x(), pos.y()); + d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform); + + d->setImageOptions(); + vgDrawImage(vgImg); +} + +// Used by qpixmapfilter_vg.cpp to draw filtered VGImage's. +void qt_vg_drawVGImage(QPainter *painter, const QPointF& pos, VGImage vgImg) +{ + QVGPaintEngine *engine = + static_cast(painter->paintEngine()); + drawVGImage(engine->vgPrivate(), pos, vgImg); +} + +void QVGPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) +{ + QPixmapData *pd = pm.pixmapData(); + if (pd->classId() == QPixmapData::OpenVGClass) { + Q_D(QVGPaintEngine); + QVGPixmapData *vgpd = static_cast(pd); + if (!vgpd->isValid()) + return; + if (d->simpleTransform) + drawVGImage(d, r, vgpd->toVGImage(), vgpd->size(), sr); + else + drawVGImage(d, r, vgpd->toVGImage(d->opacity), vgpd->size(), sr); + } else { + drawImage(r, *(pd->buffer()), sr, Qt::AutoColor); + } +} + +void QVGPaintEngine::drawPixmap(const QPointF &pos, const QPixmap &pm) +{ + QPixmapData *pd = pm.pixmapData(); + if (pd->classId() == QPixmapData::OpenVGClass) { + Q_D(QVGPaintEngine); + QVGPixmapData *vgpd = static_cast(pd); + if (!vgpd->isValid()) + return; + if (d->simpleTransform) + drawVGImage(d, pos, vgpd->toVGImage()); + else + drawVGImage(d, pos, vgpd->toVGImage(d->opacity)); + } else { + drawImage(pos, *(pd->buffer())); + } +} + +void QVGPaintEngine::drawImage + (const QRectF &r, const QImage &image, const QRectF &sr, + Qt::ImageConversionFlags flags) +{ + Q_D(QVGPaintEngine); + VGImage vgImg; + if (d->simpleTransform || d->opacity == 1.0f) + vgImg = toVGImageSubRect(image, sr.toRect(), flags); + else + vgImg = toVGImageWithOpacitySubRect(image, d->opacity, sr.toRect()); + if (vgImg != VG_INVALID_HANDLE) { + if (r.size() == sr.size()) { + drawVGImage(d, r.topLeft(), vgImg); + } else { + drawVGImage(d, r, vgImg, sr.size().toSize(), + QRectF(QPointF(0, 0), sr.size())); + } + } else { + // Monochrome images need to use the vgChildImage() path. + vgImg = toVGImage(image, flags); + drawVGImage(d, r, vgImg, image.size(), sr); + } + vgDestroyImage(vgImg); +} + +void QVGPaintEngine::drawImage(const QPointF &pos, const QImage &image) +{ + Q_D(QVGPaintEngine); + VGImage vgImg; + if (d->simpleTransform || d->opacity == 1.0f) + vgImg = toVGImage(image); + else + vgImg = toVGImageWithOpacity(image, d->opacity); + drawVGImage(d, pos, vgImg); + vgDestroyImage(vgImg); +} + +void QVGPaintEngine::drawTiledPixmap + (const QRectF &r, const QPixmap &pixmap, const QPointF &s) +{ + QBrush brush(state()->pen.color(), pixmap); + QTransform xform; + xform.translate(-s.x(), -s.y()); + brush.setTransform(xform); + fillRect(r, brush); +} + +QVGFontEngineCleaner::QVGFontEngineCleaner(QVGPaintEnginePrivate *d) + : QObject(), d_ptr(d) +{ +} + +QVGFontEngineCleaner::~QVGFontEngineCleaner() +{ +} + +void QVGFontEngineCleaner::fontEngineDestroyed() +{ +#if !defined(QVG_NO_DRAW_GLYPHS) + QFontEngine *engine = static_cast(sender()); + QVGFontCache::Iterator it = d_ptr->fontCache.find(engine); + if (it != d_ptr->fontCache.end()) { + delete it.value(); + d_ptr->fontCache.erase(it); + } +#endif +} + +#if !defined(QVG_NO_DRAW_GLYPHS) + +QVGFontGlyphCache::QVGFontGlyphCache() +{ + font = vgCreateFont(0); + scaleX = scaleY = 0.0; + memset(cachedGlyphsMask, 0, sizeof(cachedGlyphsMask)); +} + +QVGFontGlyphCache::~QVGFontGlyphCache() +{ + if (font != VG_INVALID_HANDLE) + vgDestroyFont(font); +} + +void QVGFontGlyphCache::setScaleFromText(const QTextItemInt &ti) +{ + QFontInfo fi(ti.font()); + qreal pixelSize = fi.pixelSize(); + qreal emSquare = ti.fontEngine->properties().emSquare.toReal(); + scaleX = scaleY = static_cast(pixelSize / emSquare); +} + +void QVGFontGlyphCache::cacheGlyphs + (QVGPaintEnginePrivate *d, const QTextItemInt &ti, + const QVarLengthArray &glyphs) +{ + VGfloat origin[2]; + VGfloat escapement[2]; + const glyph_t *g = glyphs.constData(); + int count = glyphs.size(); + glyph_metrics_t metrics; + // Some Qt font engines don't set yoff in getUnscaledGlyph(). + // Zero the metric structure so that everything has a default value. + memset(&metrics, 0, sizeof(metrics)); + while (count-- > 0) { + // Skip this glyph if we have already cached it before. + glyph_t glyph = *g++; + if (glyph < 256) { + if ((cachedGlyphsMask[glyph / 32] & (1 << (glyph % 32))) != 0) + continue; + cachedGlyphsMask[glyph / 32] |= (1 << (glyph % 32)); + } else if (cachedGlyphs.contains(glyph)) { + continue; + } else { + cachedGlyphs.insert(glyph); + } +#if !defined(QVG_NO_IMAGE_GLYPHS) + Q_UNUSED(d); + QImage scaledImage = ti.fontEngine->alphaMapForGlyph(glyph); + VGImage vgImage = VG_INVALID_HANDLE; + metrics = ti.fontEngine->boundingBox(glyph); + if (!scaledImage.isNull()) { // Not a space character + // The QPF implementation of alphaMapForGlyph() uses the color + // RGBA = (value, value, value, 255) instead of the color + // RGBA = (0, 0, 0, value) that the other font engines use. + // We modify the image colors to rectify this situation. + QFontEngine::Type type = ti.fontEngine->type(); + if (type == QFontEngine::QPF1 || type == QFontEngine::QPF2) { + if (scaledImage.format() == QImage::Format_Indexed8) { + for (int i = 0; i < 256; ++i) + scaledImage.setColor(i, qRgba(0, 0, 0, i)); + } else if (scaledImage.format() == QImage::Format_Mono) { + scaledImage.setColor(0, qRgba(0, 0, 0, 0)); + scaledImage.setColor(1, qRgba(0, 0, 0, 255)); + } + } + if (scaledImage.format() == QImage::Format_Indexed8) { + vgImage = vgCreateImage(VG_A_8, scaledImage.width(), scaledImage.height(), VG_IMAGE_QUALITY_FASTER); + vgImageSubData(vgImage, scaledImage.bits(), scaledImage.bytesPerLine(), VG_A_8, 0, 0, scaledImage.width(), scaledImage.height()); + } else if (scaledImage.format() == QImage::Format_Mono) { + QImage img = scaledImage.convertToFormat(QImage::Format_Indexed8); + vgImage = vgCreateImage(VG_A_8, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); + vgImageSubData(vgImage, img.bits(), img.bytesPerLine(), VG_A_8, 0, 0, img.width(), img.height()); + } else { + QImage img = scaledImage.convertToFormat(QImage::Format_ARGB32_Premultiplied); + vgImage = vgCreateImage(VG_sARGB_8888_PRE, img.width(), img.height(), VG_IMAGE_QUALITY_FASTER); + vgImageSubData(vgImage, img.bits(), img.bytesPerLine(), VG_sARGB_8888_PRE, 0, 0, img.width(), img.height()); + } + } + origin[0] = -metrics.x.toReal() + 0.5f; + origin[1] = -metrics.y.toReal() + 0.5f; + escapement[0] = metrics.xoff.toReal(); + escapement[1] = metrics.yoff.toReal(); + vgSetGlyphToImage(font, glyph, vgImage, origin, escapement); + vgDestroyImage(vgImage); // Reduce reference count. +#else + // Calculate the path for the glyph and cache it. + QPainterPath path; + ti.fontEngine->getUnscaledGlyph(glyph, &path, &metrics); + VGPath vgPath; + if (!path.isEmpty()) { + vgPath = d->painterPathToVGPath(path); + } else { + // Probably a "space" character with no visible outline. + vgPath = VG_INVALID_HANDLE; + } + origin[0] = 0; + origin[1] = 0; + escapement[0] = metrics.xoff.toReal(); + escapement[1] = metrics.yoff.toReal(); + vgSetGlyphToPath(font, glyph, vgPath, VG_FALSE, origin, escapement); + vgDestroyPath(vgPath); // Reduce reference count. +#endif // !defined(QVG_NO_IMAGE_GLYPHS) + } +} + +#endif // !defined(QVG_NO_DRAW_GLYPHS) + +void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem) +{ +#if !defined(QVG_NO_DRAW_GLYPHS) + Q_D(QVGPaintEngine); + const QTextItemInt &ti = static_cast(textItem); + + // If we are not using a simple transform, then fall back + // to the default Qt path stroking algorithm. + if (!d->simpleTransform) { + QPaintEngineEx::drawTextItem(p, textItem); + return; + } + + // Get the glyphs and positions associated with the text item. + QVarLengthArray positions; + QVarLengthArray glyphs; + QTransform matrix = d->transform; + matrix.translate(p.x(), p.y()); + ti.fontEngine->getGlyphPositions + (ti.glyphs, matrix, ti.flags, glyphs, positions); + + // Find the glyph cache for this font. + QVGFontCache::ConstIterator it = d->fontCache.constFind(ti.fontEngine); + QVGFontGlyphCache *glyphCache; + if (it != d->fontCache.constEnd()) { + glyphCache = it.value(); + } else { + glyphCache = new QVGFontGlyphCache(); + if (glyphCache->font == VG_INVALID_HANDLE) { + qWarning("QVGPaintEngine::drawTextItem: OpenVG fonts are not supported by the OpenVG engine"); + delete glyphCache; + QPaintEngineEx::drawTextItem(p, textItem); + return; + } + glyphCache->setScaleFromText(ti); + d->fontCache.insert(ti.fontEngine, glyphCache); + if (!d->fontEngineCleaner) + d->fontEngineCleaner = new QVGFontEngineCleaner(d); + QObject::connect(ti.fontEngine, SIGNAL(destroyed()), + d->fontEngineCleaner, SLOT(fontEngineDestroyed())); + } + + // Set the transformation to use for drawing the current glyphs. + QTransform glyphTransform(d->pathTransform); + glyphTransform.translate(p.x(), p.y()); +#if defined(QVG_NO_IMAGE_GLYPHS) + glyphTransform.scale(glyphCache->scaleX, glyphCache->scaleY); +#endif + d->setTransform(VG_MATRIX_GLYPH_USER_TO_SURFACE, glyphTransform); + + // Add the glyphs from the text item into the glyph cache. + glyphCache->cacheGlyphs(d, ti, glyphs); + + // Set the glyph drawing origin. + VGfloat origin[2]; + origin[0] = 0; + origin[1] = 0; + vgSetfv(VG_GLYPH_ORIGIN, 2, origin); + + // Fast anti-aliasing for paths, better for images. +#if !defined(QVG_NO_IMAGE_GLYPHS) + d->setImageQuality(VG_IMAGE_QUALITY_BETTER); + d->setImageMode(VG_DRAW_IMAGE_STENCIL); +#else + d->setRenderingQuality(VG_RENDERING_QUALITY_FASTER); +#endif + + // Draw the glyphs. We need to fill with the brush associated with + // the Qt pen, not the Qt brush. + d->ensureBrush(state()->pen.brush()); + vgDrawGlyphs(glyphCache->font, glyphs.size(), (VGuint*)glyphs.data(), + NULL, NULL, VG_FILL_PATH, VG_TRUE); +#else + // OpenGL 1.0 does not have support for VGFont and glyphs, + // so fall back to the default Qt path stroking algorithm. + QPaintEngineEx::drawTextItem(p, textItem); +#endif +} + +void QVGPaintEngine::setState(QPainterState *s) +{ + Q_D(QVGPaintEngine); + QPaintEngineEx::setState(s); + QVGPainterState *ps = static_cast(s); + if (ps->isNew) { + // Newly created state object. The call to setState() + // will either be followed by a call to begin(), or we are + // setting the state as part of a save(). + ps->isNew = false; + } else { + // This state object was set as part of a restore(). + restoreState(d->dirty); + d->dirty = ps->savedDirty; + } +} + +// Called from QPaintEngine::syncState() to force a state flush. +// This should be called before and after raw VG operations. +void QVGPaintEngine::updateState(const QPaintEngineState &state) +{ + Q_UNUSED(state); + Q_D(QVGPaintEngine); + + if (!(d->rawVG)) { + // About to enter raw VG mode: flush pending changes and make + // sure that all matrices are set to the current transformation. + QVGPainterState *s = this->state(); + d->ensurePen(s->pen); + d->ensureBrush(s->brush); + d->ensurePathTransform(); + d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, d->imageTransform); +#if !defined(QVG_NO_DRAW_GLYPHS) + d->setTransform(VG_MATRIX_GLYPH_USER_TO_SURFACE, d->pathTransform); +#endif + d->rawVG = true; + } else { + // Exiting raw VG mode: force all state values to be + // explicitly set on the VG engine to undo any changes + // that were made by the raw VG function calls. + QPaintEngine::DirtyFlags dirty = d->dirty; + d->clearModes(); + d->forcePenChange = true; + d->forceBrushChange = true; + d->penType = (VGPaintType)0; + d->brushType = (VGPaintType)0; + d->clearColor = QColor(); + d->fillPaint = d->brushPaint; + restoreState(QPaintEngine::AllDirty); + d->dirty = dirty; + d->rawVG = false; + vgSetPaint(d->penPaint, VG_STROKE_PATH); + vgSetPaint(d->brushPaint, VG_FILL_PATH); + } +} + +QPixmapFilter *QVGPaintEngine::createPixmapFilter(int type) const +{ +#if !defined(QT_SHIVAVG) + if (type == QPixmapFilter::ConvolutionFilter) + return new QVGPixmapConvolutionFilter; + else if (type == QPixmapFilter::ColorizeFilter) + return new QVGPixmapColorizeFilter; + else if (type == QPixmapFilter::DropShadowFilter) + return new QVGPixmapDropShadowFilter; + else +#endif + return QPaintEngineEx::createPixmapFilter(type); +} + +void QVGPaintEngine::restoreState(QPaintEngine::DirtyFlags dirty) +{ + Q_D(QVGPaintEngine); + + // Restore the pen, brush, and other settings. + if ((dirty & QPaintEngine::DirtyBrushOrigin) != 0) + brushOriginChanged(); + d->fillRule = 0; + if ((dirty & QPaintEngine::DirtyOpacity) != 0) + opacityChanged(); + if ((dirty & QPaintEngine::DirtyTransform) != 0) + transformChanged(); + if ((dirty & QPaintEngine::DirtyCompositionMode) != 0) + compositionModeChanged(); + if ((dirty & QPaintEngine::DirtyHints) != 0) + renderHintsChanged(); + if ((dirty & (QPaintEngine::DirtyClipRegion | + QPaintEngine::DirtyClipPath | + QPaintEngine::DirtyClipEnabled)) != 0) { + d->maskValid = false; + d->maskIsSet = false; + d->maskRect = QRect(); + clipEnabledChanged(); + } + +#if defined(QVG_SCISSOR_CLIP) + if ((dirty & (QPaintEngine::DirtyClipRegion | + QPaintEngine::DirtyClipPath | + QPaintEngine::DirtyClipEnabled)) == 0) { + updateScissor(); + } +#else + updateScissor(); +#endif +} + +#if !defined(QVG_NO_SINGLE_CONTEXT) && !defined(QT_NO_EGL) + +QVGCompositionHelper::QVGCompositionHelper() +{ + d = qt_vg_create_paint_engine()->vgPrivate(); +} + +QVGCompositionHelper::~QVGCompositionHelper() +{ +} + +void QVGCompositionHelper::startCompositing(const QSize& screenSize) +{ + this->screenSize = screenSize; + clearScissor(); + d->setBlendMode(VG_BLEND_SRC_OVER); +} + +void QVGCompositionHelper::endCompositing() +{ + clearScissor(); +} + +void QVGCompositionHelper::blitWindow + (QVGEGLWindowSurfacePrivate *surface, const QRect& rect, + const QPoint& topLeft, int opacity) +{ + // Get the VGImage that is acting as a back buffer for the window. + VGImage image = surface->surfaceImage(); + if (image == VG_INVALID_HANDLE) + return; + QSize imageSize = surface->surfaceSize(); + + // Determine which sub rectangle of the window to draw. + QRect sr = rect.translated(-topLeft); + + if (opacity >= 255) { + // Fully opaque: use vgSetPixels() to directly copy the sub-region. + int y = screenSize.height() - (rect.bottom() + 1); + vgSetPixels(rect.x(), y, image, sr.x(), + imageSize.height() - (sr.y() + sr.height()), + sr.width(), sr.height()); + } else { + // Extract the child image that we want to draw. + VGImage child; + if (sr.topLeft().isNull() && sr.size() == imageSize) + child = image; + else { + child = vgChildImage + (image, sr.x(), imageSize.height() - (sr.y() + sr.height()), + sr.width(), sr.height()); + } + + // Set the image transform. + QTransform transform; + int y = screenSize.height() - (rect.bottom() + 1); + transform.translate(rect.x() + 0.5f, y + 0.5f); + d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform); + + // Enable opacity for image drawing if necessary. + if (opacity < 255) { + if (opacity != d->paintOpacity) { + VGfloat values[4]; + values[0] = 1.0f; + values[1] = 1.0f; + values[2] = 1.0f; + values[3] = ((VGfloat)opacity) / 255.0f; + vgSetParameterfv(d->opacityPaint, VG_PAINT_COLOR, 4, values); + d->paintOpacity = values[3]; + } + if (d->fillPaint != d->opacityPaint) { + vgSetPaint(d->opacityPaint, VG_FILL_PATH); + d->fillPaint = d->opacityPaint; + } + d->setImageMode(VG_DRAW_IMAGE_MULTIPLY); + } else { + d->setImageMode(VG_DRAW_IMAGE_NORMAL); + } + + // Draw the child image. + vgDrawImage(child); + + // Destroy the child image. + if(child != image) + vgDestroyImage(child); + } +} + +static void fillBackgroundRect(const QRect& rect, QVGPaintEnginePrivate *d) +{ + VGfloat coords[8]; + coords[0] = rect.x(); + coords[1] = rect.y(); + coords[2] = rect.x() + rect.width(); + coords[3] = coords[1]; + coords[4] = coords[2]; + coords[5] = rect.y() + rect.height(); + coords[6] = coords[0]; + coords[7] = coords[5]; +#if !defined(QVG_NO_MODIFY_PATH) + vgModifyPathCoords(d->rectPath, 0, 4, coords); + vgDrawPath(d->rectPath, VG_FILL_PATH); +#else + Q_UNUSED(d); + VGPath rectPath = vgCreatePath + (VG_PATH_FORMAT_STANDARD, + VG_PATH_DATATYPE_F, + 1.0f, // scale + 0.0f, // bias + 5, // segmentCapacityHint + 8, // coordCapacityHint + VG_PATH_CAPABILITY_ALL); + static VGubyte const segments[5] = { + VG_MOVE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_LINE_TO_ABS, + VG_CLOSE_PATH + }; + vgAppendPathData(rectPath, 5, segments, coords); + vgDrawPath(rectPath, VG_FILL_PATH); + vgDestroyPath(rectPath); +#endif +} + +void QVGCompositionHelper::fillBackground + (const QRegion& region, const QBrush& brush) +{ + // Set the path transform to the default viewport transformation. + VGfloat devh = screenSize.height() - 1; + QTransform viewport(1.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.5f, devh + 0.5f, 1.0f); + d->setTransform(VG_MATRIX_PATH_USER_TO_SURFACE, viewport); + + // Set the brush to use to fill the background. + d->ensureBrush(brush); + d->setFillRule(VG_EVEN_ODD); + + if (region.numRects() == 1) { + fillBackgroundRect(region.boundingRect(), d); + } else { + const QVector rects = region.rects(); + for (int i = 0; i < rects.size(); ++i) + fillBackgroundRect(rects.at(i), d); + } + + // We will need to reset the path transform during the next paint. + d->pathTransformSet = false; +} + +void QVGCompositionHelper::drawCursorImage + (const QImage& image, const QPoint& offset) +{ + QImage img = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); + + VGImage vgImg = vgCreateImage + (VG_sARGB_8888_PRE, img.width(), img.height(), + VG_IMAGE_QUALITY_FASTER); + vgImageSubData + (vgImg, img.bits() + img.bytesPerLine() * (img.height() - 1), + -(img.bytesPerLine()), VG_sARGB_8888_PRE, 0, 0, + img.width(), img.height()); + + QTransform transform; + int y = screenSize.height() - (offset.y() + img.height()); + transform.translate(offset.x() + 0.5f, y + 0.5f); + d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform); + + d->setImageMode(VG_DRAW_IMAGE_NORMAL); + vgDrawImage(vgImg); + + vgDestroyImage(vgImg); +} + +void QVGCompositionHelper::drawCursorPixmap + (const QPixmap& pixmap, const QPoint& offset) +{ + QPixmapData *pd = pixmap.pixmapData(); + if (pd->classId() == QPixmapData::OpenVGClass) { + QVGPixmapData *vgpd = static_cast(pd); + if (vgpd->isValid()) { + VGfloat devh = screenSize.height() - 1; + QTransform transform(1.0f, 0.0f, 0.0f, + 0.0f, -1.0f, 0.0f, + 0.5f, devh + 0.5f, 1.0f); + transform.translate(offset.x(), offset.y()); + d->setTransform(VG_MATRIX_IMAGE_USER_TO_SURFACE, transform); + + d->setImageMode(VG_DRAW_IMAGE_NORMAL); + vgDrawImage(vgpd->toVGImage()); + return; + } + } + + drawCursorImage(pixmap.toImage(), offset); +} + +void QVGCompositionHelper::setScissor(const QRegion& region) +{ + QVector rects = region.rects(); + int count = rects.count(); + if (count > d->maxScissorRects) + count = d->maxScissorRects; + QVarLengthArray params(count * 4); + int height = screenSize.height(); + for (int i = 0; i < count; ++i) { + params[i * 4 + 0] = rects[i].x(); + params[i * 4 + 1] = height - rects[i].y() - rects[i].height(); + params[i * 4 + 2] = rects[i].width(); + params[i * 4 + 3] = rects[i].height(); + } + + vgSetiv(VG_SCISSOR_RECTS, count * 4, params.data()); + vgSeti(VG_SCISSORING, VG_TRUE); + d->scissorActive = true; + d->scissorRegion = region; +} + +void QVGCompositionHelper::clearScissor() +{ + if (d->scissorActive) { + vgSeti(VG_SCISSORING, VG_FALSE); + d->scissorActive = false; + } +} + +#endif // !QVG_NO_SINGLE_CONTEXT && !QT_NO_EGL + +VGImageFormat qt_vg_image_to_vg_format(QImage::Format format) +{ + switch (format) { + case QImage::Format_MonoLSB: + return VG_BW_1; + case QImage::Format_ARGB32_Premultiplied: + return VG_sARGB_8888_PRE; + case QImage::Format_RGB32: + return VG_sXRGB_8888; + case QImage::Format_ARGB32: + return VG_sARGB_8888; + case QImage::Format_RGB16: + return VG_sRGB_565; + case QImage::Format_ARGB4444_Premultiplied: + return VG_sARGB_4444; + default: break; + } + return VG_sARGB_8888; // XXX +} + +QT_END_NAMESPACE + +#include "qpaintengine_vg.moc" diff --git a/src/openvg/qpaintengine_vg_p.h b/src/openvg/qpaintengine_vg_p.h new file mode 100644 index 0000000..a390c80 --- /dev/null +++ b/src/openvg/qpaintengine_vg_p.h @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPAINTENGINE_VG_P_H +#define QPAINTENGINE_VG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QVGPaintEnginePrivate; +class QPixmapData; +class QVGEGLWindowSurfacePrivate; + +class Q_OPENVG_EXPORT QVGPainterState : public QPainterState +{ +public: + QVGPainterState(QVGPainterState& other); + QVGPainterState(); + ~QVGPainterState(); + + bool isNew; + QRegion clipRegion; + QPaintEngine::DirtyFlags savedDirty; +}; + +class Q_OPENVG_EXPORT QVGPaintEngine : public QPaintEngineEx +{ + Q_DECLARE_PRIVATE(QVGPaintEngine) +public: + QVGPaintEngine(); + ~QVGPaintEngine(); + + Type type() const { return OpenVG; } + + QPainterState *createState(QPainterState *orig) const; + + bool begin(QPaintDevice *pdev); + bool end(); + + void draw(const QVectorPath &path); + void fill(const QVectorPath &path, const QBrush &brush); + void stroke(const QVectorPath &path, const QPen &pen); + + void clip(const QVectorPath &path, Qt::ClipOperation op); + void clip(const QRect &rect, Qt::ClipOperation op); + void clip(const QRegion ®ion, Qt::ClipOperation op); + void clip(const QPainterPath &path, Qt::ClipOperation op); + + void clipEnabledChanged(); + void penChanged(); + void brushChanged(); + void brushOriginChanged(); + void opacityChanged(); + void compositionModeChanged(); + void renderHintsChanged(); + void transformChanged(); + + void fillRect(const QRectF &rect, const QBrush &brush); + void fillRect(const QRectF &rect, const QColor &color); + + void drawRects(const QRect *rects, int rectCount); + void drawRects(const QRectF *rects, int rectCount); + + void drawLines(const QLine *lines, int lineCount); + void drawLines(const QLineF *lines, int lineCount); + + void drawEllipse(const QRectF &r); + void drawEllipse(const QRect &r); + + void drawPath(const QPainterPath &path); + + void drawPoints(const QPointF *points, int pointCount); + void drawPoints(const QPoint *points, int pointCount); + + void drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode); + void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode); + + void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr); + void drawPixmap(const QPointF &pos, const QPixmap &pm); + + void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, + Qt::ImageConversionFlags flags = Qt::AutoColor); + void drawImage(const QPointF &pos, const QImage &image); + + void drawTiledPixmap(const QRectF &r, const QPixmap &pixmap, const QPointF &s); + + void drawTextItem(const QPointF &p, const QTextItem &textItem); + + void setState(QPainterState *s); + QVGPainterState *state() { return static_cast(QPaintEngineEx::state()); } + const QVGPainterState *state() const { return static_cast(QPaintEngineEx::state()); } + + void updateState(const QPaintEngineState &state); + + QPixmapFilter *createPixmapFilter(int type) const; + + QVGPaintEnginePrivate *vgPrivate() { Q_D(QVGPaintEngine); return d; } + +protected: + QVGPaintEngine(QVGPaintEnginePrivate &data); + +private: + void restoreState(QPaintEngine::DirtyFlags dirty); + void updateScissor(); + QRegion defaultClipRegion(); + bool isDefaultClipRegion(const QRegion& region); + bool clearRect(const QRectF &rect, const QColor &color); +}; + + +QT_END_NAMESPACE + +#endif diff --git a/src/openvg/qpixmapdata_vg.cpp b/src/openvg/qpixmapdata_vg.cpp new file mode 100644 index 0000000..90fd9a5 --- /dev/null +++ b/src/openvg/qpixmapdata_vg.cpp @@ -0,0 +1,344 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpixmapdata_vg_p.h" +#include "qpaintengine_vg_p.h" +#include +#include "qvg_p.h" + +QT_BEGIN_NAMESPACE + +static int qt_vg_pixmap_serial = 0; + +QVGPixmapData::QVGPixmapData(PixelType type) + : QPixmapData(type, OpenVGClass) +{ + Q_ASSERT(type == QPixmapData::PixmapType); + vgImage = VG_INVALID_HANDLE; + vgImageOpacity = VG_INVALID_HANDLE; + cachedOpacity = 1.0f; + recreate = true; +#if !defined(QT_NO_EGL) + context = 0; +#endif + setSerialNumber(++qt_vg_pixmap_serial); +} + +QVGPixmapData::~QVGPixmapData() +{ + if (vgImage != VG_INVALID_HANDLE) { + // We need to have a context current to destroy the image. +#if !defined(QT_NO_EGL) + if (context->isCurrent()) { + vgDestroyImage(vgImage); + if (vgImageOpacity != VG_INVALID_HANDLE) + vgDestroyImage(vgImageOpacity); + } else { + // We don't currently have a widget surface active, but we + // need a surface to make the context current. So use the + // shared pbuffer surface instead. + qt_vg_make_current(context, qt_vg_shared_surface()); + vgDestroyImage(vgImage); + if (vgImageOpacity != VG_INVALID_HANDLE) + vgDestroyImage(vgImageOpacity); + qt_vg_done_current(context); + context->setSurface(EGL_NO_SURFACE); + } +#else + vgDestroyImage(vgImage); + if (vgImageOpacity != VG_INVALID_HANDLE) + vgDestroyImage(vgImageOpacity); + } else { +#endif + } +#if !defined(QT_NO_EGL) + if (context) + qt_vg_destroy_context(context); +#endif +} + +bool QVGPixmapData::isValid() const +{ + return (w > 0 && h > 0); +} + +void QVGPixmapData::resize(int wid, int ht) +{ + if (w == wid && h == ht) + return; + + w = wid; + h = ht; + d = 32; // We always use ARGB_Premultiplied for VG pixmaps. + is_null = (w <= 0 || h <= 0); + source = QImage(); + recreate = true; + + setSerialNumber(++qt_vg_pixmap_serial); +} + +void QVGPixmapData::fromImage + (const QImage &image, Qt::ImageConversionFlags flags) +{ + if (image.size() == QSize(w, h)) + setSerialNumber(++qt_vg_pixmap_serial); + else + resize(image.width(), image.height()); + source = image.convertToFormat(sourceFormat(), flags); + recreate = true; +} + +void QVGPixmapData::fill(const QColor &color) +{ + if (!isValid()) + return; + + if (source.isNull()) + source = QImage(w, h, sourceFormat()); + + if (source.depth() == 1) { + // Pick the best approximate color in the image's colortable. + int gray = qGray(color.rgba()); + if (qAbs(qGray(source.color(0)) - gray) < qAbs(qGray(source.color(1)) - gray)) + source.fill(0); + else + source.fill(1); + } else { + source.fill(PREMUL(color.rgba())); + } + + // Re-upload the image to VG the next time toVGImage() is called. + recreate = true; +} + +bool QVGPixmapData::hasAlphaChannel() const +{ + if (!source.isNull()) + return source.hasAlphaChannel(); + else + return isValid(); +} + +void QVGPixmapData::setAlphaChannel(const QPixmap &alphaChannel) +{ + forceToImage(); + source.setAlphaChannel(alphaChannel.toImage()); +} + +QImage QVGPixmapData::toImage() const +{ + if (!isValid()) + return QImage(); + + if (source.isNull()) { + source = QImage(w, h, sourceFormat()); + recreate = true; + } + + return source; +} + +QImage *QVGPixmapData::buffer() +{ + forceToImage(); + return &source; +} + +QPaintEngine* QVGPixmapData::paintEngine() const +{ + // If the application wants to paint into the QPixmap, we first + // force it to QImage format and then paint into that. + // This is simpler than juggling multiple VG contexts. + const_cast(this)->forceToImage(); + return source.paintEngine(); +} + +VGImage QVGPixmapData::toVGImage() +{ + if (!isValid()) + return VG_INVALID_HANDLE; + +#if !defined(QT_NO_EGL) + // Increase the reference count on the shared context. + if (!context) + context = qt_vg_create_context(0); +#endif + + if (recreate) { + if (vgImage != VG_INVALID_HANDLE) { + vgDestroyImage(vgImage); + vgImage = VG_INVALID_HANDLE; + } + if (vgImageOpacity != VG_INVALID_HANDLE) { + vgDestroyImage(vgImageOpacity); + vgImageOpacity = VG_INVALID_HANDLE; + } + } + + if (vgImage == VG_INVALID_HANDLE) { + vgImage = vgCreateImage + (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER); + } + + if (!source.isNull() && recreate) { + vgImageSubData + (vgImage, + source.bits(), source.bytesPerLine(), + VG_sARGB_8888_PRE, 0, 0, w, h); + } + + recreate = false; + + return vgImage; +} + +VGImage QVGPixmapData::toVGImage(qreal opacity) +{ +#if !defined(QT_SHIVAVG) + if (!isValid()) + return VG_INVALID_HANDLE; + +#if !defined(QT_NO_EGL) + // Increase the reference count on the shared context. + if (!context) + context = qt_vg_create_context(0); +#endif + + if (recreate) { + if (vgImage != VG_INVALID_HANDLE) { + vgDestroyImage(vgImage); + vgImage = VG_INVALID_HANDLE; + } + if (vgImageOpacity != VG_INVALID_HANDLE) { + vgDestroyImage(vgImageOpacity); + vgImageOpacity = VG_INVALID_HANDLE; + } + } + + if (vgImage == VG_INVALID_HANDLE) { + vgImage = vgCreateImage + (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER); + } + + if (!source.isNull() && recreate) { + vgImageSubData + (vgImage, + source.bits(), source.bytesPerLine(), + VG_sARGB_8888_PRE, 0, 0, w, h); + } + + recreate = false; + + if (opacity == 1.0f) + return vgImage; + + if (vgImageOpacity == VG_INVALID_HANDLE || cachedOpacity != opacity) { + if (vgImageOpacity == VG_INVALID_HANDLE) { + vgImageOpacity = vgCreateImage + (VG_sARGB_8888_PRE, w, h, VG_IMAGE_QUALITY_FASTER); + } + VGfloat matrix[20] = { + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, opacity, + 0.0f, 0.0f, 0.0f, 0.0f + }; + vgColorMatrix(vgImageOpacity, vgImage, matrix); + cachedOpacity = opacity; + } + + return vgImageOpacity; +#else + // vgColorMatrix() doesn't work with ShivaVG, so ignore the opacity. + Q_UNUSED(opacity); + return toVGImage(); +#endif +} + +extern int qt_defaultDpiX(); +extern int qt_defaultDpiY(); + +int QVGPixmapData::metric(QPaintDevice::PaintDeviceMetric metric) const +{ + switch (metric) { + case QPaintDevice::PdmWidth: + return w; + case QPaintDevice::PdmHeight: + return h; + case QPaintDevice::PdmNumColors: + return 0; + case QPaintDevice::PdmDepth: + return d; + case QPaintDevice::PdmWidthMM: + return qRound(w * 25.4 / qt_defaultDpiX()); + case QPaintDevice::PdmHeightMM: + return qRound(h * 25.4 / qt_defaultDpiY()); + case QPaintDevice::PdmDpiX: + case QPaintDevice::PdmPhysicalDpiX: + return qt_defaultDpiX(); + case QPaintDevice::PdmDpiY: + case QPaintDevice::PdmPhysicalDpiY: + return qt_defaultDpiY(); + default: + qWarning("QVGPixmapData::metric(): Invalid metric"); + return 0; + } +} + +// Force the pixmap data to be in QImage format. +void QVGPixmapData::forceToImage() +{ + if (!isValid()) + return; + + if (source.isNull()) + source = QImage(w, h, sourceFormat()); + + recreate = true; +} + +QImage::Format QVGPixmapData::sourceFormat() const +{ + return QImage::Format_ARGB32_Premultiplied; +} + +QT_END_NAMESPACE diff --git a/src/openvg/qpixmapdata_vg_p.h b/src/openvg/qpixmapdata_vg_p.h new file mode 100644 index 0000000..bb019be --- /dev/null +++ b/src/openvg/qpixmapdata_vg_p.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPIXMAPDATA_VG_P_H +#define QPIXMAPDATA_VG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include "qvg_p.h" +#if !defined(QT_NO_EGL) +#include +#endif + +QT_BEGIN_NAMESPACE + +class QEglContext; + +class Q_OPENVG_EXPORT QVGPixmapData : public QPixmapData +{ +public: + QVGPixmapData(PixelType type); + ~QVGPixmapData(); + + // Is this pixmap valid (i.e. non-zero in size)? + bool isValid() const; + + void resize(int width, int height); + void fromImage(const QImage &image, Qt::ImageConversionFlags flags); + + void fill(const QColor &color); + bool hasAlphaChannel() const; + void setAlphaChannel(const QPixmap &alphaChannel); + QImage toImage() const; + QImage *buffer(); + QPaintEngine* paintEngine() const; + + // Return the VGImage form of this pixmap, creating it if necessary. + // This assumes that there is a VG context current. + VGImage toVGImage(); + + // Return the VGImage form for a specific opacity setting. + VGImage toVGImage(qreal opacity); + + QSize size() const { return QSize(w, h); } + +protected: + int metric(QPaintDevice::PaintDeviceMetric metric) const; + +private: + VGImage vgImage; + VGImage vgImageOpacity; + qreal cachedOpacity; + mutable QImage source; + mutable bool recreate; +#if !defined(QT_NO_EGL) + mutable QEglContext *context; +#endif + + void forceToImage(); + QImage::Format sourceFormat() const; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/openvg/qpixmapfilter_vg.cpp b/src/openvg/qpixmapfilter_vg.cpp new file mode 100644 index 0000000..ff8604b --- /dev/null +++ b/src/openvg/qpixmapfilter_vg.cpp @@ -0,0 +1,340 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpixmapfilter_vg_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +#if !defined(QT_SHIVAVG) + +QVGPixmapConvolutionFilter::QVGPixmapConvolutionFilter() + : QPixmapConvolutionFilter() +{ +} + +QVGPixmapConvolutionFilter::~QVGPixmapConvolutionFilter() +{ +} + +extern void qt_vg_drawVGImage + (QPainter *painter, const QPointF& pos, VGImage vgImg); + +void QVGPixmapConvolutionFilter::draw + (QPainter *painter, const QPointF &dest, + const QPixmap &src, const QRectF &srcRect) const +{ + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { + // The pixmap data is not an instance of QVGPixmapData, so fall + // back to the default convolution filter implementation. + QPixmapConvolutionFilter::draw(painter, dest, src, srcRect); + return; + } + + QVGPixmapData *pd = static_cast(src.pixmapData()); + + VGImage srcImage = pd->toVGImage(); + if (srcImage == VG_INVALID_HANDLE) + return; + + QSize size = pd->size(); + VGImage dstImage = vgCreateImage + (VG_sARGB_8888_PRE, size.width(), size.height(), + VG_IMAGE_QUALITY_FASTER); + if (dstImage == VG_INVALID_HANDLE) + return; + + int kernelWidth = rows(); + int kernelHeight = columns(); + const qreal *kern = convolutionKernel(); + QVarLengthArray kernel; + for (int i = 0; i < kernelWidth; ++i) { + for (int j = 0; j < kernelHeight; ++j) { + kernel.append((VGshort)(kern[j * kernelWidth + i] * 1024.0f)); + } + } + + VGfloat values[4]; + values[0] = 0.0f; + values[1] = 0.0f; + values[2] = 0.0f; + values[3] = 0.0f; + vgSetfv(VG_TILE_FILL_COLOR, 4, values); + + vgConvolve(dstImage, srcImage, + kernelWidth, kernelHeight, 0, 0, + kernel.constData(), 1.0f / 1024.0f, 0.0f, + VG_TILE_FILL); + + VGImage child = VG_INVALID_HANDLE; + + if (srcRect.isNull() || + (srcRect.topLeft().isNull() && srcRect.size() == size)) { + child = dstImage; + } else { + QRect src = srcRect.toRect(); + child = vgChildImage(dstImage, src.x(), src.y(), src.width(), src.height()); + } + + qt_vg_drawVGImage(painter, dest, child); + + if(child != dstImage) + vgDestroyImage(child); + vgDestroyImage(dstImage); +} + +QVGPixmapColorizeFilter::QVGPixmapColorizeFilter() + : QPixmapColorizeFilter(), + firstTime(true) +{ +} + +QVGPixmapColorizeFilter::~QVGPixmapColorizeFilter() +{ +} + +void QVGPixmapColorizeFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const +{ + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { + // The pixmap data is not an instance of QVGPixmapData, so fall + // back to the default convolution filter implementation. + QPixmapColorizeFilter::draw(painter, dest, src, srcRect); + return; + } + + QVGPixmapData *pd = static_cast(src.pixmapData()); + + VGImage srcImage = pd->toVGImage(); + if (srcImage == VG_INVALID_HANDLE) + return; + + QSize size = pd->size(); + VGImage dstImage = vgCreateImage + (VG_sARGB_8888_PRE, size.width(), size.height(), + VG_IMAGE_QUALITY_FASTER); + if (dstImage == VG_INVALID_HANDLE) + return; + + // Recompute the color matrix if the color has changed. + QColor c = color(); + if (c != prevColor || firstTime) { + prevColor = c; + + // Determine the weights for the matrix from the color. + VGfloat weights[3]; + VGfloat invweights[3]; + VGfloat alpha = c.alphaF(); + weights[0] = c.redF() * alpha; + weights[1] = c.greenF() * alpha; + weights[2] = c.blueF() * alpha; + invweights[0] = 1.0f - weights[0]; + invweights[1] = 1.0f - weights[1]; + invweights[2] = 1.0f - weights[2]; + + // Grayscale weights. + static const VGfloat redGray = 11.0f / 32.0f; + static const VGfloat greenGray = 16.0f / 32.0f; + static const VGfloat blueGray = 1.0f - (redGray + greenGray); + + matrix[0][0] = redGray * invweights[0]; + matrix[0][1] = redGray * invweights[1]; + matrix[0][2] = redGray * invweights[2]; + matrix[0][3] = 0.0f; + matrix[1][0] = greenGray * invweights[0]; + matrix[1][1] = greenGray * invweights[1]; + matrix[1][2] = greenGray * invweights[2]; + matrix[1][3] = 0.0f; + matrix[2][0] = blueGray * invweights[0]; + matrix[2][1] = blueGray * invweights[1]; + matrix[2][2] = blueGray * invweights[2]; + matrix[2][3] = 0.0f; + matrix[3][0] = 0.0f; + matrix[3][1] = 0.0f; + matrix[3][2] = 0.0f; + matrix[3][3] = 1.0f; + matrix[4][0] = weights[0]; + matrix[4][1] = weights[1]; + matrix[4][2] = weights[2]; + matrix[4][3] = 0.0f; + } + + firstTime = false; + + vgColorMatrix(dstImage, srcImage, matrix[0]); + + VGImage child = VG_INVALID_HANDLE; + + if (srcRect.isNull() || + (srcRect.topLeft().isNull() && srcRect.size() == size)) { + child = dstImage; + } else { + QRect src = srcRect.toRect(); + child = vgChildImage(dstImage, src.x(), src.y(), src.width(), src.height()); + } + + qt_vg_drawVGImage(painter, dest, child); + + if(child != dstImage) + vgDestroyImage(child); + vgDestroyImage(dstImage); +} + +QVGPixmapDropShadowFilter::QVGPixmapDropShadowFilter() + : QPixmapDropShadowFilter(), + prevRadius(0.0f), + kernelSize(0), + firstTime(true) +{ +} + +QVGPixmapDropShadowFilter::~QVGPixmapDropShadowFilter() +{ +} + +void QVGPixmapDropShadowFilter::draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const +{ + if (src.pixmapData()->classId() != QPixmapData::OpenVGClass) { + // The pixmap data is not an instance of QVGPixmapData, so fall + // back to the default drop shadow filter implementation. + QPixmapDropShadowFilter::draw(painter, dest, src, srcRect); + return; + } + + QVGPixmapData *pd = static_cast(src.pixmapData()); + + VGImage srcImage = pd->toVGImage(); + if (srcImage == VG_INVALID_HANDLE) + return; + + QSize size = pd->size(); + VGImage tmpImage = vgCreateImage + (VG_sARGB_8888_PRE, size.width(), size.height(), + VG_IMAGE_QUALITY_FASTER); + if (tmpImage == VG_INVALID_HANDLE) + return; + + VGImage dstImage = vgCreateImage + (VG_sARGB_8888_PRE, size.width(), size.height(), + VG_IMAGE_QUALITY_FASTER); + if (dstImage == VG_INVALID_HANDLE) { + vgDestroyImage(tmpImage); + return; + } + + // Recompute the color matrix if the color has changed. + QColor c = color(); + if (c != prevColor || firstTime) { + prevColor = c; + + matrix[0][0] = 0.0f; + matrix[0][1] = 0.0f; + matrix[0][2] = 0.0f; + matrix[0][3] = 0.0f; + matrix[1][0] = 0.0f; + matrix[1][1] = 0.0f; + matrix[1][2] = 0.0f; + matrix[1][3] = 0.0f; + matrix[2][0] = 0.0f; + matrix[2][1] = 0.0f; + matrix[2][2] = 0.0f; + matrix[2][3] = 0.0f; + matrix[3][0] = c.redF(); + matrix[3][1] = c.greenF(); + matrix[3][2] = c.blueF(); + matrix[3][3] = c.alphaF(); + matrix[4][0] = 0.0f; + matrix[4][1] = 0.0f; + matrix[4][2] = 0.0f; + matrix[4][3] = 0.0f; + } + + // Blacken the source image. + vgColorMatrix(tmpImage, srcImage, matrix[0]); + + // Recompute the convolution kernel if the blur radius has changed. + qreal radius = blurRadius(); + if (radius != prevRadius || firstTime) { + prevRadius = radius; + int dim = 2 * qRound(radius) + 1; + int size = dim * dim; + VGshort f = VGshort(1024.0f / size); + kernel.resize(size); + for (int i = 0; i < size; ++i) + kernel[i] = f; + kernelSize = dim; + } + + // Apply the convolution filter using the kernel. + VGfloat values[4]; + values[0] = 0.0f; + values[1] = 0.0f; + values[2] = 0.0f; + values[3] = 0.0f; + vgSetfv(VG_TILE_FILL_COLOR, 4, values); + vgConvolve(dstImage, tmpImage, + kernelSize, kernelSize, 0, 0, + kernel.constData(), 1.0f / 1024.0f, 0.0f, + VG_TILE_FILL); + + firstTime = false; + + VGImage child = VG_INVALID_HANDLE; + + if (srcRect.isNull() || + (srcRect.topLeft().isNull() && srcRect.size() == size)) { + child = dstImage; + } else { + QRect src = srcRect.toRect(); + child = vgChildImage(dstImage, src.x(), src.y(), src.width(), src.height()); + } + + qt_vg_drawVGImage(painter, dest + offset(), child); + + if(child != dstImage) + vgDestroyImage(child); + vgDestroyImage(tmpImage); + vgDestroyImage(dstImage); +} + +#endif + +QT_END_NAMESPACE diff --git a/src/openvg/qpixmapfilter_vg_p.h b/src/openvg/qpixmapfilter_vg_p.h new file mode 100644 index 0000000..412fb55 --- /dev/null +++ b/src/openvg/qpixmapfilter_vg_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPIXMAPFILTER_VG_P_H +#define QPIXMAPFILTER_VG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qpixmapdata_vg_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +#if !defined(QT_SHIVAVG) + +class Q_OPENVG_EXPORT QVGPixmapConvolutionFilter : public QPixmapConvolutionFilter +{ +public: + QVGPixmapConvolutionFilter(); + ~QVGPixmapConvolutionFilter(); + + void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const; +}; + +class Q_OPENVG_EXPORT QVGPixmapColorizeFilter : public QPixmapColorizeFilter +{ +public: + QVGPixmapColorizeFilter(); + ~QVGPixmapColorizeFilter(); + + void draw(QPainter *painter, const QPointF &dest, const QPixmap &src, const QRectF &srcRect) const; + +private: + mutable VGfloat matrix[5][4]; + mutable QColor prevColor; + mutable bool firstTime; +}; + +class Q_OPENVG_EXPORT QVGPixmapDropShadowFilter : public QPixmapDropShadowFilter +{ +public: + QVGPixmapDropShadowFilter(); + ~QVGPixmapDropShadowFilter(); + + void draw(QPainter *p, const QPointF &pos, const QPixmap &px, const QRectF &src) const; + +private: + mutable VGfloat matrix[5][4]; + mutable QColor prevColor; + mutable qreal prevRadius; + mutable int kernelSize; + mutable bool firstTime; + mutable QVarLengthArray kernel; +}; + +#endif + +QT_END_NAMESPACE + +#endif diff --git a/src/openvg/qvg.h b/src/openvg/qvg.h new file mode 100644 index 0000000..8da6159 --- /dev/null +++ b/src/openvg/qvg.h @@ -0,0 +1,65 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVG_H +#define QVG_H + +#include + +// Include the OpenVG headers for use in applications that +// issue raw OpenVG function calls. +#if defined(QT_LOWER_CASE_VG_INCLUDES) +#include +#else +#include +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(OpenVG) + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif diff --git a/src/openvg/qvg_p.h b/src/openvg/qvg_p.h new file mode 100644 index 0000000..7ac2430 --- /dev/null +++ b/src/openvg/qvg_p.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVG_P_H +#define QVG_P_H + +#include "qvg.h" + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#if !defined(QT_NO_EGL) +#include +#endif + +QT_BEGIN_NAMESPACE + +class QVGPaintEngine; + +#if !defined(QT_NO_EGL) + +class QEglContext; + +// Create an EGL context, but don't bind it to a surface. If single-context +// mode is enabled, this will return the previously-created context. +Q_OPENVG_EXPORT QEglContext *qt_vg_create_context(QPaintDevice *device); + +// Destroy an EGL context that was created by qt_vg_create_context(). +// If single-context mode is enabled, this will decrease the reference count. +Q_OPENVG_EXPORT void qt_vg_destroy_context(QEglContext *context); + +// Return the shared pbuffer surface that can be made current to +// destroy VGImage objects when there is no other surface available. +Q_OPENVG_EXPORT EGLSurface qt_vg_shared_surface(void); + +// Make a context current with a specific surface. +Q_OPENVG_EXPORT void qt_vg_make_current(QEglContext *context, EGLSurface surface); + +// Make a context uncurrent. +Q_OPENVG_EXPORT void qt_vg_done_current(QEglContext *context, bool force = false); + +// Destroy a surface that was previously associated with a context. +Q_OPENVG_EXPORT void qt_vg_destroy_surface(QEglContext *context, EGLSurface surface); + +// Convert the configuration format in a context to a VG or QImage format. +Q_OPENVG_EXPORT VGImageFormat qt_vg_config_to_vg_format(QEglContext *context); +Q_OPENVG_EXPORT QImage::Format qt_vg_config_to_image_format(QEglContext *context); + +#endif + +// Create a paint engine. Returns the common engine in single-context mode. +Q_OPENVG_EXPORT QVGPaintEngine *qt_vg_create_paint_engine(void); + +// Destroy a paint engine. Does nothing in single-context mode. +Q_OPENVG_EXPORT void qt_vg_destroy_paint_engine(QVGPaintEngine *engine); + +// Convert between QImage and VGImage format values. +Q_OPENVG_EXPORT VGImageFormat qt_vg_image_to_vg_format(QImage::Format format); + +QT_END_NAMESPACE + +#endif diff --git a/src/openvg/qvgcompositionhelper_p.h b/src/openvg/qvgcompositionhelper_p.h new file mode 100644 index 0000000..cdf1be9 --- /dev/null +++ b/src/openvg/qvgcompositionhelper_p.h @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QVGCOMPOSITIONHELPER_H +#define QVGCOMPOSITIONHELPER_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qwindowsurface_vgegl_p.h" + +QT_BEGIN_NAMESPACE + +#if !defined(QVG_NO_SINGLE_CONTEXT) && !defined(QT_NO_EGL) + +class QVGPaintEnginePrivate; +class QVGEGLWindowSurfacePrivate; + +class Q_OPENVG_EXPORT QVGCompositionHelper +{ +public: + QVGCompositionHelper(); + virtual ~QVGCompositionHelper(); + + void startCompositing(const QSize& screenSize); + void endCompositing(); + + void blitWindow(QVGEGLWindowSurfacePrivate *surface, const QRect& rect, + const QPoint& topLeft, int opacity); + void fillBackground(const QRegion& region, const QBrush& brush); + void drawCursorImage(const QImage& image, const QPoint& offset); + void drawCursorPixmap(const QPixmap& pixmap, const QPoint& offset); + void setScissor(const QRegion& region); + void clearScissor(); + +private: + QVGPaintEnginePrivate *d; + QSize screenSize; +}; + +#endif + +QT_END_NAMESPACE + +#endif diff --git a/src/openvg/qwindowsurface_vg.cpp b/src/openvg/qwindowsurface_vg.cpp new file mode 100644 index 0000000..c77aa93 --- /dev/null +++ b/src/openvg/qwindowsurface_vg.cpp @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsurface_vg_p.h" +#include "qwindowsurface_vgegl_p.h" +#include "qpaintengine_vg_p.h" +#include "qpixmapdata_vg_p.h" +#include "qvg_p.h" + +#if !defined(QT_NO_EGL) + +#include + +QT_BEGIN_NAMESPACE + +QVGWindowSurface::QVGWindowSurface(QWidget *window) + : QWindowSurface(window) +{ + d_ptr = QVGEGLWindowSurfacePrivate::create + (QVGEGLWindowSurfacePrivate::WindowSurface, this); +} + +QVGWindowSurface::QVGWindowSurface + (QWidget *window, QVGEGLWindowSurfacePrivate *d) + : QWindowSurface(window), d_ptr(d) +{ +} + +QVGWindowSurface::~QVGWindowSurface() +{ + delete d_ptr; +} + +QPaintDevice *QVGWindowSurface::paintDevice() +{ + d_ptr->beginPaint(window()); + return this; +} + +void QVGWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(offset); + QWidget *parent = widget->internalWinId() ? widget : widget->nativeParentWidget(); + d_ptr->endPaint(parent, region); +} + +void QVGWindowSurface::setGeometry(const QRect &rect) +{ + QWindowSurface::setGeometry(rect); + d_ptr->ensureContext(window()); +} + +bool QVGWindowSurface::scroll(const QRegion &area, int dx, int dy) +{ + return QWindowSurface::scroll(area, dx, dy); +} + +void QVGWindowSurface::beginPaint(const QRegion ®ion) +{ + // Nothing to do here. + Q_UNUSED(region); +} + +void QVGWindowSurface::endPaint(const QRegion ®ion) +{ + // Nothing to do here. + Q_UNUSED(region); +} + +QPaintEngine *QVGWindowSurface::paintEngine() const +{ + return d_ptr->paintEngine(); +} + +int QVGWindowSurface::metric(PaintDeviceMetric met) const +{ + return window()->metric(met); +} + +QT_END_NAMESPACE + +#endif diff --git a/src/openvg/qwindowsurface_vg_p.h b/src/openvg/qwindowsurface_vg_p.h new file mode 100644 index 0000000..e2ee583 --- /dev/null +++ b/src/openvg/qwindowsurface_vg_p.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSURFACE_VG_P_H +#define QWINDOWSURFACE_VG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +#if !defined(QT_NO_EGL) + +class QVGEGLWindowSurfacePrivate; + +class Q_OPENVG_EXPORT QVGWindowSurface : public QWindowSurface, public QPaintDevice +{ +public: + QVGWindowSurface(QWidget *window); + QVGWindowSurface(QWidget *window, QVGEGLWindowSurfacePrivate *d); + ~QVGWindowSurface(); + + QPaintDevice *paintDevice(); + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + void setGeometry(const QRect &rect); + bool scroll(const QRegion &area, int dx, int dy); + + void beginPaint(const QRegion ®ion); + void endPaint(const QRegion ®ion); + + QPaintEngine *paintEngine() const; + +protected: + int metric(PaintDeviceMetric metric) const; + +private: + QVGEGLWindowSurfacePrivate *d_ptr; +}; + +#endif + +QT_END_NAMESPACE + +#endif // QWINDOWSURFACE_VG_P_H diff --git a/src/openvg/qwindowsurface_vgegl.cpp b/src/openvg/qwindowsurface_vgegl.cpp new file mode 100644 index 0000000..11c7021 --- /dev/null +++ b/src/openvg/qwindowsurface_vgegl.cpp @@ -0,0 +1,751 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qwindowsurface_vgegl_p.h" +#include "qpaintengine_vg_p.h" +#include "qpixmapdata_vg_p.h" +#include "qvg_p.h" + +#if !defined(QT_NO_EGL) + +QT_BEGIN_NAMESPACE + +// Turn off "direct to window" rendering if EGL cannot support it. +#if !defined(EGL_RENDER_BUFFER) || !defined(EGL_SINGLE_BUFFER) +#if defined(QVG_DIRECT_TO_WINDOW) +#undef QVG_DIRECT_TO_WINDOW +#endif +#endif + +// Determine if preserved window contents should be used. +#if !defined(EGL_SWAP_BEHAVIOR) || !defined(EGL_BUFFER_PRESERVED) +#if !defined(QVG_NO_PRESERVED_SWAP) +#define QVG_NO_PRESERVED_SWAP 1 +#endif +#endif + +VGImageFormat qt_vg_config_to_vg_format(QEglContext *context) +{ + return qt_vg_image_to_vg_format + (qt_vg_config_to_image_format(context)); +} + +QImage::Format qt_vg_config_to_image_format(QEglContext *context) +{ + EGLint red = 0; + EGLint green = 0; + EGLint blue = 0; + EGLint alpha = 0; + context->configAttrib(EGL_RED_SIZE, &red); + context->configAttrib(EGL_GREEN_SIZE, &green); + context->configAttrib(EGL_BLUE_SIZE, &blue); + context->configAttrib(EGL_ALPHA_SIZE, &alpha); + QImage::Format argbFormat; +#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT + EGLint type = 0; + context->configAttrib(EGL_SURFACE_TYPE, &type); + if ((type & EGL_VG_ALPHA_FORMAT_PRE_BIT) != 0) + argbFormat = QImage::Format_ARGB32_Premultiplied; + else + argbFormat = QImage::Format_ARGB32; +#else + argbFormat = QImage::Format_ARGB32; +#endif + if (red == 8 && green == 8 && blue == 8 && alpha == 8) + return argbFormat; + else if (red == 8 && green == 8 && blue == 8 && alpha == 0) + return QImage::Format_RGB32; + else if (red == 5 && green == 6 && blue == 5 && alpha == 0) + return QImage::Format_RGB16; + else if (red == 4 && green == 4 && blue == 4 && alpha == 4) + return QImage::Format_ARGB4444_Premultiplied; + else + return argbFormat; // XXX +} + +static void copySubImage(QImage *image, VGImage vgImage, const QRect& rect) +{ + vgGetImageSubData + (vgImage, + image->bits() + rect.bottom() * image->bytesPerLine() + + rect.x() * (image->depth() / 8), + -(image->bytesPerLine()), + qt_vg_image_to_vg_format(image->format()), + rect.x(), (image->height() - 1) - rect.bottom(), + rect.width(), rect.height()); +} + +#if !defined(QVG_NO_SINGLE_CONTEXT) + +class QVGSharedContext +{ +public: + QVGSharedContext(); + ~QVGSharedContext(); + + QEglContext *context; + int refCount; + QVGPaintEngine *engine; + EGLSurface surface; + EGLSurface lastSurface; +}; + +QVGSharedContext::QVGSharedContext() + : context(0) + , refCount(0) + , engine(0) + , surface(EGL_NO_SURFACE) + , lastSurface(EGL_NO_SURFACE) +{ +} + +QVGSharedContext::~QVGSharedContext() +{ + if (context) + qt_vg_make_current(context, qt_vg_shared_surface()); + delete engine; + if (context) + qt_vg_done_current(context, true); + if (surface != EGL_NO_SURFACE) + qt_vg_destroy_surface(context, surface); + delete context; +} + +Q_GLOBAL_STATIC(QVGSharedContext, sharedContext); + +QVGPaintEngine *qt_vg_create_paint_engine(void) +{ + QVGSharedContext *shared = sharedContext(); + if (!shared->engine) + shared->engine = new QVGPaintEngine(); + return shared->engine; +} + +void qt_vg_destroy_paint_engine(QVGPaintEngine *engine) +{ + Q_UNUSED(engine); +} + +#else + +QVGPaintEngine *qt_vg_create_paint_engine(void) +{ + return new QVGPaintEngine(); +} + +void qt_vg_destroy_paint_engine(QVGPaintEngine *engine) +{ + delete engine; +} + +#endif + +#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT + +static bool isPremultipliedContext(const QEglContext *context) +{ + EGLint value = 0; + if (context->configAttrib(EGL_SURFACE_TYPE, &value)) + return (value & EGL_VG_ALPHA_FORMAT_PRE_BIT) != 0; + else + return false; +} + +#endif + +static QEglContext *createContext(QPaintDevice *device) +{ + QEglContext *context; + + // Create the context object and open the display. + context = new QEglContext(); + context->setApi(QEgl::OpenVG); + if (!context->openDisplay(device)) { + delete context; + return 0; + } + + // Choose an appropriate configuration for rendering into the device. + QEglProperties configProps; + configProps.setPaintDeviceFormat(device); + int redSize = configProps.value(EGL_RED_SIZE); + if (redSize == EGL_DONT_CARE || redSize == 0) + configProps.setPixelFormat(QImage::Format_ARGB32); // XXX +#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT + configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT | + EGL_VG_ALPHA_FORMAT_PRE_BIT); + configProps.setRenderableType(QEgl::OpenVG); + if (!context->chooseConfig(configProps)) { + // Try again without the "pre" bit. + configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT); + if (!context->chooseConfig(configProps)) { + delete context; + return 0; + } + } +#else + configProps.setValue(EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_PBUFFER_BIT); + configProps.setRenderableType(QEgl::OpenVG); + if (!context->chooseConfig(configProps)) { + delete context; + return 0; + } +#endif + + // Construct a new EGL context for the selected configuration. + if (!context->createContext()) { + delete context; + return 0; + } + + return context; +} + +#if !defined(QVG_NO_SINGLE_CONTEXT) + +QEglContext *qt_vg_create_context(QPaintDevice *device) +{ + QVGSharedContext *shared = sharedContext(); + if (shared->context) { + ++(shared->refCount); + return shared->context; + } else { + shared->context = createContext(device); + shared->refCount = 1; + return shared->context; + } +} + +void qt_vg_destroy_context(QEglContext *context) +{ + QVGSharedContext *shared = sharedContext(); + if (shared->context != context) { + // This is not the shared context. Shouldn't happen! + delete context; + } else if (--(shared->refCount) <= 0) { + qt_vg_make_current(shared->context, qt_vg_shared_surface()); + delete shared->engine; + shared->engine = 0; + qt_vg_done_current(shared->context, true); + if (shared->surface != EGL_NO_SURFACE) { + qt_vg_destroy_surface(shared->context, shared->surface); + shared->surface = EGL_NO_SURFACE; + } + delete shared->context; + shared->context = 0; + } +} + +EGLSurface qt_vg_shared_surface(void) +{ + QVGSharedContext *shared = sharedContext(); + if (shared->surface == EGL_NO_SURFACE) { + EGLint attribs[7]; + attribs[0] = EGL_WIDTH; + attribs[1] = 16; + attribs[2] = EGL_HEIGHT; + attribs[3] = 16; +#ifdef EGL_VG_ALPHA_FORMAT_PRE_BIT + if (isPremultipliedContext(shared->context)) { + attribs[4] = EGL_VG_ALPHA_FORMAT; + attribs[5] = EGL_VG_ALPHA_FORMAT_PRE; + attribs[6] = EGL_NONE; + } else +#endif + { + attribs[4] = EGL_NONE; + } + shared->surface = eglCreatePbufferSurface + (shared->context->display(), shared->context->config(), attribs); + } + return shared->surface; +} + +void qt_vg_make_current(QEglContext *context, EGLSurface surface) +{ + // Bail out if the context and surface are already current. + if (context->isCurrent() && context->surface() == surface) + return; + + // Are we setting the surface to the same as the last elided doneCurrent()? + QVGSharedContext *shared = sharedContext(); + if (context->isCurrent() && shared->lastSurface == surface) { + shared->lastSurface = EGL_NO_SURFACE; + context->setSurface(surface); + return; + } + + // Switch to the new context and surface. + shared->lastSurface = EGL_NO_SURFACE; + context->setSurface(surface); + context->makeCurrent(); +} + +void qt_vg_done_current(QEglContext *context, bool force) +{ + QVGSharedContext *shared = sharedContext(); + if (force) { + context->doneCurrent(); + shared->lastSurface = EGL_NO_SURFACE; + } else { + // Keep the context current for now just in case we immediately + // reuse the same surface for the next frame. + shared->lastSurface = context->surface(); + } +} + +void qt_vg_destroy_surface(QEglContext *context, EGLSurface surface) +{ + QVGSharedContext *shared = sharedContext(); + if (shared->lastSurface == surface) { + shared->lastSurface = EGL_NO_SURFACE; + context->doneCurrent(); + } + context->setSurface(surface); + context->destroySurface(); +} + +#else + +QEglContext *qt_vg_create_context(QPaintDevice *device) +{ + return createContext(device); +} + +void qt_vg_destroy_context(QEglContext *context) +{ + delete context; +} + +EGLSurface qt_vg_shared_surface(void) +{ + return EGL_NO_SURFACE; +} + +void qt_vg_make_current(QEglContext *context, EGLSurface surface) +{ + context->setSurface(surface); + context->makeCurrent(); +} + +void qt_vg_done_current(QEglContext *context, bool force) +{ + Q_UNUSED(force); + context->doneCurrent(); +} + +void qt_vg_destroy_surface(QEglContext *context, EGLSurface surface) +{ + context->setSurface(surface); + context->destroySurface(); +} + +#endif + +QVGEGLWindowSurfacePrivate::QVGEGLWindowSurfacePrivate(QWindowSurface *win) +{ + winSurface = win; + engine = 0; +} + +QVGEGLWindowSurfacePrivate::~QVGEGLWindowSurfacePrivate() +{ + // Destroy the paint engine if it hasn't been destroyed already. + destroyPaintEngine(); +} + +QVGEGLWindowSurfacePrivate *QVGEGLWindowSurfacePrivate::create + (SurfaceType type, QWindowSurface *win) +{ +#if defined(QVG_VGIMAGE_BACKBUFFERS) + if (type == VGImageSurface) + return new QVGEGLWindowSurfaceVGImage(win); + else if (type == QImageSurface) + return new QVGEGLWindowSurfaceQImage(win); +#endif + if (type == WindowSurface) + return new QVGEGLWindowSurfaceDirect(win); + return 0; +} + +QVGPaintEngine *QVGEGLWindowSurfacePrivate::paintEngine() +{ + if (!engine) + engine = qt_vg_create_paint_engine(); + return engine; +} + +VGImage QVGEGLWindowSurfacePrivate::surfaceImage() const +{ + return VG_INVALID_HANDLE; +} + +void QVGEGLWindowSurfacePrivate::destroyPaintEngine() +{ + if (engine) { + qt_vg_destroy_paint_engine(engine); + engine = 0; + } +} + +QSize QVGEGLWindowSurfacePrivate::windowSurfaceSize(QWidget *widget) const +{ + Q_UNUSED(widget); + + QRect rect = winSurface->geometry(); + QSize newSize = rect.size(); + +#if defined(Q_WS_QWS) + // Account for the widget mask, if any. + if (widget && !widget->mask().isEmpty()) { + const QRegion region = widget->mask() + & rect.translated(-widget->geometry().topLeft()); + newSize = region.boundingRect().size(); + } +#endif + + return newSize; +} + +#if defined(QVG_VGIMAGE_BACKBUFFERS) + +QVGEGLWindowSurfaceVGImage::QVGEGLWindowSurfaceVGImage(QWindowSurface *win) + : QVGEGLWindowSurfacePrivate(win) + , context(0) + , backBuffer(VG_INVALID_HANDLE) + , backBufferSurface(EGL_NO_SURFACE) + , recreateBackBuffer(false) + , isPaintingActive(false) + , windowSurface(EGL_NO_SURFACE) +{ +} + +QVGEGLWindowSurfaceVGImage::~QVGEGLWindowSurfaceVGImage() +{ + destroyPaintEngine(); + if (context) { + if (backBufferSurface != EGL_NO_SURFACE) { + // We need a current context to be able to destroy the image. + // We use the shared surface because the native window handle + // associated with "windowSurface" may have been destroyed already. + qt_vg_make_current(context, qt_vg_shared_surface()); + qt_vg_destroy_surface(context, backBufferSurface); + vgDestroyImage(backBuffer); + qt_vg_done_current(context, true); + } + if (windowSurface != EGL_NO_SURFACE) + qt_vg_destroy_surface(context, windowSurface); + qt_vg_destroy_context(context); + } +} + +QEglContext *QVGEGLWindowSurfaceVGImage::ensureContext(QWidget *widget) +{ + QSize newSize = windowSurfaceSize(widget); + if (context && size != newSize) { + // The surface size has changed, so we need to recreate + // the back buffer. Keep the same context and paint engine. + size = newSize; + if (isPaintingActive) + qt_vg_done_current(context, true); + isPaintingActive = false; + recreateBackBuffer = true; + } + if (!context) { + // Create a new EGL context. We create the surface in beginPaint(). + size = newSize; + context = qt_vg_create_context(widget); + if (!context) + return 0; + isPaintingActive = false; + } + return context; +} + +void QVGEGLWindowSurfaceVGImage::beginPaint(QWidget *widget) +{ + QEglContext *context = ensureContext(widget); + if (context) { + if (recreateBackBuffer || backBufferSurface == EGL_NO_SURFACE) { + // Create a VGImage object to act as the back buffer + // for this window. We have to create the VGImage with a + // current context, so activate the main surface for the window. + qt_vg_make_current(context, mainSurface()); + recreateBackBuffer = false; + if (backBufferSurface != EGL_NO_SURFACE) { + eglDestroySurface(context->display(), backBufferSurface); + backBufferSurface = EGL_NO_SURFACE; + } + if (backBuffer != VG_INVALID_HANDLE) { + vgDestroyImage(backBuffer); + } + VGImageFormat format = qt_vg_config_to_vg_format(context); + backBuffer = vgCreateImage + (format, size.width(), size.height(), + VG_IMAGE_QUALITY_FASTER); + if (backBuffer != VG_INVALID_HANDLE) { + // Create an EGL surface for rendering into the VGImage. + backBufferSurface = eglCreatePbufferFromClientBuffer + (context->display(), EGL_OPENVG_IMAGE, + (EGLClientBuffer)(backBuffer), + context->config(), NULL); + if (backBufferSurface == EGL_NO_SURFACE) { + vgDestroyImage(backBuffer); + backBuffer = VG_INVALID_HANDLE; + } + } + } + if (backBufferSurface != EGL_NO_SURFACE) + qt_vg_make_current(context, backBufferSurface); + else + qt_vg_make_current(context, mainSurface()); + isPaintingActive = true; + } +} + +void QVGEGLWindowSurfaceVGImage::endPaint + (QWidget *widget, const QRegion& region, QImage *image) +{ + Q_UNUSED(region); + Q_UNUSED(image); + QEglContext *context = ensureContext(widget); + if (context) { + if (backBufferSurface != EGL_NO_SURFACE) { + if (isPaintingActive) + vgFlush(); + qt_vg_done_current(context); + } + context->setSurface(EGL_NO_SURFACE); + isPaintingActive = false; + } +} + +VGImage QVGEGLWindowSurfaceVGImage::surfaceImage() const +{ + return backBuffer; +} + +EGLSurface QVGEGLWindowSurfaceVGImage::mainSurface() const +{ + if (windowSurface != EGL_NO_SURFACE) + return windowSurface; + else + return qt_vg_shared_surface(); +} + +QVGEGLWindowSurfaceQImage::QVGEGLWindowSurfaceQImage(QWindowSurface *win) + : QVGEGLWindowSurfaceVGImage(win) +{ +} + +QVGEGLWindowSurfaceQImage::~QVGEGLWindowSurfaceQImage() +{ +} + +void QVGEGLWindowSurfaceQImage::endPaint + (QWidget *widget, const QRegion& region, QImage *image) +{ + QEglContext *context = ensureContext(widget); + if (context) { + if (backBufferSurface != EGL_NO_SURFACE) { + if (isPaintingActive) + vgFlush(); + qt_vg_make_current(context, mainSurface()); + QRegion rgn = region.intersected + (QRect(0, 0, image->width(), image->height())); + if (rgn.numRects() == 1) { + copySubImage(image, backBuffer, rgn.boundingRect()); + } else { + QVector rects = rgn.rects(); + for (int index = 0; index < rects.size(); ++index) + copySubImage(image, backBuffer, rects[index]); + } + qt_vg_done_current(context); + } + context->setSurface(EGL_NO_SURFACE); + isPaintingActive = false; + } +} + +#endif // QVG_VGIMAGE_BACKBUFFERS + +QVGEGLWindowSurfaceDirect::QVGEGLWindowSurfaceDirect(QWindowSurface *win) + : QVGEGLWindowSurfacePrivate(win) + , context(0) + , isPaintingActive(false) + , needToSwap(false) + , windowSurface(EGL_NO_SURFACE) +{ +} + +QVGEGLWindowSurfaceDirect::~QVGEGLWindowSurfaceDirect() +{ +} + +QEglContext *QVGEGLWindowSurfaceDirect::ensureContext(QWidget *widget) +{ + QSize newSize = windowSurfaceSize(widget); + QEglProperties surfaceProps; + +#if defined(QVG_RECREATE_ON_SIZE_CHANGE) +#if !defined(QVG_NO_SINGLE_CONTEXT) + if (context && size != newSize) { + // The surface size has changed, so we need to recreate it. + // We can keep the same context and paint engine. + size = newSize; + if (isPaintingActive) + qt_vg_done_current(context, true); + context->setSurface(windowSurface); + context->destroySurface(); +#if defined(EGL_VG_ALPHA_FORMAT_PRE_BIT) + if (isPremultipliedContext(context)) { + surfaceProps.setValue + (EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_PRE); + } else { + surfaceProps.removeValue(EGL_VG_ALPHA_FORMAT); + } +#endif + context->createSurface(widget, &surfaceProps); + windowSurface = context->surface(); + context->setSurface(EGL_NO_SURFACE); + isPaintingActive = false; + } +#else + if (context && size != newSize) { + // The surface size has changed, so we need to recreate + // the EGL context for the widget. We also need to recreate + // the surface's paint engine if context sharing is not + // enabled because we cannot reuse the existing paint objects + // in the new context. + qt_vg_destroy_paint_engine(engine); + engine = 0; + context->setSurface(windowSurface); + context->destroySurface(); + qt_vg_destroy_context(context); + context = 0; + windowSurface = EGL_NO_SURFACE; + } +#endif +#endif + if (!context) { + // Create a new EGL context and bind it to the widget surface. + size = newSize; + context = qt_vg_create_context(widget); + if (!context) + return 0; + // We want a direct to window rendering surface if possible. +#if defined(QVG_DIRECT_TO_WINDOW) + surfaceProps.setValue(EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER); +#endif +#if defined(EGL_VG_ALPHA_FORMAT_PRE_BIT) + if (isPremultipliedContext(context)) { + surfaceProps.setValue + (EGL_VG_ALPHA_FORMAT, EGL_VG_ALPHA_FORMAT_PRE); + } else { + surfaceProps.removeValue(EGL_VG_ALPHA_FORMAT); + } +#endif + if (!context->createSurface(widget, &surfaceProps)) { + qt_vg_destroy_context(context); + context = 0; + return 0; + } + needToSwap = true; +#if defined(QVG_DIRECT_TO_WINDOW) + // Did we get a direct to window rendering surface? + EGLint buffer = 0; + if (eglQueryContext(context->display(), context->context(), + EGL_RENDER_BUFFER, &buffer) && + buffer == EGL_SINGLE_BUFFER) { + needToSwap = false; + } +#endif +#if !defined(QVG_NO_PRESERVED_SWAP) + // Try to force the surface back buffer to preserve its contents. + if (needToSwap) { + eglGetError(); // Clear error state first. + eglSurfaceAttrib(context->display(), context->surface(), + EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED); + if (eglGetError() != EGL_SUCCESS) { + qWarning("QVG: could not enable preserved swap"); + } + } +#endif + windowSurface = context->surface(); + context->setSurface(EGL_NO_SURFACE); + isPaintingActive = false; + } + return context; +} + +void QVGEGLWindowSurfaceDirect::beginPaint(QWidget *widget) +{ + QEglContext *context = ensureContext(widget); + if (context) { + qt_vg_make_current(context, windowSurface); + isPaintingActive = true; + } +} + +void QVGEGLWindowSurfaceDirect::endPaint + (QWidget *widget, const QRegion& region, QImage *image) +{ + Q_UNUSED(region); + Q_UNUSED(image); + QEglContext *context = ensureContext(widget); + if (context) { + if (needToSwap) { + if (!isPaintingActive) + qt_vg_make_current(context, windowSurface); + context->swapBuffers(); + qt_vg_done_current(context); + } else if (isPaintingActive) { + vgFlush(); + qt_vg_done_current(context); + } + context->setSurface(EGL_NO_SURFACE); + isPaintingActive = false; + } +} + +QT_END_NAMESPACE + +#endif diff --git a/src/openvg/qwindowsurface_vgegl_p.h b/src/openvg/qwindowsurface_vgegl_p.h new file mode 100644 index 0000000..aa23772 --- /dev/null +++ b/src/openvg/qwindowsurface_vgegl_p.h @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenVG module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSURFACE_VGEGL_P_H +#define QWINDOWSURFACE_VGEGL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include +#include "qvg_p.h" + +#if !defined(QT_NO_EGL) + +#include + +QT_BEGIN_NAMESPACE + +class QWindowSurface; + +class Q_OPENVG_EXPORT QVGEGLWindowSurfacePrivate +{ +public: + QVGEGLWindowSurfacePrivate(QWindowSurface *win); + virtual ~QVGEGLWindowSurfacePrivate(); + + enum SurfaceType + { + WindowSurface, + VGImageSurface, + QImageSurface + }; + + static QVGEGLWindowSurfacePrivate *create + (SurfaceType type, QWindowSurface *win); + + QVGPaintEngine *paintEngine(); + virtual QEglContext *ensureContext(QWidget *widget) = 0; + virtual void beginPaint(QWidget *widget) = 0; + virtual void endPaint + (QWidget *widget, const QRegion& region, QImage *image = 0) = 0; + virtual VGImage surfaceImage() const; + virtual QSize surfaceSize() const = 0; + +private: + QVGPaintEngine *engine; + +protected: + QWindowSurface *winSurface; + + void destroyPaintEngine(); + QSize windowSurfaceSize(QWidget *widget) const; +}; + +#if defined(EGL_OPENVG_IMAGE) && !defined(QVG_NO_SINGLE_CONTEXT) + +#define QVG_VGIMAGE_BACKBUFFERS 1 + +class Q_OPENVG_EXPORT QVGEGLWindowSurfaceVGImage : public QVGEGLWindowSurfacePrivate +{ +public: + QVGEGLWindowSurfaceVGImage(QWindowSurface *win); + virtual ~QVGEGLWindowSurfaceVGImage(); + + QEglContext *ensureContext(QWidget *widget); + void beginPaint(QWidget *widget); + void endPaint(QWidget *widget, const QRegion& region, QImage *image); + VGImage surfaceImage() const; + QSize surfaceSize() const { return size; } + +protected: + QEglContext *context; + VGImage backBuffer; + EGLSurface backBufferSurface; + bool recreateBackBuffer; + bool isPaintingActive; + QSize size; + EGLSurface windowSurface; + + EGLSurface mainSurface() const; +}; + +class Q_OPENVG_EXPORT QVGEGLWindowSurfaceQImage : public QVGEGLWindowSurfaceVGImage +{ +public: + QVGEGLWindowSurfaceQImage(QWindowSurface *win); + virtual ~QVGEGLWindowSurfaceQImage(); + + void endPaint(QWidget *widget, const QRegion& region, QImage *image); +}; + +#endif // EGL_OPENVG_IMAGE + +class Q_OPENVG_EXPORT QVGEGLWindowSurfaceDirect : public QVGEGLWindowSurfacePrivate +{ +public: + QVGEGLWindowSurfaceDirect(QWindowSurface *win); + virtual ~QVGEGLWindowSurfaceDirect(); + + QEglContext *ensureContext(QWidget *widget); + void beginPaint(QWidget *widget); + void endPaint(QWidget *widget, const QRegion& region, QImage *image); + QSize surfaceSize() const { return size; } + +protected: + QEglContext *context; + QSize size; + bool isPaintingActive; + bool needToSwap; + EGLSurface windowSurface; +}; + +QT_END_NAMESPACE + +#endif // !QT_NO_EGL + +#endif // QWINDOWSURFACE_VGEGL_P_H diff --git a/src/plugins/graphicssystems/graphicssystems.pro b/src/plugins/graphicssystems/graphicssystems.pro index b8216ff..bfdec6a 100644 --- a/src/plugins/graphicssystems/graphicssystems.pro +++ b/src/plugins/graphicssystems/graphicssystems.pro @@ -1,2 +1,8 @@ TEMPLATE = subdirs contains(QT_CONFIG, opengl):SUBDIRS += opengl +contains(QT_CONFIG, openvg):contains(QT_CONFIG, egl):SUBDIRS += openvg + +contains(QT_CONFIG, shivavg) { + # Only works under X11 at present + !win32:!embedded:!mac:SUBDIRS += shivavg +} diff --git a/src/plugins/graphicssystems/openvg/main.cpp b/src/plugins/graphicssystems/openvg/main.cpp new file mode 100644 index 0000000..265ccd3 --- /dev/null +++ b/src/plugins/graphicssystems/openvg/main.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "qgraphicssystem_vg_p.h" + +QT_BEGIN_NAMESPACE + +class QVGGraphicsSystemPlugin : public QGraphicsSystemPlugin +{ +public: + QStringList keys() const; + QGraphicsSystem *create(const QString&); +}; + +QStringList QVGGraphicsSystemPlugin::keys() const +{ + QStringList list; + list << "OpenVG"; + return list; +} + +QGraphicsSystem* QVGGraphicsSystemPlugin::create(const QString& system) +{ + if (system.toLower() == "openvg") + return new QVGGraphicsSystem; + + return 0; +} + +Q_EXPORT_PLUGIN2(openvg, QVGGraphicsSystemPlugin) + +QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/openvg/openvg.pro b/src/plugins/graphicssystems/openvg/openvg.pro new file mode 100644 index 0000000..0abbfbd --- /dev/null +++ b/src/plugins/graphicssystems/openvg/openvg.pro @@ -0,0 +1,20 @@ +TARGET = qvggraphicssystem +include(../../qpluginbase.pri) + +QT += openvg + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/graphicssystems + +SOURCES = main.cpp qgraphicssystem_vg.cpp +HEADERS = qgraphicssystem_vg_p.h + +target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems +INSTALLS += target + +!isEmpty(QMAKE_INCDIR_OPENVG): INCLUDEPATH += $$QMAKE_INCDIR_OPENVG +!isEmpty(QMAKE_LIBDIR_OPENVG): LIBS += -L$$QMAKE_LIBDIR_OPENVG +!isEmpty(QMAKE_LIBS_OPENVG): LIBS += $$QMAKE_LIBS_OPENVG + +!isEmpty(QMAKE_INCDIR_EGL): INCLUDEPATH += $$QMAKE_INCDIR_EGL +!isEmpty(QMAKE_LIBDIR_EGL): LIBS += -L$$QMAKE_LIBDIR_EGL +!isEmpty(QMAKE_LIBS_EGL): LIBS += $$QMAKE_LIBS_EGL diff --git a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp new file mode 100644 index 0000000..d975ad7 --- /dev/null +++ b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg.cpp @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qgraphicssystem_vg_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +QVGGraphicsSystem::QVGGraphicsSystem() +{ +} + +QPixmapData *QVGGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const +{ +#if !defined(QVG_NO_SINGLE_CONTEXT) && !defined(QVG_NO_PIXMAP_DATA) + // Pixmaps can use QVGPixmapData; bitmaps must use raster. + if (type == QPixmapData::PixmapType) + return new QVGPixmapData(type); + else + return new QRasterPixmapData(type); +#else + return new QRasterPixmapData(type); +#endif +} + +QWindowSurface *QVGGraphicsSystem::createWindowSurface(QWidget *widget) const +{ + return new QVGWindowSurface(widget); +} + +QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/openvg/qgraphicssystem_vg_p.h b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg_p.h new file mode 100644 index 0000000..368f48d --- /dev/null +++ b/src/plugins/graphicssystems/openvg/qgraphicssystem_vg_p.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGRAPHICSSYSTEM_VG_P_H +#define QGRAPHICSSYSTEM_VG_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QVGGraphicsSystem : public QGraphicsSystem +{ +public: + QVGGraphicsSystem(); + + QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QWindowSurface *createWindowSurface(QWidget *widget) const; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/graphicssystems/shivavg/README b/src/plugins/graphicssystems/shivavg/README new file mode 100644 index 0000000..15ee710 --- /dev/null +++ b/src/plugins/graphicssystems/shivavg/README @@ -0,0 +1,8 @@ + +This graphics system uses ShivaVG (http://sourceforge.net/projects/shivavg) +to perform OpenVG rendering on X11 systems. The graphics system name for +the "-graphicssystem" command-line option is "ShivaVG". + +ShivaVG support is experimental, mostly to demonstrate how to integrate +non-EGL OpenVG engines into the system. It will probably not produce +good output. diff --git a/src/plugins/graphicssystems/shivavg/main.cpp b/src/plugins/graphicssystems/shivavg/main.cpp new file mode 100644 index 0000000..037bfb2 --- /dev/null +++ b/src/plugins/graphicssystems/shivavg/main.cpp @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include "shivavggraphicssystem.h" + +QT_BEGIN_NAMESPACE + +class ShivaVGGraphicsSystemPlugin : public QGraphicsSystemPlugin +{ +public: + QStringList keys() const; + QGraphicsSystem *create(const QString&); +}; + +QStringList ShivaVGGraphicsSystemPlugin::keys() const +{ + QStringList list; + list << "ShivaVG"; + return list; +} + +QGraphicsSystem* ShivaVGGraphicsSystemPlugin::create(const QString& system) +{ + if (system.toLower() == "shivavg") + return new ShivaVGGraphicsSystem; + + return 0; +} + +Q_EXPORT_PLUGIN2(shivavg, ShivaVGGraphicsSystemPlugin) + +QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/shivavg/shivavg.pro b/src/plugins/graphicssystems/shivavg/shivavg.pro new file mode 100644 index 0000000..68345af --- /dev/null +++ b/src/plugins/graphicssystems/shivavg/shivavg.pro @@ -0,0 +1,16 @@ +TARGET = qshivavggraphicssystem +include(../../qpluginbase.pri) + +QT += openvg + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/graphicssystems + +SOURCES = main.cpp shivavggraphicssystem.cpp shivavgwindowsurface.cpp +HEADERS = shivavggraphicssystem.h shivavgwindowsurface.h + +target.path += $$[QT_INSTALL_PLUGINS]/graphicssystems +INSTALLS += target + +!isEmpty(QMAKE_INCDIR_OPENVG): INCLUDEPATH += $$QMAKE_INCDIR_OPENVG +!isEmpty(QMAKE_LIBDIR_OPENVG): LIBS += -L$$QMAKE_LIBDIR_OPENVG +!isEmpty(QMAKE_LIBS_OPENVG): LIBS += $$QMAKE_LIBS_OPENVG diff --git a/src/plugins/graphicssystems/shivavg/shivavggraphicssystem.cpp b/src/plugins/graphicssystems/shivavg/shivavggraphicssystem.cpp new file mode 100644 index 0000000..fb60a42 --- /dev/null +++ b/src/plugins/graphicssystems/shivavg/shivavggraphicssystem.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "shivavggraphicssystem.h" +#include "shivavgwindowsurface.h" +#include + +QT_BEGIN_NAMESPACE + +ShivaVGGraphicsSystem::ShivaVGGraphicsSystem() +{ +} + +QPixmapData *ShivaVGGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const +{ + return new QRasterPixmapData(type); +} + +QWindowSurface *ShivaVGGraphicsSystem::createWindowSurface(QWidget *widget) const +{ + return new ShivaVGWindowSurface(widget); +} + +QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/shivavg/shivavggraphicssystem.h b/src/plugins/graphicssystems/shivavg/shivavggraphicssystem.h new file mode 100644 index 0000000..1c9ec70 --- /dev/null +++ b/src/plugins/graphicssystems/shivavg/shivavggraphicssystem.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SHIVAVGGRAPHICSSYSTEM_H +#define SHIVAVGGRAPHICSSYSTEM_H + +#include + +QT_BEGIN_NAMESPACE + +class ShivaVGGraphicsSystem : public QGraphicsSystem +{ +public: + ShivaVGGraphicsSystem(); + + QPixmapData *createPixmapData(QPixmapData::PixelType type) const; + QWindowSurface *createWindowSurface(QWidget *widget) const; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/graphicssystems/shivavg/shivavgwindowsurface.cpp b/src/plugins/graphicssystems/shivavg/shivavgwindowsurface.cpp new file mode 100644 index 0000000..bf1f942 --- /dev/null +++ b/src/plugins/graphicssystems/shivavg/shivavgwindowsurface.cpp @@ -0,0 +1,370 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#define GL_GLEXT_PROTOTYPES +#include "shivavgwindowsurface.h" +#include +#if defined(Q_WS_X11) +#include "private/qt_x11_p.h" +#include "qx11info_x11.h" +#include + +extern QX11Info *qt_x11Info(const QPaintDevice *pd); +#endif + +// Define this to use framebuffer objects. +//#define QVG_USE_FBO 1 + +#include + +QT_BEGIN_NAMESPACE + +class QShivaContext +{ +public: + QShivaContext(); + ~QShivaContext(); + + bool makeCurrent(ShivaVGWindowSurfacePrivate *surface); + void doneCurrent(); + + bool initialized; + QSize currentSize; + ShivaVGWindowSurfacePrivate *currentSurface; +}; + +Q_GLOBAL_STATIC(QShivaContext, shivaContext); + +class ShivaVGWindowSurfacePrivate +{ +public: + ShivaVGWindowSurfacePrivate() + : isCurrent(false) + , needsResize(true) + , engine(0) +#if defined(QVG_USE_FBO) + , fbo(0) + , texture(0) +#endif +#if defined(Q_WS_X11) + , drawable(0) + , context(0) +#endif + { + } + ~ShivaVGWindowSurfacePrivate(); + + void ensureContext(QWidget *widget); + + QSize size; + bool isCurrent; + bool needsResize; + QVGPaintEngine *engine; +#if defined(QVG_USE_FBO) + GLuint fbo; + GLuint texture; +#endif +#if defined(Q_WS_X11) + GLXDrawable drawable; + GLXContext context; +#endif +}; + +QShivaContext::QShivaContext() + : initialized(false) + , currentSurface(0) +{ +} + +QShivaContext::~QShivaContext() +{ + if (initialized) + vgDestroyContextSH(); +} + +bool QShivaContext::makeCurrent(ShivaVGWindowSurfacePrivate *surface) +{ + if (currentSurface) + currentSurface->isCurrent = false; + surface->isCurrent = true; + currentSurface = surface; + currentSize = surface->size; +#if defined(Q_WS_X11) + glXMakeCurrent(X11->display, surface->drawable, surface->context); +#endif + if (!initialized) { + if (!vgCreateContextSH(currentSize.width(), currentSize.height())) { + qWarning("vgCreateContextSH(%d, %d): could not create context", currentSize.width(), currentSize.height()); + return false; + } + initialized = true; + } else { + vgResizeSurfaceSH(currentSize.width(), currentSize.height()); + } +#if defined(QVG_USE_FBO) + if (surface->fbo) + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, surface->fbo); + else + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); +#endif + return true; +} + +void QShivaContext::doneCurrent() +{ + if (currentSurface) { + currentSurface->isCurrent = false; + currentSurface = 0; + } +#if defined(Q_WS_X11) + glXMakeCurrent(X11->display, 0, 0); +#endif +} + +ShivaVGWindowSurfacePrivate::~ShivaVGWindowSurfacePrivate() +{ +#if defined(QVG_USE_FBO) + if (fbo) { + glDeleteTextures(1, &texture); + glDeleteFramebuffersEXT(1, &fbo); + } +#endif +} + +void ShivaVGWindowSurfacePrivate::ensureContext(QWidget *widget) +{ +#if defined(Q_WS_X11) + Window win = widget->winId(); + if (win != drawable) { + if (context) + glXDestroyContext(X11->display, context); + drawable = win; + } + if (context == 0) { + const QX11Info *xinfo = qt_x11Info(widget); + int spec[64]; + int i = 0; + spec[i++] = GLX_DOUBLEBUFFER; + spec[i++] = GLX_DEPTH_SIZE; + spec[i++] = 1; + spec[i++] = GLX_STENCIL_SIZE; + spec[i++] = 1; + spec[i++] = GLX_RGBA; + spec[i++] = GLX_RED_SIZE; + spec[i++] = 1; + spec[i++] = GLX_GREEN_SIZE; + spec[i++] = 1; + spec[i++] = GLX_BLUE_SIZE; + spec[i++] = 1; + spec[i++] = GLX_SAMPLE_BUFFERS_ARB; + spec[i++] = 1; + spec[i++] = GLX_SAMPLES_ARB; + spec[i++] = 4; + spec[i] = XNone; + XVisualInfo *visual = glXChooseVisual + (xinfo->display(), xinfo->screen(), spec); + context = glXCreateContext(X11->display, visual, 0, True); + if (!context) + qWarning("glXCreateContext: could not create GL context for VG rendering"); + } +#else + Q_UNUSED(widget); +#endif +#if defined(QVG_USE_FBO) + if (needsResize && fbo) { +#if defined(Q_WS_X11) + glXMakeCurrent(X11->display, drawable, context); +#endif + glDeleteTextures(1, &texture); + glDeleteFramebuffersEXT(1, &fbo); +#if defined(Q_WS_X11) + glXMakeCurrent(X11->display, 0, 0); +#endif + fbo = 0; + texture = 0; + } + if (!fbo) { +#if defined(Q_WS_X11) + glXMakeCurrent(X11->display, drawable, context); +#endif + glGenFramebuffersEXT(1, &fbo); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo); + + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, size.width(), size.height(), 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glFramebufferTexture2DEXT + (GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, + texture, 0); + + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); +#if defined(Q_WS_X11) + glXMakeCurrent(X11->display, 0, 0); +#endif + } +#endif + needsResize = false; +} + +ShivaVGWindowSurface::ShivaVGWindowSurface(QWidget *window) + : QWindowSurface(window), d_ptr(new ShivaVGWindowSurfacePrivate) +{ +} + +ShivaVGWindowSurface::~ShivaVGWindowSurface() +{ + if (d_ptr->isCurrent) { + shivaContext()->doneCurrent(); + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + } +#if defined(Q_WS_X11) + if (d_ptr->context) + glXDestroyContext(X11->display, d_ptr->context); +#endif + delete d_ptr; +} + +QPaintDevice *ShivaVGWindowSurface::paintDevice() +{ + d_ptr->ensureContext(window()); + shivaContext()->makeCurrent(d_ptr); + glClearDepth(0.0f); + glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + return this; +} + +void ShivaVGWindowSurface::flush(QWidget *widget, const QRegion ®ion, const QPoint &offset) +{ + Q_UNUSED(region); + Q_UNUSED(offset); + QWidget *parent = widget->internalWinId() ? widget : widget->nativeParentWidget(); + d_ptr->ensureContext(parent); + QShivaContext *context = shivaContext(); + if (!d_ptr->isCurrent) + context->makeCurrent(d_ptr); +#if defined(QVG_USE_FBO) + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + if (d_ptr->fbo) { + static GLfloat const vertices[][2] = { + {-1, -1}, {1, -1}, {1, 1}, {-1, 1} + }; + static GLfloat const texCoords[][2] = { + {0, 0}, {1, 0}, {1, 1}, {0, 1} + }; + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glVertexPointer(2, GL_FLOAT, 0, vertices); + glTexCoordPointer(2, GL_FLOAT, 0, texCoords); + glBindTexture(GL_TEXTURE_2D, d_ptr->texture); + glEnable(GL_TEXTURE_2D); + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + glDisable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + } +#endif +#if defined(Q_WS_X11) + glXSwapBuffers(X11->display, d_ptr->drawable); +#endif + context->doneCurrent(); +} + +void ShivaVGWindowSurface::setGeometry(const QRect &rect) +{ + QWindowSurface::setGeometry(rect); + d_ptr->needsResize = true; + d_ptr->size = rect.size(); +} + +bool ShivaVGWindowSurface::scroll(const QRegion &area, int dx, int dy) +{ + return QWindowSurface::scroll(area, dx, dy); +} + +void ShivaVGWindowSurface::beginPaint(const QRegion ®ion) +{ + // Nothing to do here. + Q_UNUSED(region); +} + +void ShivaVGWindowSurface::endPaint(const QRegion ®ion) +{ + // Nothing to do here. + Q_UNUSED(region); +} + +Q_GLOBAL_STATIC(QVGPaintEngine, sharedPaintEngine); + +QPaintEngine *ShivaVGWindowSurface::paintEngine() const +{ + if (!d_ptr->engine) + d_ptr->engine = sharedPaintEngine(); + return d_ptr->engine; +} + +// We need to get access to QWidget::metric() from ShivaVGWindowSurface::metric, +// but it is not a friend of QWidget. To get around this, we create a +// fake QX11PaintEngine class, which is a friend. +class QX11PaintEngine +{ +public: + static int metric(const QWidget *widget, QPaintDevice::PaintDeviceMetric met) + { + return widget->metric(met); + } +}; + +int ShivaVGWindowSurface::metric(PaintDeviceMetric met) const +{ + return QX11PaintEngine::metric(window(), met); +} + +QT_END_NAMESPACE diff --git a/src/plugins/graphicssystems/shivavg/shivavgwindowsurface.h b/src/plugins/graphicssystems/shivavg/shivavgwindowsurface.h new file mode 100644 index 0000000..5211ba4 --- /dev/null +++ b/src/plugins/graphicssystems/shivavg/shivavgwindowsurface.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://www.qtsoftware.com/contact. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SHIVAVGWINDOWSURFACE_H +#define SHIVAVGWINDOWSURFACE_H + +#include + +QT_BEGIN_NAMESPACE + +class ShivaVGWindowSurfacePrivate; + +class ShivaVGWindowSurface : public QWindowSurface, public QPaintDevice +{ +public: + ShivaVGWindowSurface(QWidget *window); + virtual ~ShivaVGWindowSurface(); + + QPaintDevice *paintDevice(); + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + void setGeometry(const QRect &rect); + bool scroll(const QRegion &area, int dx, int dy); + + void beginPaint(const QRegion ®ion); + void endPaint(const QRegion ®ion); + + QPaintEngine *paintEngine() const; + +protected: + int metric(PaintDeviceMetric metric) const; + +private: + ShivaVGWindowSurfacePrivate *d_ptr; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/src.pro b/src/src.pro index f40c6ad..9bff20d 100644 --- a/src/src.pro +++ b/src/src.pro @@ -19,6 +19,7 @@ win32:{ } contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles2): SRC_SUBDIRS += src_opengl +contains(QT_CONFIG, openvg): SRC_SUBDIRS += src_openvg contains(QT_CONFIG, xmlpatterns): SRC_SUBDIRS += src_xmlpatterns contains(QT_CONFIG, phonon): SRC_SUBDIRS += src_phonon contains(QT_CONFIG, svg): SRC_SUBDIRS += src_svg @@ -61,6 +62,8 @@ src_scripttools.subdir = $$QT_SOURCE_TREE/src/scripttools src_scripttools.target = sub-scripttools src_opengl.subdir = $$QT_SOURCE_TREE/src/opengl src_opengl.target = sub-opengl +src_openvg.subdir = $$QT_SOURCE_TREE/src/openvg +src_openvg.target = sub-openvg src_qt3support.subdir = $$QT_SOURCE_TREE/src/qt3support src_qt3support.target = sub-qt3support src_phonon.subdir = $$QT_SOURCE_TREE/src/phonon @@ -96,6 +99,7 @@ src_webkit.target = sub-webkit src_scripttools.depends = src_script src_gui src_network src_network.depends = src_corelib src_opengl.depends = src_gui + src_openvg.depends = src_gui src_sql.depends = src_corelib src_testlib.depends = src_corelib src_qt3support.depends = src_gui src_xml src_network src_sql diff --git a/tests/arthur/common/qengines.cpp b/tests/arthur/common/qengines.cpp index e94e9cc..ce1afe4 100644 --- a/tests/arthur/common/qengines.cpp +++ b/tests/arthur/common/qengines.cpp @@ -49,6 +49,7 @@ #include #include #include +#include // For QApplicationPrivate::graphics_system_name #include diff --git a/tools/qdoc3/test/qt-cpp-ignore.qdocconf b/tools/qdoc3/test/qt-cpp-ignore.qdocconf index cfb3afd..9a18abe 100644 --- a/tools/qdoc3/test/qt-cpp-ignore.qdocconf +++ b/tools/qdoc3/test/qt-cpp-ignore.qdocconf @@ -12,6 +12,7 @@ Cpp.ignoretokens = QAXFACTORY_EXPORT \ QM_EXPORT_ICONVIEW \ QM_EXPORT_NETWORK \ QM_EXPORT_OPENGL \ + QM_EXPORT_OPENVG \ QM_EXPORT_SQL \ QM_EXPORT_TABLE \ QM_EXPORT_WORKSPACE \ @@ -50,6 +51,7 @@ Cpp.ignoretokens = QAXFACTORY_EXPORT \ Q_INTERNAL_WIN_NO_THROW \ Q_NETWORK_EXPORT \ Q_OPENGL_EXPORT \ + Q_OPENVG_EXPORT \ Q_OUTOFLINE_TEMPLATE \ Q_SQL_EXPORT \ Q_SVG_EXPORT \ -- cgit v0.12