diff options
author | Markus Mohrhard <markus.mohrhard@collabora.co.uk> | 2014-11-10 08:02:18 +0100 |
---|---|---|
committer | Markus Mohrhard <markus.mohrhard@collabora.co.uk> | 2014-11-10 08:02:18 +0100 |
commit | ea48707a9d13fe94bfe4947aa28d755d19813456 (patch) | |
tree | 56b0878ba4c50efcc247de1b8a1aea8c63289d61 /vcl | |
parent | 06a5b619a76c96783ee67bdcfd21f203d3ddb53c (diff) | |
parent | 730a3ac2daa9ec5774fc7b9482ed1aa94afab67f (diff) |
merge initial work on OpenGL vcl backend
The backend builds on Windows, Linux and OSX but still does not render
everything perfectly. Based on this initial framework the remaining
improvements can be made incrementally in master.
Whether the OpenGL code or the normal code is used depends on the OpenGL
configuration variable. It currently defaults to false. Additionally we
check during runtime if the requirements for running the OpenGL backend
are fulfilled.
Diffstat (limited to 'vcl')
96 files changed, 10753 insertions, 5133 deletions
diff --git a/vcl/Executable_icontest.mk b/vcl/Executable_icontest.mk index dd5ee952a90c..d7962d846523 100644 --- a/vcl/Executable_icontest.mk +++ b/vcl/Executable_icontest.mk @@ -53,7 +53,6 @@ $(eval $(call gb_Executable_use_libraries,icontest,\ tl \ ucbhelper \ vcl \ - vclopengl \ )) $(eval $(call gb_Executable_add_exception_objects,icontest,\ diff --git a/vcl/Executable_outdevgrind.mk b/vcl/Executable_outdevgrind.mk new file mode 100644 index 000000000000..f1a822f5f4a7 --- /dev/null +++ b/vcl/Executable_outdevgrind.mk @@ -0,0 +1,39 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Executable_Executable,outdevgrind)) + +$(eval $(call gb_Executable_use_api,outdevgrind,\ + offapi \ + udkapi \ +)) + +$(eval $(call gb_Executable_use_external,outdevgrind,boost_headers)) + +$(eval $(call gb_Executable_set_include,outdevgrind,\ + $$(INCLUDE) \ + -I$(SRCDIR)/vcl/inc \ + -I$(SRCDIR)/solenv/inc \ +)) + +$(eval $(call gb_Executable_use_libraries,outdevgrind,\ + tl \ + sal \ + vcl \ + cppu \ + cppuhelper \ + comphelper \ +)) + +$(eval $(call gb_Executable_add_exception_objects,outdevgrind,\ + vcl/workben/outdevgrind \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/Executable_vcldemo.mk b/vcl/Executable_vcldemo.mk index fb29b9a1991f..561f7d6d564e 100644 --- a/vcl/Executable_vcldemo.mk +++ b/vcl/Executable_vcldemo.mk @@ -36,4 +36,8 @@ $(eval $(call gb_Executable_add_exception_objects,vcldemo,\ vcl/workben/vcldemo \ )) +$(eval $(call gb_Executable_use_static_libraries,vcldemo,\ + vclmain \ +)) + # vim: set noet sw=4 ts=4: diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index dea1d8d6c74e..81f774a98644 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -45,6 +45,7 @@ $(eval $(call gb_Library_set_include,vcl,\ $(eval $(call gb_Library_add_defs,vcl,\ -DVCL_DLLIMPLEMENTATION \ + -DVCLOPENGL_DLLIMPLEMENTATION \ -DCUI_DLL_NAME=\"$(call gb_Library_get_runtime_filename,$(call gb_Library__get_name,cui))\" \ -DDESKTOP_DETECTOR_DLL_NAME=\"$(call gb_Library_get_runtime_filename,$(call gb_Library__get_name,desktop_detector))\" \ -DTK_DLL_NAME=\"$(call gb_Library_get_runtime_filename,$(call gb_Library__get_name,tk))\" \ @@ -89,6 +90,17 @@ $(eval $(call gb_Library_add_libs,vcl,\ -lobjc \ )) endif +ifeq ($(OS),MACOSX) + +$(eval $(call gb_Library_add_cxxflags,vcl,\ + $(gb_OBJCXXFLAGS) \ +)) + +$(eval $(call gb_Library_add_exception_objects,vcl,\ + vcl/osx/OpenGLWrapper \ +)) + +endif ifeq ($(ENABLE_JAVA),TRUE) $(eval $(call gb_Library_use_libraries,vcl,\ @@ -99,13 +111,24 @@ endif $(eval $(call gb_Library_use_externals,vcl,\ boost_headers \ gio \ + glew \ + glm_headers \ harfbuzz \ - icuuc \ icu_headers \ + icuuc \ lcms2 \ + mdds_headers \ + mesa_headers \ )) $(eval $(call gb_Library_add_exception_objects,vcl,\ + vcl/opengl/gdiimpl \ + vcl/opengl/salbmp \ + vcl/opengl/scale \ + vcl/opengl/texture \ + vcl/source/opengl/OpenGLContext \ + vcl/source/opengl/OpenGLHelper \ + vcl/source/window/openglwin \ vcl/source/window/settings \ vcl/source/window/paint \ vcl/source/window/resource \ @@ -273,6 +296,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/gdi/region \ vcl/source/gdi/regionband \ vcl/source/gdi/salgdilayout \ + vcl/source/gdi/salgdiimpl \ vcl/source/gdi/sallayout \ vcl/source/gdi/salmisc \ vcl/source/gdi/salnativewidgets-none \ @@ -475,6 +499,7 @@ $(eval $(call gb_Library_use_system_darwin_frameworks,vcl,\ Cocoa \ Carbon \ CoreFoundation \ + OpenGL \ )) ifneq ($(ENABLE_MACOSX_SANDBOX),TRUE) @@ -532,6 +557,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/unx/generic/plugadapt/salplug \ vcl/unx/generic/printer/jobdata \ vcl/unx/generic/printer/ppdparser \ + vcl/unx/generic/gdi/x11windowprovider \ $(if $(filter TRUE,$(ENABLE_CUPS)),\ vcl/unx/generic/printer/cupsmgr \ vcl/unx/generic/printer/printerinfomanager \ @@ -618,11 +644,13 @@ endif ifeq ($(OS),WNT) $(eval $(call gb_Library_add_exception_objects,vcl,\ + vcl/opengl/win/gdiimpl \ vcl/win/source/app/saldata \ vcl/win/source/app/salinfo \ vcl/win/source/app/salinst \ vcl/win/source/app/salshl \ vcl/win/source/app/saltimer \ + vcl/win/source/gdi/gdiimpl \ vcl/win/source/gdi/salbmp \ vcl/win/source/gdi/salgdi \ vcl/win/source/gdi/salgdi2 \ @@ -643,9 +671,11 @@ $(eval $(call gb_Library_use_system_win32_libs,vcl,\ advapi32 \ gdi32 \ gdiplus \ + glu32 \ imm32 \ mpr \ msimg32 \ + opengl32 \ ole32 \ shell32 \ usp10 \ @@ -671,6 +701,9 @@ $(eval $(call gb_Library_add_libs,vcl,\ -lm \ -ldl \ -lpthread \ + -lGL \ + -lGLU \ + -lX11 \ )) endif diff --git a/vcl/Library_vclopengl.mk b/vcl/Library_vclopengl.mk deleted file mode 100644 index e61dd8a9bb31..000000000000 --- a/vcl/Library_vclopengl.mk +++ /dev/null @@ -1,88 +0,0 @@ -# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- -# -# This file is part of the LibreOffice project. -# -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. -# - -$(eval $(call gb_Library_Library,vclopengl)) - -$(eval $(call gb_Library_set_include,vclopengl,\ - -I$(SRCDIR)/vcl/inc/ \ - $$(INCLUDE) \ -)) - -$(eval $(call gb_Library_add_defs,vclopengl,\ - -DVCLOPENGL_DLLIMPLEMENTATION \ -)) - -$(eval $(call gb_Library_use_externals,vclopengl,\ - boost_headers \ - mdds_headers \ - glm_headers \ - mesa_headers \ - glew \ -)) - -$(eval $(call gb_Library_use_sdk_api,vclopengl)) - -$(eval $(call gb_Library_use_libraries,vclopengl,\ - comphelper \ - cppu \ - cppuhelper \ - sal \ - tl \ - vcl \ - $(gb_UWINAPI) \ -)) - -$(eval $(call gb_Library_add_exception_objects,vclopengl,\ - vcl/source/opengl/OpenGLContext \ - vcl/source/opengl/OpenGLHelper \ - vcl/source/window/openglwin \ -)) - -ifeq ($(OS),MACOSX) - -$(eval $(call gb_Library_add_cxxflags,vclopengl,\ - $(gb_OBJCXXFLAGS) \ -)) - -$(eval $(call gb_Library_add_libs,vcl,\ - -framework IOKit \ - -F/System/Library/PrivateFrameworks \ - -framework CoreUI \ - -lobjc \ -)) - -$(eval $(call gb_Library_add_exception_objects,vclopengl,\ - vcl/osx/OpenGLWrapper \ -)) - -endif - -ifeq ($(strip $(OS)),WNT) -$(eval $(call gb_Library_use_system_win32_libs,vclopengl,\ - opengl32 \ - gdi32 \ - glu32 \ -)) -else ifeq ($(OS),MACOSX) -$(eval $(call gb_Library_use_system_darwin_frameworks,vclopengl,\ - OpenGL \ - Cocoa \ - Carbon \ - CoreFoundation \ -)) -else ifeq ($(OS),LINUX) -$(eval $(call gb_Library_add_libs,vclopengl,\ - -ldl \ - -lGL \ - -lGLU \ - -lX11 \ -)) -endif - -# vim: set noet sw=4 ts=4: diff --git a/vcl/Library_vclplug_gen.mk b/vcl/Library_vclplug_gen.mk index c3f00aa4eef2..73e5d010e597 100644 --- a/vcl/Library_vclplug_gen.mk +++ b/vcl/Library_vclplug_gen.mk @@ -24,6 +24,10 @@ $(eval $(call gb_Library_set_include,vclplug_gen,\ -I$(SRCDIR)/vcl/inc \ )) +$(eval $(call gb_Library_use_custom_headers,vclplug_gen,\ + officecfg/registry \ +)) + $(eval $(call gb_Library_use_sdk_api,vclplug_gen)) $(eval $(call gb_Library_use_libraries,vclplug_gen,\ @@ -47,6 +51,7 @@ $(eval $(call gb_Library_use_externals,vclplug_gen,\ boost_headers \ cairo \ graphite \ + glew \ harfbuzz \ icuuc \ valgrind \ @@ -58,6 +63,8 @@ $(eval $(call gb_Library_add_libs,vclplug_gen,\ -lXext \ -lSM \ -lICE \ + -lGL \ + -lGLU \ )) $(eval $(call gb_Library_add_exception_objects,vclplug_gen,\ @@ -83,7 +90,12 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_gen,\ vcl/unx/generic/dtrans/X11_selection \ vcl/unx/generic/dtrans/X11_service \ vcl/unx/generic/dtrans/X11_transferable \ + vcl/unx/generic/gdi/cairotextrender \ + vcl/unx/generic/gdi/x11cairotextrender \ vcl/unx/generic/gdi/gcach_xpeer \ + vcl/unx/generic/gdi/gdiimpl \ + vcl/unx/generic/gdi/pixmap \ + vcl/unx/generic/gdi/openglx11cairotextrender \ vcl/unx/generic/gdi/salbmp \ vcl/unx/generic/gdi/salgdi2 \ vcl/unx/generic/gdi/salgdi3 \ @@ -95,6 +107,7 @@ $(eval $(call gb_Library_add_exception_objects,vclplug_gen,\ vcl/unx/generic/window/salobj \ vcl/unx/x11/x11sys \ vcl/unx/x11/xlimits \ + vcl/opengl/x11/gdiimpl \ )) # ultimately we want to split the x11 dependencies out diff --git a/vcl/Module_vcl.mk b/vcl/Module_vcl.mk index 51c5d3ff0ab1..5d1d2d2ad7fc 100644 --- a/vcl/Module_vcl.mk +++ b/vcl/Module_vcl.mk @@ -22,17 +22,18 @@ $(eval $(call gb_Module_Module,vcl)) $(eval $(call gb_Module_add_targets,vcl,\ CustomTarget_afm_hash \ Library_vcl \ + Package_opengl \ $(if $(filter DESKTOP,$(BUILD_TYPE)), \ StaticLibrary_vclmain \ Executable_ui-previewer \ $(if $(filter LINUX MACOSX WNT,$(OS)), \ - Executable_icontest)) \ + Executable_icontest \ + Executable_outdevgrind \ + Executable_vcldemo )) \ $(if $(filter-out ANDROID IOS WNT,$(OS)), \ Executable_svdemo \ Executable_svptest \ - Executable_svpclient \ - Executable_vcldemo) \ - Library_vclopengl \ + Executable_svpclient) \ )) $(eval $(call gb_Module_add_l10n_targets,vcl,\ diff --git a/vcl/Package_opengl.mk b/vcl/Package_opengl.mk new file mode 100644 index 000000000000..79dabb70bbb6 --- /dev/null +++ b/vcl/Package_opengl.mk @@ -0,0 +1,24 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# +# This file is part of the LibreOffice project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# + +$(eval $(call gb_Package_Package,vcl_opengl_shader,$(SRCDIR)/vcl/opengl)) + +$(eval $(call gb_Package_add_files,vcl_opengl_shader,$(LIBO_ETC_FOLDER)/opengl,\ + convolutionFragmentShader.glsl \ + maskFragmentShader.glsl \ + maskVertexShader.glsl \ + maskedTextureFragmentShader.glsl \ + maskedTextureVertexShader.glsl \ + solidFragmentShader.glsl \ + solidVertexShader.glsl \ + textureFragmentShader.glsl \ + textureVertexShader.glsl \ +)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/headless/svpbmp.cxx b/vcl/headless/svpbmp.cxx index 3920aea25f2d..b5fcc241d75d 100644 --- a/vcl/headless/svpbmp.cxx +++ b/vcl/headless/svpbmp.cxx @@ -339,6 +339,11 @@ bool SvpSalBitmap::GetSystemData( BitmapSystemData& ) return false; } +bool SvpSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, sal_uInt32 /*nScaleFlag*/ ) +{ + return false; +} + sal_uInt32 SvpSalBitmap::getBitCountFromScanlineFormat( basebmp::Format nFormat ) { sal_uInt32 nBitCount = 1; diff --git a/vcl/inc/cairotextrender.hxx b/vcl/inc/cairotextrender.hxx new file mode 100644 index 000000000000..e5db2ab7e612 --- /dev/null +++ b/vcl/inc/cairotextrender.hxx @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_CAIROTEXTRENDER_HXX +#define INCLUDED_VCL_INC_UNX_CAIROTEXTRENDER_HXX + +#include "textrender.hxx" +#include <vcl/region.hxx> +#include <deque> + +typedef struct FT_FaceRec_* FT_Face; + +class PspSalPrinter; +class PspSalInfoPrinter; +class ServerFont; +class GlyphCache; +class ImplLayoutArgs; +class ServerFontLayout; +class PhysicalFontCollection; +class PhysicalFontFace; +struct _cairo_surface_t; +typedef struct _cairo_surface cairo_surface_t; +typedef struct _cairo cairo_t; + +class CairoFontsCache +{ +public: + struct CacheId + { + FT_Face maFace; + const void *mpOptions; + bool mbEmbolden; + bool mbVerticalMetrics; + bool operator ==(const CacheId& rOther) const + { + return maFace == rOther.maFace && + mpOptions == rOther.mpOptions && + mbEmbolden == rOther.mbEmbolden && + mbVerticalMetrics == rOther.mbVerticalMetrics; + } + }; +private: + static int mnRefCount; + typedef std::deque< std::pair<void *, CacheId> > LRUFonts; + static LRUFonts maLRUFonts; +public: + CairoFontsCache(); + static void CacheFont(void *pFont, const CacheId &rId); + static void* FindCachedFont(const CacheId &rId); + ~CairoFontsCache(); +}; + +class CairoTextRender : public TextRenderImpl +{ + bool mbPrinter; + ServerFont* mpServerFont[ MAX_FALLBACK ]; + + SalColor nTextColor_; + CairoFontsCache m_aCairoFontsCache; + +protected: + virtual GlyphCache& getPlatformGlyphCache() = 0; + virtual cairo_surface_t* getCairoSurface() = 0; + virtual void drawSurface(cairo_t* cr) = 0; + +bool setFont( const FontSelectPattern *pEntry, int nFallbackLevel ); + + virtual void clipRegion(cairo_t* cr) = 0; + +public: + CairoTextRender(bool bPrinter); + + + virtual void SetTextColor( SalColor nSalColor ) SAL_OVERRIDE; + virtual sal_uInt16 SetFont( FontSelectPattern*, int nFallbackLevel ) SAL_OVERRIDE; + virtual void GetFontMetric( ImplFontMetricData*, int nFallbackLevel ) SAL_OVERRIDE; + virtual const FontCharMapPtr GetFontCharMap() const SAL_OVERRIDE; + virtual bool GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const SAL_OVERRIDE; + virtual void GetDevFontList( PhysicalFontCollection* ) SAL_OVERRIDE; + virtual void ClearDevFontCache() SAL_OVERRIDE; + virtual bool AddTempDevFont( PhysicalFontCollection*, const OUString& rFileURL, const OUString& rFontName ) SAL_OVERRIDE; + virtual bool CreateFontSubset( const OUString& rToFile, + const PhysicalFontFace*, + sal_GlyphId* pGlyphIDs, + sal_uInt8* pEncoding, + sal_Int32* pWidths, + int nGlyphs, + FontSubsetInfo& rInfo + ) SAL_OVERRIDE; + virtual const Ucs2SIntMap* GetFontEncodingVector( const PhysicalFontFace*, const Ucs2OStrMap** ppNonEncoded ) SAL_OVERRIDE; + virtual const void* GetEmbedFontData( const PhysicalFontFace*, + const sal_Ucs* pUnicodes, + sal_Int32* pWidths, + FontSubsetInfo& rInfo, + long* pDataLen ) SAL_OVERRIDE; + virtual void FreeEmbedFontData( const void* pData, long nDataLen ) SAL_OVERRIDE; + virtual void GetGlyphWidths( const PhysicalFontFace*, + bool bVertical, + Int32Vector& rWidths, + Ucs2UIntMap& rUnicodeEnc ) SAL_OVERRIDE; + virtual bool GetGlyphBoundRect( sal_GlyphId nIndex, Rectangle& ) SAL_OVERRIDE; + virtual bool GetGlyphOutline( sal_GlyphId nIndex, ::basegfx::B2DPolyPolygon& ) SAL_OVERRIDE; + virtual SalLayout* GetTextLayout( ImplLayoutArgs&, int nFallbackLevel ) SAL_OVERRIDE; + virtual void DrawServerFontLayout( const ServerFontLayout& ) SAL_OVERRIDE; + virtual SystemFontData GetSysFontData( int nFallbackLevel ) const SAL_OVERRIDE; + +private: + bool bDisableGraphite_; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/generic/genpspgraphics.h b/vcl/inc/generic/genpspgraphics.h index 30c8fecd5eea..fb7169afa804 100644 --- a/vcl/inc/generic/genpspgraphics.h +++ b/vcl/inc/generic/genpspgraphics.h @@ -192,6 +192,8 @@ public: virtual SystemGraphicsData GetGraphicsData() const SAL_OVERRIDE; virtual SystemFontData GetSysFontData( int nFallbacklevel ) const SAL_OVERRIDE; + + virtual bool SwapBuffers() SAL_OVERRIDE { return false; }; }; #endif // INCLUDED_VCL_INC_GENERIC_GENPSPGRAPHICS_H diff --git a/vcl/inc/generic/glyphcache.hxx b/vcl/inc/generic/glyphcache.hxx index ba44ae8412b3..ddfc7a8ef965 100644 --- a/vcl/inc/generic/glyphcache.hxx +++ b/vcl/inc/generic/glyphcache.hxx @@ -205,6 +205,7 @@ private: friend class ServerFontLayout; friend class ImplServerFontEntry; friend class X11SalGraphics; + friend class CairoTextRender; void AddRef() const { ++mnRefCount; } long GetRefCount() const { return mnRefCount; } diff --git a/vcl/inc/graphite_serverfont.hxx b/vcl/inc/graphite_serverfont.hxx index 0d533e00b7c2..7dfde21551bc 100644 --- a/vcl/inc/graphite_serverfont.hxx +++ b/vcl/inc/graphite_serverfont.hxx @@ -26,6 +26,8 @@ #ifndef _MSC_VER #include <graphite_layout.hxx> +#include "generic/glyphcache.hxx" + class PhysicalFontFace; // Modules diff --git a/vcl/inc/headless/svpbmp.hxx b/vcl/inc/headless/svpbmp.hxx index aecf79c29ef7..3a0da2e9f100 100644 --- a/vcl/inc/headless/svpbmp.hxx +++ b/vcl/inc/headless/svpbmp.hxx @@ -58,6 +58,8 @@ public: virtual void ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly ) SAL_OVERRIDE; virtual bool GetSystemData( BitmapSystemData& rData ) SAL_OVERRIDE; + virtual bool Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag ) SAL_OVERRIDE; + static sal_uInt32 getBitCountFromScanlineFormat( basebmp::Format nFormat ); }; diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx index cbbac7a4b1dd..cd5622f9aa20 100644 --- a/vcl/inc/headless/svpgdi.hxx +++ b/vcl/inc/headless/svpgdi.hxx @@ -243,6 +243,8 @@ public: virtual SystemGraphicsData GetGraphicsData() const SAL_OVERRIDE; virtual SystemFontData GetSysFontData( int nFallbacklevel ) const SAL_OVERRIDE; + virtual bool SwapBuffers() SAL_OVERRIDE { return false; }; + #ifdef IOS void SetVirDevGraphics( CGLayerRef xLayer, CGContextRef xContext, int = 0 ); diff --git a/vcl/inc/impbmp.hxx b/vcl/inc/impbmp.hxx index c0eb805090f8..bbe80649b23b 100644 --- a/vcl/inc/impbmp.hxx +++ b/vcl/inc/impbmp.hxx @@ -38,6 +38,13 @@ private: public: ImpBitmap(); + /** + * takes ownership + * same as Sequence: + * pBmp = new ImpBitmap; + * pBmp->ImplSetSalBitmap(pBitmap); + */ + ImpBitmap(SalBitmap* pBitmap); ~ImpBitmap(); void ImplSetSalBitmap( SalBitmap* pSalBitmap ); @@ -60,6 +67,9 @@ public: inline void ImplSetChecksum( sal_uLong nChecksum ) { mnChecksum = nChecksum; } inline sal_uLong ImplGetChecksum() const { return mnChecksum; } + + + bool ImplScale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag ); }; #endif // INCLUDED_VCL_INC_IMPBMP_HXX diff --git a/vcl/inc/opengl/bmpop.hxx b/vcl/inc/opengl/bmpop.hxx new file mode 100644 index 000000000000..d19410b2f253 --- /dev/null +++ b/vcl/inc/opengl/bmpop.hxx @@ -0,0 +1,35 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_BMPOP_H +#define INCLUDED_VCL_INC_OPENGL_BMPOP_H + +class OpenGLSalBitmapOp +{ +public: + OpenGLSalBitmapOp() {}; + virtual ~OpenGLSalBitmapOp() {}; + + virtual bool Execute() = 0; + virtual void GetSize( Size& rSize ) const = 0; +}; + +#endif // INCLUDED_VCL_INC_OPENGL_BMPOP_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/salbmp.hxx b/vcl/inc/opengl/salbmp.hxx new file mode 100644 index 000000000000..6f7a03af09d4 --- /dev/null +++ b/vcl/inc/opengl/salbmp.hxx @@ -0,0 +1,120 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_SALBMP_H +#define INCLUDED_VCL_INC_OPENGL_SALBMP_H + +#include <basebmp/bitmapdevice.hxx> +#include <vcl/opengl/OpenGLContext.hxx> + +#include "vcl/salbtype.hxx" +#include "opengl/bmpop.hxx" +#include "opengl/texture.hxx" + +#include <salbmp.hxx> + +#include <deque> + +// - SalBitmap - + +struct BitmapBuffer; +class BitmapPalette; + +class VCL_PLUGIN_PUBLIC OpenGLSalBitmap : public SalBitmap +{ +private: + OpenGLContext* mpContext; + OpenGLTextureSharedPtr mpTexture; + bool mbDirtyTexture; + BitmapPalette maPalette; + basebmp::RawMemorySharedArray maUserBuffer; + sal_uInt16 mnBits; + sal_uInt16 mnBytesPerRow; + int mnWidth; + int mnHeight; + int mnBufWidth; + int mnBufHeight; + std::deque< OpenGLSalBitmapOp* > maPendingOps; + +public: + OpenGLSalBitmap(); + virtual ~OpenGLSalBitmap(); + +public: + + // SalBitmap methods + bool Create( const Size& rSize, sal_uInt16 nBitCount, const BitmapPalette& rPal ) SAL_OVERRIDE; + bool Create( const SalBitmap& rSalBmp ) SAL_OVERRIDE; + bool Create( const SalBitmap& rSalBmp, SalGraphics* pGraphics ) SAL_OVERRIDE; + bool Create( const SalBitmap& rSalBmp, sal_uInt16 nNewBitCount ) SAL_OVERRIDE; + virtual bool Create( const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmapCanvas > xBitmapCanvas, + Size& rSize, + bool bMask = false ) SAL_OVERRIDE; + + void Destroy() SAL_OVERRIDE; + + Size GetSize() const SAL_OVERRIDE; + sal_uInt16 GetBitCount() const SAL_OVERRIDE; + + BitmapBuffer *AcquireBuffer( bool bReadOnly ) SAL_OVERRIDE; + void ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly ) SAL_OVERRIDE; + + bool GetSystemData( BitmapSystemData& rData ) SAL_OVERRIDE; + + bool Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag ) SAL_OVERRIDE; + +public: + + bool Create( OpenGLContext& rContext, long nX, long nY, long nWidth, long nHeight ); + bool Draw( OpenGLContext& rContext, const SalTwoRect& rPosAry ); + GLuint GetTexture( OpenGLContext& rContext ) const; + +private: + + GLuint CreateTexture(); + void DeleteTexture(); + void DrawTexture( GLuint nTexture, const SalTwoRect& rPosAry ); + bool AllocateUserData(); + bool ReadTexture(); + +private: + + GLuint ImplGetTextureProgram(); + GLuint mnTexProgram; + GLuint mnTexSamplerUniform; + + GLuint ImplGetConvolutionProgram(); + GLuint mnConvProgram; + GLuint mnConvSamplerUniform; + GLuint mnConvKernelUniform; + GLuint mnConvKernelSizeUniform; + GLuint mnConvOffsetsUniform; + + bool ImplScaleFilter( GLenum nFilter ); + void ImplCreateKernel( const double& fScale, const Kernel& rKernel, GLfloat*& pWeights, sal_uInt32& aKernelSize ); + bool ImplScaleConvolution( const double& rScaleX, const double& rScaleY, const Kernel& aKernel ); + +public: + + bool ImplScale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag ); +}; + +#endif // INCLUDED_VCL_INC_OPENGL_SALBMP_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/texture.hxx b/vcl/inc/opengl/texture.hxx new file mode 100644 index 000000000000..f9d3ad864291 --- /dev/null +++ b/vcl/inc/opengl/texture.hxx @@ -0,0 +1,54 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_TEXTURE_H +#define INCLUDED_VCL_INC_OPENGL_TEXTURE_H + +#include <boost/shared_ptr.hpp> +#include <GL/glew.h> + +class OpenGLTexture +{ +private: + GLuint mnTexture; + int mnWidth; + int mnHeight; + GLenum mnFilter; + +public: + OpenGLTexture(); + OpenGLTexture( int nWidth, int nHeight ); + OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData ); + OpenGLTexture( int nX, int nY, int nWidth, int nHeight ); + virtual ~OpenGLTexture(); + + GLuint Id() const; + void Bind(); + void Unbind(); + bool Draw(); + + GLenum GetFilter() const; + void SetFilter( GLenum nFilter ); +}; + +typedef boost::shared_ptr< OpenGLTexture > OpenGLTextureSharedPtr; + +#endif // INCLUDED_VCL_INC_OPENGL_TEXTURE_H + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/win/gdiimpl.hxx b/vcl/inc/opengl/win/gdiimpl.hxx new file mode 100644 index 000000000000..aa29dd9bb75c --- /dev/null +++ b/vcl/inc/opengl/win/gdiimpl.hxx @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_WIN_GDIIMPL_HXX +#define INCLUDED_VCL_INC_OPENGL_WIN_GDIIMPL_HXX + +#include <vcl/dllapi.h> + +#include "openglgdiimpl.hxx" +#include "win/salgdi.h" + +class WinOpenGLSalGraphicsImpl : public OpenGLSalGraphicsImpl +{ +private: + WinSalGraphics& mrParent; + +public: + WinOpenGLSalGraphicsImpl(WinSalGraphics& rGraphics); + +protected: + virtual GLfloat GetWidth() const SAL_OVERRIDE; + virtual GLfloat GetHeight() const SAL_OVERRIDE; + +public: + +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/opengl/x11/gdiimpl.hxx b/vcl/inc/opengl/x11/gdiimpl.hxx new file mode 100644 index 000000000000..878c7c2f054e --- /dev/null +++ b/vcl/inc/opengl/x11/gdiimpl.hxx @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_OPENGL_X11_GDIIMPL_HXX +#define INCLUDED_VCL_INC_OPENGL_X11_GDIIMPL_HXX + +#include <vcl/dllapi.h> + +#include "unx/salgdi.h" +#include "unx/x11/x11gdiimpl.h" +#include "openglgdiimpl.hxx" + +class VCL_PLUGIN_PUBLIC X11OpenGLSalGraphicsImpl : public OpenGLSalGraphicsImpl, public X11GraphicsImpl +{ +private: + X11SalGraphics& mrParent; + +public: + X11OpenGLSalGraphicsImpl( X11SalGraphics& rParent ); + virtual ~X11OpenGLSalGraphicsImpl(); + +protected: + GLfloat GetWidth() const SAL_OVERRIDE; + GLfloat GetHeight() const SAL_OVERRIDE; + +public: + // implementation of X11GraphicsImpl + + void Init() SAL_OVERRIDE; + X11Pixmap* GetPixmapFromScreen( const Rectangle& rRect ) SAL_OVERRIDE; + bool RenderPixmapToScreen( X11Pixmap* pPixmap, int nX, int nY ) SAL_OVERRIDE; +}; + +#endif // INCLUDED_VCL_INC_OPENGL_X11_GDIIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx new file mode 100644 index 000000000000..34c26070943d --- /dev/null +++ b/vcl/inc/openglgdiimpl.hxx @@ -0,0 +1,259 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_OPENGLGDIIMPL_HXX +#define INCLUDED_VCL_OPENGLGDIIMPL_HXX + +#include "salgdiimpl.hxx" +#include <vcl/dllapi.h> + +#include <vcl/opengl/OpenGLContext.hxx> + +class SalFrame; +class SalVirtualDevice; + +class VCL_PLUGIN_PUBLIC OpenGLSalGraphicsImpl : public SalGraphicsImpl +{ +protected: + + OpenGLContext maContext; + SalFrame* mpFrame; + SalVirtualDevice* mpVDev; + + SalColor mnLineColor; + SalColor mnFillColor; + + std::vector< GLuint > maShaders; + + GLuint mnSolidProgram; + GLuint mnColorUniform; + + GLuint mnTextureProgram; + GLuint mnSamplerUniform; + + GLuint mnMaskedTextureProgram; + GLuint mnMaskedSamplerUniform; + GLuint mnMaskSamplerUniform; + + GLuint mnMaskProgram; + GLuint mnMaskUniform; + GLuint mnMaskColorUniform; + + bool CreateSolidProgram( void ); + bool CreateTextureProgram( void ); + bool CreateMaskedTextureProgram( void ); + bool CreateMaskProgram( void ); + + void BeginSolid( SalColor nColor, sal_uInt8 nTransparency ); + void BeginSolid( SalColor nColor, double fTransparency ); + void BeginSolid( SalColor nColor ); + void EndSolid( void ); + void BeginInvert( void ); + void EndInvert( void ); + + void DrawPoint( long nX, long nY ); + void DrawLine( long nX1, long nY1, long nX2, long nY2 ); + void DrawLines( sal_uInt32 nPoints, const SalPoint* pPtAry, bool bClose ); + void DrawConvexPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ); + void DrawRect( long nX, long nY, long nWidth, long nHeight ); + void DrawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ); + void DrawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon ); + void DrawTextureRect( const Size& rSize, const SalTwoRect& rPosAry ); + void DrawTexture( GLuint nTexture, const Size& rSize, const SalTwoRect& rPosAry ); + void DrawTextureWithMask( GLuint nTexture, GLuint nMask, const Size& rSize, const SalTwoRect& rPosAry ); + void DrawMask( GLuint nMask, SalColor nMaskColor, const SalTwoRect& rPosAry ); + +protected: + // get the width of the device + virtual GLfloat GetWidth() const = 0; + + // get the height of the device + virtual GLfloat GetHeight() const = 0; + + +public: + virtual ~OpenGLSalGraphicsImpl (); + + OpenGLContext& GetOpenGLContext() { return maContext; } + + virtual void freeResources() SAL_OVERRIDE; + + virtual bool setClipRegion( const vcl::Region& ) SAL_OVERRIDE; + // + // get the depth of the device + virtual sal_uInt16 GetBitCount() const SAL_OVERRIDE; + + // get the width of the device + virtual long GetGraphicsWidth() const SAL_OVERRIDE; + + // set the clip region to empty + virtual void ResetClipRegion() SAL_OVERRIDE; + + // set the line color to transparent (= don't draw lines) + + virtual void SetLineColor() SAL_OVERRIDE; + + // set the line color to a specific color + virtual void SetLineColor( SalColor nSalColor ) SAL_OVERRIDE; + + // set the fill color to transparent (= don't fill) + virtual void SetFillColor() SAL_OVERRIDE; + + // set the fill color to a specific color, shapes will be + // filled accordingly + virtual void SetFillColor( SalColor nSalColor ) SAL_OVERRIDE; + + // enable/disable XOR drawing + virtual void SetXORMode( bool bSet, bool bInvertOnly ) SAL_OVERRIDE; + + // set line color for raster operations + virtual void SetROPLineColor( SalROPColor nROPColor ) SAL_OVERRIDE; + + // set fill color for raster operations + virtual void SetROPFillColor( SalROPColor nROPColor ) SAL_OVERRIDE; + + // draw --> LineColor and FillColor and RasterOp and ClipRegion + virtual void drawPixel( long nX, long nY ) SAL_OVERRIDE; + virtual void drawPixel( long nX, long nY, SalColor nSalColor ) SAL_OVERRIDE; + + virtual void drawLine( long nX1, long nY1, long nX2, long nY2 ) SAL_OVERRIDE; + + virtual void drawRect( long nX, long nY, long nWidth, long nHeight ) SAL_OVERRIDE; + + virtual void drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) SAL_OVERRIDE; + + virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) SAL_OVERRIDE; + + virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) SAL_OVERRIDE; + virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency ) SAL_OVERRIDE; + + virtual bool drawPolyLine( + const ::basegfx::B2DPolygon&, + double fTransparency, + const ::basegfx::B2DVector& rLineWidths, + basegfx::B2DLineJoin, + com::sun::star::drawing::LineCap) SAL_OVERRIDE; + + virtual bool drawPolyLineBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const sal_uInt8* pFlgAry ) SAL_OVERRIDE; + + virtual bool drawPolygonBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const sal_uInt8* pFlgAry ) SAL_OVERRIDE; + + virtual bool drawPolyPolygonBezier( + sal_uInt32 nPoly, + const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, + const sal_uInt8* const* pFlgAry ) SAL_OVERRIDE; + + // CopyArea --> No RasterOp, but ClipRegion + virtual void copyArea( + long nDestX, long nDestY, + long nSrcX, long nSrcY, + long nSrcWidth, long nSrcHeight, + sal_uInt16 nFlags ) SAL_OVERRIDE; + + // CopyBits and DrawBitmap --> RasterOp and ClipRegion + // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics + virtual void copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) SAL_OVERRIDE; + + virtual void drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) SAL_OVERRIDE; + + virtual void drawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + SalColor nTransparentColor ) SAL_OVERRIDE; + + virtual void drawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rMaskBitmap ) SAL_OVERRIDE; + + virtual void drawMask( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + SalColor nMaskColor ) SAL_OVERRIDE; + + virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight ) SAL_OVERRIDE; + + virtual SalColor getPixel( long nX, long nY ) SAL_OVERRIDE; + + // invert --> ClipRegion (only Windows or VirDevs) + virtual void invert( + long nX, long nY, + long nWidth, long nHeight, + SalInvert nFlags) SAL_OVERRIDE; + + virtual void invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags ) SAL_OVERRIDE; + + virtual bool drawEPS( + long nX, long nY, + long nWidth, long nHeight, + void* pPtr, + sal_uLong nSize ) SAL_OVERRIDE; + + /** Render bitmap with alpha channel + + @param rSourceBitmap + Source bitmap to blit + + @param rAlphaBitmap + Alpha channel to use for blitting + + @return true, if the operation succeeded, and false + otherwise. In this case, clients should try to emulate alpha + compositing themselves + */ + virtual bool drawAlphaBitmap( + const SalTwoRect&, + const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap ) SAL_OVERRIDE; + + /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */ + virtual bool drawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) SAL_OVERRIDE; + + /** Render solid rectangle with given transparency + + @param nTransparency + Transparency value (0-255) to use. 0 blits and opaque, 255 a + fully transparent rectangle + */ + virtual bool drawAlphaRect( + long nX, long nY, + long nWidth, long nHeight, + sal_uInt8 nTransparency ) SAL_OVERRIDE; + + virtual bool drawGradient(const tools::PolyPolygon& rPolygon, const Gradient& rGradient) SAL_OVERRIDE; + + virtual bool swapBuffers() SAL_OVERRIDE; +private: +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/quartz/salbmp.h b/vcl/inc/quartz/salbmp.h index cd944319f818..0bde5adba211 100644 --- a/vcl/inc/quartz/salbmp.h +++ b/vcl/inc/quartz/salbmp.h @@ -79,6 +79,8 @@ public: bool GetSystemData( BitmapSystemData& rData ) SAL_OVERRIDE; + bool Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag ) SAL_OVERRIDE; + private: // quartz helper bool CreateContext(); diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h index eb21e09a6710..caab5774accd 100644 --- a/vcl/inc/quartz/salgdi.h +++ b/vcl/inc/quartz/salgdi.h @@ -394,6 +394,8 @@ public: GetGraphicsData() const SAL_OVERRIDE; virtual SystemFontData GetSysFontData( int /* nFallbacklevel */ ) const SAL_OVERRIDE; + virtual bool SwapBuffers() SAL_OVERRIDE { return false; }; + private: // differences between VCL, Quartz and kHiThemeOrientation coordinate systems // make some graphics seem to be vertically-mirrored from a VCL perspective diff --git a/vcl/inc/salbmp.hxx b/vcl/inc/salbmp.hxx index d279715c0dd0..227cc3f6f57b 100644 --- a/vcl/inc/salbmp.hxx +++ b/vcl/inc/salbmp.hxx @@ -54,6 +54,8 @@ public: virtual BitmapBuffer* AcquireBuffer( bool bReadOnly ) = 0; virtual void ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly ) = 0; virtual bool GetSystemData( BitmapSystemData& rData ) = 0; + + virtual bool Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag ) = 0; }; #endif diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx index 2266d87ee64e..a3917bb3e78d 100644 --- a/vcl/inc/salgdi.hxx +++ b/vcl/inc/salgdi.hxx @@ -412,6 +412,8 @@ public: sal_uInt8 nTransparency, const OutputDevice *pOutDev ); + virtual bool SwapBuffers() = 0; + virtual SystemGraphicsData GetGraphicsData() const = 0; virtual SystemFontData GetSysFontData( int nFallbacklevel ) const = 0; diff --git a/vcl/inc/salgdiimpl.hxx b/vcl/inc/salgdiimpl.hxx new file mode 100644 index 000000000000..5d4995201274 --- /dev/null +++ b/vcl/inc/salgdiimpl.hxx @@ -0,0 +1,210 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_SALGDIIMPL_HXX +#define INCLUDED_VCL_INC_SALGDIIMPL_HXX + +#include <vcl/dllapi.h> + +#include <rtl/ustring.hxx> + +#include <tools/solar.h> + +#include <vcl/salgtype.hxx> +#include <vcl/region.hxx> +#include <vcl/salnativewidgets.hxx> + +#include <com/sun/star/drawing/LineCap.hpp> + +class SalGraphics; +class SalBitmap; +class SalFrame; +class Gradient; +class SalVirtualDevice; + +class VCL_PLUGIN_PUBLIC SalGraphicsImpl +{ +public: + + virtual ~SalGraphicsImpl(); + + virtual void freeResources() = 0; + + virtual bool setClipRegion( const vcl::Region& ) = 0; + // + // get the depth of the device + virtual sal_uInt16 GetBitCount() const = 0; + + // get the width of the device + virtual long GetGraphicsWidth() const = 0; + + // set the clip region to empty + virtual void ResetClipRegion() = 0; + + // set the line color to transparent (= don't draw lines) + + virtual void SetLineColor() = 0; + + // set the line color to a specific color + virtual void SetLineColor( SalColor nSalColor ) = 0; + + // set the fill color to transparent (= don't fill) + virtual void SetFillColor() = 0; + + // set the fill color to a specific color, shapes will be + // filled accordingly + virtual void SetFillColor( SalColor nSalColor ) = 0; + + // enable/disable XOR drawing + virtual void SetXORMode( bool bSet, bool bInvertOnly ) = 0; + + // set line color for raster operations + virtual void SetROPLineColor( SalROPColor nROPColor ) = 0; + + // set fill color for raster operations + virtual void SetROPFillColor( SalROPColor nROPColor ) = 0; + + // draw --> LineColor and FillColor and RasterOp and ClipRegion + virtual void drawPixel( long nX, long nY ) = 0; + virtual void drawPixel( long nX, long nY, SalColor nSalColor ) = 0; + + virtual void drawLine( long nX1, long nY1, long nX2, long nY2 ) = 0; + + virtual void drawRect( long nX, long nY, long nWidth, long nHeight ) = 0; + + virtual void drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) = 0; + + virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) = 0; + + virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) = 0; + virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency ) = 0; + + virtual bool drawPolyLine( + const ::basegfx::B2DPolygon&, + double fTransparency, + const ::basegfx::B2DVector& rLineWidths, + basegfx::B2DLineJoin, + com::sun::star::drawing::LineCap) = 0; + + virtual bool drawPolyLineBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const sal_uInt8* pFlgAry ) = 0; + + virtual bool drawPolygonBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const sal_uInt8* pFlgAry ) = 0; + + virtual bool drawPolyPolygonBezier( + sal_uInt32 nPoly, + const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, + const sal_uInt8* const* pFlgAry ) = 0; + + // CopyArea --> No RasterOp, but ClipRegion + virtual void copyArea( + long nDestX, long nDestY, + long nSrcX, long nSrcY, + long nSrcWidth, long nSrcHeight, + sal_uInt16 nFlags ) = 0; + + // CopyBits and DrawBitmap --> RasterOp and ClipRegion + // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics + virtual void copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) = 0; + + virtual void drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) = 0; + + virtual void drawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + SalColor nTransparentColor ) = 0; + + virtual void drawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rMaskBitmap ) = 0; + + virtual void drawMask( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + SalColor nMaskColor ) = 0; + + virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight ) = 0; + + virtual SalColor getPixel( long nX, long nY ) = 0; + + // invert --> ClipRegion (only Windows or VirDevs) + virtual void invert( + long nX, long nY, + long nWidth, long nHeight, + SalInvert nFlags) = 0; + + virtual void invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags ) = 0; + + virtual bool drawEPS( + long nX, long nY, + long nWidth, long nHeight, + void* pPtr, + sal_uLong nSize ) = 0; + + /** Render bitmap with alpha channel + + @param rSourceBitmap + Source bitmap to blit + + @param rAlphaBitmap + Alpha channel to use for blitting + + @return true, if the operation succeeded, and false + otherwise. In this case, clients should try to emulate alpha + compositing themselves + */ + virtual bool drawAlphaBitmap( + const SalTwoRect&, + const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap ) = 0; + + /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */ + virtual bool drawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) = 0; + + /** Render solid rectangle with given transparency + + @param nTransparency + Transparency value (0-255) to use. 0 blits and opaque, 255 a + fully transparent rectangle + */ + virtual bool drawAlphaRect( + long nX, long nY, + long nWidth, long nHeight, + sal_uInt8 nTransparency ) = 0; + + virtual bool drawGradient(const tools::PolyPolygon& rPolygon, const Gradient& rGradient) = 0; + + virtual bool swapBuffers() = 0; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/textrender.hxx b/vcl/inc/textrender.hxx new file mode 100644 index 000000000000..f4dcc8358cb1 --- /dev/null +++ b/vcl/inc/textrender.hxx @@ -0,0 +1,81 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_INC_UNX_CAIROFONTIMPL_HXX +#define INCLUDED_VCL_INC_UNX_CAIROFONTIMPL_HXX + +#include <sal/types.h> +#include <vcl/salgtype.hxx> +#include <vcl/vclenum.hxx> +#include <vcl/metric.hxx> + +#include "salgdi.hxx" +#include "salglyphid.hxx" +#include "fontsubset.hxx" + +class PspSalPrinter; +class PspSalInfoPrinter; +class ServerFont; +class ImplLayoutArgs; +class ServerFontLayout; +class PhysicalFontCollection; +class PhysicalFontFace; + +class TextRenderImpl +{ +public: + virtual ~TextRenderImpl() {} + + virtual void SetTextColor( SalColor nSalColor ) = 0; + virtual sal_uInt16 SetFont( FontSelectPattern*, int nFallbackLevel ) = 0; + virtual void GetFontMetric( ImplFontMetricData*, int nFallbackLevel ) = 0; + virtual const FontCharMapPtr GetFontCharMap() const = 0; + virtual bool GetFontCapabilities(vcl::FontCapabilities &rFontCapabilities) const = 0; + virtual void GetDevFontList( PhysicalFontCollection* ) = 0; + virtual void ClearDevFontCache() = 0; + virtual bool AddTempDevFont( PhysicalFontCollection*, const OUString& rFileURL, const OUString& rFontName ) = 0; + virtual bool CreateFontSubset( const OUString& rToFile, + const PhysicalFontFace*, + sal_GlyphId* pGlyphIDs, + sal_uInt8* pEncoding, + sal_Int32* pWidths, + int nGlyphs, + FontSubsetInfo& rInfo + ) = 0; + virtual const Ucs2SIntMap* GetFontEncodingVector( const PhysicalFontFace*, const Ucs2OStrMap** ppNonEncoded ) = 0; + virtual const void* GetEmbedFontData( const PhysicalFontFace*, + const sal_Ucs* pUnicodes, + sal_Int32* pWidths, + FontSubsetInfo& rInfo, + long* pDataLen ) = 0; + virtual void FreeEmbedFontData( const void* pData, long nDataLen ) = 0; + virtual void GetGlyphWidths( const PhysicalFontFace*, + bool bVertical, + Int32Vector& rWidths, + Ucs2UIntMap& rUnicodeEnc ) = 0; + virtual bool GetGlyphBoundRect( sal_GlyphId nIndex, Rectangle& ) = 0; + virtual bool GetGlyphOutline( sal_GlyphId nIndex, ::basegfx::B2DPolyPolygon& ) = 0; + virtual SalLayout* GetTextLayout( ImplLayoutArgs&, int nFallbackLevel ) = 0; + virtual void DrawServerFontLayout( const ServerFontLayout& ) = 0; + virtual SystemFontData GetSysFontData( int nFallbackLevel ) const = 0; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx index 93a7f1dccb1c..c10f0b5687f9 100644 --- a/vcl/inc/unx/gtk/gtkframe.hxx +++ b/vcl/inc/unx/gtk/gtkframe.hxx @@ -33,6 +33,7 @@ #include <salframe.hxx> #include <vcl/sysdata.hxx> +#include <unx/x11windowprovider.hxx> #include <unx/saltype.h> #include "tools/link.hxx" @@ -58,7 +59,7 @@ typedef ::Window GdkNativeWindow; typedef void GDBusConnection; #endif -class GtkSalFrame : public SalFrame +class GtkSalFrame : public SalFrame, public X11WindowProvider { static const int nMaxGraphics = 2; @@ -445,6 +446,8 @@ public: static GtkSalFrame *getFromWindow( GtkWindow *pWindow ); virtual void damaged (const basegfx::B2IBox& rDamageRect); + + virtual Window GetX11Window() SAL_OVERRIDE; }; #define OOO_TYPE_FIXED ooo_fixed_get_type() diff --git a/vcl/inc/unx/gtk/gtkgdi.hxx b/vcl/inc/unx/gtk/gtkgdi.hxx index b8b145b218d0..05d763caaae8 100644 --- a/vcl/inc/unx/gtk/gtkgdi.hxx +++ b/vcl/inc/unx/gtk/gtkgdi.hxx @@ -114,6 +114,7 @@ private: #else +class GdkX11Pixmap; class GtkSalGraphics : public X11SalGraphics { GtkWidget *m_pWindow; @@ -162,8 +163,8 @@ public: protected: typedef std::list< Rectangle > clipList; - GdkPixmap* NWGetPixmapFromScreen( Rectangle srcRect ); - bool NWRenderPixmapToScreen( GdkPixmap* pPixmap, Rectangle dstRect ); + GdkX11Pixmap* NWGetPixmapFromScreen( Rectangle srcRect ); + bool NWRenderPixmapToScreen( GdkX11Pixmap* pPixmap, Rectangle dstRect ); bool NWPaintGTKArrow( GdkDrawable* gdkDrawable, ControlType nType, ControlPart nPart, const Rectangle& rControlRectangle, diff --git a/vcl/inc/unx/pixmap.hxx b/vcl/inc/unx/pixmap.hxx new file mode 100644 index 000000000000..40bc11f0d0bf --- /dev/null +++ b/vcl/inc/unx/pixmap.hxx @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_UNX_PIXMAP_HXX +#define INCLUDED_VCL_INC_UNX_PIXMAP_HXX + +#include <prex.h> +#include <postx.h> +#include <tools/gen.hxx> +#include <unx/saltype.h> +#include <vclpluginapi.h> + +class VCLPLUG_GEN_PUBLIC X11Pixmap +{ +public: + X11Pixmap(); + X11Pixmap( Display *pDisplay, SalX11Screen nScreen, int nWidth, int nHeight, int nDepth ); + X11Pixmap( X11Pixmap& rOther ); + virtual ~X11Pixmap(); + + Pixmap GetPixmap() const { return mpPixmap; }; + Drawable GetDrawable() const { return mpPixmap; }; + int GetWidth() const { return mnWidth; }; + int GetHeight() const { return mnHeight; }; + Size GetSize() const { return Size( mnWidth, mnHeight ); }; + int GetDepth() const { return mnDepth; }; + SalX11Screen GetScreen() const { return mnScreen; } + +protected: + Display* mpDisplay; + SalX11Screen mnScreen; + Pixmap mpPixmap; + int mnWidth; + int mnHeight; + int mnDepth; +}; + +#endif // INCLUDED_VCL_INC_UNX_PIXMAP_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/salbmp.h b/vcl/inc/unx/salbmp.h index f6cadaab8145..f3f08313e585 100644 --- a/vcl/inc/unx/salbmp.h +++ b/vcl/inc/unx/salbmp.h @@ -145,6 +145,8 @@ public: virtual BitmapBuffer* AcquireBuffer( bool bReadOnly ) SAL_OVERRIDE; virtual void ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly ) SAL_OVERRIDE; virtual bool GetSystemData( BitmapSystemData& rData ) SAL_OVERRIDE; + + virtual bool Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag ) SAL_OVERRIDE; }; // - ImplSalDDB - diff --git a/vcl/inc/unx/salframe.h b/vcl/inc/unx/salframe.h index 637ef677a221..9b737f9aeca1 100644 --- a/vcl/inc/unx/salframe.h +++ b/vcl/inc/unx/salframe.h @@ -26,6 +26,7 @@ #include <unx/salunx.h> #include <unx/saltype.h> #include <unx/saldisp.hxx> +#include <unx/x11windowprovider.hxx> #include <salframe.hxx> #include <salwtype.hxx> #include <salinst.hxx> @@ -48,7 +49,7 @@ namespace vcl_sal { class WMAdaptor; class NetWMAdaptor; class GnomeWMAdaptor; } #define SHOWSTATE_NORMAL 1 #define SHOWSTATE_HIDDEN 2 -class VCLPLUG_GEN_PUBLIC X11SalFrame : public SalFrame +class VCLPLUG_GEN_PUBLIC X11SalFrame : public SalFrame, public X11WindowProvider { friend class vcl_sal::WMAdaptor; friend class vcl_sal::NetWMAdaptor; @@ -270,6 +271,8 @@ public: // done setting up the clipregion virtual void EndSetClipRegion() SAL_OVERRIDE; + virtual Window GetX11Window() SAL_OVERRIDE; + static Bool checkKeyReleaseForRepeat( Display*, XEvent*, XPointer pX11SalFrame ); /// @internal diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h index f56411227405..8a5cc0c43bae 100644 --- a/vcl/inc/unx/salgdi.h +++ b/vcl/inc/unx/salgdi.h @@ -32,6 +32,8 @@ #include "sallayout.hxx" #include "vclpluginapi.h" +#include <boost/scoped_ptr.hpp> + #include <deque> class ImplFontMetricData; @@ -40,8 +42,10 @@ class SalBitmap; class SalColormap; class SalDisplay; class SalFrame; +class X11Pixmap; class X11SalVirtualDevice; -class SalPolyLine; +class X11SalGraphicsImpl; +class X11OpenGLSalGraphicsImpl; class PspSalPrinter; class PspSalInfoPrinter; class ServerFont; @@ -49,44 +53,24 @@ class ImplLayoutArgs; class ServerFontLayout; class PhysicalFontCollection; class PhysicalFontFace; +class SalGraphicsImpl; +class TextRenderImpl; namespace basegfx { class B2DTrapezoid; } -typedef struct FT_FaceRec_* FT_Face; - -class CairoFontsCache +class VCLPLUG_GEN_PUBLIC X11SalGraphics : public SalGraphics { -public: - struct CacheId - { - FT_Face maFace; - const void *mpOptions; - bool mbEmbolden; - bool mbVerticalMetrics; - bool operator ==(const CacheId& rOther) const - { - return maFace == rOther.maFace && - mpOptions == rOther.mpOptions && - mbEmbolden == rOther.mbEmbolden && - mbVerticalMetrics == rOther.mbVerticalMetrics; - } - }; + friend class ServerFontLayout; + friend class X11SalGraphicsImpl; + friend class X11OpenGLSalGraphicsImpl; + friend class X11CairoTextRender; + private: - static int mnRefCount; - typedef std::deque< std::pair<void *, CacheId> > LRUFonts; - static LRUFonts maLRUFonts; -public: - CairoFontsCache(); - static void CacheFont(void *pFont, const CacheId &rId); - static void* FindCachedFont(const CacheId &rId); - ~CairoFontsCache(); -}; + boost::scoped_ptr<SalGraphicsImpl> mpImpl; + boost::scoped_ptr<TextRenderImpl> mpTextRenderImpl; -class VCLPLUG_GEN_PUBLIC X11SalGraphics : public SalGraphics -{ - friend class ServerFontLayout; protected: SalFrame* m_pFrame; // the SalFrame which created this Graphics or NULL X11SalVirtualDevice* m_pVDev; // the SalVirtualDevice which created this Graphics or NULL @@ -97,72 +81,26 @@ protected: SalX11Screen m_nXScreen; mutable XRenderPictFormat* m_pXRenderFormat; XID m_aXRenderPicture; - CairoFontsCache m_aCairoFontsCache; Region pPaintRegion_; Region mpClipRegion; - GC pPenGC_; // Pen attributes - SalColor nPenColor_; - Pixel nPenPixel_; - GC pFontGC_; // Font attributes - ServerFont* mpServerFont[ MAX_FALLBACK ]; + Pixel nTextPixel_; - SalColor nTextColor_; - Pixel nTextPixel_; - - bool bDisableGraphite_; - - GC pBrushGC_; // Brush attributes - SalColor nBrushColor_; - Pixel nBrushPixel_; Pixmap hBrush_; // Dither - GC pMonoGC_; - GC pCopyGC_; - GC pMaskGC_; - GC pInvertGC_; - GC pInvert50GC_; - GC pStippleGC_; - GC pTrackingGC_; - bool bWindow_ : 1; // is Window bool bPrinter_ : 1; // is Printer bool bVirDev_ : 1; // is VirDev - bool bPenGC_ : 1; // is Pen GC valid - bool bFontGC_ : 1; // is Font GC valid - bool bBrushGC_ : 1; // is Brush GC valid - bool bMonoGC_ : 1; // is Mono GC valid - bool bCopyGC_ : 1; // is Copy GC valid - bool bInvertGC_ : 1; // is Invert GC valid - bool bInvert50GC_ : 1; // is Invert50 GC valid - bool bStippleGC_ : 1; // is Stipple GC valid - bool bTrackingGC_ : 1; // is Tracking GC valid - bool bXORMode_ : 1; // is ROP XOR Mode set - bool bDitherBrush_ : 1; // is solid or tile + bool bFontGC_ : 1; // is Font GC valid using SalGraphics::SetClipRegion; void SetClipRegion( GC pGC, Region pXReg = NULL ) const; - GC GetTrackingGC(); - GC GetInvertGC(); - GC GetInvert50GC(); - GC CreateGC( Drawable hDrawable, - unsigned long nMask = GCGraphicsExposures ); - GC SelectPen(); - GC SelectBrush(); - void DrawLines( sal_uIntPtr nPoints, - const SalPolyLine &rPoints, - GC pGC, - bool bClose - ); bool GetDitherPixmap ( SalColor nSalColor ); - inline GC GetMonoGC( Pixmap hPixmap ); - inline GC GetCopyGC(); - inline GC GetStippleGC(); using SalGraphics::DrawBitmap; void DrawBitmap( const SalTwoRect& rPosAry, @@ -172,11 +110,6 @@ protected: SalColor nTransparentColor ); GC GetFontGC(); - bool setFont( const FontSelectPattern* pEntry, int nFallbackLevel ); - - void drawMaskedBitmap( const SalTwoRect& rPosAry, - const SalBitmap& rSalBitmap, - const SalBitmap& rTransparentBitmap ); protected: void DrawPrinterString( const SalLayout& ); @@ -198,12 +131,11 @@ public: inline const SalVisual& GetVisual() const; inline Drawable GetDrawable() const { return hDrawable_; } void SetDrawable( Drawable d, SalX11Screen nXScreen ); - XID GetXRenderPicture(); XRenderPictFormat* GetXRenderFormat() const; inline void SetXRenderFormat( XRenderPictFormat* pXRenderFormat ) { m_pXRenderFormat = pXRenderFormat; } inline const SalColormap& GetColormap() const { return *m_pColormap; } using SalGraphics::GetPixel; - inline Pixel GetPixel( SalColor nSalColor ) const; + inline Pixel GetPixel( SalColor nSalColor ) const; SalX11Screen GetScreenNumber() const { return m_nXScreen; } @@ -211,7 +143,6 @@ public: virtual void GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY ) SAL_OVERRIDE; virtual sal_uInt16 GetBitCount() const SAL_OVERRIDE; virtual long GetGraphicsWidth() const SAL_OVERRIDE; - virtual long GetGraphicsHeight() const; virtual void ResetClipRegion() SAL_OVERRIDE; virtual bool setClipRegion( const vcl::Region& ) SAL_OVERRIDE; @@ -263,7 +194,6 @@ public: virtual void drawPixel( long nX, long nY, SalColor nSalColor ) SAL_OVERRIDE; virtual void drawLine( long nX1, long nY1, long nX2, long nY2 ) SAL_OVERRIDE; virtual void drawRect( long nX, long nY, long nWidth, long nHeight ) SAL_OVERRIDE; - void drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry, bool bClose ); virtual void drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) SAL_OVERRIDE; virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) SAL_OVERRIDE; virtual void drawPolyPolygon( sal_uInt32 nPoly, @@ -276,9 +206,7 @@ public: const ::basegfx::B2DVector& rLineWidth, basegfx::B2DLineJoin, com::sun::star::drawing::LineCap) SAL_OVERRIDE; - virtual bool drawFilledTrapezoids( const ::basegfx::B2DTrapezoid*, int nTrapCount, double fTransparency ); - virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) SAL_OVERRIDE { return false; }; - + virtual bool drawGradient( const tools::PolyPolygon&, const Gradient& ) SAL_OVERRIDE; #if 1 // TODO: remove these obselete methods virtual bool drawPolyLineBezier( sal_uInt32 nPoints, @@ -334,7 +262,16 @@ public: long nHeight, sal_uInt8 nTransparency ) SAL_OVERRIDE; virtual SystemGraphicsData GetGraphicsData() const SAL_OVERRIDE; - virtual SystemFontData GetSysFontData( int nFallbacklevel ) const SAL_OVERRIDE; + virtual SystemFontData GetSysFontData( int nFallbackLevel ) const SAL_OVERRIDE; + + virtual bool SwapBuffers() SAL_OVERRIDE; + + // create a pixmap from a screen region + X11Pixmap* GetPixmapFromScreen( const Rectangle& rRect ); + + // render a pixmap to the screen + bool RenderPixmapToScreen( X11Pixmap* pPixmap, int nX, int nY ); + /* use to handle GraphicsExpose/NoExpose after XCopyArea & friends * if pFrame is not NULL, corresponding Paint events are generated diff --git a/vcl/inc/unx/x11/x11gdiimpl.h b/vcl/inc/unx/x11/x11gdiimpl.h new file mode 100644 index 000000000000..911ea71e8ed3 --- /dev/null +++ b/vcl/inc/unx/x11/x11gdiimpl.h @@ -0,0 +1,27 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_INC_UNX_X11_X11GDIIMPL_HXX +#define INCLUDED_VCL_INC_UNX_X11_X11GDIIMPL_HXX + +#include "unx/pixmap.hxx" + +class X11GraphicsImpl +{ +public: + virtual ~X11GraphicsImpl() {}; + + virtual void Init() = 0; + virtual X11Pixmap* GetPixmapFromScreen( const Rectangle& rRect ) = 0; + virtual bool RenderPixmapToScreen( X11Pixmap* pPixmap, int nX, int nY ) = 0; +}; + +#endif // INCLUDED_VCL_INC_UNX_X11_X11GDIIMPL_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/unx/x11windowprovider.hxx b/vcl/inc/unx/x11windowprovider.hxx new file mode 100644 index 000000000000..776c8e4c4b34 --- /dev/null +++ b/vcl/inc/unx/x11windowprovider.hxx @@ -0,0 +1,28 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_UNX_X11WINDOWPROVIDER +#define INCLUDED_VCL_UNX_X11WINDOWPROVIDER + +#include <prex.h> +#include <postx.h> + +#include <vcl/dllapi.h> + +class VCL_PLUGIN_PUBLIC X11WindowProvider +{ +public: + virtual ~X11WindowProvider(); + + virtual Window GetX11Window() = 0; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/win/salbmp.h b/vcl/inc/win/salbmp.h index 0962facb7e0c..90382363b3e5 100644 --- a/vcl/inc/win/salbmp.h +++ b/vcl/inc/win/salbmp.h @@ -96,6 +96,8 @@ public: virtual BitmapBuffer* AcquireBuffer( bool bReadOnly ); virtual void ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly ); virtual bool GetSystemData( BitmapSystemData& rData ); + + virtual bool Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag ); }; #endif // INCLUDED_VCL_INC_WIN_SALBMP_H diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h index ca423fb46f8d..f09af2813e79 100644 --- a/vcl/inc/win/salgdi.h +++ b/vcl/inc/win/salgdi.h @@ -40,6 +40,7 @@ class FontSelectPattern; class ImplWinFontEntry; class ImplFontAttrCache; class PhysicalFontCollection; +class SalGraphicsImpl; #define RGB_TO_PALRGB(nRGB) ((nRGB)|0x02000000) #define PALRGB_TO_RGB(nPalRGB) ((nPalRGB)&0x00ffffff) @@ -143,29 +144,28 @@ public: class WinSalGraphics : public SalGraphics { + friend class WinSalGraphicsImpl; + friend class ScopedFont; private: - HDC mhLocalDC; // HDC - -public: - HDC getHDC() const { return mhLocalDC; } - void setHDC(HDC aNew) { mhLocalDC = aNew; } + boost::scoped_ptr<SalGraphicsImpl> mpImpl; -public: + HDC mhLocalDC; // HDC + bool mbPrinter : 1; // is Printer + bool mbVirDev : 1; // is VirDev + bool mbWindow : 1; // is Window + bool mbScreen : 1; // is Screen compatible HWND mhWnd; // Window-Handle, when Window-Graphics + HFONT mhFonts[ MAX_FALLBACK ]; // Font + Fallbacks const ImplWinFontData* mpWinFontData[ MAX_FALLBACK ]; // pointer to the most recent font face ImplWinFontEntry* mpWinFontEntry[ MAX_FALLBACK ]; // pointer to the most recent font instance float mfFontScale[ MAX_FALLBACK ]; // allows metrics emulation of huge font sizes float mfCurrentFontScale; - HPEN mhPen; // Pen - HBRUSH mhBrush; // Brush HRGN mhRegion; // vcl::Region Handle HPEN mhDefPen; // DefaultPen HBRUSH mhDefBrush; // DefaultBrush HFONT mhDefFont; // DefaultFont HPALETTE mhDefPal; // DefaultPalette - COLORREF mnPenColor; // PenColor - COLORREF mnBrushColor; // BrushColor COLORREF mnTextColor; // TextColor RGNDATA* mpClipRgnData; // ClipRegion-Data RGNDATA* mpStdClipRgnData; // Cache Standard-ClipRegion-Data @@ -178,27 +178,43 @@ public: sal_uIntPtr mnFontKernPairCount;// Number of Kerning Pairs of the current Font int mnPenWidth; // Linienbreite - /// bitfield - bool mbStockPen : 1; // is Pen a stockpen - bool mbStockBrush : 1; // is Brush a stcokbrush - bool mbPen : 1; // is Pen (FALSE == NULL_PEN) - bool mbBrush : 1; // is Brush (FALSE == NULL_BRUSH) - bool mbPrinter : 1; // is Printer - bool mbVirDev : 1; // is VirDev - bool mbWindow : 1; // is Window - bool mbScreen : 1; // is Screen compatible - bool mbXORMode : 1; // _every_ output with RasterOp XOR +public: + HDC getHDC() const { return mhLocalDC; } + void setHDC(HDC aNew) { mhLocalDC = aNew; } + + HPALETTE getDefPal() const; + void setDefPal(HPALETTE hDefPal); + + HRGN getRegion() const; + + void InitGraphics(); + void DeInitGraphics(); - // remember RGB values for SetLineColor/SetFillColor - SalColor maLineColor; - SalColor maFillColor; + enum Type + { + PRINTER, + VIRTUAL_DEVICE, + WINDOW, + SCREEN + }; + +public: + + HWND gethWnd(); HFONT ImplDoSetFont( FontSelectPattern* i_pFont, float& o_rFontScale, HFONT& o_rOldFont ); public: - explicit WinSalGraphics(); + explicit WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hWnd); virtual ~WinSalGraphics(); + bool isPrinter() const; + bool isVirtualDevice() const; + bool isWindow() const; + bool isScreen() const; + + void setHWND(HWND hWnd); + protected: virtual bool setClipRegion( const vcl::Region& ); // draw --> LineColor and FillColor and RasterOp and ClipRegion @@ -271,7 +287,6 @@ protected: private: // local helpers - bool tryDrawBitmapGdiPlus(const SalTwoRect& rTR, const SalBitmap& rSrcBitmap); // get kernign pairs of the current font sal_uLong GetKernPairs(); @@ -382,13 +397,13 @@ public: virtual SystemGraphicsData GetGraphicsData() const; virtual SystemFontData GetSysFontData( int nFallbacklevel ) const; + virtual bool SwapBuffers() SAL_OVERRIDE; + /// Update settings based on the platform values static void updateSettingsNative( AllSettings& rSettings ); }; // Init/Deinit Graphics -void ImplSalInitGraphics( WinSalGraphics* ); -void ImplSalDeInitGraphics( WinSalGraphics* ); void ImplUpdateSysColorEntries(); int ImplIsSysColorEntry( SalColor nSalColor ); void ImplGetLogFontFromFontSelect( HDC, const FontSelectPattern*, diff --git a/vcl/inc/win/svsys.h b/vcl/inc/win/svsys.h index 5554da9e0b0c..9753a8789025 100644 --- a/vcl/inc/win/svsys.h +++ b/vcl/inc/win/svsys.h @@ -21,9 +21,12 @@ #define INCLUDED_VCL_INC_WIN_SVSYS_H #ifdef WNT +#ifndef INCLUDED_PRE_POST_WIN_H +#define INCLUDED_PRE_POST_WIN_H #include <prewin.h> #include <postwin.h> #endif +#endif #endif // INCLUDED_VCL_INC_WIN_SVSYS_H diff --git a/vcl/opengl/README.deprecated b/vcl/opengl/README.deprecated new file mode 100644 index 000000000000..eb033a0fde41 --- /dev/null +++ b/vcl/opengl/README.deprecated @@ -0,0 +1,23 @@ +deprecated features + +GL_LIGHTING +GL_TEXTURE_2D +GL_POINT_SMOOTH +GL_TEXTURE_WRAP_S +GL_TEXTURE_WRAP_T +glBegin +glEnd + + +GLSL + +texture*D +varying +attribute +missing version string + +gl_FragColor +gl_FragData +gl_Normal +gl_NormalMatrix +gl_Vertex diff --git a/vcl/opengl/convolutionFragmentShader.glsl b/vcl/opengl/convolutionFragmentShader.glsl new file mode 100644 index 000000000000..d4f78027faa3 --- /dev/null +++ b/vcl/opengl/convolutionFragmentShader.glsl @@ -0,0 +1,28 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* TODO Use textureOffset for newest version of GLSL */ + +uniform sampler2D sampler; +uniform vec2 offsets[16]; +uniform float kernel[16]; + +varying vec2 tex_coord; + +void main(void) +{ + vec4 sum = texture2D(sampler, tex_coord.st) * kernel[0]; + for (int i = 1; i < 16; i++) { + sum += texture2D(sampler, tex_coord.st - offsets[i]) * kernel[i]; + sum += texture2D(sampler, tex_coord.st + offsets[i]) * kernel[i]; + } + gl_FragColor = sum; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx new file mode 100644 index 000000000000..7094727c25d1 --- /dev/null +++ b/vcl/opengl/gdiimpl.cxx @@ -0,0 +1,1000 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "openglgdiimpl.hxx" + +#include <vcl/gradient.hxx> +#include <salframe.hxx> +#include "salvd.hxx" +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <basegfx/polygon/b2dlinegeometry.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolygontriangulator.hxx> +#include <basegfx/polygon/b2dpolypolygoncutter.hxx> +#include <basegfx/polygon/b2dtrapezoid.hxx> + +#include <vcl/opengl/OpenGLHelper.hxx> +#include "opengl/salbmp.hxx" + +#include <vector> + +#define GL_ATTRIB_POS 0 +#define GL_ATTRIB_TEX 1 + +#define glUniformColor(nUniform, nColor, nTransparency) \ + glUniform4f( nUniform, \ + ((float) SALCOLOR_RED( nColor )) / 255, \ + ((float) SALCOLOR_GREEN( nColor )) / 255, \ + ((float) SALCOLOR_BLUE( nColor )) / 255, \ + (100 - nTransparency) * (1.0 / 100) ) + +#define glUniformColorf(nUniform, nColor, fTransparency) \ + glUniform4f( nUniform, \ + ((float) SALCOLOR_RED( nColor )) / 255, \ + ((float) SALCOLOR_GREEN( nColor )) / 255, \ + ((float) SALCOLOR_BLUE( nColor )) / 255, \ + (1.0f - fTransparency) ) + +OpenGLSalGraphicsImpl::~OpenGLSalGraphicsImpl() +{ +} + +void OpenGLSalGraphicsImpl::freeResources() +{ + // Delete shaders, programs and textures if not shared +} + +bool OpenGLSalGraphicsImpl::setClipRegion( const vcl::Region& rClip ) +{ + const basegfx::B2DPolyPolygon aClip( rClip.GetAsB2DPolyPolygon() ); + + SAL_INFO( "vcl.opengl", "::setClipRegion" ); + + /*maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + + glEnable( GL_STENCIL_TEST ); + + glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); + glStencilMask( 0xFF ); + glStencilFunc( GL_NEVER, 1, 0xFF ); + glStencilOp( GL_REPLACE, GL_KEEP, GL_KEEP ); + + glClear( GL_STENCIL_BUFFER_BIT ); + BeginSolid( SALCOLOR_NONE ); + DrawPolyPolygon( aClip ); + EndSolid(); + + glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); + glStencilMask( 0x00 ); + glStencilFunc( GL_EQUAL, 1, 0xFF );*/ + + return true; +} + +// set the clip region to empty +void OpenGLSalGraphicsImpl::ResetClipRegion() +{ + SAL_INFO( "vcl.opengl", "::ResetClipRegion" ); + maContext.makeCurrent(); + glDisable(GL_STENCIL_TEST); +} + +// get the depth of the device +sal_uInt16 OpenGLSalGraphicsImpl::GetBitCount() const +{ + return 32; +} + +// get the width of the device +long OpenGLSalGraphicsImpl::GetGraphicsWidth() const +{ + return GetWidth(); +} + +// set the line color to transparent (= don't draw lines) +void OpenGLSalGraphicsImpl::SetLineColor() +{ + if( mnLineColor != SALCOLOR_NONE ) + { + mnLineColor = SALCOLOR_NONE; + } +} + +// set the line color to a specific color +void OpenGLSalGraphicsImpl::SetLineColor( SalColor nSalColor ) +{ + if( mnLineColor != nSalColor ) + { + mnLineColor = nSalColor; + } +} + +// set the fill color to transparent (= don't fill) +void OpenGLSalGraphicsImpl::SetFillColor() +{ + if( mnFillColor != SALCOLOR_NONE ) + { + mnFillColor = SALCOLOR_NONE; + } +} + +// set the fill color to a specific color, shapes will be +// filled accordingly +void OpenGLSalGraphicsImpl::SetFillColor( SalColor nSalColor ) +{ + if( mnFillColor != nSalColor ) + { + mnFillColor = nSalColor; + } +} + +// enable/disable XOR drawing +void OpenGLSalGraphicsImpl::SetXORMode( bool /*bSet*/, bool /*bInvertOnly*/ ) +{ +} + +// set line color for raster operations +void OpenGLSalGraphicsImpl::SetROPLineColor( SalROPColor /*nROPColor*/ ) +{ +} + +// set fill color for raster operations +void OpenGLSalGraphicsImpl::SetROPFillColor( SalROPColor /*nROPColor*/ ) +{ +} + +bool OpenGLSalGraphicsImpl::CreateSolidProgram( void ) +{ + mnSolidProgram = OpenGLHelper::LoadShaders( "solidVertexShader", "solidFragmentShader" ); + if( mnSolidProgram == 0 ) + return false; + + SAL_INFO( "vcl.opengl", "Solid Program Created" ); + glBindAttribLocation( mnSolidProgram, GL_ATTRIB_POS, "position" ); + mnColorUniform = glGetUniformLocation( mnSolidProgram, "color" ); + return true; +} + +bool OpenGLSalGraphicsImpl::CreateTextureProgram( void ) +{ + mnTextureProgram = OpenGLHelper::LoadShaders( "textureVertexShader", "textureFragmentShader" ); + if( mnTextureProgram == 0 ) + return false; + + glBindAttribLocation( mnTextureProgram, GL_ATTRIB_POS, "position" ); + glBindAttribLocation( mnTextureProgram, GL_ATTRIB_TEX, "tex_coord_in" ); + mnSamplerUniform = glGetUniformLocation( mnTextureProgram, "sampler" ); + return true; +} + +bool OpenGLSalGraphicsImpl::CreateMaskedTextureProgram( void ) +{ + mnMaskedTextureProgram = OpenGLHelper::LoadShaders( "maskedTextureVertexShader", "maskedTextureFragmentShader" ); + if( mnMaskedTextureProgram == 0 ) + return false; + + glBindAttribLocation( mnTextureProgram, GL_ATTRIB_POS, "position" ); + glBindAttribLocation( mnTextureProgram, GL_ATTRIB_TEX, "tex_coord_in" ); + mnMaskedSamplerUniform = glGetUniformLocation( mnMaskedTextureProgram, "sampler" ); + mnMaskSamplerUniform = glGetUniformLocation( mnMaskedTextureProgram, "mask" ); + return true; +} + +bool OpenGLSalGraphicsImpl::CreateMaskProgram( void ) +{ + mnMaskedTextureProgram = OpenGLHelper::LoadShaders( "maskVertexShader", "maskFragmentShader" ); + if( mnMaskedTextureProgram == 0 ) + return false; + + glBindAttribLocation( mnTextureProgram, GL_ATTRIB_POS, "position" ); + glBindAttribLocation( mnTextureProgram, GL_ATTRIB_TEX, "tex_coord_in" ); + mnMaskUniform = glGetUniformLocation( mnMaskProgram, "sampler" ); + mnMaskColorUniform = glGetUniformLocation( mnMaskProgram, "mask" ); + return true; +} + +void OpenGLSalGraphicsImpl::BeginSolid( SalColor nColor, sal_uInt8 nTransparency ) +{ + if( mnSolidProgram == 0 ) + { + glClearColor( 1, 1, 1, 1 ); + glClear( GL_COLOR_BUFFER_BIT ); + if( !CreateSolidProgram() ) + return; + } + + if( nTransparency > 0 ) + { + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + } + glUseProgram( mnSolidProgram ); + glUniformColor( mnColorUniform, nColor, nTransparency ); +} + +void OpenGLSalGraphicsImpl::BeginSolid( SalColor nColor, double fTransparency ) +{ + if( mnSolidProgram == 0 ) + { + if( !CreateSolidProgram() ) + return; + } + + if( fTransparency > 0.0f ) + { + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + } + glUseProgram( mnSolidProgram ); + glUniformColorf( mnColorUniform, nColor, fTransparency ); +} + +void OpenGLSalGraphicsImpl::BeginSolid( SalColor nColor ) +{ + BeginSolid( nColor, 0.0f ); +} + +void OpenGLSalGraphicsImpl::EndSolid( void ) +{ + glUseProgram( 0 ); + glDisable( GL_BLEND ); +} + +void OpenGLSalGraphicsImpl::BeginInvert( void ) +{ + glEnable( GL_BLEND ); + glBlendFunc( GL_ONE_MINUS_DST_COLOR, GL_ZERO ); + BeginSolid( MAKE_SALCOLOR( 255, 255, 255 ) ); +} + +void OpenGLSalGraphicsImpl::EndInvert( void ) +{ + EndSolid(); + glDisable( GL_BLEND ); +} + +void OpenGLSalGraphicsImpl::DrawPoint( long nX, long nY ) +{ + GLfloat pPoint[2]; + + pPoint[0] = 2 * nX / GetWidth() - 1.0f; + pPoint[1] = 2 * (GetHeight() - nY) / GetHeight() - 1.0f; + + glEnableVertexAttribArray( GL_ATTRIB_POS ); + glVertexAttribPointer( GL_ATTRIB_POS, 2, GL_UNSIGNED_SHORT, GL_FALSE, 0, pPoint ); + glDrawArrays( GL_POINTS, 0, 1 ); + glDisableVertexAttribArray( GL_ATTRIB_POS ); +} + +void OpenGLSalGraphicsImpl::DrawLine( long nX1, long nY1, long nX2, long nY2 ) +{ + GLfloat pPoints[4]; + + pPoints[0] = (2 * nX1) / GetWidth() - 1.0; + pPoints[1] = (2 * (GetHeight() - nY1)) / GetHeight() - 1.0; + pPoints[2] = (2 * nX2) / GetWidth() - 1.0;; + pPoints[3] = (2 * (GetHeight() - nY2)) / GetHeight() - 1.0; + + glEnableVertexAttribArray( GL_ATTRIB_POS ); + glVertexAttribPointer( GL_ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, pPoints ); + glDrawArrays( GL_LINES, 0, 2 ); + glDisableVertexAttribArray( GL_ATTRIB_POS ); +} + +void OpenGLSalGraphicsImpl::DrawLines( sal_uInt32 nPoints, const SalPoint* pPtAry, bool bClose ) +{ + std::vector<GLfloat> aPoints(nPoints * 2); + sal_uInt32 i, j; + + for( i = 0, j = 0; i < nPoints; i++ ) + { + aPoints[j++] = (2 * pPtAry[i].mnX) / GetWidth() - 1.0f; + aPoints[j++] = 1.0f - (2 * pPtAry[i].mnY) / GetHeight(); + } + + glEnableVertexAttribArray( GL_ATTRIB_POS ); + glVertexAttribPointer( GL_ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, &aPoints[0] ); + if( bClose ) + glDrawArrays( GL_LINE_LOOP, 0, nPoints ); + else + glDrawArrays( GL_LINE_STRIP, 0, nPoints ); + glDisableVertexAttribArray( GL_ATTRIB_POS ); +} + +void OpenGLSalGraphicsImpl::DrawConvexPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) +{ + std::vector<GLfloat> aVertices(nPoints * 2); + sal_uInt32 i, j; + + for( i = 0, j = 0; i < nPoints; i++, j += 2 ) + { + aVertices[j] = (2 * pPtAry[i].mnX) / GetWidth() - 1.0; + aVertices[j+1] = (2 * pPtAry[i].mnY) / GetHeight() - 1.0; + } + + glEnableVertexAttribArray( GL_ATTRIB_POS ); + glVertexAttribPointer( GL_ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, &aVertices[0] ); + glDrawArrays( GL_TRIANGLE_FAN, 0, nPoints ); + glDisableVertexAttribArray( GL_ATTRIB_POS ); +} + +void OpenGLSalGraphicsImpl::DrawRect( long nX, long nY, long nWidth, long nHeight ) +{ + long nX1( nX ); + long nY1( GetHeight() - nY ); + long nX2( nX + nWidth ); + long nY2( GetHeight() - nY - nHeight ); + const SalPoint aPoints[] = { { nX1, nY2 }, { nX1, nY1 }, + { nX2, nY1 }, { nX2, nY2 }}; + + DrawConvexPolygon( 4, aPoints ); +} + +void OpenGLSalGraphicsImpl::DrawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) +{ + ::basegfx::B2DPolygon aPolygon; + + for( sal_uInt32 i = 0; i < nPoints; i++ ) + aPolygon.append( ::basegfx::B2DPoint( pPtAry[i].mnX, pPtAry[i].mnY ) ); + aPolygon.setClosed( true ); + + if( ::basegfx::tools::isConvex( aPolygon ) ) + { + if( nPoints > 2L ) + DrawConvexPolygon( nPoints, pPtAry ); + } + else + { + const ::basegfx::B2DPolyPolygon aPolyPolygon( aPolygon ); + DrawPolyPolygon( aPolyPolygon ); + } +} + +void OpenGLSalGraphicsImpl::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon ) +{ + sal_uInt32 i, j; + ::std::vector< GLfloat > pVertices; + GLfloat nWidth = GetWidth(); + GLfloat nHeight = GetHeight(); + const ::basegfx::B2DPolyPolygon& aSimplePolyPolygon = ::basegfx::tools::solveCrossovers( rPolyPolygon ); + + for( i = 0; i < aSimplePolyPolygon.count(); i++ ) + { + const basegfx::B2DPolygon& rPolygon( aSimplePolyPolygon.getB2DPolygon( i ) ); + const ::basegfx::B2DPolygon& aResult( + ::basegfx::triangulator::triangulate( rPolygon ) ); + + for( j = 0; j < aResult.count(); j++ ) + { + const ::basegfx::B2DPoint& rPt( aResult.getB2DPoint( j ) ); + pVertices.push_back( 2 * rPt.getX() / nWidth - 1.0f ); + pVertices.push_back( 1.0f - 2 * rPt.getY() / nHeight ); + } + } + + glEnableVertexAttribArray( GL_ATTRIB_POS ); + glVertexAttribPointer( GL_ATTRIB_POS, 2, GL_FLOAT, GL_FALSE, 0, pVertices.data() ); + glDrawArrays( GL_TRIANGLES, 0, pVertices.size() / 2 ); + glDisableVertexAttribArray( GL_ATTRIB_POS ); +} + +void OpenGLSalGraphicsImpl::DrawTextureRect( const Size& rSize, const SalTwoRect& rPosAry ) +{ + GLfloat aTexCoord[8]; + + aTexCoord[0] = aTexCoord[2] = rPosAry.mnSrcX / (double) rSize.Width(); + aTexCoord[4] = aTexCoord[6] = (rPosAry.mnSrcX + rPosAry.mnSrcWidth) / (double) rSize.Width(); + aTexCoord[3] = aTexCoord[5] = (rSize.Height() - rPosAry.mnSrcY) / (double) rSize.Height(); + aTexCoord[1] = aTexCoord[7] = (rSize.Height() - rPosAry.mnSrcY - rPosAry.mnSrcHeight) / (double) rSize.Height(); + + glEnableVertexAttribArray( GL_ATTRIB_TEX ); + glVertexAttribPointer( GL_ATTRIB_TEX, 2, GL_FLOAT, GL_FALSE, 0, aTexCoord ); + + DrawRect( rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth, rPosAry.mnDestHeight ); + + glDisableVertexAttribArray( GL_ATTRIB_TEX ); +} + +void OpenGLSalGraphicsImpl::DrawTexture( GLuint nTexture, const Size& rSize, const SalTwoRect& pPosAry ) +{ + if( mnTextureProgram == 0 ) + { + if( !CreateTextureProgram() ) + return; + } + + glUseProgram( mnTextureProgram ); + glUniform1i( mnSamplerUniform, 0 ); + glActiveTexture( GL_TEXTURE0 ); + CHECK_GL_ERROR(); + glBindTexture( GL_TEXTURE_2D, nTexture ); + + DrawTextureRect( rSize, pPosAry ); + CHECK_GL_ERROR(); + + glBindTexture( GL_TEXTURE_2D, 0 ); + glUseProgram( 0 ); +} + +void OpenGLSalGraphicsImpl::DrawTextureWithMask( GLuint nTexture, GLuint nMask, const Size& rSize, const SalTwoRect& pPosAry ) +{ + if( mnMaskedTextureProgram == 0 ) + { + if( !CreateMaskedTextureProgram() ) + return; + } + + glUseProgram( mnMaskedTextureProgram ); + glUniform1i( mnMaskedSamplerUniform, 0 ); + glUniform1i( mnMaskSamplerUniform, 1 ); + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( GL_TEXTURE_2D, nTexture ); + glActiveTexture( GL_TEXTURE1 ); + glBindTexture( GL_TEXTURE_2D, nMask ); + + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + DrawTextureRect( rSize, pPosAry ); + glDisable( GL_BLEND ); + + glActiveTexture( GL_TEXTURE1 ); + glBindTexture( GL_TEXTURE_2D, 0 ); + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( GL_TEXTURE_2D, 0 ); + glUseProgram( 0 ); +} + +void OpenGLSalGraphicsImpl::DrawMask( GLuint nMask, SalColor nMaskColor, const SalTwoRect& /*pPosAry*/ ) +{ + if( mnMaskProgram == 0 ) + { + if( !CreateMaskProgram() ) + return; + } + + glUseProgram( mnMaskProgram ); + glUniformColor( mnMaskColorUniform, nMaskColor, 0 ); + glUniform1i( mnMaskUniform, 0 ); + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( GL_TEXTURE_2D, nMask ); + + //DrawTextureRect( pPosAry ); + + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( GL_TEXTURE_2D, 0 ); + glUseProgram( 0 ); +} + + +// draw --> LineColor and FillColor and RasterOp and ClipRegion +void OpenGLSalGraphicsImpl::drawPixel( long nX, long nY ) +{ + SAL_INFO( "vcl.opengl", "::drawPixel" ); + if( mnLineColor != SALCOLOR_NONE ) + { + maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + BeginSolid( mnLineColor ); + DrawPoint( nX, nY ); + EndSolid(); + } +} + +void OpenGLSalGraphicsImpl::drawPixel( long nX, long nY, SalColor nSalColor ) +{ + SAL_INFO( "vcl.opengl", "::drawPixel" ); + if( nSalColor != SALCOLOR_NONE ) + { + maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + BeginSolid( nSalColor ); + DrawPoint( nX, nY ); + EndSolid(); + } +} + +void OpenGLSalGraphicsImpl::drawLine( long nX1, long nY1, long nX2, long nY2 ) +{ + SAL_INFO( "vcl.opengl", "::drawLine" ); + if( mnLineColor != SALCOLOR_NONE ) + { + maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + BeginSolid( mnLineColor ); + DrawLine( nX1, nY1, nX2, nY2 ); + EndSolid(); + } +} + +void OpenGLSalGraphicsImpl::drawRect( long nX, long nY, long nWidth, long nHeight ) +{ + SAL_INFO( "vcl.opengl", "::drawRect" ); + maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + + if( mnFillColor != SALCOLOR_NONE ) + { + BeginSolid( mnFillColor ); + DrawRect( nX, nY, nWidth, nHeight ); + EndSolid(); + } + + if( mnLineColor != SALCOLOR_NONE ) + { + const long nX1( nX ); + const long nY1( nY ); + const long nX2( nX + nWidth - 1 ); + const long nY2( nY + nHeight - 1 ); + const SalPoint aPoints[] = { { nX1, nY1 }, { nX2, nY1 }, + { nX2, nY2 }, { nX1, nY2 } }; + + BeginSolid( mnLineColor ); + DrawLines( 4, aPoints, true ); + EndSolid(); + } +} + +void OpenGLSalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) +{ + SAL_INFO( "vcl.opengl", "::drawPolyLine" ); + maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + + if( mnLineColor != SALCOLOR_NONE && nPoints > 1 ) + { + BeginSolid( mnLineColor ); + DrawLines( nPoints, pPtAry, false ); + EndSolid(); + } +} + +void OpenGLSalGraphicsImpl::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) +{ + SAL_INFO( "vcl.opengl", "::drawPolygon" ); + if( nPoints == 0 ) + return; + if( nPoints == 1 ) + { + drawPixel( pPtAry[0].mnX, pPtAry[0].mnY ); + return; + } + if( nPoints == 2 ) + { + drawLine( pPtAry[0].mnX, pPtAry[0].mnY, + pPtAry[1].mnX, pPtAry[1].mnY ); + return; + } + + maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + + if( mnFillColor != SALCOLOR_NONE ) + { + BeginSolid( mnFillColor ); + DrawPolygon( nPoints, pPtAry ); + EndSolid(); + } + + if( mnLineColor != SALCOLOR_NONE ) + { + BeginSolid( mnLineColor ); + DrawLines( nPoints, pPtAry, true ); + EndSolid(); + } +} + +void OpenGLSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) +{ + SAL_INFO( "vcl.opengl", "::drawPolyPolygon" ); + if( nPoly <= 0 ) + return; + + maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + + if( mnFillColor != SALCOLOR_NONE ) + { + BeginSolid( mnFillColor ); + for( sal_uInt32 i = 0; i < nPoly; i++ ) + DrawPolygon( pPoints[i], pPtAry[i] ); + EndSolid(); + } + + if( mnLineColor != SALCOLOR_NONE ) + { + // TODO Use glMultiDrawElements or primitive restart + BeginSolid( mnLineColor ); + for( sal_uInt32 i = 0; i < nPoly; i++ ) + DrawLines( pPoints[i], pPtAry[i], true ); + EndSolid(); + } +} + +bool OpenGLSalGraphicsImpl::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency ) +{ + SAL_INFO( "vcl.opengl", "::drawPolyPolygon trans " << fTransparency ); + if( rPolyPolygon.count() <= 0 ) + return true; + + maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + + if( mnFillColor != SALCOLOR_NONE ) + { + BeginSolid( mnFillColor, fTransparency ); + for( sal_uInt32 i = 0; i < rPolyPolygon.count(); i++ ) + { + const ::basegfx::B2DPolyPolygon aOnePoly( rPolyPolygon.getB2DPolygon( i ) ); + DrawPolyPolygon( aOnePoly ); + } + EndSolid(); + } + + return true; +} + +bool OpenGLSalGraphicsImpl::drawPolyLine( + const ::basegfx::B2DPolygon& rPolygon, + double fTransparency, + const ::basegfx::B2DVector& rLineWidth, + basegfx::B2DLineJoin eLineJoin, + com::sun::star::drawing::LineCap eLineCap) +{ + SAL_INFO( "vcl.opengl", "::drawPolyLine trans " << fTransparency ); + if( mnLineColor == SALCOLOR_NONE ) + return true; + + const bool bIsHairline = (rLineWidth.getX() == rLineWidth.getY()) && (rLineWidth.getX() <= 1.2); + + // #i101491# + if( !bIsHairline && (rPolygon.count() > 1000) ) + { + // the used basegfx::tools::createAreaGeometry is simply too + // expensive with very big polygons; fallback to caller (who + // should use ImplLineConverter normally) + // AW: ImplLineConverter had to be removed since it does not even + // know LineJoins, so the fallback will now prepare the line geometry + // the same way. + return false; + } + + // #i11575#desc5#b adjust B2D tesselation result to raster positions + basegfx::B2DPolygon aPolygon = rPolygon; + const double fHalfWidth = 0.5 * rLineWidth.getX(); + + // #i122456# This is probably thought to happen to align hairlines to pixel positions, so + // it should be a 0.5 translation, not more. It will definitely go wrong with fat lines + aPolygon.transform( basegfx::tools::createTranslateB2DHomMatrix(0.5, 0.5) ); + + // shortcut for hairline drawing to improve performance + //bool bDrawnOk = true; + if( bIsHairline ) + { + // hairlines can benefit from a simplified tesselation + // e.g. for hairlines the linejoin style can be ignored + /*basegfx::B2DTrapezoidVector aB2DTrapVector; + basegfx::tools::createLineTrapezoidFromB2DPolygon( aB2DTrapVector, aPolygon, rLineWidth.getX() ); + + // draw tesselation result + const int nTrapCount = aB2DTrapVector.size(); + if( nTrapCount > 0 ) + bDrawnOk = drawFilledTrapezoids( &aB2DTrapVector[0], nTrapCount, fTransparency ); + + return bDrawnOk;*/ + } + + // get the area polygon for the line polygon + if( (rLineWidth.getX() != rLineWidth.getY()) + && !basegfx::fTools::equalZero( rLineWidth.getY() ) ) + { + // prepare for createAreaGeometry() with anisotropic linewidth + aPolygon.transform( basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getX() / rLineWidth.getY())); + } + + // create the area-polygon for the line + const basegfx::B2DPolyPolygon aAreaPolyPoly( basegfx::tools::createAreaGeometry(aPolygon, fHalfWidth, eLineJoin, eLineCap) ); + + if( (rLineWidth.getX() != rLineWidth.getY()) + && !basegfx::fTools::equalZero( rLineWidth.getX() ) ) + { + // postprocess createAreaGeometry() for anisotropic linewidth + aPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getY() / rLineWidth.getX())); + } + + maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + BeginSolid( mnLineColor, fTransparency ); + for( sal_uInt32 i = 0; i < aAreaPolyPoly.count(); i++ ) + { + const ::basegfx::B2DPolyPolygon aOnePoly( aAreaPolyPoly.getB2DPolygon( i ) ); + DrawPolyPolygon( aOnePoly ); + } + EndSolid(); + + return true; +} + +bool OpenGLSalGraphicsImpl::drawPolyLineBezier( + sal_uInt32 /*nPoints*/, + const SalPoint* /*pPtAry*/, + const sal_uInt8* /*pFlgAry*/ ) +{ + return false; +} + +bool OpenGLSalGraphicsImpl::drawPolygonBezier( + sal_uInt32 /*nPoints*/, + const SalPoint* /*pPtAry*/, + const sal_uInt8* /*pFlgAry*/ ) +{ + return false; +} + +bool OpenGLSalGraphicsImpl::drawPolyPolygonBezier( + sal_uInt32 /*nPoly*/, + const sal_uInt32* /*pPoints*/, + const SalPoint* const* /*pPtAry*/, + const sal_uInt8* const* /*pFlgAry*/ ) +{ + return NULL; +} + +// CopyArea --> No RasterOp, but ClipRegion +void OpenGLSalGraphicsImpl::copyArea( + long /*nDestX*/, long /*nDestY*/, + long /*nSrcX*/, long /*nSrcY*/, + long /*nSrcWidth*/, long /*nSrcHeight*/, + sal_uInt16 /*nFlags*/ ) +{ + SAL_INFO( "vcl.opengl", "::copyArea" ); +} + +// CopyBits and DrawBitmap --> RasterOp and ClipRegion +// CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics +void OpenGLSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics* /*pSrcGraphics*/ ) +{ + // TODO Check if SalGraphicsImpl is the same + const bool bSameGraphics( false ); + + SAL_INFO( "vcl.opengl", "::copyBits" ); + if( bSameGraphics && + (rPosAry.mnSrcWidth == rPosAry.mnDestWidth) && + (rPosAry.mnSrcHeight == rPosAry.mnDestHeight)) + { + // short circuit if there is nothing to do + if( (rPosAry.mnSrcX == rPosAry.mnDestX) && + (rPosAry.mnSrcY == rPosAry.mnDestY)) + return; + // use copyArea() if source and destination context are identical + copyArea( rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnSrcX, rPosAry.mnSrcY, + rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, 0 ); + return; + } + + // TODO Copy from one FBO to the other (glBlitFramebuffer) +} + +void OpenGLSalGraphicsImpl::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) +{ + const OpenGLSalBitmap& rBitmap = static_cast<const OpenGLSalBitmap&>(rSalBitmap); + GLuint nTexture = rBitmap.GetTexture( maContext ); + const Size aSize = rSalBitmap.GetSize(); + + SAL_INFO( "vcl.opengl", "::drawBitmap" ); + maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + DrawTexture( nTexture, aSize, rPosAry ); +} + +void OpenGLSalGraphicsImpl::drawBitmap( + const SalTwoRect& /*rPosAry*/, + const SalBitmap& /*rSalBitmap*/, + SalColor /*nTransparentColor*/ ) +{ + OSL_FAIL( "::DrawBitmap with transparent color not supported" ); +} + +void OpenGLSalGraphicsImpl::drawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rMaskBitmap ) +{ + const OpenGLSalBitmap& rBitmap = static_cast<const OpenGLSalBitmap&>(rSalBitmap); + const OpenGLSalBitmap& rMask = static_cast<const OpenGLSalBitmap&>(rMaskBitmap); + const GLuint nTexture( rBitmap.GetTexture( maContext ) ); + const GLuint nMask( rMask.GetTexture( maContext ) ); + + SAL_INFO( "vcl.opengl", "::drawBitmap with MASK" ); + maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + DrawTextureWithMask( nTexture, nMask, rBitmap.GetSize(), rPosAry ); +} + +void OpenGLSalGraphicsImpl::drawMask( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + SalColor nMaskColor ) +{ + const OpenGLSalBitmap& rBitmap = static_cast<const OpenGLSalBitmap&>(rSalBitmap); + const GLuint nTexture( rBitmap.GetTexture( maContext ) ); + + SAL_INFO( "vcl.opengl", "::drawMask" ); + maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + DrawMask( nTexture, nMaskColor, rPosAry ); +} + +SalBitmap* OpenGLSalGraphicsImpl::getBitmap( long nX, long nY, long nWidth, long nHeight ) +{ + OpenGLSalBitmap* pBitmap = new OpenGLSalBitmap; + SAL_INFO( "vcl.opengl", "::getBitmap " << nX << "," << nY << + " " << nWidth << "x" << nHeight ); + if( !pBitmap->Create( maContext, nX, nY, nWidth, nHeight ) ) + { + delete pBitmap; + pBitmap = NULL; + } + return pBitmap; +} + +SalColor OpenGLSalGraphicsImpl::getPixel( long nX, long nY ) +{ + char pixel[3]; + + maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + glReadPixels( nX, nY, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, pixel); + return MAKE_SALCOLOR( pixel[0], pixel[1], pixel[2] ); +} + +// invert --> ClipRegion (only Windows or VirDevs) +void OpenGLSalGraphicsImpl::invert( + long nX, long nY, + long nWidth, long nHeight, + SalInvert nFlags) +{ + // TODO Figure out what are those: + // * SAL_INVERT_50 (50/50 pattern?) + // * SAL_INVERT_TRACKFRAME (dash-line rectangle?) + + maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + + if( nFlags & SAL_INVERT_TRACKFRAME ) + { + + } + else if( nFlags & SAL_INVERT_50 ) + { + + } + else // just invert + { + BeginInvert(); + DrawRect( nX, nY, nWidth, nHeight ); + EndInvert(); + } +} + +void OpenGLSalGraphicsImpl::invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags ) +{ + maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + + if( nFlags & SAL_INVERT_TRACKFRAME ) + { + + } + else if( nFlags & SAL_INVERT_50 ) + { + + } + else // just invert + { + BeginInvert(); + DrawPolygon( nPoints, pPtAry ); + EndInvert(); + } +} + +bool OpenGLSalGraphicsImpl::drawEPS( + long /*nX*/, long /*nY*/, + long /*nWidth*/, long /*nHeight*/, + void* /*pPtr*/, + sal_uLong /*nSize*/ ) +{ + return false; +} + +/** Render bitmap with alpha channel + + @param rSourceBitmap + Source bitmap to blit + + @param rAlphaBitmap + Alpha channel to use for blitting + + @return true, if the operation succeeded, and false + otherwise. In this case, clients should try to emulate alpha + compositing themselves + */ +bool OpenGLSalGraphicsImpl::drawAlphaBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rAlphaBitmap ) +{ + const OpenGLSalBitmap& rBitmap = static_cast<const OpenGLSalBitmap&>(rSalBitmap); + const OpenGLSalBitmap& rAlpha = static_cast<const OpenGLSalBitmap&>(rAlphaBitmap); + const GLuint nTexture( rBitmap.GetTexture( maContext ) ); + const GLuint nAlpha( rAlpha.GetTexture( maContext ) ); + + SAL_INFO( "vcl.opengl", "::drawAlphaBitmap" ); + maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + DrawTextureWithMask( nTexture, nAlpha, rBitmap.GetSize(), rPosAry ); + return true; +} + +/** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */ +bool OpenGLSalGraphicsImpl::drawTransformedBitmap( + const basegfx::B2DPoint& /*rNull*/, + const basegfx::B2DPoint& /*rX*/, + const basegfx::B2DPoint& /*rY*/, + const SalBitmap& /*rSourceBitmap*/, + const SalBitmap* /*pAlphaBitmap*/) +{ + return false; +} + +/** Render solid rectangle with given transparency + + @param nTransparency + Transparency value (0-255) to use. 0 blits and opaque, 255 a + fully transparent rectangle + */ +bool OpenGLSalGraphicsImpl::drawAlphaRect( + long nX, long nY, + long nWidth, long nHeight, + sal_uInt8 nTransparency ) +{ + SAL_INFO( "vcl.opengl", "::drawAlphaRect" ); + if( mnFillColor != SALCOLOR_NONE && nTransparency < 100 ) + { + BeginSolid( mnFillColor, nTransparency ); + DrawRect( nX, nY, nWidth, nHeight ); + EndSolid(); + } + + return true; +} + +bool OpenGLSalGraphicsImpl::drawGradient(const tools::PolyPolygon& /*rPolygon*/, + const Gradient& /*rGradient*/) +{ + return false; +} + +bool OpenGLSalGraphicsImpl::swapBuffers() +{ + maContext.swapBuffers(); + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/maskFragmentShader.glsl b/vcl/opengl/maskFragmentShader.glsl new file mode 100644 index 000000000000..4a8204e6a663 --- /dev/null +++ b/vcl/opengl/maskFragmentShader.glsl @@ -0,0 +1,21 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +precision mediump float; +varying vec2 tex_coord; +uniform sampler2D sampler; +uniform vec4 color;" + +void main() { + vec4 texel0; + texel0 = texture2D(sampler, tex_coord); + gl_FragColor = color * texel0.a; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/maskVertexShader.glsl b/vcl/opengl/maskVertexShader.glsl new file mode 100644 index 000000000000..99d7f37eb05f --- /dev/null +++ b/vcl/opengl/maskVertexShader.glsl @@ -0,0 +1,19 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +attribute vec4 position; +attribute vec2 tex_coord_in; +varying vec2 tex_coord; + +void main() { + gl_Position = position; + tex_coord = tex_coord_in; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/maskedTextureFragmentShader.glsl b/vcl/opengl/maskedTextureFragmentShader.glsl new file mode 100644 index 000000000000..badf91e6edae --- /dev/null +++ b/vcl/opengl/maskedTextureFragmentShader.glsl @@ -0,0 +1,23 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/*precision mediump float;*/ +varying vec2 tex_coord; +uniform sampler2D sampler; +uniform sampler2D mask; + +void main() { + vec4 texel0, texel1; + texel0 = texture2D(sampler, tex_coord); + texel1 = texture2D(mask, tex_coord); + gl_FragColor = texel0; + gl_FragColor.a = texel1.r; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/maskedTextureVertexShader.glsl b/vcl/opengl/maskedTextureVertexShader.glsl new file mode 100644 index 000000000000..99d7f37eb05f --- /dev/null +++ b/vcl/opengl/maskedTextureVertexShader.glsl @@ -0,0 +1,19 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +attribute vec4 position; +attribute vec2 tex_coord_in; +varying vec2 tex_coord; + +void main() { + gl_Position = position; + tex_coord = tex_coord_in; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/salbmp.cxx b/vcl/opengl/salbmp.cxx new file mode 100644 index 000000000000..564426ce73d1 --- /dev/null +++ b/vcl/opengl/salbmp.cxx @@ -0,0 +1,513 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <vcl/opengl/OpenGLHelper.hxx> + +#include "vcl/bitmap.hxx" +#include "vcl/salbtype.hxx" +#include "salgdi.hxx" + +#include "opengl/salbmp.hxx" + +static bool isValidBitCount( sal_uInt16 nBitCount ) +{ + return (nBitCount == 1) || (nBitCount == 4) || (nBitCount == 8) || (nBitCount == 16) || (nBitCount == 24) || (nBitCount == 32); +} + +OpenGLSalBitmap::OpenGLSalBitmap() +: mpContext(NULL) +, mbDirtyTexture(true) +, mnBits(0) +, mnBytesPerRow(0) +, mnWidth(0) +, mnHeight(0) +, mnBufWidth(0) +, mnBufHeight(0) +, mnTexProgram(0) +, mnConvProgram(0) +{ +} + +OpenGLSalBitmap::~OpenGLSalBitmap() +{ + Destroy(); + SAL_INFO( "vcl.opengl", "~OpenGLSalBitmap" ); +} + +bool OpenGLSalBitmap::Create( OpenGLContext& rContext, long nX, long nY, long nWidth, long nHeight ) +{ + static const BitmapPalette aEmptyPalette; + + Destroy(); + SAL_INFO( "vcl.opengl", "OpenGLSalBitmap::Create from FBO" ); + + mpContext = &rContext; + mpContext->makeCurrent(); + mnWidth = nWidth; + mnHeight = nHeight; + mnBufWidth = 0; + mnBufHeight = 0; + + // TODO Check the framebuffer configuration + mnBits = 32; + maPalette = aEmptyPalette; + + mpTexture.reset( new OpenGLTexture( nX, nY, nWidth, nHeight ) ); + mbDirtyTexture = false; + + return true; +} + +bool OpenGLSalBitmap::Create( const Size& rSize, sal_uInt16 nBits, const BitmapPalette& rBitmapPalette ) +{ + Destroy(); + SAL_INFO( "vcl.opengl", "OpenGLSalBitmap::Create with size" ); + + if( !isValidBitCount( nBits ) ) + return false; + maPalette = rBitmapPalette; + mnBits = nBits; + mnWidth = mnBufWidth = rSize.Width(); + mnHeight = mnBufHeight = rSize.Height(); + return false; +} + +bool OpenGLSalBitmap::Create( const SalBitmap& rSalBmp ) +{ + return Create( rSalBmp, rSalBmp.GetBitCount() ); +} + +bool OpenGLSalBitmap::Create( const SalBitmap& rSalBmp, SalGraphics* pGraphics ) +{ + return Create( rSalBmp, pGraphics ? pGraphics->GetBitCount() : rSalBmp.GetBitCount() ); +} + +bool OpenGLSalBitmap::Create( const SalBitmap& rSalBmp, sal_uInt16 nNewBitCount ) +{ + const OpenGLSalBitmap& rSourceBitmap = static_cast<const OpenGLSalBitmap&>(rSalBmp); + + SAL_INFO( "vcl.opengl", "OpenGLSalBitmap::Create from BMP " << rSourceBitmap.mnHeight ); + + if( isValidBitCount( nNewBitCount ) ) + { + // TODO: lfrb: What about the pending operations?! + mnBits = nNewBitCount; + mnBytesPerRow = rSourceBitmap.mnBytesPerRow; + mnWidth = rSourceBitmap.mnWidth; + mnHeight = rSourceBitmap.mnHeight; + mnBufWidth = rSourceBitmap.mnBufWidth; + mnBufHeight = rSourceBitmap.mnBufHeight; + maPalette = rSourceBitmap.maPalette; + mpContext = rSourceBitmap.mpContext; + mpTexture = rSourceBitmap.mpTexture; + mbDirtyTexture = false; + maUserBuffer = rSourceBitmap.maUserBuffer; + + // TODO Copy buffer data if the bitcount and palette are the same + return true; + } + return false; +} + +bool OpenGLSalBitmap::Create( const ::com::sun::star::uno::Reference< ::com::sun::star::rendering::XBitmapCanvas > /*xBitmapCanvas*/, Size& /*rSize*/, bool /*bMask*/ ) +{ + // TODO Is this method needed? + return false; +} + +bool OpenGLSalBitmap::Draw( OpenGLContext& rContext, const SalTwoRect& /*rPosAry*/ ) +{ + if( !mpContext ) + mpContext = &rContext; + + if( !mpTexture || mbDirtyTexture ) + { + if( !CreateTexture() ) + return false; + } + + //DrawTexture( mnTexture, rPosAry ); + return true; +} + +GLuint OpenGLSalBitmap::GetTexture( OpenGLContext& rContext ) const +{ + if( !mpContext ) + const_cast<OpenGLSalBitmap*>(this)->mpContext = &rContext; + if( !mpTexture || mbDirtyTexture ) + const_cast<OpenGLSalBitmap*>(this)->CreateTexture(); + return mpTexture->Id(); +} + +void OpenGLSalBitmap::Destroy() +{ + SAL_INFO( "vcl.opengl", "Destroy OpenGLSalBitmap" ); + maPendingOps.clear(); + mpTexture.reset(); + maUserBuffer.reset(); +} + +bool OpenGLSalBitmap::AllocateUserData() +{ + SAL_INFO( "vcl.opengl", "OpenGLSalBitmap::AllocateUserData" ); + + if( mnWidth && mnHeight ) + { + mnBytesPerRow = 0; + + switch( mnBits ) + { + case 1: mnBytesPerRow = (mnWidth + 7) >> 3; break; + case 4: mnBytesPerRow = (mnWidth + 1) >> 1; break; + case 8: mnBytesPerRow = mnWidth; break; + case 16: mnBytesPerRow = mnWidth << 1; break; + case 24: mnBytesPerRow = (mnWidth << 1) + mnWidth; break; + case 32: mnBytesPerRow = mnWidth << 2; break; + default: + OSL_FAIL("vcl::OpenGLSalBitmap::AllocateUserData(), illegal bitcount!"); + } + } + + bool alloc = false; + if (mnBytesPerRow != 0 + && mnBytesPerRow <= std::numeric_limits<sal_uInt32>::max() / mnHeight) + { + try + { + maUserBuffer.reset( new sal_uInt8[mnBytesPerRow * mnHeight] ); + alloc = true; + } + catch (std::bad_alloc &) {} + } + if (!alloc) + { + SAL_WARN( + "vcl.opengl", "bad alloc " << mnBytesPerRow << "x" << mnHeight); + maUserBuffer.reset( static_cast<sal_uInt8*>(NULL) ); + mnBytesPerRow = 0; + } +#ifdef DBG_UTIL + else + { + for (size_t i = 0; i < size_t(mnBytesPerRow * mnHeight); i++) + maUserBuffer.get()[i] = (i & 0xFF); + } +#endif + + return maUserBuffer.get() != 0; +} + +class ImplPixelFormat +{ +protected: + sal_uInt8* mpData; +public: + static ImplPixelFormat* GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette ); + + virtual void StartLine( sal_uInt8* pLine ) { mpData = pLine; } + virtual const BitmapColor& ReadPixel() = 0; + virtual ~ImplPixelFormat() { } +}; + +class ImplPixelFormat8 : public ImplPixelFormat +{ +private: + const BitmapPalette& mrPalette; + +public: + ImplPixelFormat8( const BitmapPalette& rPalette ) + : mrPalette( rPalette ) + { + } + virtual const BitmapColor& ReadPixel() SAL_OVERRIDE + { + return mrPalette[ *mpData++ ]; + } +}; + +class ImplPixelFormat4 : public ImplPixelFormat +{ +private: + const BitmapPalette& mrPalette; + sal_uInt32 mnX; + sal_uInt32 mnShift; + +public: + ImplPixelFormat4( const BitmapPalette& rPalette ) + : mrPalette( rPalette ) + { + } + virtual void StartLine( sal_uInt8* pLine ) SAL_OVERRIDE + { + mpData = pLine; + mnX = 0; + mnShift = 4; + } + virtual const BitmapColor& ReadPixel() SAL_OVERRIDE + { + const BitmapColor& rColor = mrPalette[( mpData[mnX >> 1] >> mnShift) & 0x0f]; + mnX++; + mnShift ^= 4; + return rColor; + } +}; + +class ImplPixelFormat1 : public ImplPixelFormat +{ +private: + const BitmapPalette& mrPalette; + sal_uInt32 mnX; + +public: + ImplPixelFormat1( const BitmapPalette& rPalette ) + : mrPalette( rPalette ) + { + } + virtual void StartLine( sal_uInt8* pLine ) SAL_OVERRIDE + { + mpData = pLine; + mnX = 0; + } + virtual const BitmapColor& ReadPixel() SAL_OVERRIDE + { + const BitmapColor& rColor = mrPalette[ (mpData[mnX >> 3 ] >> ( 7 - ( mnX & 7 ) )) & 1]; + mnX++; + return rColor; + } +}; + +ImplPixelFormat* ImplPixelFormat::GetFormat( sal_uInt16 nBits, const BitmapPalette& rPalette ) +{ + switch( nBits ) + { + case 1: return new ImplPixelFormat1( rPalette ); + case 4: return new ImplPixelFormat4( rPalette ); + case 8: return new ImplPixelFormat8( rPalette ); + } + + return 0; +} + +Size OpenGLSalBitmap::GetSize() const +{ + std::deque< OpenGLSalBitmapOp* >::const_iterator it = maPendingOps.begin(); + Size aSize( mnWidth, mnHeight ); + + while( it != maPendingOps.end() ) + (*it++)->GetSize( aSize ); + + return aSize; +} + +GLuint OpenGLSalBitmap::CreateTexture() +{ + GLenum nFormat, nType; + sal_uInt8* pData( NULL ); + bool bAllocated( false ); + + if( maUserBuffer.get() != 0 ) + { + if( mnBits == 16 || mnBits == 24 || mnBits == 32 ) + { + // no conversion needed for truecolor + pData = maUserBuffer.get(); + + switch( mnBits ) + { + case 16: nFormat = GL_RGB; + nType = GL_UNSIGNED_SHORT_5_6_5; + break; + case 24: nFormat = GL_RGB; + nType = GL_UNSIGNED_BYTE; + break; + case 32: nFormat = GL_RGBA; + nType = GL_UNSIGNED_BYTE; + break; + } + } + else if( mnBits == 8 && maPalette.IsGreyPalette() ) + { + // no conversion needed for grayscale + pData = maUserBuffer.get(); + nFormat = GL_LUMINANCE; + nType = GL_UNSIGNED_BYTE; + } + else + { + // convert to 32 bits RGBA using palette + pData = new sal_uInt8[ mnBufHeight * (mnBufWidth << 2) ]; + bAllocated = true; + nFormat = GL_RGBA; + nType = GL_UNSIGNED_BYTE; + + ImplPixelFormat* pSrcFormat = ImplPixelFormat::GetFormat( mnBits, maPalette ); + sal_uInt8* pSrcData = maUserBuffer.get(); + sal_uInt8* pDstData = pData; + + sal_uInt32 nY = mnBufHeight; + while( nY-- ) + { + pSrcFormat->StartLine( pSrcData ); + + sal_uInt32 nX = mnBufWidth; + while( nX-- ) + { + const BitmapColor& c = pSrcFormat->ReadPixel(); + + *pDstData++ = c.GetRed(); + *pDstData++ = c.GetGreen(); + *pDstData++ = c.GetBlue(); + *pDstData++ = 255; + } + + pSrcData += mnBytesPerRow; + } + } + } + + SAL_INFO( "vcl.opengl", "::CreateTexture" ); + mpContext->makeCurrent(); + mpTexture.reset( new OpenGLTexture (mnBufWidth, mnBufHeight, nFormat, nType, pData ) ); + + if( bAllocated ) + delete pData; + + while( !maPendingOps.empty() ) + { + OpenGLSalBitmapOp* pOp = maPendingOps.front(); + pOp->Execute(); + maPendingOps.pop_front(); + } + + mbDirtyTexture = false; + return mpTexture->Id(); +} + +bool OpenGLSalBitmap::ReadTexture() +{ + SalTwoRect aPosAry; + GLuint nFramebufferId, nRenderbufferDepthId, nRenderbufferColorId; + sal_uInt8* pData = maUserBuffer.get(); + + // TODO Check mnTexWidth and mnTexHeight + + mpContext->makeCurrent(); + OpenGLHelper::createFramebuffer( mnWidth, mnHeight, nFramebufferId, + nRenderbufferDepthId, nRenderbufferColorId, true ); + glBindFramebuffer( GL_FRAMEBUFFER, nFramebufferId ); + + aPosAry.mnSrcX = aPosAry.mnDestX = 0; + aPosAry.mnSrcY = aPosAry.mnDestY = 0; + aPosAry.mnSrcWidth = aPosAry.mnDestWidth = mnWidth; + aPosAry.mnSrcHeight = aPosAry.mnDestHeight = mnHeight; + + //DrawTexture( mnTexture, aPosAry ); + glReadPixels( 0, 0, mnWidth, mnHeight, GL_RGBA, GL_UNSIGNED_BYTE, pData ); + + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + glDeleteFramebuffers( 1, &nFramebufferId ); + glDeleteRenderbuffers( 1, &nRenderbufferDepthId ); + glDeleteRenderbuffers( 1, &nRenderbufferColorId ); + + return true; +} + +sal_uInt16 OpenGLSalBitmap::GetBitCount() const +{ + return mnBits; +} + +BitmapBuffer* OpenGLSalBitmap::AcquireBuffer( bool /*bReadOnly*/ ) +{ + if( !maUserBuffer.get() ) + { + if( !AllocateUserData() ) + return NULL; + if( mpTexture && !ReadTexture() ) + return NULL; + } + + BitmapBuffer* pBuffer = new BitmapBuffer; + pBuffer->mnWidth = mnWidth; + pBuffer->mnHeight = mnHeight; + pBuffer->maPalette = maPalette; + pBuffer->mnScanlineSize = mnBytesPerRow; + pBuffer->mpBits = maUserBuffer.get(); + pBuffer->mnBitCount = mnBits; + switch( mnBits ) + { + case 1: pBuffer->mnFormat = BMP_FORMAT_1BIT_MSB_PAL; break; + case 4: pBuffer->mnFormat = BMP_FORMAT_4BIT_MSN_PAL; break; + case 8: pBuffer->mnFormat = BMP_FORMAT_8BIT_PAL; break; + case 16: pBuffer->mnFormat = BMP_FORMAT_16BIT_TC_MSB_MASK; + pBuffer->maColorMask = ColorMask( 0xf800, 0x07e0, 0x001f ); + break; + case 24: pBuffer->mnFormat = BMP_FORMAT_24BIT_TC_RGB; break; + case 32: pBuffer->mnFormat = BMP_FORMAT_32BIT_TC_RGBA; + pBuffer->maColorMask = ColorMask( 0xff000000, 0x00ff0000, 0x0000ff00 ); + break; + } + + return pBuffer; +} + +void OpenGLSalBitmap::ReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly ) +{ + if( !bReadOnly ) + { + mbDirtyTexture = true; + } + delete pBuffer; +} + +bool OpenGLSalBitmap::GetSystemData( BitmapSystemData& /*rData*/ ) +{ +#if 0 + // TODO Implement for ANDROID/OSX/IOS/WIN32 + X11SalBitmap rBitmap; + BitmapBuffer* pBuffer; + + rBitmap.Create( GetSize(), mnBits, maPalette ); + pBuffer = rBitmap.AcquireBuffer( false ); + if( pBuffer == NULL ) + return false; + + if( !maUserBuffer.get() ) + { + if( !AllocateUserData() || !ReadTexture() ) + { + rBitmap.ReleaseBuffer( pBuffer, false ); + return false; + } + } + + // TODO Might be more efficient to add a static method to SalBitmap + // to get system data from a buffer + memcpy( pBuffer->mpBits, maUserBuffer.get(), mnBytesPerRow * mnHeight ); + + rBitmap.ReleaseBuffer( pBuffer, false ); + return rBitmap.GetSystemData( rData ); +#else + return false; +#endif +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/scale.cxx b/vcl/opengl/scale.cxx new file mode 100644 index 000000000000..16710b41bdd1 --- /dev/null +++ b/vcl/opengl/scale.cxx @@ -0,0 +1,308 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <vcl/opengl/OpenGLHelper.hxx> + +#include "vcl/bitmap.hxx" + +#include "opengl/bmpop.hxx" +#include "opengl/salbmp.hxx" +#include "opengl/texture.hxx" + +class ScaleOp : public OpenGLSalBitmapOp +{ +private: + OpenGLSalBitmap* mpBitmap; + double mfScaleX; + double mfScaleY; + sal_uInt32 mnScaleFlag; + +public: + ScaleOp( OpenGLSalBitmap* pBitmap, const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag ); + + bool Execute() SAL_OVERRIDE; + void GetSize( Size& rSize ) const SAL_OVERRIDE; +}; + + +GLuint OpenGLSalBitmap::ImplGetTextureProgram() +{ + if( mnTexProgram == 0 ) + { + mnTexProgram = OpenGLHelper::LoadShaders( "textureVertexShader", + "textureFragmentShader" ); + if( mnTexProgram == 0 ) + return 0; + + glBindAttribLocation( mnTexProgram, 0, "position" ); + glBindAttribLocation( mnTexProgram, 1, "tex_coord_in" ); + mnTexSamplerUniform = glGetUniformLocation( mnTexProgram, "sampler" ); + } + + return mnTexProgram; +} + +GLuint OpenGLSalBitmap::ImplGetConvolutionProgram() +{ + if( mnConvProgram == 0 ) + { + mnConvProgram = OpenGLHelper::LoadShaders( "textureVertexShader", + "convolutionFragmentShader" ); + if( mnConvProgram == 0 ) + return 0; + + glBindAttribLocation( mnConvProgram, 0, "position" ); + glBindAttribLocation( mnConvProgram, 1, "tex_coord_in" ); + mnConvSamplerUniform = glGetUniformLocation( mnConvProgram, "sampler" ); + mnConvKernelUniform = glGetUniformLocation( mnConvProgram, "kernel" ); + mnConvOffsetsUniform = glGetUniformLocation( mnConvProgram, "offsets" ); + } + + return mnConvProgram; +} + +bool OpenGLSalBitmap::ImplScaleFilter( GLenum nFilter ) +{ + OpenGLTexture* pNewTex; + GLuint nProgram; + GLuint nFramebufferId; + GLenum nOldFilter; + + nProgram = ImplGetTextureProgram(); + if( nProgram == 0 ) + return false; + + glGenFramebuffers( 1, &nFramebufferId ); + glBindFramebuffer( GL_FRAMEBUFFER, nFramebufferId ); + glUseProgram( nProgram ); + glUniform1i( mnTexSamplerUniform, 0 ); + + pNewTex = new OpenGLTexture( mnWidth, mnHeight ); + glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pNewTex->Id(), 0 ); + + mpTexture->Bind(); + nOldFilter = mpTexture->GetFilter(); + mpTexture->SetFilter( nFilter ); + mpTexture->Draw(); + mpTexture->SetFilter( nOldFilter ); + mpTexture->Unbind(); + + glUseProgram( 0 ); + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + glDeleteFramebuffers( 1, &nFramebufferId ); + + mpTexture.reset( pNewTex ); + return true; +} + +void OpenGLSalBitmap::ImplCreateKernel( + const double& fScale, + const Kernel& rKernel, + GLfloat*& pWeights, + sal_uInt32& aKernelSize ) +{ + const double fSamplingRadius(rKernel.GetWidth()); + const double fScaledRadius((fScale < 1.0) ? fSamplingRadius / fScale : fSamplingRadius); + const double fFilterFactor((fScale < 1.0) ? fScale : 1.0); + int aNumberOfContributions; + double aSum( 0 ); + + aNumberOfContributions = (static_cast< sal_uInt32 >(fabs(ceil(fScaledRadius))) * 2) + 1 - 6; + aKernelSize = aNumberOfContributions / 2 + 1; + + pWeights = new GLfloat[16]; + memset( pWeights, 0, 16 * sizeof( GLfloat ) ); + + for( sal_uInt32 i(0); i < aKernelSize; i++ ) + { + const GLfloat aWeight( rKernel.Calculate( fFilterFactor * i ) ); + if( fabs( aWeight ) >= 0.0001 ) + { + pWeights[i] = aWeight; + aSum += i > 0 ? aWeight * 2 : aWeight; + } + } + + for( sal_uInt32 i(0); i < aKernelSize; i++ ) + { + pWeights[i] /= aSum; + } +} + +bool OpenGLSalBitmap::ImplScaleConvolution( + const double& rScaleX, + const double& rScaleY, + const Kernel& aKernel ) +{ + OpenGLTexture* pScratchTex; + OpenGLTexture* pNewTex; + GLfloat* pWeights( 0 ); + GLuint nFramebufferId; + GLuint nProgram; + sal_uInt32 nKernelSize; + GLfloat aOffsets[32]; + int nNewWidth( mnWidth * rScaleX ); + int nNewHeight( mnHeight * rScaleY ); + + // TODO Make sure the framebuffer is alright + + nProgram = ImplGetConvolutionProgram(); + if( nProgram == 0 ) + return false; + + glGenFramebuffers( 1, &nFramebufferId ); + glBindFramebuffer( GL_FRAMEBUFFER, nFramebufferId ); + glUseProgram( nProgram ); + glUniform1i( mnConvSamplerUniform, 0 ); + CHECK_GL_ERROR(); + + // horizontal scaling in scratch texture + pScratchTex = new OpenGLTexture( nNewWidth, mnHeight ); + glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pScratchTex->Id(), 0 ); + CHECK_GL_ERROR(); + + for( sal_uInt32 i = 0; i < 16; i++ ) + { + aOffsets[i * 2] = i / (double) mnWidth; + aOffsets[i * 2 + 1] = 0; + } + ImplCreateKernel( rScaleX, aKernel, pWeights, nKernelSize ); + glUniform1fv( mnConvKernelUniform, 16, pWeights ); + CHECK_GL_ERROR(); + glUniform2fv( mnConvOffsetsUniform, 16, aOffsets ); + CHECK_GL_ERROR(); + + glViewport( 0, 0, nNewWidth, mnHeight ); + mpTexture->Bind(); + mpTexture->Draw(); + mpTexture->Unbind(); + + // vertical scaling in final texture + pNewTex = new OpenGLTexture( nNewWidth, nNewHeight ); + glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pNewTex->Id(), 0 ); + + for( sal_uInt32 i = 0; i < 16; i++ ) + { + aOffsets[i * 2] = 0; + aOffsets[i * 2 + 1] = i / (double) mnHeight; + } + ImplCreateKernel( rScaleY, aKernel, pWeights, nKernelSize ); + glUniform1fv( mnConvKernelUniform, 16, pWeights ); + glUniform2fv( mnConvOffsetsUniform, 16, aOffsets ); + CHECK_GL_ERROR(); + + glViewport( 0, 0, nNewWidth, nNewHeight ); + pScratchTex->Bind(); + pScratchTex->Draw(); + pScratchTex->Unbind(); + + glUseProgram( 0 ); + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + glDeleteFramebuffers( 1, &nFramebufferId ); + + delete pScratchTex; + mpTexture.reset( pNewTex ); + mnWidth = nNewWidth; + mnHeight = nNewHeight; + + return true; +} + +bool OpenGLSalBitmap::ImplScale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag ) +{ + SAL_INFO( "vcl.opengl", "::ImplScale" ); + + if( nScaleFlag == BMP_SCALE_FAST ) + { + return ImplScaleFilter( GL_NEAREST ); + } + if( nScaleFlag == BMP_SCALE_BILINEAR ) + { + return ImplScaleFilter( GL_LINEAR ); + } + else if( nScaleFlag == BMP_SCALE_SUPER ) + { + const Lanczos3Kernel aKernel; + + return ImplScaleConvolution( rScaleX, rScaleY, aKernel ); + } + else if( nScaleFlag == BMP_SCALE_LANCZOS ) + { + const Lanczos3Kernel aKernel; + + return ImplScaleConvolution( rScaleX, rScaleY, aKernel ); + } + + SAL_WARN( "vcl.opengl", "Invalid flag for scaling operation" ); + return false; +} + +ScaleOp::ScaleOp( + OpenGLSalBitmap* pBitmap, + const double& rScaleX, + const double& rScaleY, + sal_uInt32 nScaleFlag ) +: mpBitmap( pBitmap ) +, mfScaleX( rScaleX ) +, mfScaleY( rScaleY ) +, mnScaleFlag( nScaleFlag ) +{ +} + +bool ScaleOp::Execute() +{ + SAL_INFO( "vcl.opengl", "::Execute" ); + return mpBitmap->ImplScale( mfScaleX, mfScaleY, mnScaleFlag ); +} + +void ScaleOp::GetSize( Size& rSize ) const +{ + SAL_INFO( "vcl.opengl", "::GetSize" ); + rSize.setWidth( rSize.Width() * mfScaleX ); + rSize.setHeight( rSize.Height() * mfScaleY ); +} + +bool OpenGLSalBitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag ) +{ + SAL_INFO( "vcl.opengl", "::Scale " << nScaleFlag ); + + if( nScaleFlag == BMP_SCALE_FAST || + nScaleFlag == BMP_SCALE_BILINEAR || + nScaleFlag == BMP_SCALE_SUPER || + nScaleFlag == BMP_SCALE_LANCZOS ) + { + //TODO maUserBuffer.reset(); + if( mpContext == NULL ) + { + SAL_INFO( "vcl.opengl", "Add ScaleOp to pending operations" ); + maPendingOps.push_back( new ScaleOp( this, rScaleX, rScaleY, nScaleFlag ) ); + } + else + { + ImplScale( rScaleX, rScaleY, nScaleFlag ); + } + return true; + } + + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/solidFragmentShader.glsl b/vcl/opengl/solidFragmentShader.glsl new file mode 100644 index 000000000000..af7533604cef --- /dev/null +++ b/vcl/opengl/solidFragmentShader.glsl @@ -0,0 +1,17 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/*precision mediump float;*/ + +uniform vec4 color; +void main() { + gl_FragColor = color; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/solidVertexShader.glsl b/vcl/opengl/solidVertexShader.glsl new file mode 100644 index 000000000000..47061f6e4223 --- /dev/null +++ b/vcl/opengl/solidVertexShader.glsl @@ -0,0 +1,16 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +attribute vec4 position; +void main() { + gl_Position = position; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/texture.cxx b/vcl/opengl/texture.cxx new file mode 100644 index 000000000000..2770c20a5519 --- /dev/null +++ b/vcl/opengl/texture.cxx @@ -0,0 +1,144 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> +#include <vcl/opengl/OpenGLHelper.hxx> + +#include "vcl/salbtype.hxx" + +#include "opengl/texture.hxx" + +OpenGLTexture::OpenGLTexture() +: mnTexture( 0 ) +, mnWidth( -1 ) +, mnHeight( -1 ) +, mnFilter( GL_NEAREST ) +{ +} + +OpenGLTexture::OpenGLTexture( int nWidth, int nHeight ) +: mnTexture( 0 ) +, mnWidth( nWidth ) +, mnHeight( nHeight ) +, mnFilter( GL_NEAREST ) +{ + glGenTextures( 1, &mnTexture ); + glBindTexture( GL_TEXTURE_2D, mnTexture ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nWidth, nHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL ); + glBindTexture( GL_TEXTURE_2D, 0 ); +} + +OpenGLTexture::OpenGLTexture( int nX, int nY, int nWidth, int nHeight ) +: mnTexture( 0 ) +, mnWidth( nWidth ) +, mnHeight( nHeight ) +, mnFilter( GL_NEAREST ) +{ + glGenTextures( 1, &mnTexture ); + glBindTexture( GL_TEXTURE_2D, mnTexture ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + glCopyTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, nX, nY, nWidth, nHeight, 0 ); + CHECK_GL_ERROR(); + glBindTexture( GL_TEXTURE_2D, 0 ); + CHECK_GL_ERROR(); +} + +OpenGLTexture::OpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData ) +: mnTexture( 0 ) +, mnWidth( nWidth ) +, mnHeight( nHeight ) +, mnFilter( GL_NEAREST ) +{ + if( !mnTexture ) + glGenTextures( 1, &mnTexture ); + glBindTexture( GL_TEXTURE_2D, mnTexture ); + glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, mnWidth, mnHeight, 0, nFormat, nType, pData ); + glBindTexture( GL_TEXTURE_2D, 0 ); +} + +OpenGLTexture::~OpenGLTexture() +{ + if( mnTexture != 0 ) + glDeleteTextures( 1, &mnTexture ); +} + +GLuint OpenGLTexture::Id() const +{ + return mnTexture; +} + +GLenum OpenGLTexture::GetFilter() const +{ + return mnFilter; +} + +void OpenGLTexture::SetFilter( GLenum nFilter ) +{ + mnFilter = nFilter; + if( mnTexture ) + { + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, nFilter ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, nFilter ); + } +} + +void OpenGLTexture::Bind() +{ + glBindTexture( GL_TEXTURE_2D, mnTexture ); +} + +void OpenGLTexture::Unbind() +{ + glBindTexture( GL_TEXTURE_2D, 0 ); +} + +bool OpenGLTexture::Draw() +{ + const GLfloat aPosition[8] = { -1, -1, -1, 1, 1, 1, 1, -1 }; + const GLfloat aTexCoord[8] = { 0, 0, 0, 1, 1, 1, 1, 0 }; + + if( mnTexture == 0 ) + return false; + + glBindTexture( GL_TEXTURE_2D, mnTexture ); + glEnableVertexAttribArray( 0 ); + glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, 0, aPosition ); + glEnableVertexAttribArray( 1 ); + glVertexAttribPointer( 1, 2, GL_FLOAT, GL_FALSE, 0, aTexCoord ); + glDrawArrays( GL_TRIANGLE_FAN, 0, 4 ); + glDisableVertexAttribArray( 0 ); + glDisableVertexAttribArray( 1 ); + glBindTexture( GL_TEXTURE_2D, 0 ); + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/textureFragmentShader.glsl b/vcl/opengl/textureFragmentShader.glsl new file mode 100644 index 000000000000..cc95f2ffb17c --- /dev/null +++ b/vcl/opengl/textureFragmentShader.glsl @@ -0,0 +1,18 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +/* precision mediump float; */ +varying vec2 tex_coord; +uniform sampler2D sampler; + +void main() { + gl_FragColor = texture2D(sampler, tex_coord); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/textureVertexShader.glsl b/vcl/opengl/textureVertexShader.glsl new file mode 100644 index 000000000000..99d7f37eb05f --- /dev/null +++ b/vcl/opengl/textureVertexShader.glsl @@ -0,0 +1,19 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +attribute vec4 position; +attribute vec2 tex_coord_in; +varying vec2 tex_coord; + +void main() { + gl_Position = position; + tex_coord = tex_coord_in; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/win/gdiimpl.cxx b/vcl/opengl/win/gdiimpl.cxx new file mode 100644 index 000000000000..e829ca445f42 --- /dev/null +++ b/vcl/opengl/win/gdiimpl.cxx @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "opengl/win/gdiimpl.hxx" + +#include <win/wincomp.hxx> +#include <win/saldata.hxx> +#include <win/salframe.h> + +WinOpenGLSalGraphicsImpl::WinOpenGLSalGraphicsImpl(WinSalGraphics& rGraphics): + mrParent(rGraphics) +{ +} + +GLfloat WinOpenGLSalGraphicsImpl::GetWidth() const +{ + if( mrParent.gethWnd() && IsWindow( mrParent.gethWnd() ) ) + { + WinSalFrame* pFrame = GetWindowPtr( mrParent.gethWnd() ); + if( pFrame ) + { + if( pFrame->maGeometry.nWidth ) + return pFrame->maGeometry.nWidth; + else + { + // TODO: perhaps not needed, maGeometry should always be up-to-date + RECT aRect; + GetClientRect( mrParent.gethWnd(), &aRect ); + return aRect.right; + } + } + } + + return 1; +} + +GLfloat WinOpenGLSalGraphicsImpl::GetHeight() const +{ + if( mrParent.gethWnd() && IsWindow( mrParent.gethWnd() ) ) + { + WinSalFrame* pFrame = GetWindowPtr( mrParent.gethWnd() ); + if( pFrame ) + { + if( pFrame->maGeometry.nHeight ) + return pFrame->maGeometry.nHeight; + else + { + // TODO: perhaps not needed, maGeometry should always be up-to-date + RECT aRect; + GetClientRect( mrParent.gethWnd(), &aRect ); + return aRect.bottom; + } + } + } + + return 1; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/opengl/x11/gdiimpl.cxx b/vcl/opengl/x11/gdiimpl.cxx new file mode 100644 index 000000000000..11735edb271c --- /dev/null +++ b/vcl/opengl/x11/gdiimpl.cxx @@ -0,0 +1,139 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "vcl/salbtype.hxx" + +#include "unx/pixmap.hxx" +#include "unx/saldisp.hxx" +#include "unx/salframe.h" +#include "unx/salgdi.h" +#include "unx/salvd.h" + +#include "opengl/x11/gdiimpl.hxx" + +#include <vcl/opengl/OpenGLContext.hxx> +#include <vcl/opengl/OpenGLHelper.hxx> + +X11OpenGLSalGraphicsImpl::X11OpenGLSalGraphicsImpl( X11SalGraphics& rParent ): + OpenGLSalGraphicsImpl(), + mrParent(rParent) +{ +} + +X11OpenGLSalGraphicsImpl::~X11OpenGLSalGraphicsImpl() +{ +} + +GLfloat X11OpenGLSalGraphicsImpl::GetWidth() const +{ + if( mrParent.m_pFrame ) + return mrParent.m_pFrame->maGeometry.nWidth; + else if( mrParent.m_pVDev ) + { + long nWidth = 0; + long nHeight = 0; + mrParent.m_pVDev->GetSize( nWidth, nHeight ); + return nWidth; + } + return 1; +} + +GLfloat X11OpenGLSalGraphicsImpl::GetHeight() const +{ + if( mrParent.m_pFrame ) + return mrParent.m_pFrame->maGeometry.nHeight; + else if( mrParent.m_pVDev ) + { + long nWidth = 0; + long nHeight = 0; + mrParent.m_pVDev->GetSize( nWidth, nHeight ); + return nHeight; + } + return 1; +} + +void X11OpenGLSalGraphicsImpl::Init() +{ + if( mrParent.m_pFrame && dynamic_cast<X11WindowProvider*>(mrParent.m_pFrame) ) + { + Window aWin = dynamic_cast<X11WindowProvider*>(mrParent.m_pFrame)->GetX11Window(); + maContext.init( mrParent.GetXDisplay(), aWin, mrParent.m_nXScreen.getXScreen()); + } + else if( mrParent.m_pVDev ) + { + maContext.init( mrParent.GetXDisplay(), mrParent.m_pVDev->GetDrawable(), + mrParent.m_pVDev->GetWidth(), mrParent.m_pVDev->GetHeight(), + mrParent.m_nXScreen.getXScreen() ); + } + else + { + SAL_WARN( "vcl.opengl", "what happened here?" ); + } +} + +X11Pixmap* X11OpenGLSalGraphicsImpl::GetPixmapFromScreen( const Rectangle& rRect ) +{ + Display* pDisplay = mrParent.GetXDisplay(); + SalX11Screen nScreen = mrParent.GetScreenNumber(); + + SAL_INFO( "vcl.opengl", "GetPixmapFromScreen" ); + return new X11Pixmap( pDisplay, nScreen, rRect.GetWidth(), rRect.GetHeight(), 24 ); +} + +bool X11OpenGLSalGraphicsImpl::RenderPixmapToScreen( X11Pixmap* pPixmap, int nX, int nY ) +{ + const int aAttribs[] = { + GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, + GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT, + None + }; + Display* pDisplay = mrParent.GetXDisplay(); + GLXFBConfig pFbConfig; + GLXPixmap pGlxPixmap; + GLuint nTexture; + SalTwoRect aPosAry; + bool bInverted; + + SAL_INFO( "vcl.opengl", "RenderPixmapToScreen (" << nX << " " << nY << ")" ); + + aPosAry.mnSrcX = 0; + aPosAry.mnSrcY = 0; + aPosAry.mnDestX = nX; + aPosAry.mnDestY = nY; + aPosAry.mnSrcWidth = aPosAry.mnDestWidth = pPixmap->GetWidth(); + aPosAry.mnSrcHeight = aPosAry.mnDestHeight = pPixmap->GetHeight(); + + XSync( pDisplay, 0 ); + pFbConfig = OpenGLHelper::GetPixmapFBConfig( pDisplay, bInverted ); + pGlxPixmap = glXCreatePixmap( pDisplay, pFbConfig, pPixmap->GetPixmap(), aAttribs); + XSync( pDisplay, 0 ); + + maContext.makeCurrent(); + glViewport( 0, 0, GetWidth(), GetHeight() ); + + glGenTextures( 1, &nTexture ); + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( GL_TEXTURE_2D, nTexture ); + + //TODO: lfrb: glXGetProc to get the functions + glXBindTexImageEXT( pDisplay, pGlxPixmap, GLX_FRONT_LEFT_EXT, NULL ); + + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + DrawTexture( nTexture, pPixmap->GetSize(), aPosAry ); + + glXReleaseTexImageEXT( pDisplay, pGlxPixmap, GLX_FRONT_LEFT_EXT ); + glDeleteTextures( 1, &nTexture ); + glXDestroyPixmap( pDisplay, pGlxPixmap ); + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/quartz/salbmp.cxx b/vcl/quartz/salbmp.cxx index a9805100d907..c4cf2b00a011 100644 --- a/vcl/quartz/salbmp.cxx +++ b/vcl/quartz/salbmp.cxx @@ -963,4 +963,9 @@ bool QuartzSalBitmap::GetSystemData( BitmapSystemData& rData ) return bRet; } +bool QuartzSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, sal_uInt32 /*nScaleFlag*/ ) +{ + return false; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/gdi/bitmap.cxx b/vcl/source/gdi/bitmap.cxx index 5f6477a00b82..ccd914d5b924 100644 --- a/vcl/source/gdi/bitmap.cxx +++ b/vcl/source/gdi/bitmap.cxx @@ -60,8 +60,7 @@ Bitmap::Bitmap( const Bitmap& rBitmap ) : Bitmap::Bitmap( SalBitmap* pSalBitmap ) { - mpImpBmp = new ImpBitmap(); - mpImpBmp->ImplSetSalBitmap( pSalBitmap ); + mpImpBmp = new ImpBitmap(pSalBitmap); maPrefMapMode = MapMode( MAP_PIXEL ); maPrefSize = mpImpBmp->ImplGetSize(); } diff --git a/vcl/source/gdi/bitmap3.cxx b/vcl/source/gdi/bitmap3.cxx index 588dd0a2d50c..335d625b29ab 100644 --- a/vcl/source/gdi/bitmap3.cxx +++ b/vcl/source/gdi/bitmap3.cxx @@ -27,6 +27,7 @@ #include <boost/scoped_array.hpp> +#include <impbmp.hxx> #include <impoct.hxx> #include <impvect.hxx> @@ -873,6 +874,25 @@ bool Bitmap::Scale( const double& rScaleX, const double& rScaleY, sal_uInt32 nSc bRetval = true; } + if( mpImpBmp ) + { + // implementation specific scaling + ImpBitmap* pImpBmp = new ImpBitmap; + + if( pImpBmp->ImplCreate( *mpImpBmp ) && pImpBmp->ImplScale( rScaleX, rScaleY, nScaleFlag ) ) + { + ImplSetImpBitmap( pImpBmp ); + SAL_INFO( "vcl.opengl", "Ref count: " << mpImpBmp->ImplGetRefCount() ); + maPrefMapMode = MapMode( MAP_PIXEL ); + maPrefSize = pImpBmp->ImplGetSize(); + return true; + } + else + { + delete pImpBmp; + } + } + //fdo#33455 // //If we start with a 1 bit image, then after scaling it in any mode except diff --git a/vcl/source/gdi/impbmp.cxx b/vcl/source/gdi/impbmp.cxx index 005a45e6e9aa..633cff2a5c64 100644 --- a/vcl/source/gdi/impbmp.cxx +++ b/vcl/source/gdi/impbmp.cxx @@ -31,6 +31,13 @@ ImpBitmap::ImpBitmap() : { } +ImpBitmap::ImpBitmap(SalBitmap* pBitmap) : + mnRefCount ( 1 ), + mnChecksum ( 0 ), + mpSalBitmap ( pBitmap ) +{ +} + ImpBitmap::~ImpBitmap() { delete mpSalBitmap; @@ -86,4 +93,9 @@ void ImpBitmap::ImplReleaseBuffer( BitmapBuffer* pBuffer, bool bReadOnly ) mnChecksum = 0; } +bool ImpBitmap::ImplScale( const double& rScaleX, const double& rScaleY, sal_uInt32 nScaleFlag ) +{ + return mpSalBitmap->Scale( rScaleX, rScaleY, nScaleFlag ); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/gdi/salgdiimpl.cxx b/vcl/source/gdi/salgdiimpl.cxx new file mode 100644 index 000000000000..96ba3828996b --- /dev/null +++ b/vcl/source/gdi/salgdiimpl.cxx @@ -0,0 +1,26 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "salgdiimpl.hxx" + +SalGraphicsImpl::~SalGraphicsImpl() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/opengl/OpenGLContext.cxx b/vcl/source/opengl/OpenGLContext.cxx index 79430ba5a78e..1062a879a09d 100644 --- a/vcl/source/opengl/OpenGLContext.cxx +++ b/vcl/source/opengl/OpenGLContext.cxx @@ -25,6 +25,10 @@ using namespace com::sun::star; +#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID +static std::vector< GLXContext > vShareList; +#endif + GLWindow::~GLWindow() { #if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID @@ -36,8 +40,13 @@ OpenGLContext::OpenGLContext(): mpWindow(NULL), m_pChildWindow(NULL), mbInitialized(false), - mbRequestLegacyContext(false) + mbRequestLegacyContext(false), + mbUseDoubleBufferedRendering(true), + mbRequestVirtualDevice(false) { +#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID + mbPixmap = false; +#endif } OpenGLContext::~OpenGLContext() @@ -56,12 +65,17 @@ OpenGLContext::~OpenGLContext() #elif defined( UNX ) if(m_aGLWin.ctx) { + std::remove( vShareList.begin(), vShareList.end(), m_aGLWin.ctx ); + glXMakeCurrent(m_aGLWin.dpy, None, NULL); if( glGetError() != GL_NO_ERROR ) { SAL_WARN("vcl.opengl", "glError: " << (char *)gluErrorString(glGetError())); } glXDestroyContext(m_aGLWin.dpy, m_aGLWin.ctx); + + if (mbPixmap) + glXDestroyGLXPixmap(m_aGLWin.dpy, m_aGLWin.glPix); } #endif } @@ -71,6 +85,16 @@ void OpenGLContext::requestLegacyContext() mbRequestLegacyContext = true; } +void OpenGLContext::requestSingleBufferedRendering() +{ + mbUseDoubleBufferedRendering = false; +} + +void OpenGLContext::requestVirtualDevice() +{ + mbRequestVirtualDevice = true; +} + #if defined( _WIN32 ) static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -154,7 +178,7 @@ bool WGLisExtensionSupported(const char *extension) supported = (char*)glGetString(GL_EXTENSIONS); // If That Failed Too, Must Be No Extensions Supported if (supported == NULL) - return 0; + return false; // Begin Examination At Start Of String, Increment By 1 On False Match for (const char* p = supported; ; p++) @@ -176,7 +200,8 @@ bool WGLisExtensionSupported(const char *extension) } } -bool InitMultisample(PIXELFORMATDESCRIPTOR pfd, int& rPixelFormat) +bool InitMultisample(PIXELFORMATDESCRIPTOR pfd, int& rPixelFormat, + bool bUseDoubleBufferedRendering, bool bRequestVirtualDevice) { HWND hWnd = NULL; GLWindow glWin; @@ -213,6 +238,7 @@ bool InitMultisample(PIXELFORMATDESCRIPTOR pfd, int& rPixelFormat) // We Support Multisampling On This Hardware. int iAttributes[] = { + WGL_DOUBLE_BUFFER_ARB,GL_TRUE, WGL_DRAW_TO_WINDOW_ARB,GL_TRUE, WGL_SUPPORT_OPENGL_ARB,GL_TRUE, WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB, @@ -220,12 +246,19 @@ bool InitMultisample(PIXELFORMATDESCRIPTOR pfd, int& rPixelFormat) WGL_ALPHA_BITS_ARB,8, WGL_DEPTH_BITS_ARB,24, WGL_STENCIL_BITS_ARB,0, - WGL_DOUBLE_BUFFER_ARB,GL_TRUE, WGL_SAMPLE_BUFFERS_ARB,GL_TRUE, WGL_SAMPLES_ARB,8, 0,0 }; + if (!bUseDoubleBufferedRendering) + iAttributes[1] = GL_FALSE; + + if (bRequestVirtualDevice) + { + iAttributes[2] = WGL_DRAW_TO_BITMAP_ARB; + } + bool bArbMultisampleSupported = true; // First We Check To See If We Can Get A Pixel Format For 4 Samples @@ -369,22 +402,69 @@ int oglErrorHandler( Display* /*dpy*/, XErrorEvent* /*evnt*/ ) return 0; } -GLXFBConfig* getFBConfig(const SystemEnvData* sysData, int& nBestFBC) +GLXFBConfig* getFBConfigForPixmap(Display* dpy, int& nBestFBC, bool bUseDoubleBufferedRendering, int screen) { - Display *dpy = reinterpret_cast<Display*>(sysData->pDisplay); + static int visual_attribs[] = + { + GLX_DOUBLEBUFFER, False, + GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT, + GLX_X_RENDERABLE, True, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_ALPHA_SIZE, 8, + GLX_DEPTH_SIZE, 24, + GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, + None + }; - if( dpy == 0 || !glXQueryExtension( dpy, NULL, NULL ) ) + if (bUseDoubleBufferedRendering) + visual_attribs[1] = True; + + int fbCount = 0; + GLXFBConfig* pFBC = glXChooseFBConfig( dpy, + screen, + visual_attribs, &fbCount ); + + if(!pFBC) + { + SAL_WARN("vcl.opengl", "no suitable fb format found"); return NULL; + } - Window win = sysData->aWindow; + int best_num_samp = -1; + for(int i = 0; i < fbCount; ++i) + { + // pick the one with the most samples per pixel + int nSampleBuf = 0; + int nSamples = 0; + glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLE_BUFFERS, &nSampleBuf ); + glXGetFBConfigAttrib( dpy, pFBC[i], GLX_SAMPLES , &nSamples ); + + if ( nBestFBC < 0 || (nSampleBuf && ( nSamples > best_num_samp )) ) + { + nBestFBC = i; + best_num_samp = nSamples; + } + } - SAL_INFO("vcl.opengl", "parent window: " << win); + return pFBC; +} + +#ifdef DBG_UTIL +GLXFBConfig* getFBConfig(Display* dpy, Window win, int& nBestFBC, bool bUseDoubleBufferedRendering) +{ + if( dpy == 0 || !glXQueryExtension( dpy, NULL, NULL ) ) + return NULL; + + SAL_INFO("vcl.opengl", "window: " << win); XWindowAttributes xattr; XGetWindowAttributes( dpy, win, &xattr ); int screen = XScreenNumberOfScreen( xattr.screen ); + // TODO: moggi: Select colour channel depth based on visual attributes, not hardcoded */ static int visual_attribs[] = { GLX_DOUBLEBUFFER, True, @@ -397,6 +477,10 @@ GLXFBConfig* getFBConfig(const SystemEnvData* sysData, int& nBestFBC) GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR, None }; + + if (!bUseDoubleBufferedRendering) + visual_attribs[1] = False; + int fbCount = 0; GLXFBConfig* pFBC = glXChooseFBConfig( dpy, screen, @@ -412,7 +496,7 @@ GLXFBConfig* getFBConfig(const SystemEnvData* sysData, int& nBestFBC) for(int i = 0; i < fbCount; ++i) { XVisualInfo* pVi = glXGetVisualFromFBConfig( dpy, pFBC[i] ); - if(pVi) + if(pVi && pVi->visualid == xattr.visual->visualid) { // pick the one with the most samples per pixel int nSampleBuf = 0; @@ -431,6 +515,27 @@ GLXFBConfig* getFBConfig(const SystemEnvData* sysData, int& nBestFBC) return pFBC; } +#endif + +// we need them before glew can initialize them +// glew needs an OpenGL context so we need to get the address manually +void initOpenGLFunctionPointers() +{ + glXChooseFBConfig = (GLXFBConfig*(*)(Display *dpy, int screen, const int *attrib_list, int *nelements))glXGetProcAddressARB((GLubyte*)"glXChooseFBConfig"); + glXGetVisualFromFBConfig = (XVisualInfo*(*)(Display *dpy, GLXFBConfig config))glXGetProcAddressARB((GLubyte*)"glXGetVisualFromFBConfig"); // try to find a visual for the current set of attributes + glXGetFBConfigAttrib = (int(*)(Display *dpy, GLXFBConfig config, int attribute, int* value))glXGetProcAddressARB((GLubyte*)"glXGetFBConfigAttrib"); + glXCreateContextAttribsARB = (GLXContext(*) (Display*, GLXFBConfig, GLXContext, Bool, const int*)) glXGetProcAddressARB((const GLubyte *) "glXCreateContextAttribsARB");; +} + +Visual* getVisual(Display* dpy, Window win) +{ + initOpenGLFunctionPointers(); + + XWindowAttributes xattr; + XGetWindowAttributes( dpy, win, &xattr ); + SAL_INFO("vcl.opengl", "using VisualID " << xattr.visual); + return xattr.visual; +} } @@ -443,6 +548,8 @@ bool OpenGLContext::init( vcl::Window* pParent ) m_pWindow.reset(pParent ? NULL : new vcl::Window(0, WB_NOBORDER|WB_NODIALOGCONTROL)); mpWindow = pParent ? pParent : m_pWindow.get(); + if(m_pWindow) + m_pWindow->setPosSizePixel(0,0,0,0); m_pChildWindow = 0; initWindow(); return ImplInit(); @@ -462,74 +569,186 @@ bool OpenGLContext::init(SystemChildWindow* pChildWindow) return ImplInit(); } -bool OpenGLContext::ImplInit() +#if defined( UNX ) && !defined MACOSX && !defined IOS && !defined ANDROID +bool OpenGLContext::init(Display* dpy, Window win, int screen) { - SAL_INFO("vcl.opengl", "OpenGLContext::ImplInit----start"); - if(m_pWindow) - m_pWindow->setPosSizePixel(0,0,0,0); - m_aGLWin.Width = 0; - m_aGLWin.Height = 0; + if(mbInitialized) + return true; -#if defined( WNT ) - m_aGLWin.hDC = GetDC(m_aGLWin.hWnd); -#elif defined( MACOSX ) + if (!dpy) + return false; -#elif defined( IOS ) + m_aGLWin.dpy = dpy; + m_aGLWin.win = win; + m_aGLWin.screen = screen; - SAL_INFO("vcl.opengl", "OpenGLContext not implemented yet for iOS"); - return false; + Visual* pVisual = getVisual(dpy, win); -#elif defined( ANDROID ) + initGLWindow(pVisual); - SAL_INFO("vcl.opengl", "OpenGLContext not implemented yet for Android"); - return false; + return ImplInit(); +} -#elif defined( UNX ) -#ifdef DBG_UTIL +bool OpenGLContext::init(Display* dpy, Pixmap pix, unsigned int width, unsigned int height, int nScreen) +{ + if(mbInitialized) + return true; + + if (!dpy) + return false; + + SAL_INFO("vcl.opengl", "init with pixmap"); + m_aGLWin.dpy = dpy; + m_aGLWin.Width = width; + m_aGLWin.Height = height; + m_aGLWin.pix = pix; + const int attrib_list[] = { GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGB_EXT, + GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT, + None}; + int best_fbc = -1; + GLXFBConfig* config = getFBConfigForPixmap(dpy, best_fbc, mbUseDoubleBufferedRendering, nScreen); + if (best_fbc == -1) + return false; + + m_aGLWin.vi = glXGetVisualFromFBConfig( dpy, config[best_fbc] ); + m_aGLWin.glPix = glXCreatePixmap(dpy, config[best_fbc], pix, attrib_list); - if (glXCreateContextAttribsARB && !mbRequestLegacyContext) + mbPixmap = true; + + initOpenGLFunctionPointers(); + + return ImplInit(); +} + +bool OpenGLContext::ImplInit() +{ + SAL_INFO("vcl.opengl", "OpenGLContext::ImplInit----start"); +#ifdef DBG_UTIL + if (!mbPixmap && glXCreateContextAttribsARB && !mbRequestLegacyContext) { int best_fbc = -1; - const SystemEnvData* sysData(m_pChildWindow->GetSystemData()); - GLXFBConfig* pFBC = getFBConfig(sysData, best_fbc); + GLXFBConfig* pFBC = getFBConfig(m_aGLWin.dpy, m_aGLWin.win, best_fbc, mbUseDoubleBufferedRendering); if (!pFBC) return false; - int nContextAttribs[] = + if (best_fbc != -1) { - GLX_CONTEXT_MAJOR_VERSION_ARB, 3, - GLX_CONTEXT_MINOR_VERSION_ARB, 2, - None - }; - m_aGLWin.ctx = glXCreateContextAttribsARB(m_aGLWin.dpy, pFBC[best_fbc], 0, GL_TRUE, nContextAttribs); + int nContextAttribs[] = + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 2, + None + }; + m_aGLWin.ctx = glXCreateContextAttribsARB(m_aGLWin.dpy, pFBC[best_fbc], 0, GL_TRUE, nContextAttribs); + SAL_INFO_IF(m_aGLWin.ctx, "vcl.opengl", "created a 3.2 core context"); + } + else + SAL_WARN("vcl.opengl", "unable to find correct FBC"); } #endif + if (!m_aGLWin.ctx) { + GLXContext pSharedCtx( NULL ); + if (!m_aGLWin.dpy || !m_aGLWin.vi) return false; + if( !vShareList.empty() ) + pSharedCtx = vShareList.front(); + m_aGLWin.ctx = m_aGLWin.dpy == 0 ? 0 : glXCreateContext(m_aGLWin.dpy, m_aGLWin.vi, - 0, + pSharedCtx, GL_TRUE); + + if( m_aGLWin.ctx ) + vShareList.push_back( m_aGLWin.ctx ); } + + if( m_aGLWin.ctx == NULL ) { SAL_WARN("vcl.opengl", "unable to create GLX context"); return false; } -#endif -#if defined( WNT ) - PIXELFORMATDESCRIPTOR PixelFormatFront = // PixelFormat Tells Windows How We Want Things To Be + if( !glXMakeCurrent( m_aGLWin.dpy, mbPixmap ? m_aGLWin.glPix : m_aGLWin.win, m_aGLWin.ctx ) ) + { + SAL_WARN("vcl.opengl", "unable to select current GLX context"); + return false; + } + + int glxMinor, glxMajor; + double nGLXVersion = 0; + if( glXQueryVersion( m_aGLWin.dpy, &glxMajor, &glxMinor ) ) + nGLXVersion = glxMajor + 0.1*glxMinor; + SAL_INFO("vcl.opengl", "available GLX version: " << nGLXVersion); + + m_aGLWin.GLExtensions = glGetString( GL_EXTENSIONS ); + SAL_INFO("vcl.opengl", "available GL extensions: " << m_aGLWin.GLExtensions); + + XWindowAttributes xWinAttr; + XGetWindowAttributes( m_aGLWin.dpy, m_aGLWin.win, &xWinAttr ); + m_aGLWin.Width = xWinAttr.width; + m_aGLWin.Height = xWinAttr.height; + + if( m_aGLWin.HasGLXExtension("GLX_SGI_swap_control" ) ) + { + // enable vsync + typedef GLint (*glXSwapIntervalProc)(GLint); + glXSwapIntervalProc glXSwapInterval = (glXSwapIntervalProc) glXGetProcAddress( (const GLubyte*) "glXSwapIntervalSGI" ); + if( glXSwapInterval ) + { + int (*oldHandler)(Display* /*dpy*/, XErrorEvent* /*evnt*/); + + XLockDisplay(m_aGLWin.dpy); + XSync(m_aGLWin.dpy, false); + // replace error handler temporarily + oldHandler = XSetErrorHandler( oglErrorHandler ); + + errorTriggered = false; + + glXSwapInterval( 1 ); + + // sync so that we possibly get an XError + glXWaitGL(); + XSync(m_aGLWin.dpy, false); + + if( errorTriggered ) + SAL_WARN("vcl.opengl", "error when trying to set swap interval, NVIDIA or Mesa bug?"); + else + SAL_INFO("vcl.opengl", "set swap interval to 1 (enable vsync)"); + + // restore the error handler + XSetErrorHandler( oldHandler ); + XUnlockDisplay(m_aGLWin.dpy); + } + } + return InitGLEW(); +} + +#elif defined( _WIN32 ) + +bool OpenGLContext::init(HDC hDC, HWND hWnd) +{ + if (mbInitialized) + return false; + + m_aGLWin.hDC = hDC; + m_aGLWin.hWnd = hWnd; + return ImplInit(); +} + +bool OpenGLContext::ImplInit() +{ + SAL_INFO("vcl.opengl", "OpenGLContext::ImplInit----start"); + PIXELFORMATDESCRIPTOR PixelFormatFront = // PixelFormat Tells Windows How We Want Things To Be { sizeof(PIXELFORMATDESCRIPTOR), 1, // Version Number - PFD_DRAW_TO_WINDOW | - PFD_SUPPORT_OPENGL | - PFD_DOUBLEBUFFER, + PFD_SUPPORT_OPENGL, PFD_TYPE_RGBA, // Request An RGBA Format (BYTE)32, // Select Our Color Depth 0, 0, 0, 0, 0, 0, // Color Bits Ignored @@ -545,9 +764,18 @@ bool OpenGLContext::ImplInit() 0, 0, 0 // Layer Masks Ignored }; + if (mbUseDoubleBufferedRendering) + PixelFormatFront.dwFlags |= PFD_DOUBLEBUFFER; + + if (mbRequestVirtualDevice) + PixelFormatFront.dwFlags |= PFD_DRAW_TO_BITMAP; + else + PixelFormatFront.dwFlags |= PFD_DRAW_TO_WINDOW; + // we must check whether can set the MSAA int WindowPix = 0; - bool bMultiSampleSupport = InitMultisample(PixelFormatFront, WindowPix); + bool bMultiSampleSupport = InitMultisample(PixelFormatFront, WindowPix, + mbUseDoubleBufferedRendering, mbRequestVirtualDevice); if (bMultiSampleSupport && WindowPix != 0) { m_aGLWin.bMultiSampleSupported = true; @@ -577,64 +805,37 @@ bool OpenGLContext::ImplInit() return false; } + RECT clientRect; + GetClientRect(WindowFromDC(m_aGLWin.hDC), &clientRect); + m_aGLWin.Width = clientRect.right - clientRect.left; + m_aGLWin.Height = clientRect.bottom - clientRect.top; + + return InitGLEW(); +} + #elif defined( MACOSX ) +bool OpenGLContext::ImplInit() +{ + SAL_INFO("vcl.opengl", "OpenGLContext::ImplInit----start"); NSOpenGLView* pView = getOpenGLView(); OpenGLWrapper::makeCurrent(pView); -#elif defined( IOS ) - -#elif defined( ANDROID ) - -#elif defined( UNX ) - if( !glXMakeCurrent( m_aGLWin.dpy, m_aGLWin.win, m_aGLWin.ctx ) ) - { - SAL_INFO("vcl.opengl", "unable to select current GLX context"); - return false; - } - - int glxMinor, glxMajor; - double nGLXVersion = 0; - if( glXQueryVersion( m_aGLWin.dpy, &glxMajor, &glxMinor ) ) - nGLXVersion = glxMajor + 0.1*glxMinor; - SAL_INFO("vcl.opengl", "available GLX version: " << nGLXVersion); - - m_aGLWin.GLExtensions = glGetString( GL_EXTENSIONS ); - SAL_INFO("vcl.opengl", "available GL extensions: " << m_aGLWin.GLExtensions); - - if( m_aGLWin.HasGLXExtension("GLX_SGI_swap_control" ) ) - { - // enable vsync - typedef GLint (*glXSwapIntervalProc)(GLint); - glXSwapIntervalProc glXSwapInterval = (glXSwapIntervalProc) glXGetProcAddress( (const GLubyte*) "glXSwapIntervalSGI" ); - if( glXSwapInterval ) { - int (*oldHandler)(Display* /*dpy*/, XErrorEvent* /*evnt*/); - - // replace error handler temporarily - oldHandler = XSetErrorHandler( oglErrorHandler ); - - errorTriggered = false; - - glXSwapInterval( 1 ); - - // sync so that we possibly get an XError - glXWaitGL(); - XSync(m_aGLWin.dpy, false); + return InitGLEW(); +} - if( errorTriggered ) - SAL_WARN("vcl.opengl", "error when trying to set swap interval, NVIDIA or Mesa bug?"); - else - SAL_INFO("vcl.opengl", "set swap interval to 1 (enable vsync)"); +#else - // restore the error handler - XSetErrorHandler( oldHandler ); - } - } +bool OpenGLContext::ImplInit() +{ + SAL_INFO("vcl.opengl", "OpenGLContext not implemented for this platform"); + return false; +} #endif - //rGLRender.InitOpenGL(m_aGLWin); - +bool OpenGLContext::InitGLEW() +{ static bool bGlewInit = false; if(!bGlewInit) { @@ -688,7 +889,6 @@ void OpenGLContext::setWinSize(const Size& rSize) m_aGLWin.Height = rSize.Height(); } - void OpenGLContext::renderToFile() { int iWidth = m_aGLWin.Width; @@ -722,6 +922,7 @@ bool OpenGLContext::initWindow() m_aGLWin.hWnd = sysData->hWnd; } + m_aGLWin.hDC = GetDC(m_aGLWin.hWnd); return true; } @@ -786,9 +987,16 @@ bool OpenGLContext::initWindow() m_aGLWin.win = pChildSysData->aWindow; m_aGLWin.screen = pChildSysData->nScreen; + Visual* pVisual = (Visual*)pChildSysData->pVisual; + initGLWindow(pVisual); + + return true; +} + +void OpenGLContext::initGLWindow(Visual* pVisual) +{ // Get visual info { - Visual* pVisual = (Visual*)pChildSysData->pVisual; XVisualInfo aTemplate; aTemplate.visualid = XVisualIDFromVisual( pVisual ); int nVisuals = 0; @@ -799,6 +1007,8 @@ bool OpenGLContext::initWindow() } // Check multi sample support + /* TODO: moggi: This is not necessarily correct in the DBG_UTIL path, as it picks + * an FBConfig instead ... */ int nSamples = 0; glXGetConfig(m_aGLWin.dpy, m_aGLWin.vi, GLX_SAMPLES, &nSamples); if( nSamples > 0 ) @@ -806,8 +1016,6 @@ bool OpenGLContext::initWindow() m_aGLWin.GLXExtensions = glXQueryExtensionsString( m_aGLWin.dpy, m_aGLWin.screen ); SAL_INFO("vcl.opengl", "available GLX extensions: " << m_aGLWin.GLXExtensions); - - return true; } #endif @@ -828,20 +1036,6 @@ SystemWindowData OpenGLContext::generateWinData(vcl::Window* /*pParent*/, bool b #elif defined( UNX ) -namespace { - -// we need them before glew can initialize them -// glew needs an OpenGL context so we need to get the address manually -void initOpenGLFunctionPointers() -{ - glXChooseFBConfig = (GLXFBConfig*(*)(Display *dpy, int screen, const int *attrib_list, int *nelements))glXGetProcAddressARB((GLubyte*)"glXChooseFBConfig"); - glXGetVisualFromFBConfig = (XVisualInfo*(*)(Display *dpy, GLXFBConfig config))glXGetProcAddressARB((GLubyte*)"glXGetVisualFromFBConfig"); // try to find a visual for the current set of attributes - glXGetFBConfigAttrib = (int(*)(Display *dpy, GLXFBConfig config, int attribute, int* value))glXGetProcAddressARB((GLubyte*)"glXGetFBConfigAttrib"); - glXCreateContextAttribsARB = (GLXContext(*) (Display*, GLXFBConfig, GLXContext, Bool, const int*)) glXGetProcAddressARB((const GLubyte *) "glXCreateContextAttribsARB");; -} - -} - SystemWindowData OpenGLContext::generateWinData(vcl::Window* pParent, bool) { SystemWindowData aWinData; @@ -851,23 +1045,12 @@ SystemWindowData OpenGLContext::generateWinData(vcl::Window* pParent, bool) const SystemEnvData* sysData(pParent->GetSystemData()); Display *dpy = reinterpret_cast<Display*>(sysData->pDisplay); + Window win = sysData->aWindow; if( dpy == 0 || !glXQueryExtension( dpy, NULL, NULL ) ) return aWinData; - initOpenGLFunctionPointers(); - - int best_fbc = -1; - GLXFBConfig* pFBC = getFBConfig(sysData, best_fbc); - - XVisualInfo* vi = glXGetVisualFromFBConfig( dpy, pFBC[best_fbc] ); - if( vi ) - { - SAL_INFO("vcl.opengl", "using VisualID " << vi->visualid); - aWinData.pVisual = (void*)(vi->visual); - } - - XFree(pFBC); + aWinData.pVisual = getVisual(dpy, win); return aWinData; } @@ -887,7 +1070,8 @@ void OpenGLContext::makeCurrent() #elif defined( IOS ) || defined( ANDROID ) // nothing #elif defined( UNX ) - glXMakeCurrent( m_aGLWin.dpy, m_aGLWin.win, m_aGLWin.ctx ); + if (!glXMakeCurrent( m_aGLWin.dpy, mbPixmap ? m_aGLWin.glPix : m_aGLWin.win, m_aGLWin.ctx )) + SAL_WARN("vcl.opengl", "OpenGLContext::makeCurrent failed"); #endif } @@ -914,7 +1098,7 @@ void OpenGLContext::swapBuffers() #elif defined( IOS ) || defined( ANDROID ) // nothing #elif defined( UNX ) - glXSwapBuffers(m_aGLWin.dpy, m_aGLWin.win); + glXSwapBuffers(m_aGLWin.dpy, mbPixmap ? m_aGLWin.glPix : m_aGLWin.win); #endif } diff --git a/vcl/source/opengl/OpenGLHelper.cxx b/vcl/source/opengl/OpenGLHelper.cxx index c94e290ac7f0..5823b80d63a6 100644 --- a/vcl/source/opengl/OpenGLHelper.cxx +++ b/vcl/source/opengl/OpenGLHelper.cxx @@ -86,7 +86,7 @@ GLint OpenGLHelper::LoadShaders(const OUString& rVertexShaderName,const OUString SAL_WARN("vcl.opengl", "vertex shader compile for " << rVertexShaderName << " failed : " << &VertexShaderErrorMessage[0]); } else - SAL_WARN("vcl.opengl", "vertex shader compile failed without error log"); + SAL_WARN("vcl.opengl", "vertex shader: " << rVertexShaderName << " compile failed without error log"); return 0; } @@ -358,4 +358,85 @@ void OpenGLHelper::checkGLError(const char* pFile, size_t nLine) } } +bool OpenGLHelper::supportsVCLOpenGL() +{ + static bool bDisableGL = !getenv("SAL_DISABLEGL"); + return bDisableGL; +} + +#if defined UNX && !defined MACOSX && !defined IOS && !defined ANDROID + +bool OpenGLHelper::GetVisualInfo(Display* pDisplay, int nScreen, XVisualInfo& rVI) +{ + XVisualInfo* pVI; + int aAttrib[] = { GLX_RGBA, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_DEPTH_SIZE, 24, + GLX_DOUBLEBUFFER, + None }; + + pVI = glXChooseVisual( pDisplay, nScreen, aAttrib ); + if( !pVI ) + return false; + + rVI = *pVI; + XFree( pVI ); + + return true; +} + +GLXFBConfig OpenGLHelper::GetPixmapFBConfig( Display* pDisplay, bool& bInverted ) +{ + int nScreen = DefaultScreen( pDisplay ); + GLXFBConfig *aFbConfigs; + int i, nFbConfigs, nValue; + + aFbConfigs = glXGetFBConfigs( pDisplay, nScreen, &nFbConfigs ); + for( i = 0; i < nFbConfigs; i++ ) + { + glXGetFBConfigAttrib( pDisplay, aFbConfigs[i], GLX_DRAWABLE_TYPE, &nValue ); + if( !(nValue & GLX_PIXMAP_BIT) ) + continue; + + glXGetFBConfigAttrib( pDisplay, aFbConfigs[i], GLX_BIND_TO_TEXTURE_TARGETS_EXT, &nValue ); + if( !(nValue & GLX_TEXTURE_2D_BIT_EXT) ) + continue; + + glXGetFBConfigAttrib( pDisplay, aFbConfigs[i], GLX_DEPTH_SIZE, &nValue ); + if( nValue != 24 ) + continue; + + glXGetFBConfigAttrib( pDisplay, aFbConfigs[i], GLX_RED_SIZE, &nValue ); + if( nValue != 8 ) + continue; + SAL_INFO( "vcl.opengl", "Red is " << nValue ); + + // TODO: lfrb: Make it configurable wrt RGB/RGBA + glXGetFBConfigAttrib( pDisplay, aFbConfigs[i], GLX_BIND_TO_TEXTURE_RGB_EXT, &nValue ); + if( nValue == False ) + { + glXGetFBConfigAttrib( pDisplay, aFbConfigs[i], GLX_BIND_TO_TEXTURE_RGBA_EXT, &nValue ); + if( nValue == False ) + continue; + } + + glXGetFBConfigAttrib( pDisplay, aFbConfigs[i], GLX_Y_INVERTED_EXT, &nValue ); + bInverted = (nValue == True) ? true : false; + + break; + } + + if( i == nFbConfigs ) + { + SAL_WARN( "vcl.opengl", "Unable to find FBconfig for pixmap texturing" ); + return 0; + } + + return aFbConfigs[i]; +} + +#endif + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/outdev/bitmap.cxx b/vcl/source/outdev/bitmap.cxx index a191b8b2c703..20e6367ac30c 100644 --- a/vcl/source/outdev/bitmap.cxx +++ b/vcl/source/outdev/bitmap.cxx @@ -457,8 +457,7 @@ Bitmap OutputDevice::GetBitmap( const Point& rSrcPt, const Size& rSize ) const if( pSalBmp ) { - ImpBitmap* pImpBmp = new ImpBitmap; - pImpBmp->ImplSetSalBitmap( pSalBmp ); + ImpBitmap* pImpBmp = new ImpBitmap(pSalBmp); aBmp.ImplSetImpBitmap( pImpBmp ); } } diff --git a/vcl/source/outdev/outdev.cxx b/vcl/source/outdev/outdev.cxx index 3c9e519cc71d..ad7779dc597d 100644 --- a/vcl/source/outdev/outdev.cxx +++ b/vcl/source/outdev/outdev.cxx @@ -839,4 +839,11 @@ bool OutputDevice::DrawEPS( const Point& rPoint, const Size& rSize, return bDrawn; } +bool OutputDevice::SwapBuffers() +{ + if( !mpGraphics && !AcquireGraphics() ) + return false; + return mpGraphics->SwapBuffers(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/outdev/polygon.cxx b/vcl/source/outdev/polygon.cxx index 39c2b6807a77..03fa16888ea3 100644 --- a/vcl/source/outdev/polygon.cxx +++ b/vcl/source/outdev/polygon.cxx @@ -231,7 +231,7 @@ void OutputDevice::DrawPolygon( const Polygon& rPoly ) // Caution: This method is nearly the same as // OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency), -// so when changes are made here do not forget to make change sthere, too +// so when changes are made here do not forget to make changes there, too void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rB2DPolyPoly ) { diff --git a/vcl/source/window/paint.cxx b/vcl/source/window/paint.cxx index 7ec329cc1388..b3576db29689 100644 --- a/vcl/source/window/paint.cxx +++ b/vcl/source/window/paint.cxx @@ -278,6 +278,8 @@ void Window::ImplCallOverlapPaint() // - RTL - notify ImplCallPaint to check for re-mirroring (CHECKRTL) // because we were called from the Sal layer ImplCallPaint( NULL, mpWindowImpl->mnPaintFlags /*| IMPL_PAINT_CHECKRTL */); + OutputDevice *pOutDev = GetOutDev(); + pOutDev->SwapBuffers(); } } diff --git a/vcl/unx/generic/app/saldisp.cxx b/vcl/unx/generic/app/saldisp.cxx index 88be46307f7d..5803733c4ca6 100644 --- a/vcl/unx/generic/app/saldisp.cxx +++ b/vcl/unx/generic/app/saldisp.cxx @@ -67,10 +67,14 @@ #include <unx/sm.hxx> #include <unx/wmadaptor.hxx> +#include <vcl/opengl/OpenGLHelper.hxx> + #include <osl/socket.h> #include <poll.h> #include <boost/scoped_array.hpp> +#include <officecfg/Office/Common.hxx> + using namespace vcl_sal; #define SALCOLOR_WHITE MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ) @@ -187,6 +191,10 @@ bool SalDisplay::BestVisual( Display *pDisplay, if( nVID && sal_GetVisualInfo( pDisplay, nVID, rVI ) ) return rVI.visualid == nDefVID; + bool bUseOpenGL = officecfg::Office::Common::VCL::UseOpenGL::get(); + if( bUseOpenGL && OpenGLHelper::GetVisualInfo( pDisplay, nScreen, rVI ) ) + return rVI.visualid == nDefVID; + XVisualInfo aVI; aVI.screen = nScreen; // get all visuals diff --git a/vcl/unx/generic/gdi/cairotextrender.cxx b/vcl/unx/generic/gdi/cairotextrender.cxx new file mode 100644 index 000000000000..5b31b92fd42a --- /dev/null +++ b/vcl/unx/generic/gdi/cairotextrender.cxx @@ -0,0 +1,660 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "cairotextrender.hxx" + +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <vcl/settings.hxx> +#include <vcl/sysdata.hxx> + +#include "generic/printergfx.hxx" +#include "generic/genpspgraphics.h" +#include "generic/geninst.h" +#include "PhysicalFontFace.hxx" +#include "impfont.hxx" + +#include <config_graphite.h> +#if ENABLE_GRAPHITE +#include <graphite_layout.hxx> +#include <graphite_serverfont.hxx> +#endif + +#include <cairo.h> +#include <cairo-ft.h> +#include <cairo-xlib.h> +#include <cairo-xlib-xrender.h> + +CairoTextRender::CairoTextRender(bool bPrinter): + mbPrinter(bPrinter), + nTextColor_(MAKE_SALCOLOR(0x00, 0x00, 0x00)) //black +{ + for( int i = 0; i < MAX_FALLBACK; ++i ) + mpServerFont[i] = NULL; + +#if ENABLE_GRAPHITE + // check if graphite fonts have been disabled + static const char* pDisableGraphiteStr = getenv( "SAL_DISABLE_GRAPHITE" ); + bDisableGraphite_ = pDisableGraphiteStr && (pDisableGraphiteStr[0]!='0'); +#endif +} + +bool CairoTextRender::setFont( const FontSelectPattern *pEntry, int nFallbackLevel ) +{ + // release all no longer needed font resources + for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i ) + { + if( mpServerFont[i] != NULL ) + { + // old server side font is no longer referenced + GlyphCache::GetInstance().UncacheFont( *mpServerFont[i] ); + mpServerFont[i] = NULL; + } + } + + // return early if there is no new font + if( !pEntry ) + return false; + + // return early if this is not a valid font for this graphics + if( !pEntry->mpFontData ) + return false; + + // handle the request for a non-native X11-font => use the GlyphCache + ServerFont* pServerFont = GlyphCache::GetInstance().CacheFont( *pEntry ); + if( pServerFont != NULL ) + { + // ignore fonts with e.g. corrupted font files + if( !pServerFont->TestFont() ) + { + GlyphCache::GetInstance().UncacheFont( *pServerFont ); + return false; + } + + // register to use the font + mpServerFont[ nFallbackLevel ] = pServerFont; + + // apply font specific-hint settings if needed + // TODO: also disable it for reference devices + if( !mbPrinter ) + { + ImplServerFontEntry* pSFE = static_cast<ImplServerFontEntry*>( pEntry->mpFontEntry ); + pSFE->HandleFontOptions(); + } + + return true; + } + + return false; +} + +ImplFontOptions* GetFCFontOptions( const ImplFontAttributes& rFontAttributes, int nSize); + +void ImplServerFontEntry::HandleFontOptions( void ) +{ + if( !mpServerFont ) + return; + if( !mbGotFontOptions ) + { + // get and cache the font options + mbGotFontOptions = true; + mpFontOptions.reset(GetFCFontOptions( *maFontSelData.mpFontData, + maFontSelData.mnHeight )); + } + // apply the font options + mpServerFont->SetFontOptions( mpFontOptions ); +} + +CairoFontsCache::LRUFonts CairoFontsCache::maLRUFonts; +int CairoFontsCache::mnRefCount = 0; + +CairoFontsCache::CairoFontsCache() +{ + ++mnRefCount; +} + +CairoFontsCache::~CairoFontsCache() +{ + --mnRefCount; + if (!mnRefCount && !maLRUFonts.empty()) + { + LRUFonts::iterator aEnd = maLRUFonts.end(); + for (LRUFonts::iterator aI = maLRUFonts.begin(); aI != aEnd; ++aI) + cairo_font_face_destroy((cairo_font_face_t*)aI->first); + } +} + +void CairoFontsCache::CacheFont(void *pFont, const CairoFontsCache::CacheId &rId) +{ + maLRUFonts.push_front( std::pair<void*, CairoFontsCache::CacheId>(pFont, rId) ); + if (maLRUFonts.size() > 8) + { + cairo_font_face_destroy((cairo_font_face_t*)maLRUFonts.back().first); + maLRUFonts.pop_back(); + } +} + +void* CairoFontsCache::FindCachedFont(const CairoFontsCache::CacheId &rId) +{ + LRUFonts::iterator aEnd = maLRUFonts.end(); + for (LRUFonts::iterator aI = maLRUFonts.begin(); aI != aEnd; ++aI) + if (aI->second == rId) + return aI->first; + return NULL; +} + +namespace +{ + bool hasRotation(int nRotation) + { + return nRotation != 0; + } + + double toRadian(int nDegree10th) + { + return (3600 - (nDegree10th)) * M_PI / 1800.0; + } +} + +void CairoTextRender::DrawServerFontLayout( const ServerFontLayout& rLayout ) +{ + std::vector<cairo_glyph_t> cairo_glyphs; + std::vector<int> glyph_extrarotation; + cairo_glyphs.reserve( 256 ); + + Point aPos; + sal_GlyphId aGlyphId; + for( int nStart = 0; rLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); ) + { + cairo_glyph_t aGlyph; + aGlyph.index = aGlyphId & GF_IDXMASK; + aGlyph.x = aPos.X(); + aGlyph.y = aPos.Y(); + cairo_glyphs.push_back(aGlyph); + + switch (aGlyphId & GF_ROTMASK) + { + case GF_ROTL: // left + glyph_extrarotation.push_back(1); + break; + case GF_ROTR: // right + glyph_extrarotation.push_back(-1); + break; + default: + glyph_extrarotation.push_back(0); + break; + } + } + + if (cairo_glyphs.empty()) + return; + + cairo_surface_t *surface = getCairoSurface(); + + DBG_ASSERT( surface!=NULL, "no cairo surface for text" ); + if( !surface ) + return; + + /* + * It might be ideal to cache surface and cairo context between calls and + * only destroy it when the drawable changes, but to do that we need to at + * least change the SalFrame etc impls to dtor the SalGraphics *before* the + * destruction of the windows they reference + */ + cairo_t *cr = cairo_create(surface); + cairo_surface_destroy(surface); + + if (const void *pOptions = Application::GetSettings().GetStyleSettings().GetCairoFontOptions()) + cairo_set_font_options(cr, static_cast<const cairo_font_options_t*>(pOptions)); + + clipRegion(cr); + + cairo_set_source_rgb(cr, + SALCOLOR_RED(nTextColor_)/255.0, + SALCOLOR_GREEN(nTextColor_)/255.0, + SALCOLOR_BLUE(nTextColor_)/255.0); + + ServerFont& rFont = rLayout.GetServerFont(); + + FT_Face aFace = rFont.GetFtFace(); + CairoFontsCache::CacheId aId; + aId.maFace = aFace; + aId.mpOptions = rFont.GetFontOptions().get(); + aId.mbEmbolden = rFont.NeedsArtificialBold(); + + cairo_matrix_t m; + const FontSelectPattern& rFSD = rFont.GetFontSelData(); + int nHeight = rFSD.mnHeight; + int nWidth = rFSD.mnWidth ? rFSD.mnWidth : nHeight; + + std::vector<int>::const_iterator aEnd = glyph_extrarotation.end(); + std::vector<int>::const_iterator aStart = glyph_extrarotation.begin(); + std::vector<int>::const_iterator aI = aStart; + while (aI != aEnd) + { + int nGlyphRotation = *aI; + + std::vector<int>::const_iterator aNext = std::find_if(aI+1, aEnd, hasRotation); + + size_t nStartIndex = std::distance(aStart, aI); + size_t nLen = std::distance(aI, aNext); + + aId.mbVerticalMetrics = nGlyphRotation != 0.0; + cairo_font_face_t* font_face = (cairo_font_face_t*)CairoFontsCache::FindCachedFont(aId); + if (!font_face) + { + const ImplFontOptions *pOptions = rFont.GetFontOptions().get(); + void *pPattern = pOptions ? pOptions->GetPattern(aFace, aId.mbEmbolden, aId.mbVerticalMetrics) : NULL; + if (pPattern) + font_face = cairo_ft_font_face_create_for_pattern(reinterpret_cast<FcPattern*>(pPattern)); + if (!font_face) + font_face = cairo_ft_font_face_create_for_ft_face(reinterpret_cast<FT_Face>(aFace), rFont.GetLoadFlags()); + CairoFontsCache::CacheFont(font_face, aId); + } + cairo_set_font_face(cr, font_face); + + cairo_set_font_size(cr, nHeight); + + cairo_matrix_init_identity(&m); + + if (rLayout.GetOrientation()) + cairo_matrix_rotate(&m, toRadian(rLayout.GetOrientation())); + + cairo_matrix_scale(&m, nWidth, nHeight); + + if (nGlyphRotation) + { + cairo_matrix_rotate(&m, toRadian(nGlyphRotation*900)); + + cairo_matrix_t em_square; + cairo_matrix_init_identity(&em_square); + cairo_get_matrix(cr, &em_square); + + cairo_matrix_scale(&em_square, aFace->units_per_EM, + aFace->units_per_EM); + cairo_set_matrix(cr, &em_square); + + cairo_font_extents_t font_extents; + cairo_font_extents(cr, &font_extents); + + cairo_matrix_init_identity(&em_square); + cairo_set_matrix(cr, &em_square); + + //gives the same positions as pre-cairo conversion, but I don't + //like them + double xdiff = 0.0; + double ydiff = 0.0; + if (nGlyphRotation == 1) + { + ydiff = font_extents.ascent/nHeight; + xdiff = -font_extents.descent/nHeight; + } + else if (nGlyphRotation == -1) + { + cairo_text_extents_t text_extents; + cairo_glyph_extents(cr, &cairo_glyphs[nStartIndex], nLen, + &text_extents); + + xdiff = -text_extents.x_advance/nHeight; + //to restore an apparent bug in the original X11 impl, replace + //nHeight with nWidth below + xdiff += font_extents.descent/nHeight; + } + cairo_matrix_translate(&m, xdiff, ydiff); + } + + if (rFont.NeedsArtificialItalic()) + { + cairo_matrix_t shear; + cairo_matrix_init_identity(&shear); + shear.xy = -shear.xx * 0x6000L / 0x10000L; + cairo_matrix_multiply(&m, &shear, &m); + } + + cairo_set_font_matrix(cr, &m); + cairo_show_glyphs(cr, &cairo_glyphs[nStartIndex], nLen); + +#if OSL_DEBUG_LEVEL > 2 + //draw origin + cairo_save (cr); + cairo_rectangle (cr, cairo_glyphs[nStartIndex].x, cairo_glyphs[nStartIndex].y, 5, 5); + cairo_set_source_rgba (cr, 1, 0, 0, 0.80); + cairo_fill (cr); + cairo_restore (cr); +#endif + + aI = aNext; + } + + drawSurface(cr); + cairo_destroy(cr); +} + +const FontCharMapPtr CairoTextRender::GetFontCharMap() const +{ + if( !mpServerFont[0] ) + return NULL; + + const FontCharMapPtr pFCMap = mpServerFont[0]->GetFontCharMap(); + return pFCMap; +} + +bool CairoTextRender::GetFontCapabilities(vcl::FontCapabilities &rGetImplFontCapabilities) const +{ + if (!mpServerFont[0]) + return false; + return mpServerFont[0]->GetFontCapabilities(rGetImplFontCapabilities); +} + +// SalGraphics + +sal_uInt16 CairoTextRender::SetFont( FontSelectPattern *pEntry, int nFallbackLevel ) +{ + sal_uInt16 nRetVal = 0; + if( !setFont( pEntry, nFallbackLevel ) ) + nRetVal |= SAL_SETFONT_BADFONT; + if( mbPrinter || (mpServerFont[ nFallbackLevel ] != NULL) ) + nRetVal |= SAL_SETFONT_USEDRAWTEXTARRAY; + return nRetVal; +} + +void +CairoTextRender::SetTextColor( SalColor nSalColor ) +{ + if( nTextColor_ != nSalColor ) + { + nTextColor_ = nSalColor; + } +} + +bool CairoTextRender::AddTempDevFont( PhysicalFontCollection* pFontCollection, + const OUString& rFileURL, + const OUString& rFontName ) +{ + // inform PSP font manager + OUString aUSystemPath; + OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFileURL, aUSystemPath ) ); + rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); + OString aOFileName( OUStringToOString( aUSystemPath, aEncoding ) ); + psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + std::vector<psp::fontID> aFontIds = rMgr.addFontFile( aOFileName ); + if( aFontIds.empty() ) + return false; + + GlyphCache& rGC = getPlatformGlyphCache(); + + for (std::vector<psp::fontID>::iterator aI = aFontIds.begin(), aEnd = aFontIds.end(); aI != aEnd; ++aI) + { + // prepare font data + psp::FastPrintFontInfo aInfo; + rMgr.getFontFastInfo( *aI, aInfo ); + aInfo.m_aFamilyName = rFontName; + + // inform glyph cache of new font + ImplDevFontAttributes aDFA = GenPspGraphics::Info2DevFontAttributes( aInfo ); + aDFA.mnQuality += 5800; + + int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID ); + + const OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID ); + rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA ); + } + + // announce new font to device's font list + rGC.AnnounceFonts( pFontCollection ); + return true; +} + +void CairoTextRender::ClearDevFontCache() +{ + GlyphCache& rGC = getPlatformGlyphCache(); + rGC.ClearFontCache(); +} + +void CairoTextRender::GetDevFontList( PhysicalFontCollection* pFontCollection ) +{ + // prepare the GlyphCache using psprint's font infos + GlyphCache& rGC = getPlatformGlyphCache(); + + psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + ::std::list< psp::fontID > aList; + ::std::list< psp::fontID >::iterator it; + psp::FastPrintFontInfo aInfo; + rMgr.getFontList( aList ); + for( it = aList.begin(); it != aList.end(); ++it ) + { + if( !rMgr.getFontFastInfo( *it, aInfo ) ) + continue; + + // normalize face number to the GlyphCache + int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID ); + + // inform GlyphCache about this font provided by the PsPrint subsystem + ImplDevFontAttributes aDFA = GenPspGraphics::Info2DevFontAttributes( aInfo ); + aDFA.mnQuality += 4096; + const OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID ); + rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA ); + } + + // announce glyphcache fonts + rGC.AnnounceFonts( pFontCollection ); + + // register platform specific font substitutions if available + SalGenericInstance::RegisterFontSubstitutors( pFontCollection ); + + ImplGetSVData()->maGDIData.mbNativeFontConfig = true; +} + +void cairosubcallback(void* pPattern) +{ + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + const void* pFontOptions = rStyleSettings.GetCairoFontOptions(); + if( !pFontOptions ) + return; + cairo_ft_font_options_substitute(static_cast<const cairo_font_options_t*>(pFontOptions), + static_cast<FcPattern*>(pPattern)); +} + +ImplFontOptions* GetFCFontOptions( const ImplFontAttributes& rFontAttributes, int nSize) +{ + psp::FastPrintFontInfo aInfo; + + aInfo.m_aFamilyName = rFontAttributes.GetFamilyName(); + aInfo.m_eItalic = rFontAttributes.GetSlant(); + aInfo.m_eWeight = rFontAttributes.GetWeight(); + aInfo.m_eWidth = rFontAttributes.GetWidthType(); + + const psp::PrintFontManager& rPFM = psp::PrintFontManager::get(); + return rPFM.getFontOptions(aInfo, nSize, cairosubcallback); +} + +void +CairoTextRender::GetFontMetric( ImplFontMetricData *pMetric, int nFallbackLevel ) +{ + if( nFallbackLevel >= MAX_FALLBACK ) + return; + + if( mpServerFont[nFallbackLevel] != NULL ) + { + long rDummyFactor; + mpServerFont[nFallbackLevel]->FetchFontMetric( *pMetric, rDummyFactor ); + } +} + +bool CairoTextRender::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect ) +{ + const int nLevel = aGlyphId >> GF_FONTSHIFT; + if( nLevel >= MAX_FALLBACK ) + return false; + + ServerFont* pSF = mpServerFont[ nLevel ]; + if( !pSF ) + return false; + + aGlyphId &= GF_IDXMASK; + const GlyphMetric& rGM = pSF->GetGlyphMetric(aGlyphId); + Rectangle aRect( rGM.GetOffset(), rGM.GetSize() ); + + if ( pSF->mnCos != 0x10000 && pSF->mnSin != 0 ) + { + double nCos = pSF->mnCos / 65536.0; + double nSin = pSF->mnSin / 65536.0; + rRect.Left() = nCos*aRect.Left() + nSin*aRect.Top(); + rRect.Top() = -nSin*aRect.Left() - nCos*aRect.Top(); + + rRect.Right() = nCos*aRect.Right() + nSin*aRect.Bottom(); + rRect.Bottom() = -nSin*aRect.Right() - nCos*aRect.Bottom(); + } + else + rRect = aRect; + + return true; +} + +bool CairoTextRender::GetGlyphOutline( sal_GlyphId aGlyphId, + ::basegfx::B2DPolyPolygon& rPolyPoly ) +{ + const int nLevel = aGlyphId >> GF_FONTSHIFT; + if( nLevel >= MAX_FALLBACK ) + return false; + + ServerFont* pSF = mpServerFont[ nLevel ]; + if( !pSF ) + return false; + + aGlyphId &= GF_IDXMASK; + if( pSF->GetGlyphOutline( aGlyphId, rPolyPoly ) ) + return true; + + return false; +} + +SalLayout* CairoTextRender::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel ) +{ + SalLayout* pLayout = NULL; + + if( mpServerFont[ nFallbackLevel ] + && !(rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) ) + { +#if ENABLE_GRAPHITE + // Is this a Graphite font? + if (!bDisableGraphite_ && + GraphiteServerFontLayout::IsGraphiteEnabledFont(*mpServerFont[nFallbackLevel])) + { + pLayout = new GraphiteServerFontLayout(*mpServerFont[nFallbackLevel]); + } + else +#endif + pLayout = new ServerFontLayout( *mpServerFont[ nFallbackLevel ] ); + } + + return pLayout; +} + +SystemFontData CairoTextRender::GetSysFontData( int nFallbackLevel ) const +{ + SystemFontData aSysFontData; + aSysFontData.nSize = sizeof( SystemFontData ); + aSysFontData.nFontId = 0; + + if (nFallbackLevel >= MAX_FALLBACK) nFallbackLevel = MAX_FALLBACK - 1; + if (nFallbackLevel < 0 ) nFallbackLevel = 0; + + if (mpServerFont[nFallbackLevel] != NULL) + { + ServerFont* rFont = mpServerFont[nFallbackLevel]; + aSysFontData.nFontId = rFont->GetFtFace(); + aSysFontData.nFontFlags = rFont->GetLoadFlags(); + aSysFontData.bFakeBold = rFont->NeedsArtificialBold(); + aSysFontData.bFakeItalic = rFont->NeedsArtificialItalic(); + aSysFontData.bAntialias = rFont->GetAntialiasAdvice(); + aSysFontData.bVerticalCharacterType = rFont->GetFontSelData().mbVertical; + } + + return aSysFontData; +} + +bool CairoTextRender::CreateFontSubset( + const OUString& rToFile, + const PhysicalFontFace* pFont, + sal_GlyphId* pGlyphIds, + sal_uInt8* pEncoding, + sal_Int32* pWidths, + int nGlyphCount, + FontSubsetInfo& rInfo + ) +{ + // in this context the pFont->GetFontId() is a valid PSP + // font since they are the only ones left after the PDF + // export has filtered its list of subsettable fonts (for + // which this method was created). The correct way would + // be to have the GlyphCache search for the PhysicalFontFace pFont + psp::fontID aFont = pFont->GetFontId(); + + psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); + bool bSuccess = rMgr.createFontSubset( rInfo, + aFont, + rToFile, + pGlyphIds, + pEncoding, + pWidths, + nGlyphCount ); + return bSuccess; +} + +const void* CairoTextRender::GetEmbedFontData( const PhysicalFontFace* pFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen ) +{ + // in this context the pFont->GetFontId() is a valid PSP + // font since they are the only ones left after the PDF + // export has filtered its list of subsettable fonts (for + // which this method was created). The correct way would + // be to have the GlyphCache search for the PhysicalFontFace pFont + psp::fontID aFont = pFont->GetFontId(); + return GenPspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, rInfo, pDataLen ); +} + +void CairoTextRender::FreeEmbedFontData( const void* pData, long nLen ) +{ + GenPspGraphics::DoFreeEmbedFontData( pData, nLen ); +} + +const Ucs2SIntMap* CairoTextRender::GetFontEncodingVector( const PhysicalFontFace* pFont, const Ucs2OStrMap** pNonEncoded ) +{ + // in this context the pFont->GetFontId() is a valid PSP + // font since they are the only ones left after the PDF + // export has filtered its list of subsettable fonts (for + // which this method was created). The correct way would + // be to have the GlyphCache search for the PhysicalFontFace pFont + psp::fontID aFont = pFont->GetFontId(); + return GenPspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded ); +} + +void CairoTextRender::GetGlyphWidths( const PhysicalFontFace* pFont, + bool bVertical, + Int32Vector& rWidths, + Ucs2UIntMap& rUnicodeEnc ) +{ + // in this context the pFont->GetFontId() is a valid PSP + // font since they are the only ones left after the PDF + // export has filtered its list of subsettable fonts (for + // which this method was created). The correct way would + // be to have the GlyphCache search for the PhysicalFontFace pFont + psp::fontID aFont = pFont->GetFontId(); + GenPspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc ); +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/gdi/gdiimpl.cxx b/vcl/unx/generic/gdi/gdiimpl.cxx new file mode 100644 index 000000000000..172ebd6314fb --- /dev/null +++ b/vcl/unx/generic/gdi/gdiimpl.cxx @@ -0,0 +1,1850 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <prex.h> +#include <X11/Xproto.h> +#include <postx.h> + +#include "gdiimpl.hxx" + +#include "vcl/salbtype.hxx" +#include <vcl/gradient.hxx> + +#include "unx/salunx.h" +#include "unx/saldata.hxx" +#include "unx/saldisp.hxx" +#include "unx/salbmp.h" +#include "unx/salgdi.h" +#include "unx/salframe.h" +#include "unx/salvd.h" +#include <unx/x11/xlimits.hxx> +#include "xrender_peer.hxx" + +#include "outdata.hxx" + +#include "basegfx/polygon/b2dpolygon.hxx" +#include "basegfx/polygon/b2dpolypolygon.hxx" +#include "basegfx/polygon/b2dpolypolygontools.hxx" +#include "basegfx/polygon/b2dpolygontools.hxx" +#include "basegfx/polygon/b2dpolygonclipper.hxx" +#include "basegfx/polygon/b2dlinegeometry.hxx" +#include "basegfx/matrix/b2dhommatrix.hxx" +#include "basegfx/matrix/b2dhommatrixtools.hxx" +#include "basegfx/polygon/b2dpolypolygoncutter.hxx" +#include "basegfx/polygon/b2dtrapezoid.hxx" + +#undef SALGDI2_TESTTRANS + +#if (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS +#define DBG_TESTTRANS( _def_drawable ) \ +{ \ + XCopyArea( pXDisp, _def_drawable, aDrawable, GetCopyGC(), \ + 0, 0, \ + rPosAry.mnDestWidth, rPosAry.mnDestHeight, \ + 0, 0 ); \ +} +#else // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS +#define DBG_TESTTRANS( _def_drawable ) +#endif // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS + +#define STATIC_POINTS 64 + +class SalPolyLine +{ + XPoint Points_[STATIC_POINTS]; + XPoint *pFirst_; +public: + SalPolyLine(sal_uLong nPoints, const SalPoint *p) + : pFirst_(nPoints+1 > STATIC_POINTS ? new XPoint[nPoints+1] : Points_) + { + for( sal_uLong i = 0; i < nPoints; i++ ) + { + pFirst_[i].x = (short)p[i].mnX; + pFirst_[i].y = (short)p[i].mnY; + } + pFirst_[nPoints] = pFirst_[0]; // close polyline + } + + ~SalPolyLine() + { + if( pFirst_ != Points_ ) + delete [] pFirst_; + } + + XPoint &operator [] ( sal_uLong n ) const + { + return pFirst_[n]; + } +}; + +#undef STATIC_POINTS + +namespace +{ + void setForeBack(XGCValues& rValues, const SalColormap& rColMap, const SalBitmap& rSalBitmap) + { + rValues.foreground = rColMap.GetWhitePixel(); + rValues.background = rColMap.GetBlackPixel(); + + //fdo#33455 and fdo#80160 handle 1 bit depth pngs with palette entries + //to set fore/back colors + SalBitmap& rBitmap = const_cast<SalBitmap&>(rSalBitmap); + if (BitmapBuffer* pBitmapBuffer = rBitmap.AcquireBuffer(true)) + { + const BitmapPalette& rPalette = pBitmapBuffer->maPalette; + if (rPalette.GetEntryCount() == 2) + { + const BitmapColor aWhite(rPalette[rPalette.GetBestIndex(Color(COL_WHITE))]); + rValues.foreground = rColMap.GetPixel(ImplColorToSal(aWhite)); + + const BitmapColor aBlack(rPalette[rPalette.GetBestIndex(Color(COL_BLACK))]); + rValues.background = rColMap.GetPixel(ImplColorToSal(aBlack)); + } + rBitmap.ReleaseBuffer(pBitmapBuffer, true); + } + } +} + +X11SalGraphicsImpl::X11SalGraphicsImpl(X11SalGraphics& rParent): + mrParent(rParent), + mnBrushColor( MAKE_SALCOLOR( 0xFF, 0xFF, 0XFF ) ), + mpBrushGC(NULL), + mnBrushPixel(0), + mbPenGC(false), + mbBrushGC(false), + mbMonoGC(false), + mbCopyGC(false), + mbInvertGC(false), + mbInvert50GC(false), + mbStippleGC(false), + mbTrackingGC(false), + mbDitherBrush(false), + mbXORMode(false), + mpPenGC(NULL), + mnPenColor( MAKE_SALCOLOR( 0x00, 0x00, 0x00 ) ), + mnPenPixel(0), + mpMonoGC(NULL), + mpCopyGC(NULL), + mpMaskGC(NULL), + mpInvertGC(NULL), + mpInvert50GC(NULL), + mpStippleGC(NULL), + mpTrackingGC(NULL) +{ +} + +X11SalGraphicsImpl::~X11SalGraphicsImpl() +{ +} + +void X11SalGraphicsImpl::Init() +{ + mnPenPixel = mrParent.GetPixel( mnPenColor ); + mnBrushPixel = mrParent.GetPixel( mnBrushColor ); +} + +X11Pixmap* X11SalGraphicsImpl::GetPixmapFromScreen( const Rectangle& rRect ) +{ + //TODO lfrb: don't hardcode the depth + Display* pDpy = mrParent.GetXDisplay(); + X11Pixmap* pPixmap = new X11Pixmap( pDpy, mrParent.GetScreenNumber(), + rRect.GetWidth(), rRect.GetHeight(), 24 ); + GC aTmpGC = XCreateGC( pDpy, pPixmap->GetPixmap(), 0, NULL ); + + if( !pPixmap || !aTmpGC ) + { + if ( pPixmap ) + delete pPixmap; + if ( aTmpGC ) + XFreeGC( pDpy, aTmpGC ); + SAL_WARN( "vcl", "Could not get valid pixmap from screen" ); + return NULL; + } + + // Copy the background of the screen into a composite pixmap + mrParent.CopyScreenArea( mrParent.GetXDisplay(), + mrParent.GetDrawable(), mrParent.GetScreenNumber(), + mrParent.GetVisual().GetDepth(), + pPixmap->GetDrawable(), pPixmap->GetScreen(), + pPixmap->GetDepth(), + aTmpGC, + rRect.Left(), rRect.Top(), + rRect.GetWidth(), rRect.GetHeight(), + 0, 0 ); + + XFreeGC( pDpy, aTmpGC ); + return pPixmap; +} + +bool X11SalGraphicsImpl::RenderPixmapToScreen( X11Pixmap* pPixmap, int nX, int nY ) +{ + GC aFontGC = mrParent.GetFontGC(); + + // The GC can't be null, otherwise we'd have no clip region + if( aFontGC == NULL ) + { + SAL_WARN( "vcl", "no valid GC to render pixmap" ); + return false; + } + + if( !pPixmap ) + return false; + + mrParent.CopyScreenArea( mrParent.GetXDisplay(), + pPixmap->GetDrawable(), pPixmap->GetScreen(), + pPixmap->GetDepth(), + mrParent.GetDrawable(), mrParent.m_nXScreen, + mrParent.GetVisual().GetDepth(), + aFontGC, + 0, 0, + pPixmap->GetWidth(), pPixmap->GetHeight(), + nX, nY ); + return true; +} + +XID X11SalGraphicsImpl::GetXRenderPicture() +{ + XRenderPeer& rRenderPeer = XRenderPeer::GetInstance(); + + if( !mrParent.m_aXRenderPicture ) + { + // check xrender support for matching visual + XRenderPictFormat* pXRenderFormat = mrParent.GetXRenderFormat(); + if( !pXRenderFormat ) + return 0; + // get the matching xrender target for drawable + mrParent.m_aXRenderPicture = rRenderPeer.CreatePicture( mrParent.hDrawable_, pXRenderFormat, 0, NULL ); + } + + { + // reset clip region + // TODO: avoid clip reset if already done + XRenderPictureAttributes aAttr; + aAttr.clip_mask = None; + rRenderPeer.ChangePicture( mrParent.m_aXRenderPicture, CPClipMask, &aAttr ); + } + + return mrParent.m_aXRenderPicture; +} + +void X11SalGraphicsImpl::freeResources() +{ + Display *pDisplay = mrParent.GetXDisplay(); + + if( mpPenGC ) XFreeGC( pDisplay, mpPenGC ), mpPenGC = None; + if( mpBrushGC ) XFreeGC( pDisplay, mpBrushGC ), mpBrushGC = None; + if( mpMonoGC ) XFreeGC( pDisplay, mpMonoGC ), mpMonoGC = None; + if( mpTrackingGC ) XFreeGC( pDisplay, mpTrackingGC ), mpTrackingGC = None; + if( mpCopyGC ) XFreeGC( pDisplay, mpCopyGC ), mpCopyGC = None; + if( mpMaskGC ) XFreeGC( pDisplay, mpMaskGC ), mpMaskGC = None; + if( mpInvertGC ) XFreeGC( pDisplay, mpInvertGC ), mpInvertGC = None; + if( mpInvert50GC ) XFreeGC( pDisplay, mpInvert50GC ), mpInvert50GC = None; + if( mpStippleGC ) XFreeGC( pDisplay, mpStippleGC ), mpStippleGC = None; + mbTrackingGC = mbPenGC = mbBrushGC = mbMonoGC = mbCopyGC = mbInvertGC = mbInvert50GC = mbStippleGC = false; +} + +GC X11SalGraphicsImpl::CreateGC( Drawable hDrawable, unsigned long nMask ) +{ + XGCValues values; + + values.graphics_exposures = False; + values.foreground = mrParent.m_pColormap->GetBlackPixel() + ^ mrParent.m_pColormap->GetWhitePixel(); + values.function = GXxor; + values.line_width = 1; + values.fill_style = FillStippled; + values.stipple = mrParent.GetDisplay()->GetInvert50( mrParent.m_nXScreen ); + values.subwindow_mode = ClipByChildren; + + return XCreateGC( mrParent.GetXDisplay(), hDrawable, nMask | GCSubwindowMode, &values ); +} + +inline GC X11SalGraphicsImpl::GetCopyGC() +{ + if( mbXORMode ) return GetInvertGC(); + + if( !mpCopyGC ) + mpCopyGC = CreateGC( mrParent.GetDrawable() ); + + if( !mbCopyGC ) + { + mrParent.SetClipRegion( mpCopyGC ); + mbCopyGC = true; + } + return mpCopyGC; +} + +GC X11SalGraphicsImpl::GetTrackingGC() +{ + const char dash_list[2] = {2, 2}; + + if( !mpTrackingGC ) + { + XGCValues values; + + values.graphics_exposures = False; + values.foreground = mrParent.m_pColormap->GetBlackPixel() + ^ mrParent.m_pColormap->GetWhitePixel(); + values.function = GXxor; + values.line_width = 1; + values.line_style = LineOnOffDash; + + mpTrackingGC = XCreateGC( mrParent.GetXDisplay(), mrParent.GetDrawable(), + GCGraphicsExposures | GCForeground | GCFunction + | GCLineWidth | GCLineStyle, + &values ); + XSetDashes( mrParent.GetXDisplay(), mpTrackingGC, 0, dash_list, 2 ); + } + + if( !mbTrackingGC ) + { + mrParent.SetClipRegion( mpTrackingGC ); + mbTrackingGC = true; + } + + return mpTrackingGC; +} + +inline GC X11SalGraphicsImpl::GetMonoGC( Pixmap hPixmap ) +{ + if( !mpMonoGC ) + mpMonoGC = CreateGC( hPixmap ); + + if( !mbMonoGC ) + { + mrParent.SetClipRegion( mpMonoGC ); + mbMonoGC = true; + } + + return mpMonoGC; +} + +GC X11SalGraphicsImpl::GetInvertGC() +{ + if( !mpInvertGC ) + mpInvertGC = CreateGC( mrParent.GetDrawable(), + GCGraphicsExposures + | GCForeground + | GCFunction + | GCLineWidth ); + + if( !mbInvertGC ) + { + mrParent.SetClipRegion( mpInvertGC ); + mbInvertGC = true; + } + return mpInvertGC; +} + +GC X11SalGraphicsImpl::GetInvert50GC() +{ + if( !mpInvert50GC ) + { + XGCValues values; + + values.graphics_exposures = False; + values.foreground = mrParent.m_pColormap->GetWhitePixel(); + values.background = mrParent.m_pColormap->GetBlackPixel(); + values.function = GXinvert; + values.line_width = 1; + values.line_style = LineSolid; + unsigned long nValueMask = + GCGraphicsExposures + | GCForeground + | GCBackground + | GCFunction + | GCLineWidth + | GCLineStyle + | GCFillStyle + | GCStipple; + + char* pEnv = getenv( "SAL_DO_NOT_USE_INVERT50" ); + if( pEnv && ! strcasecmp( pEnv, "true" ) ) + { + values.fill_style = FillSolid; + nValueMask &= ~ GCStipple; + } + else + { + values.fill_style = FillStippled; + values.stipple = mrParent.GetDisplay()->GetInvert50( mrParent.m_nXScreen ); + } + + mpInvert50GC = XCreateGC( mrParent.GetXDisplay(), mrParent.GetDrawable(), + nValueMask, + &values ); + } + + if( !mbInvert50GC ) + { + mrParent.SetClipRegion( mpInvert50GC ); + mbInvert50GC = true; + } + return mpInvert50GC; +} + +inline GC X11SalGraphicsImpl::GetStippleGC() +{ + if( !mpStippleGC ) + mpStippleGC = CreateGC( mrParent.GetDrawable(), + GCGraphicsExposures + | GCFillStyle + | GCLineWidth ); + + if( !mbStippleGC ) + { + XSetFunction( mrParent.GetXDisplay(), mpStippleGC, mbXORMode ? GXxor : GXcopy ); + mrParent.SetClipRegion( mpStippleGC ); + mbStippleGC = true; + } + + return mpStippleGC; +} + +GC X11SalGraphicsImpl::SelectBrush() +{ + Display *pDisplay = mrParent.GetXDisplay(); + + DBG_ASSERT( mnBrushColor != SALCOLOR_NONE, "Brush Transparent" ); + + if( !mpBrushGC ) + { + XGCValues values; + values.subwindow_mode = ClipByChildren; + values.fill_rule = EvenOddRule; // Pict import/ Gradient + values.graphics_exposures = False; + + mpBrushGC = XCreateGC( pDisplay, mrParent.hDrawable_, + GCSubwindowMode | GCFillRule | GCGraphicsExposures, + &values ); + } + + if( !mbBrushGC ) + { + if( !mbDitherBrush ) + { + XSetFillStyle ( pDisplay, mpBrushGC, FillSolid ); + XSetForeground( pDisplay, mpBrushGC, mnBrushPixel ); + if( mrParent.bPrinter_ ) + XSetTile( pDisplay, mpBrushGC, None ); + } + else + { + // Bug in Sun Solaris 2.5.1, XFillPolygon doesn't always reflect + // changes of the tile. PROPERTY_BUG_Tile doesn't fix this ! + if (mrParent.GetDisplay()->GetProperties() & PROPERTY_BUG_FillPolygon_Tile) + XSetFillStyle ( pDisplay, mpBrushGC, FillSolid ); + + XSetFillStyle ( pDisplay, mpBrushGC, FillTiled ); + XSetTile ( pDisplay, mpBrushGC, mrParent.hBrush_ ); + } + XSetFunction ( pDisplay, mpBrushGC, mbXORMode ? GXxor : GXcopy ); + mrParent.SetClipRegion( mpBrushGC ); + + mbBrushGC = true; + } + + return mpBrushGC; +} + +GC X11SalGraphicsImpl::SelectPen() +{ + Display *pDisplay = mrParent.GetXDisplay(); + + if( !mpPenGC ) + { + XGCValues values; + values.subwindow_mode = ClipByChildren; + values.fill_rule = EvenOddRule; // Pict import/ Gradient + values.graphics_exposures = False; + + mpPenGC = XCreateGC( pDisplay, mrParent.hDrawable_, + GCSubwindowMode | GCFillRule | GCGraphicsExposures, + &values ); + } + + if( !mbPenGC ) + { + if( mnPenColor != SALCOLOR_NONE ) + XSetForeground( pDisplay, mpPenGC, mnPenPixel ); + XSetFunction ( pDisplay, mpPenGC, mbXORMode ? GXxor : GXcopy ); + mrParent.SetClipRegion( mpPenGC ); + mbPenGC = true; + } + + return mpPenGC; +} + +void X11SalGraphicsImpl::DrawLines( sal_uLong nPoints, + const SalPolyLine &rPoints, + GC pGC, + bool bClose + ) +{ + // calculate how many lines XWindow can draw in one go + sal_uLong nMaxLines = (mrParent.GetDisplay()->GetMaxRequestSize() - sizeof(xPolyPointReq)) + / sizeof(xPoint); + if( nMaxLines > nPoints ) nMaxLines = nPoints; + + // print all lines that XWindows can draw + sal_uLong n; + for( n = 0; nPoints - n > nMaxLines; n += nMaxLines - 1 ) + XDrawLines( mrParent.GetXDisplay(), + mrParent.GetDrawable(), + pGC, + &rPoints[n], + nMaxLines, + CoordModeOrigin ); + + if( n < nPoints ) + XDrawLines( mrParent.GetXDisplay(), + mrParent.GetDrawable(), + pGC, + &rPoints[n], + nPoints - n, + CoordModeOrigin ); + if( bClose ) + { + if( rPoints[nPoints-1].x != rPoints[0].x || rPoints[nPoints-1].y != rPoints[0].y ) + drawLine( rPoints[nPoints-1].x, rPoints[nPoints-1].y, rPoints[0].x, rPoints[0].y ); + } +} + +void X11SalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, + SalGraphics *pSSrcGraphics ) +{ + X11SalGraphics* pSrcGraphics = pSSrcGraphics + ? static_cast<X11SalGraphics*>(pSSrcGraphics) + : &mrParent; + + if( rPosAry.mnSrcWidth <= 0 + || rPosAry.mnSrcHeight <= 0 + || rPosAry.mnDestWidth <= 0 + || rPosAry.mnDestHeight <= 0 ) + { + return; + } + + int n; + if( pSrcGraphics == &mrParent ) + { + n = 2; + } + else if( pSrcGraphics->bWindow_ ) + { + // window or compatible virtual device + if( pSrcGraphics->GetDisplay() == mrParent.GetDisplay() && + pSrcGraphics->m_nXScreen == mrParent.m_nXScreen && + pSrcGraphics->GetVisual().GetDepth() == mrParent.GetVisual().GetDepth() + ) + n = 2; // same Display + else + n = 1; // printer or other display + } + else if( pSrcGraphics->bVirDev_ ) + { + // printer compatible virtual device + if( mrParent.bPrinter_ ) + n = 2; // printer or compatible virtual device == same display + else + n = 1; // window or compatible virtual device + } + else + n = 0; + + if( n == 2 + && rPosAry.mnSrcWidth == rPosAry.mnDestWidth + && rPosAry.mnSrcHeight == rPosAry.mnDestHeight + ) + { + // #i60699# Need to generate graphics exposures (to repaint + // obscured areas beneath overlapping windows), src and dest + // are the same window. + const bool bNeedGraphicsExposures( pSrcGraphics == &mrParent && + !mrParent.bVirDev_ && + pSrcGraphics->bWindow_ ); + + GC pCopyGC; + + if( mbXORMode + && !pSrcGraphics->bVirDev_ + && (mrParent.GetDisplay()->GetProperties() & PROPERTY_BUG_XCopyArea_GXxor) ) + { + Pixmap hPixmap = limitXCreatePixmap( mrParent.GetXDisplay(), + pSrcGraphics->GetDrawable(), // source + rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, + pSrcGraphics->GetBitCount() ); + + pCopyGC = mrParent.GetDisplay()->GetCopyGC( mrParent.m_nXScreen ); + + if( bNeedGraphicsExposures ) + XSetGraphicsExposures( mrParent.GetXDisplay(), + pCopyGC, + True ); + + XCopyArea( mrParent.GetXDisplay(), + pSrcGraphics->GetDrawable(), // source + hPixmap, // destination + pCopyGC, // no clipping + rPosAry.mnSrcX, rPosAry.mnSrcY, + rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, + 0, 0 ); // destination + XCopyArea( mrParent.GetXDisplay(), + hPixmap, // source + mrParent.GetDrawable(), // destination + GetInvertGC(), // destination clipping + 0, 0, // source + rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, + rPosAry.mnDestX, rPosAry.mnDestY ); + XFreePixmap( mrParent.GetXDisplay(), hPixmap ); + } + else + { + pCopyGC = GetCopyGC(); + + if( bNeedGraphicsExposures ) + XSetGraphicsExposures( mrParent.GetXDisplay(), + pCopyGC, + True ); + + XCopyArea( mrParent.GetXDisplay(), + pSrcGraphics->GetDrawable(), // source + mrParent.GetDrawable(), // destination + pCopyGC, // destination clipping + rPosAry.mnSrcX, rPosAry.mnSrcY, + rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, + rPosAry.mnDestX, rPosAry.mnDestY ); + } + + if( bNeedGraphicsExposures ) + { + mrParent.YieldGraphicsExpose(); + + if( pCopyGC ) + XSetGraphicsExposures( mrParent.GetXDisplay(), + pCopyGC, + False ); + } + } + else if( n ) + { + // #i60699# No chance to handle graphics exposures - we copy + // to a temp bitmap first, into which no repaints are + // technically possible. + boost::scoped_ptr<SalBitmap> pDDB(pSrcGraphics->getBitmap( rPosAry.mnSrcX, + rPosAry.mnSrcY, + rPosAry.mnSrcWidth, + rPosAry.mnSrcHeight )); + + if( !pDDB ) + { + stderr0( "SalGraphics::CopyBits !pSrcGraphics->GetBitmap()\n" ); + return; + } + + SalTwoRect aPosAry( rPosAry ); + + aPosAry.mnSrcX = 0, aPosAry.mnSrcY = 0; + drawBitmap( aPosAry, *pDDB ); + } + else { + stderr0( "X11SalGraphicsImpl::CopyBits from Printer not yet implemented\n" ); + } +} + +void X11SalGraphicsImpl::copyArea ( long nDestX, long nDestY, + long nSrcX, long nSrcY, + long nSrcWidth, long nSrcHeight, + sal_uInt16 ) +{ + SalTwoRect aPosAry; + + aPosAry.mnDestX = nDestX; + aPosAry.mnDestY = nDestY; + aPosAry.mnDestWidth = nSrcWidth; + aPosAry.mnDestHeight = nSrcHeight; + + aPosAry.mnSrcX = nSrcX; + aPosAry.mnSrcY = nSrcY; + aPosAry.mnSrcWidth = nSrcWidth; + aPosAry.mnSrcHeight = nSrcHeight; + + copyBits ( aPosAry, 0 ); +} + +void X11SalGraphicsImpl::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) +{ + const SalDisplay* pSalDisp = mrParent.GetDisplay(); + Display* pXDisp = pSalDisp->GetDisplay(); + const Drawable aDrawable( mrParent.GetDrawable() ); + const SalColormap& rColMap = pSalDisp->GetColormap( mrParent.m_nXScreen ); + const long nDepth = mrParent.GetDisplay()->GetVisual( mrParent.m_nXScreen ).GetDepth(); + GC aGC( GetCopyGC() ); + XGCValues aOldVal, aNewVal; + int nValues = GCForeground | GCBackground; + + if( rSalBitmap.GetBitCount() == 1 ) + { + // set foreground/background values for 1Bit bitmaps + XGetGCValues( pXDisp, aGC, nValues, &aOldVal ); + setForeBack(aNewVal, rColMap, rSalBitmap); + XChangeGC( pXDisp, aGC, nValues, &aNewVal ); + } + + static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aDrawable, mrParent.m_nXScreen, nDepth, rPosAry, aGC ); + + if( rSalBitmap.GetBitCount() == 1 ) + XChangeGC( pXDisp, aGC, nValues, &aOldVal ); + XFlush( pXDisp ); +} + +void X11SalGraphicsImpl::drawBitmap( const SalTwoRect& rPosAry, + const SalBitmap& rSrcBitmap, + const SalBitmap& rMaskBitmap ) +{ + DBG_ASSERT( !mrParent.bPrinter_, "Drawing of transparent bitmaps on printer devices is strictly forbidden" ); + + // decide if alpha masking or transparency masking is needed + BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rMaskBitmap).AcquireBuffer( true ); + if( pAlphaBuffer != NULL ) + { + int nMaskFormat = pAlphaBuffer->mnFormat; + const_cast<SalBitmap&>(rMaskBitmap).ReleaseBuffer( pAlphaBuffer, true ); + if( nMaskFormat == BMP_FORMAT_8BIT_PAL ) + drawAlphaBitmap( rPosAry, rSrcBitmap, rMaskBitmap ); + } + + drawMaskedBitmap( rPosAry, rSrcBitmap, rMaskBitmap ); +} + +void X11SalGraphicsImpl::drawMaskedBitmap( const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rTransBitmap ) +{ + const SalDisplay* pSalDisp = mrParent.GetDisplay(); + Display* pXDisp = pSalDisp->GetDisplay(); + Drawable aDrawable( mrParent.GetDrawable() ); + + // figure work mode depth. If this is a VDev Drawable, use its + // bitdepth to create pixmaps for, otherwise, XCopyArea will + // refuse to work. + const sal_uInt16 nDepth( mrParent.m_pVDev ? + mrParent.m_pVDev->GetDepth() : + pSalDisp->GetVisual( mrParent.m_nXScreen ).GetDepth() ); + Pixmap aFG( limitXCreatePixmap( pXDisp, aDrawable, rPosAry.mnDestWidth, + rPosAry.mnDestHeight, nDepth ) ); + Pixmap aBG( limitXCreatePixmap( pXDisp, aDrawable, rPosAry.mnDestWidth, + rPosAry.mnDestHeight, nDepth ) ); + + if( aFG && aBG ) + { + GC aTmpGC; + XGCValues aValues; + setForeBack(aValues, pSalDisp->GetColormap(mrParent.m_nXScreen), rSalBitmap); + const int nValues = GCFunction | GCForeground | GCBackground; + SalTwoRect aTmpRect( rPosAry ); aTmpRect.mnDestX = aTmpRect.mnDestY = 0; + + // draw paint bitmap in pixmap #1 + aValues.function = GXcopy; + aTmpGC = XCreateGC( pXDisp, aFG, nValues, &aValues ); + static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aFG, mrParent.m_nXScreen, nDepth, aTmpRect, aTmpGC ); + DBG_TESTTRANS( aFG ); + + // draw background in pixmap #2 + XCopyArea( pXDisp, aDrawable, aBG, aTmpGC, + rPosAry.mnDestX, rPosAry.mnDestY, + rPosAry.mnDestWidth, rPosAry.mnDestHeight, + 0, 0 ); + + DBG_TESTTRANS( aBG ); + + // mask out paint bitmap in pixmap #1 (transparent areas 0) + aValues.function = GXand, aValues.foreground = 0x00000000, aValues.background = 0xffffffff; + XChangeGC( pXDisp, aTmpGC, nValues, &aValues ); + static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aFG, mrParent.m_nXScreen, 1, aTmpRect, aTmpGC ); + + DBG_TESTTRANS( aFG ); + + // #105055# For XOR mode, keep background behind bitmap intact + if( !mbXORMode ) + { + // mask out background in pixmap #2 (nontransparent areas 0) + aValues.function = GXand, aValues.foreground = 0xffffffff, aValues.background = 0x00000000; + XChangeGC( pXDisp, aTmpGC, nValues, &aValues ); + static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aBG, mrParent.m_nXScreen, 1, aTmpRect, aTmpGC ); + + DBG_TESTTRANS( aBG ); + } + + // merge pixmap #1 and pixmap #2 in pixmap #2 + aValues.function = GXxor, aValues.foreground = 0xffffffff, aValues.background = 0x00000000; + XChangeGC( pXDisp, aTmpGC, nValues, &aValues ); + XCopyArea( pXDisp, aFG, aBG, aTmpGC, + 0, 0, + rPosAry.mnDestWidth, rPosAry.mnDestHeight, + 0, 0 ); + DBG_TESTTRANS( aBG ); + + // #105055# Disable XOR temporarily + bool bOldXORMode( mbXORMode ); + mbXORMode = false; + + // copy pixmap #2 (result) to background + XCopyArea( pXDisp, aBG, aDrawable, GetCopyGC(), + 0, 0, + rPosAry.mnDestWidth, rPosAry.mnDestHeight, + rPosAry.mnDestX, rPosAry.mnDestY ); + + DBG_TESTTRANS( aBG ); + + mbXORMode = bOldXORMode; + + XFreeGC( pXDisp, aTmpGC ); + XFlush( pXDisp ); + } + else + drawBitmap( rPosAry, rSalBitmap ); + + if( aFG ) + XFreePixmap( pXDisp, aFG ); + + if( aBG ) + XFreePixmap( pXDisp, aBG ); +} + +bool X11SalGraphicsImpl::drawAlphaBitmap( const SalTwoRect& rTR, + const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp ) +{ + // non 8-bit alpha not implemented yet + if( rAlphaBmp.GetBitCount() != 8 ) + return false; + + // horizontal mirroring not implemented yet + if( rTR.mnDestWidth < 0 ) + return false; + + // stretched conversion is not implemented yet + if( rTR.mnDestWidth != rTR.mnSrcWidth ) + return false; + if( rTR.mnDestHeight!= rTR.mnSrcHeight ) + return false; + + // create destination picture + Picture aDstPic = GetXRenderPicture(); + if( !aDstPic ) + return false; + + const SalDisplay* pSalDisp = mrParent.GetDisplay(); + const SalVisual& rSalVis = pSalDisp->GetVisual( mrParent.m_nXScreen ); + Display* pXDisplay = pSalDisp->GetDisplay(); + + // create source Picture + int nDepth = mrParent.m_pVDev ? mrParent.m_pVDev->GetDepth() : rSalVis.GetDepth(); + const X11SalBitmap& rSrcX11Bmp = static_cast<const X11SalBitmap&>( rSrcBitmap ); + ImplSalDDB* pSrcDDB = rSrcX11Bmp.ImplGetDDB( mrParent.hDrawable_, mrParent.m_nXScreen, nDepth, rTR ); + if( !pSrcDDB ) + return false; + + //#i75249# workaround for ImplGetDDB() giving us back a different depth than + // we requested. E.g. mask pixmaps are always compatible with the drawable + // TODO: find an appropriate picture format for these cases + // then remove the workaround below and the one for #i75531# + if( nDepth != pSrcDDB->ImplGetDepth() ) + return false; + + Pixmap aSrcPM = pSrcDDB->ImplGetPixmap(); + if( !aSrcPM ) + return false; + + // create source picture + // TODO: use scoped picture + Visual* pSrcXVisual = rSalVis.GetVisual(); + XRenderPeer& rPeer = XRenderPeer::GetInstance(); + XRenderPictFormat* pSrcVisFmt = rPeer.FindVisualFormat( pSrcXVisual ); + if( !pSrcVisFmt ) + return false; + Picture aSrcPic = rPeer.CreatePicture( aSrcPM, pSrcVisFmt, 0, NULL ); + if( !aSrcPic ) + return false; + + // create alpha Picture + + // TODO: use SalX11Bitmap functionality and caching for the Alpha Pixmap + // problem is that they don't provide an 8bit Pixmap on a non-8bit display + BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rAlphaBmp).AcquireBuffer( true ); + + // an XImage needs its data top_down + // TODO: avoid wrongly oriented images in upper layers! + const int nImageSize = pAlphaBuffer->mnHeight * pAlphaBuffer->mnScanlineSize; + const char* pSrcBits = (char*)pAlphaBuffer->mpBits; + char* pAlphaBits = new char[ nImageSize ]; + if( BMP_SCANLINE_ADJUSTMENT( pAlphaBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN ) + memcpy( pAlphaBits, pSrcBits, nImageSize ); + else + { + char* pDstBits = pAlphaBits + nImageSize; + const int nLineSize = pAlphaBuffer->mnScanlineSize; + for(; (pDstBits -= nLineSize) >= pAlphaBits; pSrcBits += nLineSize ) + memcpy( pDstBits, pSrcBits, nLineSize ); + } + + // the alpha values need to be inverted for XRender + // TODO: make upper layers use standard alpha + long* pLDst = (long*)pAlphaBits; + for( int i = nImageSize/sizeof(long); --i >= 0; ++pLDst ) + *pLDst = ~*pLDst; + + char* pCDst = (char*)pLDst; + for( int i = nImageSize & (sizeof(long)-1); --i >= 0; ++pCDst ) + *pCDst = ~*pCDst; + + const XRenderPictFormat* pAlphaFormat = rPeer.GetStandardFormatA8(); + XImage* pAlphaImg = XCreateImage( pXDisplay, pSrcXVisual, 8, ZPixmap, 0, + pAlphaBits, pAlphaBuffer->mnWidth, pAlphaBuffer->mnHeight, + pAlphaFormat->depth, pAlphaBuffer->mnScanlineSize ); + + Pixmap aAlphaPM = limitXCreatePixmap( pXDisplay, mrParent.hDrawable_, + rTR.mnDestWidth, rTR.mnDestHeight, 8 ); + + XGCValues aAlphaGCV; + aAlphaGCV.function = GXcopy; + GC aAlphaGC = XCreateGC( pXDisplay, aAlphaPM, GCFunction, &aAlphaGCV ); + XPutImage( pXDisplay, aAlphaPM, aAlphaGC, pAlphaImg, + rTR.mnSrcX, rTR.mnSrcY, 0, 0, rTR.mnDestWidth, rTR.mnDestHeight ); + XFreeGC( pXDisplay, aAlphaGC ); + XFree( pAlphaImg ); + if( pAlphaBits != (char*)pAlphaBuffer->mpBits ) + delete[] pAlphaBits; + + const_cast<SalBitmap&>(rAlphaBmp).ReleaseBuffer( pAlphaBuffer, true ); + + XRenderPictureAttributes aAttr; + aAttr.repeat = int(true); + Picture aAlphaPic = rPeer.CreatePicture( aAlphaPM, pAlphaFormat, CPRepeat, &aAttr ); + if( !aAlphaPic ) + return false; + + // set clipping + if( mrParent.mpClipRegion && !XEmptyRegion( mrParent.mpClipRegion ) ) + rPeer.SetPictureClipRegion( aDstPic, mrParent.mpClipRegion ); + + // paint source * mask over destination picture + rPeer.CompositePicture( PictOpOver, aSrcPic, aAlphaPic, aDstPic, + rTR.mnSrcX, rTR.mnSrcY, 0, 0, + rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight ); + + rPeer.FreePicture( aAlphaPic ); + XFreePixmap(pXDisplay, aAlphaPM); + rPeer.FreePicture( aSrcPic ); + return true; +} + +bool X11SalGraphicsImpl::drawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) +{ + // here direct support for transformed bitmaps can be impemented + (void)rNull; (void)rX; (void)rY; (void)rSourceBitmap; (void)pAlphaBitmap; + return false; +} + +bool X11SalGraphicsImpl::drawAlphaRect( long nX, long nY, long nWidth, + long nHeight, sal_uInt8 nTransparency ) +{ + if( ! mrParent.m_pFrame && ! mrParent.m_pVDev ) + return false; + + if( mbPenGC || !mbBrushGC || mbXORMode ) + return false; // can only perform solid fills without XOR. + + if( mrParent.m_pVDev && mrParent.m_pVDev->GetDepth() < 8 ) + return false; + + Picture aDstPic = GetXRenderPicture(); + if( !aDstPic ) + return false; + + const double fTransparency = (100 - nTransparency) * (1.0/100); + const XRenderColor aRenderColor = GetXRenderColor( mnBrushColor , fTransparency); + + XRenderPeer& rPeer = XRenderPeer::GetInstance(); + rPeer.FillRectangle( PictOpOver, + aDstPic, + &aRenderColor, + nX, nY, + nWidth, nHeight ); + + return true; +} + +void X11SalGraphicsImpl::drawBitmap( const SalTwoRect&, + const SalBitmap&, + SalColor ) +{ + OSL_FAIL( "::DrawBitmap with transparent color not supported" ); +} + +void X11SalGraphicsImpl::drawMask( const SalTwoRect& rPosAry, + const SalBitmap &rSalBitmap, + SalColor nMaskColor ) +{ + const SalDisplay* pSalDisp = mrParent.GetDisplay(); + Display* pXDisp = pSalDisp->GetDisplay(); + Drawable aDrawable( mrParent.GetDrawable() ); + Pixmap aStipple( limitXCreatePixmap( pXDisp, aDrawable, + rPosAry.mnDestWidth, + rPosAry.mnDestHeight, 1 ) ); + + if( aStipple ) + { + SalTwoRect aTwoRect( rPosAry ); aTwoRect.mnDestX = aTwoRect.mnDestY = 0; + GC aTmpGC; + XGCValues aValues; + + // create a stipple bitmap first (set bits are changed to unset bits and vice versa) + aValues.function = GXcopyInverted; + aValues.foreground = 1, aValues.background = 0; + aTmpGC = XCreateGC( pXDisp, aStipple, GCFunction | GCForeground | GCBackground, &aValues ); + static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aStipple, mrParent.m_nXScreen, 1, aTwoRect, aTmpGC ); + + XFreeGC( pXDisp, aTmpGC ); + + // Set stipple and draw rectangle + GC aStippleGC( GetStippleGC() ); + int nX = rPosAry.mnDestX, nY = rPosAry.mnDestY; + + XSetStipple( pXDisp, aStippleGC, aStipple ); + XSetTSOrigin( pXDisp, aStippleGC, nX, nY ); + XSetForeground( pXDisp, aStippleGC, mrParent.GetPixel( nMaskColor ) ); + XFillRectangle( pXDisp, aDrawable, aStippleGC, + nX, nY, + rPosAry.mnDestWidth, rPosAry.mnDestHeight ); + XFreePixmap( pXDisp, aStipple ); + XFlush( pXDisp ); + } + else + drawBitmap( rPosAry, rSalBitmap ); +} + +void X11SalGraphicsImpl::ResetClipRegion() +{ + if( mrParent.mpClipRegion ) + { + mbPenGC = false; + mrParent.bFontGC_ = false; + mbBrushGC = false; + mbMonoGC = false; + mbCopyGC = false; + mbInvertGC = false; + mbInvert50GC = false; + mbStippleGC = false; + mbTrackingGC = false; + + XDestroyRegion( mrParent.mpClipRegion ); + mrParent.mpClipRegion = NULL; + } +} + +bool X11SalGraphicsImpl::setClipRegion( const vcl::Region& i_rClip ) +{ + if( mrParent.mpClipRegion ) + XDestroyRegion( mrParent.mpClipRegion ); + mrParent.mpClipRegion = XCreateRegion(); + + RectangleVector aRectangles; + i_rClip.GetRegionRectangles(aRectangles); + + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter) + { + const long nW(aRectIter->GetWidth()); + + if(nW) + { + const long nH(aRectIter->GetHeight()); + + if(nH) + { + XRectangle aRect; + + aRect.x = (short)aRectIter->Left(); + aRect.y = (short)aRectIter->Top(); + aRect.width = (unsigned short)nW; + aRect.height = (unsigned short)nH; + XUnionRectWithRegion(&aRect, mrParent.mpClipRegion, mrParent.mpClipRegion); + } + } + } + + //ImplRegionInfo aInfo; + //long nX, nY, nW, nH; + //bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); + //while( bRegionRect ) + //{ + // if ( nW && nH ) + // { + // XRectangle aRect; + // aRect.x = (short)nX; + // aRect.y = (short)nY; + // aRect.width = (unsigned short)nW; + // aRect.height = (unsigned short)nH; + + // XUnionRectWithRegion( &aRect, mrParent.mpClipRegion, mrParent.mpClipRegion ); + // } + // bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); + //} + + // done, invalidate GCs + mbPenGC = false; + mrParent.bFontGC_ = false; + mbBrushGC = false; + mbMonoGC = false; + mbCopyGC = false; + mbInvertGC = false; + mbInvert50GC = false; + mbStippleGC = false; + mbTrackingGC = false; + + if( XEmptyRegion( mrParent.mpClipRegion ) ) + { + XDestroyRegion( mrParent.mpClipRegion ); + mrParent.mpClipRegion= NULL; + } + return true; +} + +void X11SalGraphicsImpl::SetLineColor() +{ + if( mnPenColor != SALCOLOR_NONE ) + { + mnPenColor = SALCOLOR_NONE; + mbPenGC = false; + } +} + +void X11SalGraphicsImpl::SetLineColor( SalColor nSalColor ) +{ + if( mnPenColor != nSalColor ) + { + mnPenColor = nSalColor; + mnPenPixel = mrParent.GetPixel( nSalColor ); + mbPenGC = false; + } +} + +void X11SalGraphicsImpl::SetFillColor() +{ + if( mnBrushColor != SALCOLOR_NONE ) + { + mbDitherBrush = false; + mnBrushColor = SALCOLOR_NONE; + mbBrushGC = false; + } +} + +void X11SalGraphicsImpl::SetFillColor( SalColor nSalColor ) +{ + if( mnBrushColor != nSalColor ) + { + mbDitherBrush = false; + mnBrushColor = nSalColor; + mnBrushPixel = mrParent.GetPixel( nSalColor ); + if( TrueColor != mrParent.GetColormap().GetVisual().GetClass() + && mrParent.GetColormap().GetColor( mnBrushPixel ) != mnBrushColor + && nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0x00 ) // black + && nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0x80 ) // blue + && nSalColor != MAKE_SALCOLOR( 0x00, 0x80, 0x00 ) // green + && nSalColor != MAKE_SALCOLOR( 0x00, 0x80, 0x80 ) // cyan + && nSalColor != MAKE_SALCOLOR( 0x80, 0x00, 0x00 ) // red + && nSalColor != MAKE_SALCOLOR( 0x80, 0x00, 0x80 ) // magenta + && nSalColor != MAKE_SALCOLOR( 0x80, 0x80, 0x00 ) // brown + && nSalColor != MAKE_SALCOLOR( 0x80, 0x80, 0x80 ) // gray + && nSalColor != MAKE_SALCOLOR( 0xC0, 0xC0, 0xC0 ) // light gray + && nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0xFF ) // light blue + && nSalColor != MAKE_SALCOLOR( 0x00, 0xFF, 0x00 ) // light green + && nSalColor != MAKE_SALCOLOR( 0x00, 0xFF, 0xFF ) // light cyan + && nSalColor != MAKE_SALCOLOR( 0xFF, 0x00, 0x00 ) // light red + && nSalColor != MAKE_SALCOLOR( 0xFF, 0x00, 0xFF ) // light magenta + && nSalColor != MAKE_SALCOLOR( 0xFF, 0xFF, 0x00 ) // light brown + && nSalColor != MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ) ) + mbDitherBrush = mrParent.GetDitherPixmap(nSalColor); + mbBrushGC = false; + } +} + +void X11SalGraphicsImpl::SetROPLineColor( SalROPColor nROPColor ) +{ + switch( nROPColor ) + { + case SAL_ROP_0 : // 0 + mnPenPixel = (Pixel)0; + break; + case SAL_ROP_1 : // 1 + mnPenPixel = (Pixel)(1 << mrParent.GetVisual().GetDepth()) - 1; + break; + case SAL_ROP_INVERT : // 2 + mnPenPixel = (Pixel)(1 << mrParent.GetVisual().GetDepth()) - 1; + break; + } + mnPenColor = mrParent.GetColormap().GetColor( mnPenPixel ); + mbPenGC = false; +} + +void X11SalGraphicsImpl::SetROPFillColor( SalROPColor nROPColor ) +{ + switch( nROPColor ) + { + case SAL_ROP_0 : // 0 + mnBrushPixel = (Pixel)0; + break; + case SAL_ROP_1 : // 1 + mnBrushPixel = (Pixel)(1 << mrParent.GetVisual().GetDepth()) - 1; + break; + case SAL_ROP_INVERT : // 2 + mnBrushPixel = (Pixel)(1 << mrParent.GetVisual().GetDepth()) - 1; + break; + } + mbDitherBrush = false; + mnBrushColor = mrParent.GetColormap().GetColor( mnBrushPixel ); + mbBrushGC = false; +} + +void X11SalGraphicsImpl::SetXORMode( bool bSet, bool ) +{ + if( !mbXORMode == bSet ) + { + mbXORMode = bSet; + mbPenGC = false; + mrParent.bFontGC_ = false; + mbBrushGC = false; + mbMonoGC = false; + mbCopyGC = false; + mbInvertGC = false; + mbInvert50GC = false; + mbStippleGC = false; + mbTrackingGC = false; + } +} + +void X11SalGraphicsImpl::drawPixel( long nX, long nY ) +{ + if( mnPenColor != SALCOLOR_NONE ) + XDrawPoint( mrParent.GetXDisplay(), mrParent.GetDrawable(), SelectPen(), nX, nY ); +} + +void X11SalGraphicsImpl::drawPixel( long nX, long nY, SalColor nSalColor ) +{ + if( nSalColor != SALCOLOR_NONE ) + { + Display *pDisplay = mrParent.GetXDisplay(); + + if( (mnPenColor == SALCOLOR_NONE) && !mbPenGC ) + { + SetLineColor( nSalColor ); + XDrawPoint( pDisplay, mrParent.GetDrawable(), SelectPen(), nX, nY ); + mnPenColor = SALCOLOR_NONE; + mbPenGC = False; + } + else + { + GC pGC = SelectPen(); + + if( nSalColor != mnPenColor ) + XSetForeground( pDisplay, pGC, mrParent.GetPixel( nSalColor ) ); + + XDrawPoint( pDisplay, mrParent.GetDrawable(), pGC, nX, nY ); + + if( nSalColor != mnPenColor ) + XSetForeground( pDisplay, pGC, mnPenPixel ); + } + } +} + +void X11SalGraphicsImpl::drawLine( long nX1, long nY1, long nX2, long nY2 ) +{ + if( mnPenColor != SALCOLOR_NONE ) + { + if ( mrParent.GetDisplay()->GetProperties() & PROPERTY_BUG_DrawLine ) + { + GC aGC = SelectPen(); + XDrawPoint (mrParent.GetXDisplay(), mrParent.GetDrawable(), aGC, (int)nX1, (int)nY1); + XDrawPoint (mrParent.GetXDisplay(), mrParent.GetDrawable(), aGC, (int)nX2, (int)nY2); + XDrawLine (mrParent.GetXDisplay(), mrParent.GetDrawable(), aGC, nX1, nY1, nX2, nY2 ); + } + else + XDrawLine( mrParent.GetXDisplay(), mrParent.GetDrawable(),SelectPen(), + nX1, nY1, nX2, nY2 ); + } +} + +void X11SalGraphicsImpl::drawRect( long nX, long nY, long nDX, long nDY ) +{ + if( mnBrushColor != SALCOLOR_NONE ) + { + XFillRectangle( mrParent.GetXDisplay(), + mrParent.GetDrawable(), + SelectBrush(), + nX, nY, nDX, nDY ); + } + // description DrawRect is wrong; thus -1 + if( mnPenColor != SALCOLOR_NONE ) + XDrawRectangle( mrParent.GetXDisplay(), + mrParent.GetDrawable(), + SelectPen(), + nX, nY, nDX-1, nDY-1 ); +} + +void X11SalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints, const SalPoint *pPtAry ) +{ + drawPolyLine( nPoints, pPtAry, false ); +} + +void X11SalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints, const SalPoint *pPtAry, bool bClose ) +{ + if( mnPenColor != SALCOLOR_NONE ) + { + SalPolyLine Points( nPoints, pPtAry ); + + DrawLines( nPoints, Points, SelectPen(), bClose ); + } +} + +void X11SalGraphicsImpl::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) +{ + if( nPoints == 0 ) + return; + + if( nPoints < 3 ) + { + if( !mbXORMode ) + { + if( 1 == nPoints ) + drawPixel( pPtAry[0].mnX, pPtAry[0].mnY ); + else + drawLine( pPtAry[0].mnX, pPtAry[0].mnY, + pPtAry[1].mnX, pPtAry[1].mnY ); + } + return; + } + + SalPolyLine Points( nPoints, pPtAry ); + + nPoints++; + + /* WORKAROUND: some Xservers (Xorg, VIA chipset in this case) + * do not draw the visible part of a polygon + * if it overlaps to the left of screen 0,y. + * This happens to be the case in the gradient drawn in the + * menubar background. workaround for the special case of + * of a rectangle overlapping to the left. + */ + if( nPoints == 5 && + Points[ 0 ].x == Points[ 1 ].x && + Points[ 1 ].y == Points[ 2 ].y && + Points[ 2 ].x == Points[ 3 ].x && + Points[ 0 ].x == Points[ 4 ].x && Points[ 0 ].y == Points[ 4 ].y + ) + { + bool bLeft = false; + bool bRight = false; + for(unsigned int i = 0; i < nPoints; i++ ) + { + if( Points[i].x < 0 ) + bLeft = true; + else + bRight= true; + } + if( bLeft && ! bRight ) + return; + if( bLeft && bRight ) + { + for( unsigned int i = 0; i < nPoints; i++ ) + if( Points[i].x < 0 ) + Points[i].x = 0; + } + } + + if( mnBrushColor != SALCOLOR_NONE ) + XFillPolygon( mrParent.GetXDisplay(), + mrParent.GetDrawable(), + SelectBrush(), + &Points[0], nPoints, + Complex, CoordModeOrigin ); + + if( mnPenColor != SALCOLOR_NONE ) + DrawLines( nPoints, Points, SelectPen(), true ); +} + +void X11SalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly, + const sal_uInt32 *pPoints, + PCONSTSALPOINT *pPtAry ) +{ + if( mnBrushColor != SALCOLOR_NONE ) + { + sal_uInt32 i, n; + Region pXRegA = NULL; + + for( i = 0; i < nPoly; i++ ) { + n = pPoints[i]; + SalPolyLine Points( n, pPtAry[i] ); + if( n > 2 ) + { + Region pXRegB = XPolygonRegion( &Points[0], n+1, WindingRule ); + if( !pXRegA ) + pXRegA = pXRegB; + else + { + XXorRegion( pXRegA, pXRegB, pXRegA ); + XDestroyRegion( pXRegB ); + } + } + } + + if( pXRegA ) + { + XRectangle aXRect; + XClipBox( pXRegA, &aXRect ); + + GC pGC = SelectBrush(); + mrParent.SetClipRegion( pGC, pXRegA ); // ??? twice + XDestroyRegion( pXRegA ); + mbBrushGC = false; + + XFillRectangle( mrParent.GetXDisplay(), + mrParent.GetDrawable(), + pGC, + aXRect.x, aXRect.y, aXRect.width, aXRect.height ); + } + } + + if( mnPenColor != SALCOLOR_NONE ) + for( sal_uInt32 i = 0; i < nPoly; i++ ) + drawPolyLine( pPoints[i], pPtAry[i], true ); +} + +bool X11SalGraphicsImpl::drawPolyLineBezier( sal_uInt32, const SalPoint*, const sal_uInt8* ) +{ + return false; +} + +bool X11SalGraphicsImpl::drawPolygonBezier( sal_uInt32, const SalPoint*, const sal_uInt8* ) +{ + return false; +} + +bool X11SalGraphicsImpl::drawPolyPolygonBezier( sal_uInt32, const sal_uInt32*, + const SalPoint* const*, const sal_uInt8* const* ) +{ + return false; +} + +void X11SalGraphicsImpl::invert( long nX, + long nY, + long nDX, + long nDY, + SalInvert nFlags ) +{ + GC pGC; + if( SAL_INVERT_50 & nFlags ) + { + pGC = GetInvert50GC(); + XFillRectangle( mrParent.GetXDisplay(), mrParent.GetDrawable(), pGC, nX, nY, nDX, nDY ); + } + else + { + if ( SAL_INVERT_TRACKFRAME & nFlags ) + { + pGC = GetTrackingGC(); + XDrawRectangle( mrParent.GetXDisplay(), mrParent.GetDrawable(), pGC, nX, nY, nDX, nDY ); + } + else + { + pGC = GetInvertGC(); + XFillRectangle( mrParent.GetXDisplay(), mrParent.GetDrawable(), pGC, nX, nY, nDX, nDY ); + } + } +} + +void X11SalGraphicsImpl::invert( sal_uInt32 nPoints, + const SalPoint* pPtAry, + SalInvert nFlags ) +{ + SalPolyLine Points ( nPoints, pPtAry ); + + GC pGC; + if( SAL_INVERT_50 & nFlags ) + pGC = GetInvert50GC(); + else + if ( SAL_INVERT_TRACKFRAME & nFlags ) + pGC = GetTrackingGC(); + else + pGC = GetInvertGC(); + + if( SAL_INVERT_TRACKFRAME & nFlags ) + DrawLines ( nPoints, Points, pGC, true ); + else + XFillPolygon( mrParent.GetXDisplay(), + mrParent.GetDrawable(), + pGC, + &Points[0], nPoints, + Complex, CoordModeOrigin ); +} + +bool X11SalGraphicsImpl::drawEPS( long,long,long,long,void*,sal_uLong ) +{ + return false; +} + +// draw a poly-polygon +bool X11SalGraphicsImpl::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPolyPoly, double fTransparency ) +{ + // nothing to do for empty polypolygons + const int nOrigPolyCount = rOrigPolyPoly.count(); + if( nOrigPolyCount <= 0 ) + return true; + + // nothing to do if everything is transparent + if( (mnBrushColor == SALCOLOR_NONE) + && (mnPenColor == SALCOLOR_NONE) ) + return true; + + // cannot handle pencolor!=brushcolor yet + if( (mnPenColor != SALCOLOR_NONE) + && (mnPenColor != mnBrushColor) ) + return false; + + // TODO: remove the env-variable when no longer needed + static const char* pRenderEnv = getenv( "SAL_DISABLE_RENDER_POLY" ); + if( pRenderEnv ) + return false; + + // snap to raster if requested + basegfx::B2DPolyPolygon aPolyPoly = rOrigPolyPoly; + const bool bSnapToRaster = !mrParent.getAntiAliasB2DDraw(); + if( bSnapToRaster ) + aPolyPoly = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges( aPolyPoly ); + + // don't bother with polygons outside of visible area + const basegfx::B2DRange aViewRange( 0, 0, GetGraphicsWidth(), GetGraphicsHeight() ); + aPolyPoly = basegfx::tools::clipPolyPolygonOnRange( aPolyPoly, aViewRange, true, false ); + if( !aPolyPoly.count() ) + return true; + + // tesselate the polypolygon into trapezoids + basegfx::B2DTrapezoidVector aB2DTrapVector; + basegfx::tools::trapezoidSubdivide( aB2DTrapVector, aPolyPoly ); + const int nTrapCount = aB2DTrapVector.size(); + if( !nTrapCount ) + return true; + const bool bDrawn = drawFilledTrapezoids( &aB2DTrapVector[0], nTrapCount, fTransparency ); + return bDrawn; +} + +long X11SalGraphicsImpl::GetGraphicsHeight() const +{ + if( mrParent.m_pFrame ) + return mrParent.m_pFrame->maGeometry.nHeight; + else if( mrParent.m_pVDev ) + return mrParent.m_pVDev->GetHeight(); + else + return 0; +} + +bool X11SalGraphicsImpl::drawFilledTrapezoids( const ::basegfx::B2DTrapezoid* pB2DTraps, int nTrapCount, double fTransparency ) +{ + if( nTrapCount <= 0 ) + return true; + + Picture aDstPic = GetXRenderPicture(); + // check xrender support for this drawable + if( !aDstPic ) + return false; + + // convert the B2DTrapezoids into XRender-Trapezoids + typedef std::vector<XTrapezoid> TrapezoidVector; + TrapezoidVector aTrapVector( nTrapCount ); + const basegfx::B2DTrapezoid* pB2DTrap = pB2DTraps; + for( int i = 0; i < nTrapCount; ++pB2DTrap, ++i ) + { + XTrapezoid& rTrap = aTrapVector[ i ] ; + + // set y-coordinates + const double fY1 = pB2DTrap->getTopY(); + rTrap.left.p1.y = rTrap.right.p1.y = rTrap.top = XDoubleToFixed( fY1 ); + const double fY2 = pB2DTrap->getBottomY(); + rTrap.left.p2.y = rTrap.right.p2.y = rTrap.bottom = XDoubleToFixed( fY2 ); + + // set x-coordinates + const double fXL1 = pB2DTrap->getTopXLeft(); + rTrap.left.p1.x = XDoubleToFixed( fXL1 ); + const double fXR1 = pB2DTrap->getTopXRight(); + rTrap.right.p1.x = XDoubleToFixed( fXR1 ); + const double fXL2 = pB2DTrap->getBottomXLeft(); + rTrap.left.p2.x = XDoubleToFixed( fXL2 ); + const double fXR2 = pB2DTrap->getBottomXRight(); + rTrap.right.p2.x = XDoubleToFixed( fXR2 ); + } + + // get xrender Picture for polygon foreground + // TODO: cache it like the target picture which uses GetXRenderPicture() + XRenderPeer& rRenderPeer = XRenderPeer::GetInstance(); + SalDisplay::RenderEntry& rEntry = mrParent.GetDisplay()->GetRenderEntries( mrParent.m_nXScreen )[ 32 ]; + if( !rEntry.m_aPicture ) + { + Display* pXDisplay = mrParent.GetXDisplay(); + + rEntry.m_aPixmap = limitXCreatePixmap( pXDisplay, mrParent.hDrawable_, 1, 1, 32 ); + XRenderPictureAttributes aAttr; + aAttr.repeat = int(true); + + XRenderPictFormat* pXRPF = rRenderPeer.FindStandardFormat( PictStandardARGB32 ); + rEntry.m_aPicture = rRenderPeer.CreatePicture( rEntry.m_aPixmap, pXRPF, CPRepeat, &aAttr ); + } + + // set polygon foreground color and opacity + XRenderColor aRenderColor = GetXRenderColor( mnBrushColor , fTransparency ); + rRenderPeer.FillRectangle( PictOpSrc, rEntry.m_aPicture, &aRenderColor, 0, 0, 1, 1 ); + + // set clipping + // TODO: move into GetXRenderPicture? + if( mrParent.mpClipRegion && !XEmptyRegion( mrParent.mpClipRegion ) ) + rRenderPeer.SetPictureClipRegion( aDstPic, mrParent.mpClipRegion ); + + // render the trapezoids + const XRenderPictFormat* pMaskFormat = rRenderPeer.GetStandardFormatA8(); + rRenderPeer.CompositeTrapezoids( PictOpOver, + rEntry.m_aPicture, aDstPic, pMaskFormat, 0, 0, &aTrapVector[0], aTrapVector.size() ); + + return true; +} + +bool X11SalGraphicsImpl::drawPolyLine( + const ::basegfx::B2DPolygon& rPolygon, + double fTransparency, + const ::basegfx::B2DVector& rLineWidth, + basegfx::B2DLineJoin eLineJoin, + com::sun::star::drawing::LineCap eLineCap) +{ + const bool bIsHairline = (rLineWidth.getX() == rLineWidth.getY()) && (rLineWidth.getX() <= 1.2); + + // #i101491# + if( !bIsHairline && (rPolygon.count() > 1000) ) + { + // the used basegfx::tools::createAreaGeometry is simply too + // expensive with very big polygons; fallback to caller (who + // should use ImplLineConverter normally) + // AW: ImplLineConverter had to be removed since it does not even + // know LineJoins, so the fallback will now prepare the line geometry + // the same way. + return false; + } + + // temporarily adjust brush color to pen color + // since the line is drawn as an area-polygon + const SalColor aKeepBrushColor = mnBrushColor; + mnBrushColor = mnPenColor; + + // #i11575#desc5#b adjust B2D tesselation result to raster positions + basegfx::B2DPolygon aPolygon = rPolygon; + const double fHalfWidth = 0.5 * rLineWidth.getX(); + + // #i122456# This is probably thought to happen to align hairlines to pixel positions, so + // it should be a 0.5 translation, not more. It will definitely go wrong with fat lines + aPolygon.transform( basegfx::tools::createTranslateB2DHomMatrix(0.5, 0.5) ); + + // shortcut for hairline drawing to improve performance + bool bDrawnOk = true; + if( bIsHairline ) + { + // hairlines can benefit from a simplified tesselation + // e.g. for hairlines the linejoin style can be ignored + basegfx::B2DTrapezoidVector aB2DTrapVector; + basegfx::tools::createLineTrapezoidFromB2DPolygon( aB2DTrapVector, aPolygon, rLineWidth.getX() ); + + // draw tesselation result + const int nTrapCount = aB2DTrapVector.size(); + if( nTrapCount > 0 ) + bDrawnOk = drawFilledTrapezoids( &aB2DTrapVector[0], nTrapCount, fTransparency ); + + // restore the original brush GC + mnBrushColor = aKeepBrushColor; + return bDrawnOk; + } + + // get the area polygon for the line polygon + if( (rLineWidth.getX() != rLineWidth.getY()) + && !basegfx::fTools::equalZero( rLineWidth.getY() ) ) + { + // prepare for createAreaGeometry() with anisotropic linewidth + aPolygon.transform( basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getX() / rLineWidth.getY())); + } + + // create the area-polygon for the line + const basegfx::B2DPolyPolygon aAreaPolyPoly( basegfx::tools::createAreaGeometry(aPolygon, fHalfWidth, eLineJoin, eLineCap) ); + + if( (rLineWidth.getX() != rLineWidth.getY()) + && !basegfx::fTools::equalZero( rLineWidth.getX() ) ) + { + // postprocess createAreaGeometry() for anisotropic linewidth + aPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getY() / rLineWidth.getX())); + } + + // draw each area polypolygon component individually + // to emulate the polypolygon winding rule "non-zero" + const int nPolyCount = aAreaPolyPoly.count(); + for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) + { + const ::basegfx::B2DPolyPolygon aOnePoly( aAreaPolyPoly.getB2DPolygon( nPolyIdx ) ); + bDrawnOk = drawPolyPolygon( aOnePoly, fTransparency ); + if( !bDrawnOk ) + break; + } + + // restore the original brush GC + mnBrushColor = aKeepBrushColor; + return bDrawnOk; +} + +SalColor X11SalGraphicsImpl::getPixel( long nX, long nY ) +{ + if( mrParent.bWindow_ && !mrParent.bVirDev_ ) + { + XWindowAttributes aAttrib; + + XGetWindowAttributes( mrParent.GetXDisplay(), mrParent.GetDrawable(), &aAttrib ); + if( aAttrib.map_state != IsViewable ) + { + stderr0( "X11SalGraphics::GetPixel drawable not viewable\n" ); + return 0; + } + } + + XImage *pXImage = XGetImage( mrParent.GetXDisplay(), + mrParent.GetDrawable(), + nX, nY, + 1, 1, + AllPlanes, + ZPixmap ); + if( !pXImage ) + { + stderr0( "X11SalGraphics::GetPixel !XGetImage()\n" ); + return 0; + } + + XColor aXColor; + + aXColor.pixel = XGetPixel( pXImage, 0, 0 ); + XDestroyImage( pXImage ); + + return mrParent.GetColormap().GetColor( aXColor.pixel ); +} + +SalBitmap *X11SalGraphicsImpl::getBitmap( long nX, long nY, long nDX, long nDY ) +{ + if( mrParent.bPrinter_ && !mrParent.bVirDev_ ) + return NULL; + + bool bFakeWindowBG = false; + + // normalize + if( nDX < 0 ) + { + nX += nDX; + nDX = -nDX; + } + if ( nDY < 0 ) + { + nY += nDY; + nDY = -nDY; + } + + if( mrParent.bWindow_ && !mrParent.bVirDev_ ) + { + XWindowAttributes aAttrib; + + XGetWindowAttributes( mrParent.GetXDisplay(), mrParent.GetDrawable(), &aAttrib ); + if( aAttrib.map_state != IsViewable ) + bFakeWindowBG = true; + else + { + long nOrgDX = nDX, nOrgDY = nDY; + + // clip to window size + if ( nX < 0 ) + { + nDX += nX; + nX = 0; + } + if ( nY < 0 ) + { + nDY += nY; + nY = 0; + } + if( nX + nDX > aAttrib.width ) + nDX = aAttrib.width - nX; + if( nY + nDY > aAttrib.height ) + nDY = aAttrib.height - nY; + + // inside ? + if( nDX <= 0 || nDY <= 0 ) + { + bFakeWindowBG = true; + nDX = nOrgDX; + nDY = nOrgDY; + } + } + } + + X11SalBitmap* pSalBitmap = new X11SalBitmap; + sal_uInt16 nBitCount = GetBitCount(); + + if( &mrParent.GetDisplay()->GetColormap( mrParent.m_nXScreen ) != &mrParent.GetColormap() ) + nBitCount = 1; + + if( ! bFakeWindowBG ) + pSalBitmap->ImplCreateFromDrawable( mrParent.GetDrawable(), mrParent.m_nXScreen, nBitCount, nX, nY, nDX, nDY ); + else + pSalBitmap->Create( Size( nDX, nDY ), (nBitCount > 8) ? 24 : nBitCount, BitmapPalette( nBitCount > 8 ? nBitCount : 0 ) ); + + return pSalBitmap; +} + +sal_uInt16 X11SalGraphicsImpl::GetBitCount() const +{ + return mrParent.GetVisual().GetDepth(); +} + +long X11SalGraphicsImpl::GetGraphicsWidth() const +{ + if( mrParent.m_pFrame ) + return mrParent.m_pFrame->maGeometry.nWidth; + else if( mrParent.m_pVDev ) + return mrParent.m_pVDev->GetWidth(); + else + return 0; +} + +bool X11SalGraphicsImpl::drawGradient(const tools::PolyPolygon& /*rPolygon*/, const Gradient& /*rGradient*/) +{ + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/gdi/gdiimpl.hxx b/vcl/unx/generic/gdi/gdiimpl.hxx new file mode 100644 index 000000000000..252fe358f505 --- /dev/null +++ b/vcl/unx/generic/gdi/gdiimpl.hxx @@ -0,0 +1,278 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCULDED_VCL_GENERIC_GDI_GDIIMPL_HXX +#define INCLUDED_VCL_GENERIC_GDI_GDIIMPL_HXX + +#include <prex.h> +#include <postx.h> + +#include "unx/saltype.h" +#include "unx/x11/x11gdiimpl.h" + +#include "salgdiimpl.hxx" + +#include <basegfx/polygon/b2dtrapezoid.hxx> + +class SalGraphics; +class SalBitmap; +class SalPolyLine; +class X11SalGraphics; +class Gradient; + +class X11SalGraphicsImpl : public SalGraphicsImpl, public X11GraphicsImpl +{ +private: + X11SalGraphics& mrParent; + + SalColor mnBrushColor; + GC mpBrushGC; // Brush attributes + Pixel mnBrushPixel; + + bool mbPenGC : 1; // is Pen GC valid + bool mbBrushGC : 1; // is Brush GC valid + bool mbMonoGC : 1; // is Mono GC valid + bool mbCopyGC : 1; // is Copy GC valid + bool mbInvertGC : 1; // is Invert GC valid + bool mbInvert50GC : 1; // is Invert50 GC valid + bool mbStippleGC : 1; // is Stipple GC valid + bool mbTrackingGC : 1; // is Tracking GC valid + bool mbDitherBrush : 1; // is solid or tile + + bool mbXORMode : 1; // is ROP XOR Mode set + + GC mpPenGC; // Pen attributes + SalColor mnPenColor; + Pixel mnPenPixel; + + + GC mpMonoGC; + GC mpCopyGC; + GC mpMaskGC; + GC mpInvertGC; + GC mpInvert50GC; + GC mpStippleGC; + GC mpTrackingGC; + + GC CreateGC( Drawable hDrawable, + unsigned long nMask = GCGraphicsExposures ); + + GC SelectBrush(); + GC SelectPen(); + inline GC GetCopyGC(); + inline GC GetStippleGC(); + GC GetTrackingGC(); + GC GetInvertGC(); + GC GetInvert50GC(); + inline GC GetMonoGC( Pixmap hPixmap ); + + void DrawLines( sal_uIntPtr nPoints, + const SalPolyLine &rPoints, + GC pGC, + bool bClose + ); + + XID GetXRenderPicture(); + bool drawFilledTrapezoids( const ::basegfx::B2DTrapezoid*, int nTrapCount, double fTransparency ); + + long GetGraphicsHeight() const; + + void drawMaskedBitmap( const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rTransparentBitmap ); + + void drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry, bool bClose ); + +public: + + X11SalGraphicsImpl(X11SalGraphics& rParent); + + virtual void freeResources() SAL_OVERRIDE; + + virtual ~X11SalGraphicsImpl(); + + virtual bool setClipRegion( const vcl::Region& ) SAL_OVERRIDE; + // + // get the depth of the device + virtual sal_uInt16 GetBitCount() const SAL_OVERRIDE; + + // get the width of the device + virtual long GetGraphicsWidth() const SAL_OVERRIDE; + + // set the clip region to empty + virtual void ResetClipRegion() SAL_OVERRIDE; + + // set the line color to transparent (= don't draw lines) + + virtual void SetLineColor() SAL_OVERRIDE; + + // set the line color to a specific color + virtual void SetLineColor( SalColor nSalColor ) SAL_OVERRIDE; + + // set the fill color to transparent (= don't fill) + virtual void SetFillColor() SAL_OVERRIDE; + + // set the fill color to a specific color, shapes will be + // filled accordingly + virtual void SetFillColor( SalColor nSalColor ) SAL_OVERRIDE; + + // enable/disable XOR drawing + virtual void SetXORMode( bool bSet, bool bInvertOnly ) SAL_OVERRIDE; + + // set line color for raster operations + virtual void SetROPLineColor( SalROPColor nROPColor ) SAL_OVERRIDE; + + // set fill color for raster operations + virtual void SetROPFillColor( SalROPColor nROPColor ) SAL_OVERRIDE; + + // draw --> LineColor and FillColor and RasterOp and ClipRegion + virtual void drawPixel( long nX, long nY ) SAL_OVERRIDE; + virtual void drawPixel( long nX, long nY, SalColor nSalColor ) SAL_OVERRIDE; + + virtual void drawLine( long nX1, long nY1, long nX2, long nY2 ) SAL_OVERRIDE; + + virtual void drawRect( long nX, long nY, long nWidth, long nHeight ) SAL_OVERRIDE; + + virtual void drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) SAL_OVERRIDE; + + virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) SAL_OVERRIDE; + + virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) SAL_OVERRIDE; + virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency ) SAL_OVERRIDE; + + virtual bool drawPolyLine( + const ::basegfx::B2DPolygon&, + double fTransparency, + const ::basegfx::B2DVector& rLineWidths, + basegfx::B2DLineJoin, + com::sun::star::drawing::LineCap) SAL_OVERRIDE; + + virtual bool drawPolyLineBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const sal_uInt8* pFlgAry ) SAL_OVERRIDE; + + virtual bool drawPolygonBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const sal_uInt8* pFlgAry ) SAL_OVERRIDE; + + virtual bool drawPolyPolygonBezier( + sal_uInt32 nPoly, + const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, + const sal_uInt8* const* pFlgAry ) SAL_OVERRIDE; + + // CopyArea --> No RasterOp, but ClipRegion + virtual void copyArea( + long nDestX, long nDestY, + long nSrcX, long nSrcY, + long nSrcWidth, long nSrcHeight, + sal_uInt16 nFlags ) SAL_OVERRIDE; + + // CopyBits and DrawBitmap --> RasterOp and ClipRegion + // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics + virtual void copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) SAL_OVERRIDE; + + virtual void drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) SAL_OVERRIDE; + + virtual void drawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + SalColor nTransparentColor ) SAL_OVERRIDE; + + virtual void drawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rMaskBitmap ) SAL_OVERRIDE; + + virtual void drawMask( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + SalColor nMaskColor ) SAL_OVERRIDE; + + virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight ) SAL_OVERRIDE; + + virtual SalColor getPixel( long nX, long nY ) SAL_OVERRIDE; + + // invert --> ClipRegion (only Windows or VirDevs) + virtual void invert( + long nX, long nY, + long nWidth, long nHeight, + SalInvert nFlags) SAL_OVERRIDE; + + virtual void invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags ) SAL_OVERRIDE; + + virtual bool drawEPS( + long nX, long nY, + long nWidth, long nHeight, + void* pPtr, + sal_uLong nSize ) SAL_OVERRIDE; + + /** Render bitmap with alpha channel + + @param rSourceBitmap + Source bitmap to blit + + @param rAlphaBitmap + Alpha channel to use for blitting + + @return true, if the operation succeeded, and false + otherwise. In this case, clients should try to emulate alpha + compositing themselves + */ + virtual bool drawAlphaBitmap( + const SalTwoRect&, + const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap ) SAL_OVERRIDE; + + /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */ + virtual bool drawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) SAL_OVERRIDE; + + /** Render solid rectangle with given transparency + + @param nTransparency + Transparency value (0-255) to use. 0 blits and opaque, 255 a + fully transparent rectangle + */ + virtual bool drawAlphaRect( + long nX, long nY, + long nWidth, long nHeight, + sal_uInt8 nTransparency ) SAL_OVERRIDE; + + virtual bool drawGradient(const tools::PolyPolygon& rPolygon, const Gradient& rGradient) SAL_OVERRIDE; + + virtual bool swapBuffers() SAL_OVERRIDE { return false; } + +public: + // implementation of X11GraphicsImpl + + void Init() SAL_OVERRIDE; + X11Pixmap* GetPixmapFromScreen( const Rectangle& rRect ) SAL_OVERRIDE; + bool RenderPixmapToScreen( X11Pixmap* pPixmap, int nX, int nY ) SAL_OVERRIDE; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/gdi/openglx11cairotextrender.cxx b/vcl/unx/generic/gdi/openglx11cairotextrender.cxx new file mode 100644 index 000000000000..9b7c49ed450f --- /dev/null +++ b/vcl/unx/generic/gdi/openglx11cairotextrender.cxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "openglx11cairotextrender.hxx" + +#include "salbmp.hxx" +#include <vcl/salbtype.hxx> + +#include <cairo-svg.h> + +OpenGLX11CairoTextRender::OpenGLX11CairoTextRender(bool bPrinter, X11SalGraphics& rParent): + X11CairoTextRender(bPrinter, rParent) +{ +} + +cairo_surface_t* OpenGLX11CairoTextRender::getCairoSurface() +{ + // static size_t id = 0; + // OString aFileName = OString("/tmp/libo_logs/text_rendering") + OString::number(id++) + OString(".svg"); + // cairo_surface_t* surface = cairo_svg_surface_create(aFileName.getStr(), GetWidth(), GetHeight()); + cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24, GetWidth(), GetHeight()); + return surface; +} + +void OpenGLX11CairoTextRender::drawSurface(cairo_t* cr) +{ + cairo_surface_t* surface = cairo_get_target(cr); + int width = cairo_image_surface_get_width(surface); + int height = cairo_image_surface_get_height(surface); + SalBitmap* pBitmap = ImplGetSVData()->mpDefInst->CreateSalBitmap(); + pBitmap->Create(Size(width, height), 24, BitmapPalette()); + BitmapBuffer* pBuffer = pBitmap->AcquireBuffer(false); + std::memcpy(pBuffer->mpBits, cairo_image_surface_get_data(surface), width*height*3); + pBitmap->ReleaseBuffer(pBuffer, false); + SalTwoRect aRect; + aRect.mnSrcX = 0; + aRect.mnSrcY = 0; + aRect.mnSrcWidth = width; + aRect.mnSrcHeight = height; + mrParent.drawBitmap(aRect, *pBitmap); + delete pBitmap; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/gdi/openglx11cairotextrender.hxx b/vcl/unx/generic/gdi/openglx11cairotextrender.hxx new file mode 100644 index 000000000000..87ef9483cacb --- /dev/null +++ b/vcl/unx/generic/gdi/openglx11cairotextrender.hxx @@ -0,0 +1,26 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef INCLUDED_VCL_UNX_GENERIC_GDI_OPENGLX11CAIROTEXTRENDER_HXX +#define INCLUDED_VCL_UNX_GENERIC_GDI_OPENGLX11CAIROTEXTRENDER_HXX value + +#include "x11cairotextrender.hxx" + +class OpenGLX11CairoTextRender : public X11CairoTextRender +{ +public: + OpenGLX11CairoTextRender(bool bPrinter, X11SalGraphics& rParent); + + virtual cairo_surface_t* getCairoSurface() SAL_OVERRIDE; + virtual void drawSurface(cairo_t* cr) SAL_OVERRIDE; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/gdi/pixmap.cxx b/vcl/unx/generic/gdi/pixmap.cxx new file mode 100644 index 000000000000..beb5589e2425 --- /dev/null +++ b/vcl/unx/generic/gdi/pixmap.cxx @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "unx/pixmap.hxx" + +X11Pixmap::X11Pixmap() +: mpDisplay( NULL ) +, mnScreen( 0 ) +, mnWidth( -1 ) +, mnHeight( -1 ) +, mnDepth( 0 ) +{ +} + +X11Pixmap::X11Pixmap( Display* pDisplay, SalX11Screen nScreen, int nWidth, int nHeight, int nDepth ) +: mpDisplay( pDisplay ) +, mnScreen( nScreen ) +, mnWidth( nWidth ) +, mnHeight( nHeight ) +, mnDepth( nDepth ) +{ + Window root = RootWindow( pDisplay, 0 ); + mpPixmap = XCreatePixmap( pDisplay, root, nWidth, nHeight, nDepth ); +} + +X11Pixmap::X11Pixmap( X11Pixmap& rOther ) +: mpDisplay( rOther.mpDisplay ) +, mnScreen( rOther.mnScreen ) +, mnWidth( rOther.mnWidth ) +, mnHeight( rOther.mnHeight ) +, mnDepth( rOther.mnDepth ) +{ + mpPixmap = rOther.mpPixmap; + rOther.mpPixmap = 0; +} + +X11Pixmap::~X11Pixmap() +{ + if( mpPixmap ) + XFreePixmap( mpDisplay, mpPixmap ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/gdi/salbmp.cxx b/vcl/unx/generic/gdi/salbmp.cxx index e68078e7c919..6b2042c842c4 100644 --- a/vcl/unx/generic/gdi/salbmp.cxx +++ b/vcl/unx/generic/gdi/salbmp.cxx @@ -43,6 +43,10 @@ #include <unx/salinst.h> #include <unx/x11/xlimits.hxx> +#include <opengl/salbmp.hxx> +#include <vcl/opengl/OpenGLHelper.hxx> +#include <officecfg/Office/Common.hxx> + #if defined HAVE_VALGRIND_HEADERS #include <valgrind/memcheck.h> #endif @@ -53,7 +57,12 @@ SalBitmap* X11SalInstance::CreateSalBitmap() { - return new X11SalBitmap(); + static bool bOpenGLPossible = OpenGLHelper::supportsVCLOpenGL(); + bool bUseOpenGL = bOpenGLPossible ? officecfg::Office::Common::VCL::UseOpenGL::get() : false; + if (bUseOpenGL) + return new OpenGLSalBitmap(); + else + return new X11SalBitmap(); } ImplSalBitmapCache* X11SalBitmap::mpCache = NULL; @@ -854,6 +863,11 @@ bool X11SalBitmap::GetSystemData( BitmapSystemData& rData ) return false; } +bool X11SalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, sal_uInt32 /*nScaleFlag*/ ) +{ + return false; +} + // - ImplSalDDB - ImplSalDDB::ImplSalDDB( XImage* pImage, Drawable aDrawable, diff --git a/vcl/unx/generic/gdi/salgdi.cxx b/vcl/unx/generic/gdi/salgdi.cxx index 4441458578b0..47b20bc84d82 100644 --- a/vcl/unx/generic/gdi/salgdi.cxx +++ b/vcl/unx/generic/gdi/salgdi.cxx @@ -48,101 +48,55 @@ #include "unx/salgdi.h" #include "unx/salframe.h" #include "unx/salvd.h" +#include "unx/x11/x11gdiimpl.h" #include <unx/x11/xlimits.hxx> +#include "salgdiimpl.hxx" +#include "unx/x11windowprovider.hxx" +#include "textrender.hxx" +#include "gdiimpl.hxx" +#include "opengl/x11/gdiimpl.hxx" +#include "x11cairotextrender.hxx" +#include "openglx11cairotextrender.hxx" + #include "generic/printergfx.hxx" #include "xrender_peer.hxx" -#define STATIC_POINTS 64 - -class SalPolyLine -{ - XPoint Points_[STATIC_POINTS]; - XPoint *pFirst_; -public: - SalPolyLine(sal_uLong nPoints, const SalPoint *p) - : pFirst_(nPoints+1 > STATIC_POINTS ? new XPoint[nPoints+1] : Points_) - { - for( sal_uLong i = 0; i < nPoints; i++ ) - { - pFirst_[i].x = (short)p[i].mnX; - pFirst_[i].y = (short)p[i].mnY; - } - pFirst_[nPoints] = pFirst_[0]; // close polyline +#include <officecfg/Office/Common.hxx> + +#include <vcl/opengl/OpenGLHelper.hxx> + +X11SalGraphics::X11SalGraphics(): + m_pFrame(NULL), + m_pVDev(NULL), + m_pColormap(NULL), + m_pDeleteColormap(NULL), + hDrawable_(None), + m_nXScreen( 0 ), + m_pXRenderFormat(NULL), + m_aXRenderPicture(0), + pPaintRegion_(NULL), + mpClipRegion(NULL), + pFontGC_(NULL), + nTextPixel_(0), + hBrush_(None), + bWindow_(false), + bPrinter_(false), + bVirDev_(false) +{ + static bool bOpenGLPossible = OpenGLHelper::supportsVCLOpenGL(); + bool bUseOpenGL = bOpenGLPossible ? officecfg::Office::Common::VCL::UseOpenGL::get() : false; + if (bUseOpenGL) + { + mpImpl.reset(new X11OpenGLSalGraphicsImpl(*this)); + mpTextRenderImpl.reset((new OpenGLX11CairoTextRender(false, *this))); } - - ~SalPolyLine() - { - if( pFirst_ != Points_ ) - delete [] pFirst_; - } - - XPoint &operator [] ( sal_uLong n ) const + else { - return pFirst_[n]; + mpTextRenderImpl.reset((new X11CairoTextRender(false, *this))); + mpImpl.reset(new X11SalGraphicsImpl(*this)); } -}; - -#undef STATIC_POINTS -X11SalGraphics::X11SalGraphics() - : m_nXScreen( 0 ) -{ - m_pFrame = NULL; - m_pVDev = NULL; - m_pColormap = NULL; - m_pDeleteColormap = NULL; - hDrawable_ = None; - m_aXRenderPicture = 0; - m_pXRenderFormat = NULL; - - mpClipRegion = NULL; - pPaintRegion_ = NULL; - - pPenGC_ = NULL; - nPenPixel_ = 0; - nPenColor_ = MAKE_SALCOLOR( 0x00, 0x00, 0x00 ); // Black - - pFontGC_ = NULL; - for( int i = 0; i < MAX_FALLBACK; ++i ) - mpServerFont[i] = NULL; - - nTextPixel_ = 0; - nTextColor_ = MAKE_SALCOLOR( 0x00, 0x00, 0x00 ); // Black - -#if ENABLE_GRAPHITE - // check if graphite fonts have been disabled - static const char* pDisableGraphiteStr = getenv( "SAL_DISABLE_GRAPHITE" ); - bDisableGraphite_ = pDisableGraphiteStr && (pDisableGraphiteStr[0]!='0'); -#endif - - pBrushGC_ = NULL; - nBrushPixel_ = 0; - nBrushColor_ = MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ); // White - hBrush_ = None; - - pMonoGC_ = NULL; - pCopyGC_ = NULL; - pMaskGC_ = NULL; - pInvertGC_ = NULL; - pInvert50GC_ = NULL; - pStippleGC_ = NULL; - pTrackingGC_ = NULL; - - bWindow_ = false; - bPrinter_ = false; - bVirDev_ = false; - bPenGC_ = false; - bFontGC_ = false; - bBrushGC_ = false; - bMonoGC_ = false; - bCopyGC_ = false; - bInvertGC_ = false; - bInvert50GC_ = false; - bStippleGC_ = false; - bTrackingGC_ = false; - bXORMode_ = false; - bDitherBrush_ = false; } X11SalGraphics::~X11SalGraphics() @@ -158,24 +112,17 @@ void X11SalGraphics::freeResources() DBG_ASSERT( !pPaintRegion_, "pPaintRegion_" ); if( mpClipRegion ) XDestroyRegion( mpClipRegion ), mpClipRegion = None; + mpImpl->freeResources(); + if( hBrush_ ) XFreePixmap( pDisplay, hBrush_ ), hBrush_ = None; - if( pPenGC_ ) XFreeGC( pDisplay, pPenGC_ ), pPenGC_ = None; - if( pFontGC_ ) XFreeGC( pDisplay, pFontGC_ ), pFontGC_ = None; - if( pBrushGC_ ) XFreeGC( pDisplay, pBrushGC_ ), pBrushGC_ = None; - if( pMonoGC_ ) XFreeGC( pDisplay, pMonoGC_ ), pMonoGC_ = None; - if( pCopyGC_ ) XFreeGC( pDisplay, pCopyGC_ ), pCopyGC_ = None; - if( pMaskGC_ ) XFreeGC( pDisplay, pMaskGC_ ), pMaskGC_ = None; - if( pInvertGC_ ) XFreeGC( pDisplay, pInvertGC_ ), pInvertGC_ = None; - if( pInvert50GC_ ) XFreeGC( pDisplay, pInvert50GC_ ), pInvert50GC_ = None; - if( pStippleGC_ ) XFreeGC( pDisplay, pStippleGC_ ), pStippleGC_ = None; - if( pTrackingGC_ ) XFreeGC( pDisplay, pTrackingGC_ ), pTrackingGC_ = None; + if( pFontGC_ ) XFreeGC( pDisplay, pFontGC_ ), pFontGC_ = None; if( m_pDeleteColormap ) delete m_pDeleteColormap, m_pColormap = m_pDeleteColormap = NULL; if( m_aXRenderPicture ) XRenderPeer::GetInstance().FreePicture( m_aXRenderPicture ), m_aXRenderPicture = 0; - bPenGC_ = bFontGC_ = bBrushGC_ = bMonoGC_ = bCopyGC_ = bInvertGC_ = bInvert50GC_ = bStippleGC_ = bTrackingGC_ = false; + bFontGC_ = false; } void X11SalGraphics::SetDrawable( Drawable aDrawable, SalX11Screen nXScreen ) @@ -202,9 +149,8 @@ void X11SalGraphics::SetDrawable( Drawable aDrawable, SalX11Screen nXScreen ) if( hDrawable_ ) { - nPenPixel_ = GetPixel( nPenColor_ ); - nTextPixel_ = GetPixel( nTextColor_ ); - nBrushPixel_ = GetPixel( nBrushColor_ ); + dynamic_cast<X11GraphicsImpl*>(mpImpl.get())->Init(); + // TODO: moggi: FIXME nTextPixel_ = GetPixel( nTextColor_ ); } } @@ -213,10 +159,10 @@ void X11SalGraphics::Init( SalFrame *pFrame, Drawable aTarget, { m_pColormap = &GetGenericData()->GetSalDisplay()->GetColormap(nXScreen); m_nXScreen = nXScreen; + m_pFrame = pFrame; SetDrawable( aTarget, nXScreen ); bWindow_ = true; - m_pFrame = pFrame; m_pVDev = NULL; } @@ -252,146 +198,6 @@ void X11SalGraphics::SetClipRegion( GC pGC, Region pXReg ) const } } -GC X11SalGraphics::SelectPen() -{ - Display *pDisplay = GetXDisplay(); - - if( !pPenGC_ ) - { - XGCValues values; - values.subwindow_mode = ClipByChildren; - values.fill_rule = EvenOddRule; // Pict import/ Gradient - values.graphics_exposures = False; - - pPenGC_ = XCreateGC( pDisplay, hDrawable_, - GCSubwindowMode | GCFillRule | GCGraphicsExposures, - &values ); - } - - if( !bPenGC_ ) - { - if( nPenColor_ != SALCOLOR_NONE ) - XSetForeground( pDisplay, pPenGC_, nPenPixel_ ); - XSetFunction ( pDisplay, pPenGC_, bXORMode_ ? GXxor : GXcopy ); - SetClipRegion( pPenGC_ ); - bPenGC_ = true; - } - - return pPenGC_; -} - -GC X11SalGraphics::SelectBrush() -{ - Display *pDisplay = GetXDisplay(); - - DBG_ASSERT( nBrushColor_ != SALCOLOR_NONE, "Brush Transparent" ); - - if( !pBrushGC_ ) - { - XGCValues values; - values.subwindow_mode = ClipByChildren; - values.fill_rule = EvenOddRule; // Pict import/ Gradient - values.graphics_exposures = False; - - pBrushGC_ = XCreateGC( pDisplay, hDrawable_, - GCSubwindowMode | GCFillRule | GCGraphicsExposures, - &values ); - } - - if( !bBrushGC_ ) - { - if( !bDitherBrush_ ) - { - XSetFillStyle ( pDisplay, pBrushGC_, FillSolid ); - XSetForeground( pDisplay, pBrushGC_, nBrushPixel_ ); - if( bPrinter_ ) - XSetTile( pDisplay, pBrushGC_, None ); - } - else - { - // Bug in Sun Solaris 2.5.1, XFillPolygon doesn't always reflect - // changes of the tile. PROPERTY_BUG_Tile doesn't fix this ! - if (GetDisplay()->GetProperties() & PROPERTY_BUG_FillPolygon_Tile) - XSetFillStyle ( pDisplay, pBrushGC_, FillSolid ); - - XSetFillStyle ( pDisplay, pBrushGC_, FillTiled ); - XSetTile ( pDisplay, pBrushGC_, hBrush_ ); - } - XSetFunction ( pDisplay, pBrushGC_, bXORMode_ ? GXxor : GXcopy ); - SetClipRegion( pBrushGC_ ); - - bBrushGC_ = true; - } - - return pBrushGC_; -} - -GC X11SalGraphics::GetTrackingGC() -{ - const char dash_list[2] = {2, 2}; - - if( !pTrackingGC_ ) - { - XGCValues values; - - values.graphics_exposures = False; - values.foreground = m_pColormap->GetBlackPixel() - ^ m_pColormap->GetWhitePixel(); - values.function = GXxor; - values.line_width = 1; - values.line_style = LineOnOffDash; - - pTrackingGC_ = XCreateGC( GetXDisplay(), GetDrawable(), - GCGraphicsExposures | GCForeground | GCFunction - | GCLineWidth | GCLineStyle, - &values ); - XSetDashes( GetXDisplay(), pTrackingGC_, 0, dash_list, 2 ); - } - - if( !bTrackingGC_ ) - { - SetClipRegion( pTrackingGC_ ); - bTrackingGC_ = true; - } - - return pTrackingGC_; -} - -void X11SalGraphics::DrawLines( sal_uLong nPoints, - const SalPolyLine &rPoints, - GC pGC, - bool bClose - ) -{ - // calculate how many lines XWindow can draw in one go - sal_uLong nMaxLines = (GetDisplay()->GetMaxRequestSize() - sizeof(xPolyPointReq)) - / sizeof(xPoint); - if( nMaxLines > nPoints ) nMaxLines = nPoints; - - // print all lines that XWindows can draw - sal_uLong n; - for( n = 0; nPoints - n > nMaxLines; n += nMaxLines - 1 ) - XDrawLines( GetXDisplay(), - GetDrawable(), - pGC, - &rPoints[n], - nMaxLines, - CoordModeOrigin ); - - if( n < nPoints ) - XDrawLines( GetXDisplay(), - GetDrawable(), - pGC, - &rPoints[n], - nPoints - n, - CoordModeOrigin ); - if( bClose ) - { - if( rPoints[nPoints-1].x != rPoints[0].x || rPoints[nPoints-1].y != rPoints[0].y ) - drawLine( rPoints[nPoints-1].x, rPoints[nPoints-1].y, rPoints[0].x, rPoints[0].y ); - } -} - // Calculate a dither-pixmap and make a brush of it #define P_DELTA 51 #define DMAP( v, m ) ((v % P_DELTA) > m ? (v / P_DELTA) + 1 : (v / P_DELTA)) @@ -506,493 +312,123 @@ void X11SalGraphics::GetResolution( sal_Int32 &rDPIX, sal_Int32 &rDPIY ) // cons sal_uInt16 X11SalGraphics::GetBitCount() const { - return GetVisual().GetDepth(); + return mpImpl->GetBitCount(); } long X11SalGraphics::GetGraphicsWidth() const { - if( m_pFrame ) - return m_pFrame->maGeometry.nWidth; - else if( m_pVDev ) - return m_pVDev->GetWidth(); - else - return 0; -} - -long X11SalGraphics::GetGraphicsHeight() const -{ - if( m_pFrame ) - return m_pFrame->maGeometry.nHeight; - else if( m_pVDev ) - return m_pVDev->GetHeight(); - else - return 0; + return mpImpl->GetGraphicsWidth(); } void X11SalGraphics::ResetClipRegion() { - if( mpClipRegion ) - { - bPenGC_ = false; - bFontGC_ = false; - bBrushGC_ = false; - bMonoGC_ = false; - bCopyGC_ = false; - bInvertGC_ = false; - bInvert50GC_ = false; - bStippleGC_ = false; - bTrackingGC_ = false; - - XDestroyRegion( mpClipRegion ); - mpClipRegion = NULL; - } + mpImpl->ResetClipRegion(); } bool X11SalGraphics::setClipRegion( const vcl::Region& i_rClip ) { - if( mpClipRegion ) - XDestroyRegion( mpClipRegion ); - mpClipRegion = XCreateRegion(); - - RectangleVector aRectangles; - i_rClip.GetRegionRectangles(aRectangles); - - for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter) - { - const long nW(aRectIter->GetWidth()); - - if(nW) - { - const long nH(aRectIter->GetHeight()); - - if(nH) - { - XRectangle aRect; - - aRect.x = (short)aRectIter->Left(); - aRect.y = (short)aRectIter->Top(); - aRect.width = (unsigned short)nW; - aRect.height = (unsigned short)nH; - XUnionRectWithRegion(&aRect, mpClipRegion, mpClipRegion); - } - } - } - - //ImplRegionInfo aInfo; - //long nX, nY, nW, nH; - //bool bRegionRect = i_rClip.ImplGetFirstRect(aInfo, nX, nY, nW, nH ); - //while( bRegionRect ) - //{ - // if ( nW && nH ) - // { - // XRectangle aRect; - // aRect.x = (short)nX; - // aRect.y = (short)nY; - // aRect.width = (unsigned short)nW; - // aRect.height = (unsigned short)nH; - - // XUnionRectWithRegion( &aRect, mpClipRegion, mpClipRegion ); - // } - // bRegionRect = i_rClip.ImplGetNextRect( aInfo, nX, nY, nW, nH ); - //} - - // done, invalidate GCs - bPenGC_ = false; - bFontGC_ = false; - bBrushGC_ = false; - bMonoGC_ = false; - bCopyGC_ = false; - bInvertGC_ = false; - bInvert50GC_ = false; - bStippleGC_ = false; - bTrackingGC_ = false; - - if( XEmptyRegion( mpClipRegion ) ) - { - XDestroyRegion( mpClipRegion ); - mpClipRegion= NULL; - } - return true; + return mpImpl->setClipRegion( i_rClip ); } void X11SalGraphics::SetLineColor() { - if( nPenColor_ != SALCOLOR_NONE ) - { - nPenColor_ = SALCOLOR_NONE; - bPenGC_ = false; - } + mpImpl->SetLineColor(); } void X11SalGraphics::SetLineColor( SalColor nSalColor ) { - if( nPenColor_ != nSalColor ) - { - nPenColor_ = nSalColor; - nPenPixel_ = GetPixel( nSalColor ); - bPenGC_ = false; - } + mpImpl->SetLineColor( nSalColor ); } void X11SalGraphics::SetFillColor() { - if( nBrushColor_ != SALCOLOR_NONE ) - { - bDitherBrush_ = false; - nBrushColor_ = SALCOLOR_NONE; - bBrushGC_ = false; - } + mpImpl->SetFillColor(); } void X11SalGraphics::SetFillColor( SalColor nSalColor ) { - if( nBrushColor_ != nSalColor ) - { - bDitherBrush_ = false; - nBrushColor_ = nSalColor; - nBrushPixel_ = GetPixel( nSalColor ); - if( TrueColor != GetColormap().GetVisual().GetClass() - && GetColormap().GetColor( nBrushPixel_ ) != nBrushColor_ - && nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0x00 ) // black - && nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0x80 ) // blue - && nSalColor != MAKE_SALCOLOR( 0x00, 0x80, 0x00 ) // green - && nSalColor != MAKE_SALCOLOR( 0x00, 0x80, 0x80 ) // cyan - && nSalColor != MAKE_SALCOLOR( 0x80, 0x00, 0x00 ) // red - && nSalColor != MAKE_SALCOLOR( 0x80, 0x00, 0x80 ) // magenta - && nSalColor != MAKE_SALCOLOR( 0x80, 0x80, 0x00 ) // brown - && nSalColor != MAKE_SALCOLOR( 0x80, 0x80, 0x80 ) // gray - && nSalColor != MAKE_SALCOLOR( 0xC0, 0xC0, 0xC0 ) // light gray - && nSalColor != MAKE_SALCOLOR( 0x00, 0x00, 0xFF ) // light blue - && nSalColor != MAKE_SALCOLOR( 0x00, 0xFF, 0x00 ) // light green - && nSalColor != MAKE_SALCOLOR( 0x00, 0xFF, 0xFF ) // light cyan - && nSalColor != MAKE_SALCOLOR( 0xFF, 0x00, 0x00 ) // light red - && nSalColor != MAKE_SALCOLOR( 0xFF, 0x00, 0xFF ) // light magenta - && nSalColor != MAKE_SALCOLOR( 0xFF, 0xFF, 0x00 ) // light brown - && nSalColor != MAKE_SALCOLOR( 0xFF, 0xFF, 0xFF ) ) - bDitherBrush_ = GetDitherPixmap(nSalColor); - bBrushGC_ = false; - } + mpImpl->SetFillColor( nSalColor ); } void X11SalGraphics::SetROPLineColor( SalROPColor nROPColor ) { - switch( nROPColor ) - { - case SAL_ROP_0 : // 0 - nPenPixel_ = (Pixel)0; - break; - case SAL_ROP_1 : // 1 - nPenPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1; - break; - case SAL_ROP_INVERT : // 2 - nPenPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1; - break; - } - nPenColor_ = GetColormap().GetColor( nPenPixel_ ); - bPenGC_ = false; + mpImpl->SetROPLineColor( nROPColor ); } void X11SalGraphics::SetROPFillColor( SalROPColor nROPColor ) { - switch( nROPColor ) - { - case SAL_ROP_0 : // 0 - nBrushPixel_ = (Pixel)0; - break; - case SAL_ROP_1 : // 1 - nBrushPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1; - break; - case SAL_ROP_INVERT : // 2 - nBrushPixel_ = (Pixel)(1 << GetVisual().GetDepth()) - 1; - break; - } - bDitherBrush_ = false; - nBrushColor_ = GetColormap().GetColor( nBrushPixel_ ); - bBrushGC_ = false; + mpImpl->SetROPFillColor( nROPColor ); } -void X11SalGraphics::SetXORMode( bool bSet, bool ) +void X11SalGraphics::SetXORMode( bool bSet, bool bInvertOnly ) { - if( !bXORMode_ == bSet ) - { - bXORMode_ = bSet; - bPenGC_ = false; - bFontGC_ = false; - bBrushGC_ = false; - bMonoGC_ = false; - bCopyGC_ = false; - bInvertGC_ = false; - bInvert50GC_ = false; - bStippleGC_ = false; - bTrackingGC_ = false; - } + mpImpl->SetXORMode( bSet, bInvertOnly ); } void X11SalGraphics::drawPixel( long nX, long nY ) { - if( nPenColor_ != SALCOLOR_NONE ) - XDrawPoint( GetXDisplay(), GetDrawable(), SelectPen(), nX, nY ); + mpImpl->drawPixel( nX, nY ); } void X11SalGraphics::drawPixel( long nX, long nY, SalColor nSalColor ) { - if( nSalColor != SALCOLOR_NONE ) - { - Display *pDisplay = GetXDisplay(); - - if( (nPenColor_ == SALCOLOR_NONE) && !bPenGC_ ) - { - SetLineColor( nSalColor ); - XDrawPoint( pDisplay, GetDrawable(), SelectPen(), nX, nY ); - nPenColor_ = SALCOLOR_NONE; - bPenGC_ = False; - } - else - { - GC pGC = SelectPen(); - - if( nSalColor != nPenColor_ ) - XSetForeground( pDisplay, pGC, GetPixel( nSalColor ) ); - - XDrawPoint( pDisplay, GetDrawable(), pGC, nX, nY ); - - if( nSalColor != nPenColor_ ) - XSetForeground( pDisplay, pGC, nPenPixel_ ); - } - } + mpImpl->drawPixel( nX, nY, nSalColor ); } void X11SalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 ) { - if( nPenColor_ != SALCOLOR_NONE ) - { - if ( GetDisplay()->GetProperties() & PROPERTY_BUG_DrawLine ) - { - GC aGC = SelectPen(); - XDrawPoint (GetXDisplay(), GetDrawable(), aGC, (int)nX1, (int)nY1); - XDrawPoint (GetXDisplay(), GetDrawable(), aGC, (int)nX2, (int)nY2); - XDrawLine (GetXDisplay(), GetDrawable(), aGC, nX1, nY1, nX2, nY2 ); - } - else - XDrawLine( GetXDisplay(), GetDrawable(),SelectPen(), - nX1, nY1, nX2, nY2 ); - } + mpImpl->drawLine( nX1, nY1, nX2, nY2 ); } void X11SalGraphics::drawRect( long nX, long nY, long nDX, long nDY ) { - if( nBrushColor_ != SALCOLOR_NONE ) - { - XFillRectangle( GetXDisplay(), - GetDrawable(), - SelectBrush(), - nX, nY, nDX, nDY ); - } - // description DrawRect is wrong; thus -1 - if( nPenColor_ != SALCOLOR_NONE ) - XDrawRectangle( GetXDisplay(), - GetDrawable(), - SelectPen(), - nX, nY, nDX-1, nDY-1 ); + mpImpl->drawRect( nX, nY, nDX, nDY ); } void X11SalGraphics::drawPolyLine( sal_uInt32 nPoints, const SalPoint *pPtAry ) { - drawPolyLine( nPoints, pPtAry, false ); -} - -void X11SalGraphics::drawPolyLine( sal_uInt32 nPoints, const SalPoint *pPtAry, bool bClose ) -{ - if( nPenColor_ != SALCOLOR_NONE ) - { - SalPolyLine Points( nPoints, pPtAry ); - - DrawLines( nPoints, Points, SelectPen(), bClose ); - } + mpImpl->drawPolyLine( nPoints, pPtAry ); } void X11SalGraphics::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) { - if( nPoints == 0 ) - return; - - if( nPoints < 3 ) - { - if( !bXORMode_ ) - { - if( 1 == nPoints ) - drawPixel( pPtAry[0].mnX, pPtAry[0].mnY ); - else - drawLine( pPtAry[0].mnX, pPtAry[0].mnY, - pPtAry[1].mnX, pPtAry[1].mnY ); - } - return; - } - - SalPolyLine Points( nPoints, pPtAry ); - - nPoints++; - - /* WORKAROUND: some Xservers (Xorg, VIA chipset in this case) - * do not draw the visible part of a polygon - * if it overlaps to the left of screen 0,y. - * This happens to be the case in the gradient drawn in the - * menubar background. workaround for the special case of - * of a rectangle overlapping to the left. - */ - if( nPoints == 5 && - Points[ 0 ].x == Points[ 1 ].x && - Points[ 1 ].y == Points[ 2 ].y && - Points[ 2 ].x == Points[ 3 ].x && - Points[ 0 ].x == Points[ 4 ].x && Points[ 0 ].y == Points[ 4 ].y - ) - { - bool bLeft = false; - bool bRight = false; - for(unsigned int i = 0; i < nPoints; i++ ) - { - if( Points[i].x < 0 ) - bLeft = true; - else - bRight= true; - } - if( bLeft && ! bRight ) - return; - if( bLeft && bRight ) - { - for( unsigned int i = 0; i < nPoints; i++ ) - if( Points[i].x < 0 ) - Points[i].x = 0; - } - } - - if( nBrushColor_ != SALCOLOR_NONE ) - XFillPolygon( GetXDisplay(), - GetDrawable(), - SelectBrush(), - &Points[0], nPoints, - Complex, CoordModeOrigin ); - - if( nPenColor_ != SALCOLOR_NONE ) - DrawLines( nPoints, Points, SelectPen(), true ); + mpImpl->drawPolygon( nPoints, pPtAry ); } void X11SalGraphics::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32 *pPoints, PCONSTSALPOINT *pPtAry ) { - if( nBrushColor_ != SALCOLOR_NONE ) - { - sal_uInt32 i, n; - Region pXRegA = NULL; - - for( i = 0; i < nPoly; i++ ) { - n = pPoints[i]; - SalPolyLine Points( n, pPtAry[i] ); - if( n > 2 ) - { - Region pXRegB = XPolygonRegion( &Points[0], n+1, WindingRule ); - if( !pXRegA ) - pXRegA = pXRegB; - else - { - XXorRegion( pXRegA, pXRegB, pXRegA ); - XDestroyRegion( pXRegB ); - } - } - } - - if( pXRegA ) - { - XRectangle aXRect; - XClipBox( pXRegA, &aXRect ); - - GC pGC = SelectBrush(); - SetClipRegion( pGC, pXRegA ); // ??? twice - XDestroyRegion( pXRegA ); - bBrushGC_ = false; - - XFillRectangle( GetXDisplay(), - GetDrawable(), - pGC, - aXRect.x, aXRect.y, aXRect.width, aXRect.height ); - } - } - - if( nPenColor_ != SALCOLOR_NONE ) - for( sal_uInt32 i = 0; i < nPoly; i++ ) - drawPolyLine( pPoints[i], pPtAry[i], true ); + mpImpl->drawPolyPolygon( nPoly, pPoints, pPtAry ); } -bool X11SalGraphics::drawPolyLineBezier( sal_uInt32, const SalPoint*, const sal_uInt8* ) +bool X11SalGraphics::drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry ) { - return false; + return mpImpl->drawPolyLineBezier( nPoints, pPtAry, pFlgAry ); } -bool X11SalGraphics::drawPolygonBezier( sal_uInt32, const SalPoint*, const sal_uInt8* ) +bool X11SalGraphics::drawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const sal_uInt8* pFlgAry ) { - return false; + return mpImpl->drawPolygonBezier( nPoints, pPtAry, pFlgAry ); } -bool X11SalGraphics::drawPolyPolygonBezier( sal_uInt32, const sal_uInt32*, - const SalPoint* const*, const sal_uInt8* const* ) +bool X11SalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoints, const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, const sal_uInt8* const* pFlgAry) { - return false; + return mpImpl->drawPolyPolygonBezier( nPoints, pPoints, pPtAry, pFlgAry ); } void X11SalGraphics::invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags ) { - SalPolyLine Points ( nPoints, pPtAry ); - - GC pGC; - if( SAL_INVERT_50 & nFlags ) - pGC = GetInvert50GC(); - else - if ( SAL_INVERT_TRACKFRAME & nFlags ) - pGC = GetTrackingGC(); - else - pGC = GetInvertGC(); - - if( SAL_INVERT_TRACKFRAME & nFlags ) - DrawLines ( nPoints, Points, pGC, true ); - else - XFillPolygon( GetXDisplay(), - GetDrawable(), - pGC, - &Points[0], nPoints, - Complex, CoordModeOrigin ); -} - -bool X11SalGraphics::drawEPS( long,long,long,long,void*,sal_uLong ) -{ - return false; + mpImpl->invert( nPoints, pPtAry, nFlags ); } -XID X11SalGraphics::GetXRenderPicture() +bool X11SalGraphics::drawEPS( long nX, long nY, long nWidth, + long nHeight, void* pPtr, sal_uLong nSize ) { - XRenderPeer& rRenderPeer = XRenderPeer::GetInstance(); - - if( !m_aXRenderPicture ) - { - // check xrender support for matching visual - XRenderPictFormat* pXRenderFormat = GetXRenderFormat(); - if( !pXRenderFormat ) - return 0; - // get the matching xrender target for drawable - m_aXRenderPicture = rRenderPeer.CreatePicture( hDrawable_, pXRenderFormat, 0, NULL ); - } - - { - // reset clip region - // TODO: avoid clip reset if already done - XRenderPictureAttributes aAttr; - aAttr.clip_mask = None; - rRenderPeer.ChangePicture( m_aXRenderPicture, CPClipMask, &aAttr ); - } - - return m_aXRenderPicture; + return mpImpl->drawEPS( nX, nY, nWidth, nHeight, pPtr, nSize ); } XRenderPictFormat* X11SalGraphics::GetXRenderFormat() const @@ -1020,114 +456,7 @@ SystemGraphicsData X11SalGraphics::GetGraphicsData() const // draw a poly-polygon bool X11SalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rOrigPolyPoly, double fTransparency ) { - // nothing to do for empty polypolygons - const int nOrigPolyCount = rOrigPolyPoly.count(); - if( nOrigPolyCount <= 0 ) - return true; - - // nothing to do if everything is transparent - if( (nBrushColor_ == SALCOLOR_NONE) - && (nPenColor_ == SALCOLOR_NONE) ) - return true; - - // cannot handle pencolor!=brushcolor yet - if( (nPenColor_ != SALCOLOR_NONE) - && (nPenColor_ != nBrushColor_) ) - return false; - - // TODO: remove the env-variable when no longer needed - static const char* pRenderEnv = getenv( "SAL_DISABLE_RENDER_POLY" ); - if( pRenderEnv ) - return false; - - // snap to raster if requested - basegfx::B2DPolyPolygon aPolyPoly = rOrigPolyPoly; - const bool bSnapToRaster = !getAntiAliasB2DDraw(); - if( bSnapToRaster ) - aPolyPoly = basegfx::tools::snapPointsOfHorizontalOrVerticalEdges( aPolyPoly ); - - // don't bother with polygons outside of visible area - const basegfx::B2DRange aViewRange( 0, 0, GetGraphicsWidth(), GetGraphicsHeight() ); - aPolyPoly = basegfx::tools::clipPolyPolygonOnRange( aPolyPoly, aViewRange, true, false ); - if( !aPolyPoly.count() ) - return true; - - // tesselate the polypolygon into trapezoids - basegfx::B2DTrapezoidVector aB2DTrapVector; - basegfx::tools::trapezoidSubdivide( aB2DTrapVector, aPolyPoly ); - const int nTrapCount = aB2DTrapVector.size(); - if( !nTrapCount ) - return true; - const bool bDrawn = drawFilledTrapezoids( &aB2DTrapVector[0], nTrapCount, fTransparency ); - return bDrawn; -} - -bool X11SalGraphics::drawFilledTrapezoids( const ::basegfx::B2DTrapezoid* pB2DTraps, int nTrapCount, double fTransparency ) -{ - if( nTrapCount <= 0 ) - return true; - - Picture aDstPic = GetXRenderPicture(); - // check xrender support for this drawable - if( !aDstPic ) - return false; - - // convert the B2DTrapezoids into XRender-Trapezoids - typedef std::vector<XTrapezoid> TrapezoidVector; - TrapezoidVector aTrapVector( nTrapCount ); - const basegfx::B2DTrapezoid* pB2DTrap = pB2DTraps; - for( int i = 0; i < nTrapCount; ++pB2DTrap, ++i ) - { - XTrapezoid& rTrap = aTrapVector[ i ] ; - - // set y-coordinates - const double fY1 = pB2DTrap->getTopY(); - rTrap.left.p1.y = rTrap.right.p1.y = rTrap.top = XDoubleToFixed( fY1 ); - const double fY2 = pB2DTrap->getBottomY(); - rTrap.left.p2.y = rTrap.right.p2.y = rTrap.bottom = XDoubleToFixed( fY2 ); - - // set x-coordinates - const double fXL1 = pB2DTrap->getTopXLeft(); - rTrap.left.p1.x = XDoubleToFixed( fXL1 ); - const double fXR1 = pB2DTrap->getTopXRight(); - rTrap.right.p1.x = XDoubleToFixed( fXR1 ); - const double fXL2 = pB2DTrap->getBottomXLeft(); - rTrap.left.p2.x = XDoubleToFixed( fXL2 ); - const double fXR2 = pB2DTrap->getBottomXRight(); - rTrap.right.p2.x = XDoubleToFixed( fXR2 ); - } - - // get xrender Picture for polygon foreground - // TODO: cache it like the target picture which uses GetXRenderPicture() - XRenderPeer& rRenderPeer = XRenderPeer::GetInstance(); - SalDisplay::RenderEntry& rEntry = GetDisplay()->GetRenderEntries( m_nXScreen )[ 32 ]; - if( !rEntry.m_aPicture ) - { - Display* pXDisplay = GetXDisplay(); - - rEntry.m_aPixmap = limitXCreatePixmap( pXDisplay, hDrawable_, 1, 1, 32 ); - XRenderPictureAttributes aAttr; - aAttr.repeat = int(true); - - XRenderPictFormat* pXRPF = rRenderPeer.FindStandardFormat( PictStandardARGB32 ); - rEntry.m_aPicture = rRenderPeer.CreatePicture( rEntry.m_aPixmap, pXRPF, CPRepeat, &aAttr ); - } - - // set polygon foreground color and opacity - XRenderColor aRenderColor = GetXRenderColor( nBrushColor_ , fTransparency ); - rRenderPeer.FillRectangle( PictOpSrc, rEntry.m_aPicture, &aRenderColor, 0, 0, 1, 1 ); - - // set clipping - // TODO: move into GetXRenderPicture? - if( mpClipRegion && !XEmptyRegion( mpClipRegion ) ) - rRenderPeer.SetPictureClipRegion( aDstPic, mpClipRegion ); - - // render the trapezoids - const XRenderPictFormat* pMaskFormat = rRenderPeer.GetStandardFormatA8(); - rRenderPeer.CompositeTrapezoids( PictOpOver, - rEntry.m_aPicture, aDstPic, pMaskFormat, 0, 0, &aTrapVector[0], aTrapVector.size() ); - - return true; + return mpImpl->drawPolyPolygon( rOrigPolyPoly, fTransparency ); } bool X11SalGraphics::drawPolyLine( @@ -1137,84 +466,18 @@ bool X11SalGraphics::drawPolyLine( basegfx::B2DLineJoin eLineJoin, com::sun::star::drawing::LineCap eLineCap) { - const bool bIsHairline = (rLineWidth.getX() == rLineWidth.getY()) && (rLineWidth.getX() <= 1.2); - - // #i101491# - if( !bIsHairline && (rPolygon.count() > 1000) ) - { - // the used basegfx::tools::createAreaGeometry is simply too - // expensive with very big polygons; fallback to caller (who - // should use ImplLineConverter normally) - // AW: ImplLineConverter had to be removed since it does not even - // know LineJoins, so the fallback will now prepare the line geometry - // the same way. - return false; - } - - // temporarily adjust brush color to pen color - // since the line is drawn as an area-polygon - const SalColor aKeepBrushColor = nBrushColor_; - nBrushColor_ = nPenColor_; - - // #i11575#desc5#b adjust B2D tesselation result to raster positions - basegfx::B2DPolygon aPolygon = rPolygon; - const double fHalfWidth = 0.5 * rLineWidth.getX(); - - // #i122456# This is probably thought to happen to align hairlines to pixel positions, so - // it should be a 0.5 translation, not more. It will definitely go wrong with fat lines - aPolygon.transform( basegfx::tools::createTranslateB2DHomMatrix(0.5, 0.5) ); - - // shortcut for hairline drawing to improve performance - bool bDrawnOk = true; - if( bIsHairline ) - { - // hairlines can benefit from a simplified tesselation - // e.g. for hairlines the linejoin style can be ignored - basegfx::B2DTrapezoidVector aB2DTrapVector; - basegfx::tools::createLineTrapezoidFromB2DPolygon( aB2DTrapVector, aPolygon, rLineWidth.getX() ); - - // draw tesselation result - const int nTrapCount = aB2DTrapVector.size(); - if( nTrapCount > 0 ) - bDrawnOk = drawFilledTrapezoids( &aB2DTrapVector[0], nTrapCount, fTransparency ); - - // restore the original brush GC - nBrushColor_ = aKeepBrushColor; - return bDrawnOk; - } - - // get the area polygon for the line polygon - if( (rLineWidth.getX() != rLineWidth.getY()) - && !basegfx::fTools::equalZero( rLineWidth.getY() ) ) - { - // prepare for createAreaGeometry() with anisotropic linewidth - aPolygon.transform( basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getX() / rLineWidth.getY())); - } - - // create the area-polygon for the line - const basegfx::B2DPolyPolygon aAreaPolyPoly( basegfx::tools::createAreaGeometry(aPolygon, fHalfWidth, eLineJoin, eLineCap) ); - - if( (rLineWidth.getX() != rLineWidth.getY()) - && !basegfx::fTools::equalZero( rLineWidth.getX() ) ) - { - // postprocess createAreaGeometry() for anisotropic linewidth - aPolygon.transform(basegfx::tools::createScaleB2DHomMatrix(1.0, rLineWidth.getY() / rLineWidth.getX())); - } + return mpImpl->drawPolyLine( rPolygon, fTransparency, rLineWidth, + eLineJoin, eLineCap ); +} - // draw each area polypolygon component individually - // to emulate the polypolygon winding rule "non-zero" - const int nPolyCount = aAreaPolyPoly.count(); - for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx ) - { - const ::basegfx::B2DPolyPolygon aOnePoly( aAreaPolyPoly.getB2DPolygon( nPolyIdx ) ); - bDrawnOk = drawPolyPolygon( aOnePoly, fTransparency ); - if( !bDrawnOk ) - break; - } +bool X11SalGraphics::drawGradient(const tools::PolyPolygon& rPoly, const Gradient& rGradient) +{ + return mpImpl->drawGradient(rPoly, rGradient); +} - // restore the original brush GC - nBrushColor_ = aKeepBrushColor; - return bDrawnOk; +bool X11SalGraphics::SwapBuffers() +{ + return mpImpl->swapBuffers(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/gdi/salgdi2.cxx b/vcl/unx/generic/gdi/salgdi2.cxx index 8059449c1371..63ab32b8981d 100644 --- a/vcl/unx/generic/gdi/salgdi2.cxx +++ b/vcl/unx/generic/gdi/salgdi2.cxx @@ -19,9 +19,11 @@ #include <stdio.h> #include <poll.h> +#include "salgdiimpl.hxx" #include "vcl/salbtype.hxx" +#include "unx/pixmap.hxx" #include "unx/salunx.h" #include "unx/saldata.hxx" #include "unx/saldisp.hxx" @@ -29,6 +31,7 @@ #include "unx/salgdi.h" #include "unx/salframe.h" #include "unx/salvd.h" +#include "unx/x11/x11gdiimpl.h" #include <unx/x11/xlimits.hxx> #include "xrender_peer.hxx" @@ -38,20 +41,6 @@ #include <outdata.hxx> #include <boost/scoped_ptr.hpp> -#undef SALGDI2_TESTTRANS - -#if (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS -#define DBG_TESTTRANS( _def_drawable ) \ -{ \ - XCopyArea( pXDisp, _def_drawable, aDrawable, GetCopyGC(), \ - 0, 0, \ - rPosAry.mnDestWidth, rPosAry.mnDestHeight, \ - 0, 0 ); \ -} -#else // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS -#define DBG_TESTTRANS( _def_drawable ) -#endif // (OSL_DEBUG_LEVEL > 1) && defined SALGDI2_TESTTRANS - void X11SalGraphics::CopyScreenArea( Display* pDisplay, Drawable aSrc, SalX11Screen nXScreenSrc, int nSrcDepth, Drawable aDest, SalX11Screen nXScreenDest, int nDestDepth, @@ -94,131 +83,17 @@ void X11SalGraphics::CopyScreenArea( Display* pDisplay, } } -GC X11SalGraphics::CreateGC( Drawable hDrawable, unsigned long nMask ) -{ - XGCValues values; - - values.graphics_exposures = False; - values.foreground = m_pColormap->GetBlackPixel() - ^ m_pColormap->GetWhitePixel(); - values.function = GXxor; - values.line_width = 1; - values.fill_style = FillStippled; - values.stipple = GetDisplay()->GetInvert50( m_nXScreen ); - values.subwindow_mode = ClipByChildren; - - return XCreateGC( GetXDisplay(), hDrawable, nMask | GCSubwindowMode, &values ); -} - -inline GC X11SalGraphics::GetMonoGC( Pixmap hPixmap ) -{ - if( !pMonoGC_ ) - pMonoGC_ = CreateGC( hPixmap ); - - if( !bMonoGC_ ) - { - SetClipRegion( pMonoGC_ ); - bMonoGC_ = true; - } - - return pMonoGC_; -} - -inline GC X11SalGraphics::GetCopyGC() +X11Pixmap* X11SalGraphics::GetPixmapFromScreen( const Rectangle& rRect ) { - if( bXORMode_ ) return GetInvertGC(); - - if( !pCopyGC_ ) - pCopyGC_ = CreateGC( GetDrawable() ); - - if( !bCopyGC_ ) - { - SetClipRegion( pCopyGC_ ); - bCopyGC_ = true; - } - return pCopyGC_; + X11GraphicsImpl* pImpl = dynamic_cast<X11GraphicsImpl*>(mpImpl.get()); + return pImpl->GetPixmapFromScreen( rRect ); } -GC X11SalGraphics::GetInvertGC() +bool X11SalGraphics::RenderPixmapToScreen( X11Pixmap* pPixmap, int nX, int nY ) { - if( !pInvertGC_ ) - pInvertGC_ = CreateGC( GetDrawable(), - GCGraphicsExposures - | GCForeground - | GCFunction - | GCLineWidth ); - - if( !bInvertGC_ ) - { - SetClipRegion( pInvertGC_ ); - bInvertGC_ = true; - } - return pInvertGC_; -} - -GC X11SalGraphics::GetInvert50GC() -{ - if( !pInvert50GC_ ) - { - XGCValues values; - - values.graphics_exposures = False; - values.foreground = m_pColormap->GetWhitePixel(); - values.background = m_pColormap->GetBlackPixel(); - values.function = GXinvert; - values.line_width = 1; - values.line_style = LineSolid; - unsigned long nValueMask = - GCGraphicsExposures - | GCForeground - | GCBackground - | GCFunction - | GCLineWidth - | GCLineStyle - | GCFillStyle - | GCStipple; - - char* pEnv = getenv( "SAL_DO_NOT_USE_INVERT50" ); - if( pEnv && ! strcasecmp( pEnv, "true" ) ) - { - values.fill_style = FillSolid; - nValueMask &= ~ GCStipple; - } - else - { - values.fill_style = FillStippled; - values.stipple = GetDisplay()->GetInvert50( m_nXScreen ); - } - - pInvert50GC_ = XCreateGC( GetXDisplay(), GetDrawable(), - nValueMask, - &values ); - } - - if( !bInvert50GC_ ) - { - SetClipRegion( pInvert50GC_ ); - bInvert50GC_ = true; - } - return pInvert50GC_; -} - -inline GC X11SalGraphics::GetStippleGC() -{ - if( !pStippleGC_ ) - pStippleGC_ = CreateGC( GetDrawable(), - GCGraphicsExposures - | GCFillStyle - | GCLineWidth ); - - if( !bStippleGC_ ) - { - XSetFunction( GetXDisplay(), pStippleGC_, bXORMode_ ? GXxor : GXcopy ); - SetClipRegion( pStippleGC_ ); - bStippleGC_ = true; - } - - return pStippleGC_; + SAL_INFO( "vcl", "RenderPixmapToScreen" ); + X11GraphicsImpl* pImpl = dynamic_cast<X11GraphicsImpl*>(mpImpl.get()); + return pImpl->RenderPixmapToScreen( pPixmap, nX, nY ); } extern "C" @@ -281,456 +156,33 @@ void X11SalGraphics::YieldGraphicsExpose() void X11SalGraphics::copyBits( const SalTwoRect& rPosAry, SalGraphics *pSSrcGraphics ) { - X11SalGraphics* pSrcGraphics = pSSrcGraphics - ? static_cast<X11SalGraphics*>(pSSrcGraphics) - : this; - - if( rPosAry.mnSrcWidth <= 0 - || rPosAry.mnSrcHeight <= 0 - || rPosAry.mnDestWidth <= 0 - || rPosAry.mnDestHeight <= 0 ) - { - return; - } - - int n; - if( pSrcGraphics == this ) - { - n = 2; - } - else if( pSrcGraphics->bWindow_ ) - { - // window or compatible virtual device - if( pSrcGraphics->GetDisplay() == GetDisplay() && - pSrcGraphics->m_nXScreen == m_nXScreen && - pSrcGraphics->GetVisual().GetDepth() == GetVisual().GetDepth() - ) - n = 2; // same Display - else - n = 1; // printer or other display - } - else if( pSrcGraphics->bVirDev_ ) - { - // printer compatible virtual device - if( bPrinter_ ) - n = 2; // printer or compatible virtual device == same display - else - n = 1; // window or compatible virtual device - } - else - n = 0; - - if( n == 2 - && rPosAry.mnSrcWidth == rPosAry.mnDestWidth - && rPosAry.mnSrcHeight == rPosAry.mnDestHeight - ) - { - // #i60699# Need to generate graphics exposures (to repaint - // obscured areas beneath overlapping windows), src and dest - // are the same window. - const bool bNeedGraphicsExposures( pSrcGraphics == this && - !bVirDev_ && - pSrcGraphics->bWindow_ ); - - GC pCopyGC; - - if( bXORMode_ - && !pSrcGraphics->bVirDev_ - && (GetDisplay()->GetProperties() & PROPERTY_BUG_XCopyArea_GXxor) ) - { - Pixmap hPixmap = limitXCreatePixmap( GetXDisplay(), - pSrcGraphics->GetDrawable(), // source - rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, - pSrcGraphics->GetBitCount() ); - - pCopyGC = GetDisplay()->GetCopyGC( m_nXScreen ); - - if( bNeedGraphicsExposures ) - XSetGraphicsExposures( GetXDisplay(), - pCopyGC, - True ); - - XCopyArea( GetXDisplay(), - pSrcGraphics->GetDrawable(), // source - hPixmap, // destination - pCopyGC, // no clipping - rPosAry.mnSrcX, rPosAry.mnSrcY, - rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, - 0, 0 ); // destination - XCopyArea( GetXDisplay(), - hPixmap, // source - GetDrawable(), // destination - GetInvertGC(), // destination clipping - 0, 0, // source - rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, - rPosAry.mnDestX, rPosAry.mnDestY ); - XFreePixmap( GetXDisplay(), hPixmap ); - } - else - { - pCopyGC = GetCopyGC(); - - if( bNeedGraphicsExposures ) - XSetGraphicsExposures( GetXDisplay(), - pCopyGC, - True ); - - XCopyArea( GetXDisplay(), - pSrcGraphics->GetDrawable(), // source - GetDrawable(), // destination - pCopyGC, // destination clipping - rPosAry.mnSrcX, rPosAry.mnSrcY, - rPosAry.mnSrcWidth, rPosAry.mnSrcHeight, - rPosAry.mnDestX, rPosAry.mnDestY ); - } - - if( bNeedGraphicsExposures ) - { - YieldGraphicsExpose(); - - if( pCopyGC ) - XSetGraphicsExposures( GetXDisplay(), - pCopyGC, - False ); - } - } - else if( n ) - { - // #i60699# No chance to handle graphics exposures - we copy - // to a temp bitmap first, into which no repaints are - // technically possible. - boost::scoped_ptr<SalBitmap> pDDB(pSrcGraphics->getBitmap( rPosAry.mnSrcX, - rPosAry.mnSrcY, - rPosAry.mnSrcWidth, - rPosAry.mnSrcHeight )); - - if( !pDDB ) - { - stderr0( "SalGraphics::CopyBits !pSrcGraphics->GetBitmap()\n" ); - return; - } - - SalTwoRect aPosAry( rPosAry ); - - aPosAry.mnSrcX = 0, aPosAry.mnSrcY = 0; - drawBitmap( aPosAry, *pDDB ); - } - else { - stderr0( "X11SalGraphics::CopyBits from Printer not yet implemented\n" ); - } + mpImpl->copyBits( rPosAry, pSSrcGraphics ); } void X11SalGraphics::copyArea ( long nDestX, long nDestY, long nSrcX, long nSrcY, long nSrcWidth, long nSrcHeight, - sal_uInt16 ) + sal_uInt16 n ) { - SalTwoRect aPosAry; - - aPosAry.mnDestX = nDestX; - aPosAry.mnDestY = nDestY; - aPosAry.mnDestWidth = nSrcWidth; - aPosAry.mnDestHeight = nSrcHeight; - - aPosAry.mnSrcX = nSrcX; - aPosAry.mnSrcY = nSrcY; - aPosAry.mnSrcWidth = nSrcWidth; - aPosAry.mnSrcHeight = nSrcHeight; - - copyBits ( aPosAry, 0 ); -} - -namespace -{ - void setForeBack(XGCValues& rValues, const SalColormap& rColMap, const SalBitmap& rSalBitmap) - { - rValues.foreground = rColMap.GetWhitePixel(); - rValues.background = rColMap.GetBlackPixel(); - - //fdo#33455 and fdo#80160 handle 1 bit depth pngs with palette entries - //to set fore/back colors - SalBitmap& rBitmap = const_cast<SalBitmap&>(rSalBitmap); - if (BitmapBuffer* pBitmapBuffer = rBitmap.AcquireBuffer(true)) - { - const BitmapPalette& rPalette = pBitmapBuffer->maPalette; - if (rPalette.GetEntryCount() == 2) - { - const BitmapColor aWhite(rPalette[rPalette.GetBestIndex(Color(COL_WHITE))]); - rValues.foreground = rColMap.GetPixel(ImplColorToSal(aWhite)); - - const BitmapColor aBlack(rPalette[rPalette.GetBestIndex(Color(COL_BLACK))]); - rValues.background = rColMap.GetPixel(ImplColorToSal(aBlack)); - } - rBitmap.ReleaseBuffer(pBitmapBuffer, true); - } - } + mpImpl->copyArea( nDestX, nDestY, nSrcX, nSrcY, nSrcWidth, nSrcHeight, n ); } void X11SalGraphics::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) { - const SalDisplay* pSalDisp = GetDisplay(); - Display* pXDisp = pSalDisp->GetDisplay(); - const Drawable aDrawable( GetDrawable() ); - const SalColormap& rColMap = pSalDisp->GetColormap( m_nXScreen ); - const long nDepth = GetDisplay()->GetVisual( m_nXScreen ).GetDepth(); - GC aGC( GetCopyGC() ); - XGCValues aOldVal, aNewVal; - int nValues = GCForeground | GCBackground; - - if( rSalBitmap.GetBitCount() == 1 ) - { - // set foreground/background values for 1Bit bitmaps - XGetGCValues( pXDisp, aGC, nValues, &aOldVal ); - setForeBack(aNewVal, rColMap, rSalBitmap); - XChangeGC( pXDisp, aGC, nValues, &aNewVal ); - } - - static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aDrawable, m_nXScreen, nDepth, rPosAry, aGC ); - - if( rSalBitmap.GetBitCount() == 1 ) - XChangeGC( pXDisp, aGC, nValues, &aOldVal ); - XFlush( pXDisp ); + mpImpl->drawBitmap( rPosAry, rSalBitmap ); } void X11SalGraphics::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSrcBitmap, const SalBitmap& rMaskBitmap ) { - DBG_ASSERT( !bPrinter_, "Drawing of transparent bitmaps on printer devices is strictly forbidden" ); - - // decide if alpha masking or transparency masking is needed - BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rMaskBitmap).AcquireBuffer( true ); - if( pAlphaBuffer != NULL ) - { - int nMaskFormat = pAlphaBuffer->mnFormat; - const_cast<SalBitmap&>(rMaskBitmap).ReleaseBuffer( pAlphaBuffer, true ); - if( nMaskFormat == BMP_FORMAT_8BIT_PAL ) - drawAlphaBitmap( rPosAry, rSrcBitmap, rMaskBitmap ); - } - - drawMaskedBitmap( rPosAry, rSrcBitmap, rMaskBitmap ); -} - -void X11SalGraphics::drawMaskedBitmap( const SalTwoRect& rPosAry, - const SalBitmap& rSalBitmap, - const SalBitmap& rTransBitmap ) -{ - const SalDisplay* pSalDisp = GetDisplay(); - Display* pXDisp = pSalDisp->GetDisplay(); - Drawable aDrawable( GetDrawable() ); - - // figure work mode depth. If this is a VDev Drawable, use its - // bitdepth to create pixmaps for, otherwise, XCopyArea will - // refuse to work. - const sal_uInt16 nDepth( m_pVDev ? - m_pVDev->GetDepth() : - pSalDisp->GetVisual( m_nXScreen ).GetDepth() ); - Pixmap aFG( limitXCreatePixmap( pXDisp, aDrawable, rPosAry.mnDestWidth, - rPosAry.mnDestHeight, nDepth ) ); - Pixmap aBG( limitXCreatePixmap( pXDisp, aDrawable, rPosAry.mnDestWidth, - rPosAry.mnDestHeight, nDepth ) ); - - if( aFG && aBG ) - { - GC aTmpGC; - XGCValues aValues; - setForeBack(aValues, pSalDisp->GetColormap(m_nXScreen), rSalBitmap); - const int nValues = GCFunction | GCForeground | GCBackground; - SalTwoRect aTmpRect( rPosAry ); aTmpRect.mnDestX = aTmpRect.mnDestY = 0; - - // draw paint bitmap in pixmap #1 - aValues.function = GXcopy; - aTmpGC = XCreateGC( pXDisp, aFG, nValues, &aValues ); - static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aFG, m_nXScreen, nDepth, aTmpRect, aTmpGC ); - DBG_TESTTRANS( aFG ); - - // draw background in pixmap #2 - XCopyArea( pXDisp, aDrawable, aBG, aTmpGC, - rPosAry.mnDestX, rPosAry.mnDestY, - rPosAry.mnDestWidth, rPosAry.mnDestHeight, - 0, 0 ); - - DBG_TESTTRANS( aBG ); - - // mask out paint bitmap in pixmap #1 (transparent areas 0) - aValues.function = GXand, aValues.foreground = 0x00000000, aValues.background = 0xffffffff; - XChangeGC( pXDisp, aTmpGC, nValues, &aValues ); - static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aFG, m_nXScreen, 1, aTmpRect, aTmpGC ); - - DBG_TESTTRANS( aFG ); - - // #105055# For XOR mode, keep background behind bitmap intact - if( !bXORMode_ ) - { - // mask out background in pixmap #2 (nontransparent areas 0) - aValues.function = GXand, aValues.foreground = 0xffffffff, aValues.background = 0x00000000; - XChangeGC( pXDisp, aTmpGC, nValues, &aValues ); - static_cast<const X11SalBitmap&>(rTransBitmap).ImplDraw( aBG, m_nXScreen, 1, aTmpRect, aTmpGC ); - - DBG_TESTTRANS( aBG ); - } - - // merge pixmap #1 and pixmap #2 in pixmap #2 - aValues.function = GXxor, aValues.foreground = 0xffffffff, aValues.background = 0x00000000; - XChangeGC( pXDisp, aTmpGC, nValues, &aValues ); - XCopyArea( pXDisp, aFG, aBG, aTmpGC, - 0, 0, - rPosAry.mnDestWidth, rPosAry.mnDestHeight, - 0, 0 ); - DBG_TESTTRANS( aBG ); - - // #105055# Disable XOR temporarily - bool bOldXORMode( bXORMode_ ); - bXORMode_ = false; - - // copy pixmap #2 (result) to background - XCopyArea( pXDisp, aBG, aDrawable, GetCopyGC(), - 0, 0, - rPosAry.mnDestWidth, rPosAry.mnDestHeight, - rPosAry.mnDestX, rPosAry.mnDestY ); - - DBG_TESTTRANS( aBG ); - - bXORMode_ = bOldXORMode; - - XFreeGC( pXDisp, aTmpGC ); - XFlush( pXDisp ); - } - else - drawBitmap( rPosAry, rSalBitmap ); - - if( aFG ) - XFreePixmap( pXDisp, aFG ); - - if( aBG ) - XFreePixmap( pXDisp, aBG ); + mpImpl->drawBitmap( rPosAry, rSrcBitmap, rMaskBitmap ); } bool X11SalGraphics::drawAlphaBitmap( const SalTwoRect& rTR, const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp ) { - // non 8-bit alpha not implemented yet - if( rAlphaBmp.GetBitCount() != 8 ) - return false; - - // horizontal mirroring not implemented yet - if( rTR.mnDestWidth < 0 ) - return false; - - // stretched conversion is not implemented yet - if( rTR.mnDestWidth != rTR.mnSrcWidth ) - return false; - if( rTR.mnDestHeight!= rTR.mnSrcHeight ) - return false; - - // create destination picture - Picture aDstPic = GetXRenderPicture(); - if( !aDstPic ) - return false; - - const SalDisplay* pSalDisp = GetDisplay(); - const SalVisual& rSalVis = pSalDisp->GetVisual( m_nXScreen ); - Display* pXDisplay = pSalDisp->GetDisplay(); - - // create source Picture - int nDepth = m_pVDev ? m_pVDev->GetDepth() : rSalVis.GetDepth(); - const X11SalBitmap& rSrcX11Bmp = static_cast<const X11SalBitmap&>( rSrcBitmap ); - ImplSalDDB* pSrcDDB = rSrcX11Bmp.ImplGetDDB( hDrawable_, m_nXScreen, nDepth, rTR ); - if( !pSrcDDB ) - return false; - - //#i75249# workaround for ImplGetDDB() giving us back a different depth than - // we requested. E.g. mask pixmaps are always compatible with the drawable - // TODO: find an appropriate picture format for these cases - // then remove the workaround below and the one for #i75531# - if( nDepth != pSrcDDB->ImplGetDepth() ) - return false; - - Pixmap aSrcPM = pSrcDDB->ImplGetPixmap(); - if( !aSrcPM ) - return false; - - // create source picture - // TODO: use scoped picture - Visual* pSrcXVisual = rSalVis.GetVisual(); - XRenderPeer& rPeer = XRenderPeer::GetInstance(); - XRenderPictFormat* pSrcVisFmt = rPeer.FindVisualFormat( pSrcXVisual ); - if( !pSrcVisFmt ) - return false; - Picture aSrcPic = rPeer.CreatePicture( aSrcPM, pSrcVisFmt, 0, NULL ); - if( !aSrcPic ) - return false; - - // create alpha Picture - - // TODO: use SalX11Bitmap functionality and caching for the Alpha Pixmap - // problem is that they don't provide an 8bit Pixmap on a non-8bit display - BitmapBuffer* pAlphaBuffer = const_cast<SalBitmap&>(rAlphaBmp).AcquireBuffer( true ); - - // an XImage needs its data top_down - // TODO: avoid wrongly oriented images in upper layers! - const int nImageSize = pAlphaBuffer->mnHeight * pAlphaBuffer->mnScanlineSize; - const char* pSrcBits = (char*)pAlphaBuffer->mpBits; - char* pAlphaBits = new char[ nImageSize ]; - if( BMP_SCANLINE_ADJUSTMENT( pAlphaBuffer->mnFormat ) == BMP_FORMAT_TOP_DOWN ) - memcpy( pAlphaBits, pSrcBits, nImageSize ); - else - { - char* pDstBits = pAlphaBits + nImageSize; - const int nLineSize = pAlphaBuffer->mnScanlineSize; - for(; (pDstBits -= nLineSize) >= pAlphaBits; pSrcBits += nLineSize ) - memcpy( pDstBits, pSrcBits, nLineSize ); - } - - // the alpha values need to be inverted for XRender - // TODO: make upper layers use standard alpha - long* pLDst = (long*)pAlphaBits; - for( int i = nImageSize/sizeof(long); --i >= 0; ++pLDst ) - *pLDst = ~*pLDst; - - char* pCDst = (char*)pLDst; - for( int i = nImageSize & (sizeof(long)-1); --i >= 0; ++pCDst ) - *pCDst = ~*pCDst; - - const XRenderPictFormat* pAlphaFormat = rPeer.GetStandardFormatA8(); - XImage* pAlphaImg = XCreateImage( pXDisplay, pSrcXVisual, 8, ZPixmap, 0, - pAlphaBits, pAlphaBuffer->mnWidth, pAlphaBuffer->mnHeight, - pAlphaFormat->depth, pAlphaBuffer->mnScanlineSize ); - - Pixmap aAlphaPM = limitXCreatePixmap( pXDisplay, hDrawable_, - rTR.mnDestWidth, rTR.mnDestHeight, 8 ); - - XGCValues aAlphaGCV; - aAlphaGCV.function = GXcopy; - GC aAlphaGC = XCreateGC( pXDisplay, aAlphaPM, GCFunction, &aAlphaGCV ); - XPutImage( pXDisplay, aAlphaPM, aAlphaGC, pAlphaImg, - rTR.mnSrcX, rTR.mnSrcY, 0, 0, rTR.mnDestWidth, rTR.mnDestHeight ); - XFreeGC( pXDisplay, aAlphaGC ); - XFree( pAlphaImg ); - if( pAlphaBits != (char*)pAlphaBuffer->mpBits ) - delete[] pAlphaBits; - - const_cast<SalBitmap&>(rAlphaBmp).ReleaseBuffer( pAlphaBuffer, true ); - - XRenderPictureAttributes aAttr; - aAttr.repeat = int(true); - Picture aAlphaPic = rPeer.CreatePicture( aAlphaPM, pAlphaFormat, CPRepeat, &aAttr ); - if( !aAlphaPic ) - return false; - - // set clipping - if( mpClipRegion && !XEmptyRegion( mpClipRegion ) ) - rPeer.SetPictureClipRegion( aDstPic, mpClipRegion ); - - // paint source * mask over destination picture - rPeer.CompositePicture( PictOpOver, aSrcPic, aAlphaPic, aDstPic, - rTR.mnSrcX, rTR.mnSrcY, 0, 0, - rTR.mnDestX, rTR.mnDestY, rTR.mnDestWidth, rTR.mnDestHeight ); - - rPeer.FreePicture( aAlphaPic ); - XFreePixmap(pXDisplay, aAlphaPM); - rPeer.FreePicture( aSrcPic ); - return true; + return mpImpl->drawAlphaBitmap( rTR, rSrcBitmap, rAlphaBmp ); } bool X11SalGraphics::drawTransformedBitmap( @@ -740,191 +192,37 @@ bool X11SalGraphics::drawTransformedBitmap( const SalBitmap& rSourceBitmap, const SalBitmap* pAlphaBitmap) { - // here direct support for transformed bitmaps can be impemented - (void)rNull; (void)rX; (void)rY; (void)rSourceBitmap; (void)pAlphaBitmap; - return false; + return mpImpl->drawTransformedBitmap( rNull, rX, rY, rSourceBitmap, pAlphaBitmap ); } bool X11SalGraphics::drawAlphaRect( long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency ) { - if( ! m_pFrame && ! m_pVDev ) - return false; - - if( bPenGC_ || !bBrushGC_ || bXORMode_ ) - return false; // can only perform solid fills without XOR. - - if( m_pVDev && m_pVDev->GetDepth() < 8 ) - return false; - - Picture aDstPic = GetXRenderPicture(); - if( !aDstPic ) - return false; - - const double fTransparency = (100 - nTransparency) * (1.0/100); - const XRenderColor aRenderColor = GetXRenderColor( nBrushColor_ , fTransparency); - - XRenderPeer& rPeer = XRenderPeer::GetInstance(); - rPeer.FillRectangle( PictOpOver, - aDstPic, - &aRenderColor, - nX, nY, - nWidth, nHeight ); - - return true; + return mpImpl->drawAlphaRect( nX, nY, nWidth, nHeight, nTransparency ); } -void X11SalGraphics::drawBitmap( const SalTwoRect&, - const SalBitmap&, - SalColor ) +void X11SalGraphics::drawBitmap( const SalTwoRect& rRect, + const SalBitmap& rBitmap, + SalColor nColor ) { - OSL_FAIL( "::DrawBitmap with transparent color not supported" ); + mpImpl->drawBitmap( rRect, rBitmap, nColor ); } void X11SalGraphics::drawMask( const SalTwoRect& rPosAry, const SalBitmap &rSalBitmap, SalColor nMaskColor ) { - const SalDisplay* pSalDisp = GetDisplay(); - Display* pXDisp = pSalDisp->GetDisplay(); - Drawable aDrawable( GetDrawable() ); - Pixmap aStipple( limitXCreatePixmap( pXDisp, aDrawable, - rPosAry.mnDestWidth, - rPosAry.mnDestHeight, 1 ) ); - - if( aStipple ) - { - SalTwoRect aTwoRect( rPosAry ); aTwoRect.mnDestX = aTwoRect.mnDestY = 0; - GC aTmpGC; - XGCValues aValues; - - // create a stipple bitmap first (set bits are changed to unset bits and vice versa) - aValues.function = GXcopyInverted; - aValues.foreground = 1, aValues.background = 0; - aTmpGC = XCreateGC( pXDisp, aStipple, GCFunction | GCForeground | GCBackground, &aValues ); - static_cast<const X11SalBitmap&>(rSalBitmap).ImplDraw( aStipple, m_nXScreen, 1, aTwoRect, aTmpGC ); - - XFreeGC( pXDisp, aTmpGC ); - - // Set stipple and draw rectangle - GC aStippleGC( GetStippleGC() ); - int nX = rPosAry.mnDestX, nY = rPosAry.mnDestY; - - XSetStipple( pXDisp, aStippleGC, aStipple ); - XSetTSOrigin( pXDisp, aStippleGC, nX, nY ); - XSetForeground( pXDisp, aStippleGC, GetPixel( nMaskColor ) ); - XFillRectangle( pXDisp, aDrawable, aStippleGC, - nX, nY, - rPosAry.mnDestWidth, rPosAry.mnDestHeight ); - XFreePixmap( pXDisp, aStipple ); - XFlush( pXDisp ); - } - else - drawBitmap( rPosAry, rSalBitmap ); + mpImpl->drawMask( rPosAry, rSalBitmap, nMaskColor ); } SalBitmap *X11SalGraphics::getBitmap( long nX, long nY, long nDX, long nDY ) { - if( bPrinter_ && !bVirDev_ ) - return NULL; - - bool bFakeWindowBG = false; - - // normalize - if( nDX < 0 ) - { - nX += nDX; - nDX = -nDX; - } - if ( nDY < 0 ) - { - nY += nDY; - nDY = -nDY; - } - - if( bWindow_ && !bVirDev_ ) - { - XWindowAttributes aAttrib; - - XGetWindowAttributes( GetXDisplay(), GetDrawable(), &aAttrib ); - if( aAttrib.map_state != IsViewable ) - bFakeWindowBG = true; - else - { - long nOrgDX = nDX, nOrgDY = nDY; - - // clip to window size - if ( nX < 0 ) - { - nDX += nX; - nX = 0; - } - if ( nY < 0 ) - { - nDY += nY; - nY = 0; - } - if( nX + nDX > aAttrib.width ) - nDX = aAttrib.width - nX; - if( nY + nDY > aAttrib.height ) - nDY = aAttrib.height - nY; - - // inside ? - if( nDX <= 0 || nDY <= 0 ) - { - bFakeWindowBG = true; - nDX = nOrgDX; - nDY = nOrgDY; - } - } - } - - X11SalBitmap* pSalBitmap = new X11SalBitmap; - sal_uInt16 nBitCount = GetBitCount(); - - if( &GetDisplay()->GetColormap( m_nXScreen ) != &GetColormap() ) - nBitCount = 1; - - if( ! bFakeWindowBG ) - pSalBitmap->ImplCreateFromDrawable( GetDrawable(), m_nXScreen, nBitCount, nX, nY, nDX, nDY ); - else - pSalBitmap->Create( Size( nDX, nDY ), (nBitCount > 8) ? 24 : nBitCount, BitmapPalette( nBitCount > 8 ? nBitCount : 0 ) ); - - return pSalBitmap; + return mpImpl->getBitmap( nX, nY, nDX, nDY ); } SalColor X11SalGraphics::getPixel( long nX, long nY ) { - if( bWindow_ && !bVirDev_ ) - { - XWindowAttributes aAttrib; - - XGetWindowAttributes( GetXDisplay(), GetDrawable(), &aAttrib ); - if( aAttrib.map_state != IsViewable ) - { - stderr0( "X11SalGraphics::GetPixel drawable not viewable\n" ); - return 0; - } - } - - XImage *pXImage = XGetImage( GetXDisplay(), - GetDrawable(), - nX, nY, - 1, 1, - AllPlanes, - ZPixmap ); - if( !pXImage ) - { - stderr0( "X11SalGraphics::GetPixel !XGetImage()\n" ); - return 0; - } - - XColor aXColor; - - aXColor.pixel = XGetPixel( pXImage, 0, 0 ); - XDestroyImage( pXImage ); - - return GetColormap().GetColor( aXColor.pixel ); + return mpImpl->getPixel( nX, nY ); } void X11SalGraphics::invert( long nX, @@ -933,25 +231,7 @@ void X11SalGraphics::invert( long nX, long nDY, SalInvert nFlags ) { - GC pGC; - if( SAL_INVERT_50 & nFlags ) - { - pGC = GetInvert50GC(); - XFillRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY ); - } - else - { - if ( SAL_INVERT_TRACKFRAME & nFlags ) - { - pGC = GetTrackingGC(); - XDrawRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY ); - } - else - { - pGC = GetInvertGC(); - XFillRectangle( GetXDisplay(), GetDrawable(), pGC, nX, nY, nDX, nDY ); - } - } + mpImpl->invert( nX, nY, nDX, nDY, nFlags ); } bool X11SalGraphics::supportsOperation( OutDevSupportType eType ) const diff --git a/vcl/unx/generic/gdi/salgdi3.cxx b/vcl/unx/generic/gdi/salgdi3.cxx index 3cd42cdd09a9..3f47712e68ba 100644 --- a/vcl/unx/generic/gdi/salgdi3.cxx +++ b/vcl/unx/generic/gdi/salgdi3.cxx @@ -36,7 +36,6 @@ #include <osl/module.hxx> #include <rtl/tencinfo.h> #include <sal/alloca.h> -#include <tools/debug.hxx> #include <tools/stream.hxx> #include <vcl/settings.hxx> #include <vcl/sysdata.hxx> @@ -59,31 +58,9 @@ #include "unx/salgdi.h" #include "unx/salunx.h" #include "unx/salvd.h" +#include "textrender.hxx" #include "xrender_peer.hxx" -#include <config_graphite.h> -#if ENABLE_GRAPHITE -#include <graphite_layout.hxx> -#include <graphite_serverfont.hxx> -#endif - -#include <cairo.h> -#include <cairo-ft.h> -#include <cairo-xlib.h> -#include <cairo-xlib-xrender.h> - -struct BOX -{ - short x1, x2, y1, y2; -}; -struct _XRegion -{ - long size; - long numRects; - BOX *rects; - BOX extents; -}; - // X11SalGraphics GC @@ -113,569 +90,80 @@ X11SalGraphics::GetFontGC() return pFontGC_; } -bool X11SalGraphics::setFont( const FontSelectPattern *pEntry, int nFallbackLevel ) -{ - // release all no longer needed font resources - for( int i = nFallbackLevel; i < MAX_FALLBACK; ++i ) - { - if( mpServerFont[i] != NULL ) - { - // old server side font is no longer referenced - GlyphCache::GetInstance().UncacheFont( *mpServerFont[i] ); - mpServerFont[i] = NULL; - } - } - - // return early if there is no new font - if( !pEntry ) - return false; - - // return early if this is not a valid font for this graphics - if( !pEntry->mpFontData ) - return false; - - // handle the request for a non-native X11-font => use the GlyphCache - ServerFont* pServerFont = GlyphCache::GetInstance().CacheFont( *pEntry ); - if( pServerFont != NULL ) - { - // ignore fonts with e.g. corrupted font files - if( !pServerFont->TestFont() ) - { - GlyphCache::GetInstance().UncacheFont( *pServerFont ); - return false; - } - - // register to use the font - mpServerFont[ nFallbackLevel ] = pServerFont; - - // apply font specific-hint settings if needed - // TODO: also disable it for reference devices - if( !bPrinter_ ) - { - ImplServerFontEntry* pSFE = static_cast<ImplServerFontEntry*>( pEntry->mpFontEntry ); - pSFE->HandleFontOptions(); - } - - return true; - } - - return false; -} - ImplFontOptions* GetFCFontOptions( const ImplFontAttributes& rFontAttributes, int nSize); -void ImplServerFontEntry::HandleFontOptions( void ) -{ - if( !mpServerFont ) - return; - if( !mbGotFontOptions ) - { - // get and cache the font options - mbGotFontOptions = true; - mpFontOptions.reset(GetFCFontOptions( *maFontSelData.mpFontData, - maFontSelData.mnHeight )); - } - // apply the font options - mpServerFont->SetFontOptions( mpFontOptions ); -} - -CairoFontsCache::LRUFonts CairoFontsCache::maLRUFonts; -int CairoFontsCache::mnRefCount = 0; - -CairoFontsCache::CairoFontsCache() -{ - ++mnRefCount; -} - -CairoFontsCache::~CairoFontsCache() -{ - --mnRefCount; - if (!mnRefCount && !maLRUFonts.empty()) - { - LRUFonts::iterator aEnd = maLRUFonts.end(); - for (LRUFonts::iterator aI = maLRUFonts.begin(); aI != aEnd; ++aI) - cairo_font_face_destroy((cairo_font_face_t*)aI->first); - } -} - -void CairoFontsCache::CacheFont(void *pFont, const CairoFontsCache::CacheId &rId) -{ - maLRUFonts.push_front( std::pair<void*, CairoFontsCache::CacheId>(pFont, rId) ); - if (maLRUFonts.size() > 8) - { - cairo_font_face_destroy((cairo_font_face_t*)maLRUFonts.back().first); - maLRUFonts.pop_back(); - } -} - -void* CairoFontsCache::FindCachedFont(const CairoFontsCache::CacheId &rId) -{ - LRUFonts::iterator aEnd = maLRUFonts.end(); - for (LRUFonts::iterator aI = maLRUFonts.begin(); aI != aEnd; ++aI) - if (aI->second == rId) - return aI->first; - return NULL; -} - -namespace -{ - bool hasRotation(int nRotation) - { - return nRotation != 0; - } - - double toRadian(int nDegree10th) - { - return (3600 - (nDegree10th)) * M_PI / 1800.0; - } -} - void X11SalGraphics::DrawServerFontLayout( const ServerFontLayout& rLayout ) { - std::vector<cairo_glyph_t> cairo_glyphs; - std::vector<int> glyph_extrarotation; - cairo_glyphs.reserve( 256 ); - - Point aPos; - sal_GlyphId aGlyphId; - for( int nStart = 0; rLayout.GetNextGlyphs( 1, &aGlyphId, aPos, nStart ); ) - { - cairo_glyph_t aGlyph; - aGlyph.index = aGlyphId & GF_IDXMASK; - aGlyph.x = aPos.X(); - aGlyph.y = aPos.Y(); - cairo_glyphs.push_back(aGlyph); - - switch (aGlyphId & GF_ROTMASK) - { - case GF_ROTL: // left - glyph_extrarotation.push_back(1); - break; - case GF_ROTR: // right - glyph_extrarotation.push_back(-1); - break; - default: - glyph_extrarotation.push_back(0); - break; - } - } - - if (cairo_glyphs.empty()) - return; - - // find a XRenderPictFormat compatible with the Drawable - XRenderPictFormat* pVisualFormat = GetXRenderFormat(); - - Display* pDisplay = GetXDisplay(); - - cairo_surface_t *surface; - - if (pVisualFormat) - { - surface = cairo_xlib_surface_create_with_xrender_format ( - pDisplay, hDrawable_, - ScreenOfDisplay(pDisplay, m_nXScreen.getXScreen()), - pVisualFormat, SAL_MAX_INT16, SAL_MAX_INT16); - } - else - { - surface = cairo_xlib_surface_create(pDisplay, hDrawable_, - GetVisual().visual, SAL_MAX_INT16, SAL_MAX_INT16); - } - - DBG_ASSERT( surface!=NULL, "no cairo surface for text" ); - if( !surface ) - return; - - /* - * It might be ideal to cache surface and cairo context between calls and - * only destroy it when the drawable changes, but to do that we need to at - * least change the SalFrame etc impls to dtor the SalGraphics *before* the - * destruction of the windows they reference - */ - cairo_t *cr = cairo_create(surface); - cairo_surface_destroy(surface); - - if (const void *pOptions = Application::GetSettings().GetStyleSettings().GetCairoFontOptions()) - cairo_set_font_options(cr, static_cast<const cairo_font_options_t*>(pOptions)); - - if( mpClipRegion && !XEmptyRegion( mpClipRegion ) ) - { - for (long i = 0; i < mpClipRegion->numRects; ++i) - { - cairo_rectangle(cr, - mpClipRegion->rects[i].x1, - mpClipRegion->rects[i].y1, - mpClipRegion->rects[i].x2 - mpClipRegion->rects[i].x1, - mpClipRegion->rects[i].y2 - mpClipRegion->rects[i].y1); - } - cairo_clip(cr); - } - - cairo_set_source_rgb(cr, - SALCOLOR_RED(nTextColor_)/255.0, - SALCOLOR_GREEN(nTextColor_)/255.0, - SALCOLOR_BLUE(nTextColor_)/255.0); - - ServerFont& rFont = rLayout.GetServerFont(); - - FT_Face aFace = rFont.GetFtFace(); - CairoFontsCache::CacheId aId; - aId.maFace = aFace; - aId.mpOptions = rFont.GetFontOptions().get(); - aId.mbEmbolden = rFont.NeedsArtificialBold(); - - cairo_matrix_t m; - const FontSelectPattern& rFSD = rFont.GetFontSelData(); - int nHeight = rFSD.mnHeight; - int nWidth = rFSD.mnWidth ? rFSD.mnWidth : nHeight; - - std::vector<int>::const_iterator aEnd = glyph_extrarotation.end(); - std::vector<int>::const_iterator aStart = glyph_extrarotation.begin(); - std::vector<int>::const_iterator aI = aStart; - while (aI != aEnd) - { - int nGlyphRotation = *aI; - - std::vector<int>::const_iterator aNext = std::find_if(aI+1, aEnd, hasRotation); - - size_t nStartIndex = std::distance(aStart, aI); - size_t nLen = std::distance(aI, aNext); - - aId.mbVerticalMetrics = nGlyphRotation != 0.0; - cairo_font_face_t* font_face = (cairo_font_face_t*)CairoFontsCache::FindCachedFont(aId); - if (!font_face) - { - const ImplFontOptions *pOptions = rFont.GetFontOptions().get(); - void *pPattern = pOptions ? pOptions->GetPattern(aFace, aId.mbEmbolden, aId.mbVerticalMetrics) : NULL; - if (pPattern) - font_face = cairo_ft_font_face_create_for_pattern(reinterpret_cast<FcPattern*>(pPattern)); - if (!font_face) - font_face = cairo_ft_font_face_create_for_ft_face(reinterpret_cast<FT_Face>(aFace), rFont.GetLoadFlags()); - CairoFontsCache::CacheFont(font_face, aId); - } - cairo_set_font_face(cr, font_face); - - cairo_set_font_size(cr, nHeight); - - cairo_matrix_init_identity(&m); - - if (rLayout.GetOrientation()) - cairo_matrix_rotate(&m, toRadian(rLayout.GetOrientation())); - - cairo_matrix_scale(&m, nWidth, nHeight); - - if (nGlyphRotation) - { - cairo_matrix_rotate(&m, toRadian(nGlyphRotation*900)); - - cairo_matrix_t em_square; - cairo_matrix_init_identity(&em_square); - cairo_get_matrix(cr, &em_square); - - cairo_matrix_scale(&em_square, aFace->units_per_EM, - aFace->units_per_EM); - cairo_set_matrix(cr, &em_square); - - cairo_font_extents_t font_extents; - cairo_font_extents(cr, &font_extents); - - cairo_matrix_init_identity(&em_square); - cairo_set_matrix(cr, &em_square); - - //gives the same positions as pre-cairo conversion, but I don't - //like them - double xdiff = 0.0; - double ydiff = 0.0; - if (nGlyphRotation == 1) - { - ydiff = font_extents.ascent/nHeight; - xdiff = -font_extents.descent/nHeight; - } - else if (nGlyphRotation == -1) - { - cairo_text_extents_t text_extents; - cairo_glyph_extents(cr, &cairo_glyphs[nStartIndex], nLen, - &text_extents); - - xdiff = -text_extents.x_advance/nHeight; - //to restore an apparent bug in the original X11 impl, replace - //nHeight with nWidth below - xdiff += font_extents.descent/nHeight; - } - cairo_matrix_translate(&m, xdiff, ydiff); - } - - if (rFont.NeedsArtificialItalic()) - { - cairo_matrix_t shear; - cairo_matrix_init_identity(&shear); - shear.xy = -shear.xx * 0x6000L / 0x10000L; - cairo_matrix_multiply(&m, &shear, &m); - } - - cairo_set_font_matrix(cr, &m); - cairo_show_glyphs(cr, &cairo_glyphs[nStartIndex], nLen); - -#if OSL_DEBUG_LEVEL > 2 - //draw origin - cairo_save (cr); - cairo_rectangle (cr, cairo_glyphs[nStartIndex].x, cairo_glyphs[nStartIndex].y, 5, 5); - cairo_set_source_rgba (cr, 1, 0, 0, 0.80); - cairo_fill (cr); - cairo_restore (cr); -#endif - - aI = aNext; - } - - cairo_destroy(cr); + mpTextRenderImpl->DrawServerFontLayout(rLayout); } const FontCharMapPtr X11SalGraphics::GetFontCharMap() const { - if( !mpServerFont[0] ) - return NULL; - - const FontCharMapPtr pFCMap = mpServerFont[0]->GetFontCharMap(); - return pFCMap; + return mpTextRenderImpl->GetFontCharMap(); } bool X11SalGraphics::GetFontCapabilities(vcl::FontCapabilities &rGetImplFontCapabilities) const { - if (!mpServerFont[0]) - return false; - return mpServerFont[0]->GetFontCapabilities(rGetImplFontCapabilities); + return mpTextRenderImpl->GetFontCapabilities(rGetImplFontCapabilities); } // SalGraphics sal_uInt16 X11SalGraphics::SetFont( FontSelectPattern *pEntry, int nFallbackLevel ) { - sal_uInt16 nRetVal = 0; - if( !setFont( pEntry, nFallbackLevel ) ) - nRetVal |= SAL_SETFONT_BADFONT; - if( bPrinter_ || (mpServerFont[ nFallbackLevel ] != NULL) ) - nRetVal |= SAL_SETFONT_USEDRAWTEXTARRAY; - return nRetVal; + return mpTextRenderImpl->SetFont(pEntry, nFallbackLevel); } void X11SalGraphics::SetTextColor( SalColor nSalColor ) { - if( nTextColor_ != nSalColor ) - { - nTextColor_ = nSalColor; - nTextPixel_ = GetPixel( nSalColor ); - bFontGC_ = false; - } + mpTextRenderImpl->SetTextColor(nSalColor); + nTextPixel_ = GetPixel( nSalColor ); + bFontGC_ = false; } bool X11SalGraphics::AddTempDevFont( PhysicalFontCollection* pFontCollection, const OUString& rFileURL, const OUString& rFontName ) { - // inform PSP font manager - OUString aUSystemPath; - OSL_VERIFY( !osl::FileBase::getSystemPathFromFileURL( rFileURL, aUSystemPath ) ); - rtl_TextEncoding aEncoding = osl_getThreadTextEncoding(); - OString aOFileName( OUStringToOString( aUSystemPath, aEncoding ) ); - psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); - std::vector<psp::fontID> aFontIds = rMgr.addFontFile( aOFileName ); - if( aFontIds.empty() ) - return false; - - GlyphCache& rGC = X11GlyphCache::GetInstance(); - - for (std::vector<psp::fontID>::iterator aI = aFontIds.begin(), aEnd = aFontIds.end(); aI != aEnd; ++aI) - { - // prepare font data - psp::FastPrintFontInfo aInfo; - rMgr.getFontFastInfo( *aI, aInfo ); - aInfo.m_aFamilyName = rFontName; - - // inform glyph cache of new font - ImplDevFontAttributes aDFA = GenPspGraphics::Info2DevFontAttributes( aInfo ); - aDFA.mnQuality += 5800; - - int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID ); - - const OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID ); - rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA ); - } - - // announce new font to device's font list - rGC.AnnounceFonts( pFontCollection ); - return true; + return mpTextRenderImpl->AddTempDevFont(pFontCollection, rFileURL, rFontName); } void X11SalGraphics::ClearDevFontCache() { - X11GlyphCache& rGC = X11GlyphCache::GetInstance(); - rGC.ClearFontCache(); + mpTextRenderImpl->ClearDevFontCache(); } void X11SalGraphics::GetDevFontList( PhysicalFontCollection* pFontCollection ) { - // prepare the GlyphCache using psprint's font infos - X11GlyphCache& rGC = X11GlyphCache::GetInstance(); - - psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); - ::std::list< psp::fontID > aList; - ::std::list< psp::fontID >::iterator it; - psp::FastPrintFontInfo aInfo; - rMgr.getFontList( aList ); - for( it = aList.begin(); it != aList.end(); ++it ) - { - if( !rMgr.getFontFastInfo( *it, aInfo ) ) - continue; - - // normalize face number to the GlyphCache - int nFaceNum = rMgr.getFontFaceNumber( aInfo.m_nID ); - - // inform GlyphCache about this font provided by the PsPrint subsystem - ImplDevFontAttributes aDFA = GenPspGraphics::Info2DevFontAttributes( aInfo ); - aDFA.mnQuality += 4096; - const OString& rFileName = rMgr.getFontFileSysPath( aInfo.m_nID ); - rGC.AddFontFile( rFileName, nFaceNum, aInfo.m_nID, aDFA ); - } - - // announce glyphcache fonts - rGC.AnnounceFonts( pFontCollection ); - - // register platform specific font substitutions if available - SalGenericInstance::RegisterFontSubstitutors( pFontCollection ); - - ImplGetSVData()->maGDIData.mbNativeFontConfig = true; -} - -void cairosubcallback(void* pPattern) -{ - const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); - const void* pFontOptions = rStyleSettings.GetCairoFontOptions(); - if( !pFontOptions ) - return; - cairo_ft_font_options_substitute(static_cast<const cairo_font_options_t*>(pFontOptions), - static_cast<FcPattern*>(pPattern)); -} - -ImplFontOptions* GetFCFontOptions( const ImplFontAttributes& rFontAttributes, int nSize) -{ - psp::FastPrintFontInfo aInfo; - - aInfo.m_aFamilyName = rFontAttributes.GetFamilyName(); - aInfo.m_eItalic = rFontAttributes.GetSlant(); - aInfo.m_eWeight = rFontAttributes.GetWeight(); - aInfo.m_eWidth = rFontAttributes.GetWidthType(); - - const psp::PrintFontManager& rPFM = psp::PrintFontManager::get(); - return rPFM.getFontOptions(aInfo, nSize, cairosubcallback); + mpTextRenderImpl->GetDevFontList(pFontCollection); } void X11SalGraphics::GetFontMetric( ImplFontMetricData *pMetric, int nFallbackLevel ) { - if( nFallbackLevel >= MAX_FALLBACK ) - return; - - if( mpServerFont[nFallbackLevel] != NULL ) - { - long rDummyFactor; - mpServerFont[nFallbackLevel]->FetchFontMetric( *pMetric, rDummyFactor ); - } + mpTextRenderImpl->GetFontMetric(pMetric, nFallbackLevel); } bool X11SalGraphics::GetGlyphBoundRect( sal_GlyphId aGlyphId, Rectangle& rRect ) { - const int nLevel = aGlyphId >> GF_FONTSHIFT; - if( nLevel >= MAX_FALLBACK ) - return false; - - ServerFont* pSF = mpServerFont[ nLevel ]; - if( !pSF ) - return false; - - aGlyphId &= GF_IDXMASK; - const GlyphMetric& rGM = pSF->GetGlyphMetric(aGlyphId); - Rectangle aRect( rGM.GetOffset(), rGM.GetSize() ); - - if ( pSF->mnCos != 0x10000 && pSF->mnSin != 0 ) - { - double nCos = pSF->mnCos / 65536.0; - double nSin = pSF->mnSin / 65536.0; - rRect.Left() = nCos*aRect.Left() + nSin*aRect.Top(); - rRect.Top() = -nSin*aRect.Left() - nCos*aRect.Top(); - - rRect.Right() = nCos*aRect.Right() + nSin*aRect.Bottom(); - rRect.Bottom() = -nSin*aRect.Right() - nCos*aRect.Bottom(); - } - else - rRect = aRect; - - return true; + return mpTextRenderImpl->GetGlyphBoundRect(aGlyphId, rRect); } bool X11SalGraphics::GetGlyphOutline( sal_GlyphId aGlyphId, ::basegfx::B2DPolyPolygon& rPolyPoly ) { - const int nLevel = aGlyphId >> GF_FONTSHIFT; - if( nLevel >= MAX_FALLBACK ) - return false; - - ServerFont* pSF = mpServerFont[ nLevel ]; - if( !pSF ) - return false; - - aGlyphId &= GF_IDXMASK; - if( pSF->GetGlyphOutline( aGlyphId, rPolyPoly ) ) - return true; - - return false; + return mpTextRenderImpl->GetGlyphOutline(aGlyphId, rPolyPoly); } SalLayout* X11SalGraphics::GetTextLayout( ImplLayoutArgs& rArgs, int nFallbackLevel ) { - SalLayout* pLayout = NULL; - - if( mpServerFont[ nFallbackLevel ] - && !(rArgs.mnFlags & SAL_LAYOUT_DISABLE_GLYPH_PROCESSING) ) - { -#if ENABLE_GRAPHITE - // Is this a Graphite font? - if (!bDisableGraphite_ && - GraphiteServerFontLayout::IsGraphiteEnabledFont(*mpServerFont[nFallbackLevel])) - { - pLayout = new GraphiteServerFontLayout(*mpServerFont[nFallbackLevel]); - } - else -#endif - pLayout = new ServerFontLayout( *mpServerFont[ nFallbackLevel ] ); - } - - return pLayout; + return mpTextRenderImpl->GetTextLayout(rArgs, nFallbackLevel); } -SystemFontData X11SalGraphics::GetSysFontData( int nFallbacklevel ) const +SystemFontData X11SalGraphics::GetSysFontData( int nFallbackLevel ) const { - SystemFontData aSysFontData; - aSysFontData.nSize = sizeof( SystemFontData ); - aSysFontData.nFontId = 0; - - if (nFallbacklevel >= MAX_FALLBACK) nFallbacklevel = MAX_FALLBACK - 1; - if (nFallbacklevel < 0 ) nFallbacklevel = 0; - - if (mpServerFont[nFallbacklevel] != NULL) - { - ServerFont* rFont = mpServerFont[nFallbacklevel]; - aSysFontData.nFontId = rFont->GetFtFace(); - aSysFontData.nFontFlags = rFont->GetLoadFlags(); - aSysFontData.bFakeBold = rFont->NeedsArtificialBold(); - aSysFontData.bFakeItalic = rFont->NeedsArtificialItalic(); - aSysFontData.bAntialias = rFont->GetAntialiasAdvice(); - aSysFontData.bVerticalCharacterType = rFont->GetFontSelData().mbVertical; - } - - return aSysFontData; + return mpTextRenderImpl->GetSysFontData(nFallbackLevel); } bool X11SalGraphics::CreateFontSubset( @@ -688,49 +176,23 @@ bool X11SalGraphics::CreateFontSubset( FontSubsetInfo& rInfo ) { - // in this context the pFont->GetFontId() is a valid PSP - // font since they are the only ones left after the PDF - // export has filtered its list of subsettable fonts (for - // which this method was created). The correct way would - // be to have the GlyphCache search for the PhysicalFontFace pFont - psp::fontID aFont = pFont->GetFontId(); - - psp::PrintFontManager& rMgr = psp::PrintFontManager::get(); - bool bSuccess = rMgr.createFontSubset( rInfo, - aFont, - rToFile, - pGlyphIds, - pEncoding, - pWidths, - nGlyphCount ); - return bSuccess; + return mpTextRenderImpl->CreateFontSubset(rToFile, pFont, + pGlyphIds, pEncoding, pWidths, nGlyphCount, rInfo); } const void* X11SalGraphics::GetEmbedFontData( const PhysicalFontFace* pFont, const sal_Ucs* pUnicodes, sal_Int32* pWidths, FontSubsetInfo& rInfo, long* pDataLen ) { - // in this context the pFont->GetFontId() is a valid PSP - // font since they are the only ones left after the PDF - // export has filtered its list of subsettable fonts (for - // which this method was created). The correct way would - // be to have the GlyphCache search for the PhysicalFontFace pFont - psp::fontID aFont = pFont->GetFontId(); - return GenPspGraphics::DoGetEmbedFontData( aFont, pUnicodes, pWidths, rInfo, pDataLen ); + return mpTextRenderImpl->GetEmbedFontData(pFont, pUnicodes, pWidths, rInfo, pDataLen); } void X11SalGraphics::FreeEmbedFontData( const void* pData, long nLen ) { - GenPspGraphics::DoFreeEmbedFontData( pData, nLen ); + mpTextRenderImpl->FreeEmbedFontData(pData, nLen); } const Ucs2SIntMap* X11SalGraphics::GetFontEncodingVector( const PhysicalFontFace* pFont, const Ucs2OStrMap** pNonEncoded ) { - // in this context the pFont->GetFontId() is a valid PSP - // font since they are the only ones left after the PDF - // export has filtered its list of subsettable fonts (for - // which this method was created). The correct way would - // be to have the GlyphCache search for the PhysicalFontFace pFont - psp::fontID aFont = pFont->GetFontId(); - return GenPspGraphics::DoGetFontEncodingVector( aFont, pNonEncoded ); + return mpTextRenderImpl->GetFontEncodingVector(pFont, pNonEncoded); } void X11SalGraphics::GetGlyphWidths( const PhysicalFontFace* pFont, @@ -738,13 +200,7 @@ void X11SalGraphics::GetGlyphWidths( const PhysicalFontFace* pFont, Int32Vector& rWidths, Ucs2UIntMap& rUnicodeEnc ) { - // in this context the pFont->GetFontId() is a valid PSP - // font since they are the only ones left after the PDF - // export has filtered its list of subsettable fonts (for - // which this method was created). The correct way would - // be to have the GlyphCache search for the PhysicalFontFace pFont - psp::fontID aFont = pFont->GetFontId(); - GenPspGraphics::DoGetGlyphWidths( aFont, bVertical, rWidths, rUnicodeEnc ); + mpTextRenderImpl->GetGlyphWidths(pFont, bVertical, rWidths, rUnicodeEnc); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/gdi/salvd.cxx b/vcl/unx/generic/gdi/salvd.cxx index 83925d9f3186..8e08cc2019fa 100644 --- a/vcl/unx/generic/gdi/salvd.cxx +++ b/vcl/unx/generic/gdi/salvd.cxx @@ -102,14 +102,14 @@ void X11SalGraphics::Init( X11SalVirtualDevice *pDevice, SalColormap* pColormap, if (m_pDeleteColormap != pOrigDeleteColormap) delete pOrigDeleteColormap; - const Drawable aVdevDrawable = pDevice->GetDrawable(); - SetDrawable( aVdevDrawable, m_nXScreen ); - m_pVDev = pDevice; m_pFrame = NULL; bWindow_ = pDisplay->IsDisplay(); bVirDev_ = true; + + const Drawable aVdevDrawable = pDevice->GetDrawable(); + SetDrawable( aVdevDrawable, m_nXScreen ); } bool X11SalVirtualDevice::Init( SalDisplay *pDisplay, diff --git a/vcl/unx/generic/gdi/x11cairotextrender.cxx b/vcl/unx/generic/gdi/x11cairotextrender.cxx new file mode 100644 index 000000000000..2533107908c2 --- /dev/null +++ b/vcl/unx/generic/gdi/x11cairotextrender.cxx @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "x11cairotextrender.hxx" +#include "unx/saldata.hxx" +#include "unx/saldisp.hxx" +#include "unx/salvd.h" + +#include "gcach_xpeer.hxx" + +#include <cairo.h> +#include <cairo-ft.h> + +#include <cairo-xlib.h> +#include <cairo-xlib-xrender.h> + +struct BOX +{ + short x1, x2, y1, y2; +}; +struct _XRegion +{ + long size; + long numRects; + BOX *rects; + BOX extents; +}; + +X11CairoTextRender::X11CairoTextRender(bool bPrinter, X11SalGraphics& rParent): + CairoTextRender(bPrinter), + mrParent(rParent) +{ +} + +GlyphCache& X11CairoTextRender::getPlatformGlyphCache() +{ + return X11GlyphCache::GetInstance(); +} + +cairo_surface_t* X11CairoTextRender::getCairoSurface() +{ + // find a XRenderPictFormat compatible with the Drawable + XRenderPictFormat* pVisualFormat = mrParent.GetXRenderFormat(); + + Display* pDisplay = mrParent.GetXDisplay(); + + cairo_surface_t* surface = NULL; + if (pVisualFormat) + { + surface = cairo_xlib_surface_create_with_xrender_format ( + pDisplay, mrParent.hDrawable_, + ScreenOfDisplay(pDisplay, mrParent.m_nXScreen.getXScreen()), + pVisualFormat, SAL_MAX_INT16, SAL_MAX_INT16); + } + else + { + surface = cairo_xlib_surface_create(pDisplay, mrParent.hDrawable_, + mrParent.GetVisual().visual, SAL_MAX_INT16, SAL_MAX_INT16); + } + + return surface; +} + +void X11CairoTextRender::clipRegion(cairo_t* cr) +{ + Region pClipRegion = mrParent.mpClipRegion; + if( pClipRegion && !XEmptyRegion( pClipRegion ) ) + { + for (long i = 0; i < pClipRegion->numRects; ++i) + { + cairo_rectangle(cr, + pClipRegion->rects[i].x1, + pClipRegion->rects[i].y1, + pClipRegion->rects[i].x2 - pClipRegion->rects[i].x1, + pClipRegion->rects[i].y2 - pClipRegion->rects[i].y1); + } + cairo_clip(cr); + } +} + +size_t X11CairoTextRender::GetWidth() const +{ + if( mrParent.m_pFrame ) + return mrParent.m_pFrame->maGeometry.nWidth; + else if( mrParent.m_pVDev ) + { + long nWidth = 0; + long nHeight = 0; + mrParent.m_pVDev->GetSize( nWidth, nHeight ); + return nWidth; + } + return 1; +} + +size_t X11CairoTextRender::GetHeight() const +{ + if( mrParent.m_pFrame ) + return mrParent.m_pFrame->maGeometry.nHeight; + else if( mrParent.m_pVDev ) + { + long nWidth = 0; + long nHeight = 0; + mrParent.m_pVDev->GetSize( nWidth, nHeight ); + return nHeight; + } + return 1; +} + +void X11CairoTextRender::drawSurface(cairo_t* /*cr*/) +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/gdi/x11cairotextrender.hxx b/vcl/unx/generic/gdi/x11cairotextrender.hxx new file mode 100644 index 000000000000..fb0c130ab292 --- /dev/null +++ b/vcl/unx/generic/gdi/x11cairotextrender.hxx @@ -0,0 +1,50 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#ifndef INCLUDED_VCL_UNX_GENERIC_GDI_X11CAIROTEXTRENDER_HXX +#define INCLUDED_VCL_UNX_GENERIC_GDI_X11CAIROTEXTRENDER_HXX value + +#include "cairotextrender.hxx" + +#include "unx/saldata.hxx" +#include "unx/saldisp.hxx" + +#include "unx/salgdi.h" + +class X11CairoTextRender : public CairoTextRender +{ +protected: + X11SalGraphics& mrParent; + +protected: + size_t GetWidth() const; + size_t GetHeight() const; + +public: + X11CairoTextRender(bool bPrinter, X11SalGraphics& rParent); + + virtual GlyphCache& getPlatformGlyphCache() SAL_OVERRIDE; + virtual cairo_surface_t* getCairoSurface() SAL_OVERRIDE; + virtual void clipRegion(cairo_t* cr) SAL_OVERRIDE; + virtual void drawSurface(cairo_t* cr) SAL_OVERRIDE; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/gdi/x11windowprovider.cxx b/vcl/unx/generic/gdi/x11windowprovider.cxx new file mode 100644 index 000000000000..5eaa3f612c45 --- /dev/null +++ b/vcl/unx/generic/gdi/x11windowprovider.cxx @@ -0,0 +1,16 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "unx/x11windowprovider.hxx" + +X11WindowProvider::~X11WindowProvider() +{ +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/generic/window/salframe.cxx b/vcl/unx/generic/window/salframe.cxx index 0bda729feb22..6c98968f9a93 100644 --- a/vcl/unx/generic/window/salframe.cxx +++ b/vcl/unx/generic/window/salframe.cxx @@ -4268,4 +4268,9 @@ void X11SalFrame::EndSetClipRegion() } +Window X11SalFrame::GetX11Window() +{ + return mhWindow; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx index bab4f5c6f888..50cb193fb95a 100644 --- a/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx +++ b/vcl/unx/gtk/gdi/salnativewidgets-gtk.cxx @@ -26,6 +26,7 @@ #include "unx/gtk/gtkinst.hxx" #include "unx/gtk/gtkgdi.hxx" +#include "unx/pixmap.hxx" #include "unx/saldata.hxx" #include "unx/saldisp.hxx" @@ -257,6 +258,71 @@ static int getFrameWidth(GtkWidget* widget); static Rectangle NWGetScrollButtonRect( SalX11Screen nScreen, ControlPart nPart, Rectangle aAreaRect ); + +/************************************************************************ + * GDK implementation of X11Pixmap + ************************************************************************/ + +class GdkX11Pixmap : public X11Pixmap +{ +public: + GdkX11Pixmap( int nWidth, int nHeight, int nDepth ); + GdkX11Pixmap( X11Pixmap& rOther, GdkWindow *pWindow ); + virtual ~GdkX11Pixmap(); + + GdkPixmap* GetGdkPixmap() const; + GdkDrawable* GetGdkDrawable() const; + +protected: + GdkPixmap* mpGdkPixmap; +}; + +GdkX11Pixmap::GdkX11Pixmap( int nWidth, int nHeight, int nDepth ) +{ + mpGdkPixmap = gdk_pixmap_new( NULL, nWidth, nHeight, nDepth ); + + //mpDisplay = ? + mnScreen = SalX11Screen( gdk_screen_get_number( gdk_drawable_get_screen( GDK_DRAWABLE(mpGdkPixmap) ) ) ); + mnWidth = nWidth; + mnHeight = nHeight; + mnDepth = nDepth; + mpPixmap = GDK_PIXMAP_XID( mpGdkPixmap ); +} + +GdkX11Pixmap::GdkX11Pixmap( X11Pixmap& rOther, GdkWindow *pWindow ) +: X11Pixmap( rOther ) +{ + GdkColormap* pColormap; + +#if GTK_CHECK_VERSION(2,10,0) + GdkScreen *pScreen = gdk_window_get_screen( pWindow ); + mpGdkPixmap = gdk_pixmap_foreign_new_for_screen( pScreen, mpPixmap, + mnWidth, mnHeight, + mnDepth ); +#else + mpGdkPixmap = gdk_pixmap_foreign_new( mpPixmap ); +#endif + + pColormap = gdk_drawable_get_colormap( pWindow ); + gdk_drawable_set_colormap( GDK_DRAWABLE (mpGdkPixmap), pColormap ); +} + +GdkX11Pixmap::~GdkX11Pixmap() +{ + g_object_unref( mpGdkPixmap ); +} + +GdkPixmap* GdkX11Pixmap::GetGdkPixmap() const +{ + return mpGdkPixmap; +} + +GdkDrawable* GdkX11Pixmap::GetGdkDrawable() const +{ + return GDK_DRAWABLE( mpGdkPixmap ); +} + + /********************************************************* * PixmapCache *********************************************************/ @@ -271,13 +337,13 @@ class NWPixmapCacheData public: ControlType m_nType; ControlState m_nState; - Rectangle m_pixmapRect; - GdkPixmap* m_pixmap; + Rectangle m_pixmapRect; + GdkX11Pixmap* m_pixmap; NWPixmapCacheData() : m_nType(0), m_nState(0), m_pixmap(0) {} ~NWPixmapCacheData() { SetPixmap( NULL ); }; - void SetPixmap( GdkPixmap* pPixmap ); + void SetPixmap( GdkX11Pixmap* pPixmap ); }; class NWPixmapCache @@ -294,8 +360,8 @@ public: { delete [] pData; m_idx = 0; m_size = n; pData = new NWPixmapCacheData[m_size]; } int GetSize() const { return m_size; } - bool Find( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap** pPixmap ); - void Fill( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap* pPixmap ); + bool Find( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkX11Pixmap** pPixmap ); + void Fill( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkX11Pixmap* pPixmap ); void ThemeChanged(); }; @@ -312,15 +378,12 @@ public: // --- implementation --- -void NWPixmapCacheData::SetPixmap( GdkPixmap* pPixmap ) +void NWPixmapCacheData::SetPixmap( GdkX11Pixmap* pPixmap ) { if( m_pixmap ) - g_object_unref( m_pixmap ); + delete m_pixmap; m_pixmap = pPixmap; - - if( m_pixmap ) - g_object_ref( m_pixmap ); } NWPixmapCache::NWPixmapCache( SalX11Screen nScreen ) @@ -346,7 +409,7 @@ void NWPixmapCache::ThemeChanged() pData[i].SetPixmap( NULL ); } -bool NWPixmapCache::Find( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap** pPixmap ) +bool NWPixmapCache::Find( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkX11Pixmap** pPixmap ) { aState &= ~CTRL_CACHING_ALLOWED; // mask clipping flag int i; @@ -365,7 +428,7 @@ bool NWPixmapCache::Find( ControlType aType, ControlState aState, const Rectang return false; } -void NWPixmapCache::Fill( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkPixmap* pPixmap ) +void NWPixmapCache::Fill( ControlType aType, ControlState aState, const Rectangle& r_pixmapRect, GdkX11Pixmap* pPixmap ) { if( !(aState & CTRL_CACHING_ALLOWED) ) return; @@ -801,7 +864,7 @@ bool GtkSalGraphics::drawNativeControl( ControlType nType, clipList aClip; GdkDrawable* gdkDrawable = GDK_DRAWABLE( GetGdkWindow() ); - GdkPixmap* pixmap = NULL; + GdkX11Pixmap* pixmap = NULL; Rectangle aPixmapRect; if( ( bNeedPixmapPaint ) && nType != CTRL_SCROLLBAR @@ -819,7 +882,7 @@ bool GtkSalGraphics::drawNativeControl( ControlType nType, pixmap = NWGetPixmapFromScreen( aPixmapRect ); if( ! pixmap ) return false; - gdkDrawable = GDK_DRAWABLE( pixmap ); + gdkDrawable = pixmap->GetGdkDrawable(); aCtrlRect = Rectangle( Point(1,1), aCtrlRect.GetSize() ); aClip.push_back( aCtrlRect ); } @@ -956,7 +1019,7 @@ bool GtkSalGraphics::drawNativeControl( ControlType nType, if( pixmap ) { returnVal = NWRenderPixmapToScreen( pixmap, aPixmapRect ) && returnVal; - g_object_unref( pixmap ); + delete pixmap; } return( returnVal ); @@ -1742,7 +1805,7 @@ bool GtkSalGraphics::NWPaintGTKScrollbar( ControlType, ControlPart nPart, { assert(aValue.getType() == CTRL_SCROLLBAR); const ScrollbarValue& rScrollbarVal = static_cast<const ScrollbarValue&>(aValue); - GdkPixmap* pixmap = NULL; + GdkX11Pixmap* pixmap = NULL; Rectangle pixmapRect, scrollbarRect; GtkStateType stateType; GtkShadowType shadowType; @@ -1930,7 +1993,7 @@ bool GtkSalGraphics::NWPaintGTKScrollbar( ControlType, ControlPart nPart, w = pixmapRect.GetWidth(); h = pixmapRect.GetHeight(); - GdkDrawable* const &gdkDrawable = GDK_DRAWABLE( pixmap ); + GdkDrawable* const &gdkDrawable = pixmap->GetGdkDrawable(); GdkRectangle* gdkRect = NULL; NWConvertVCLStateToGTKState( nState, &stateType, &shadowType ); @@ -2051,14 +2114,10 @@ bool GtkSalGraphics::NWPaintGTKScrollbar( ControlType, ControlPart nPart, arrowRect.GetWidth(), arrowRect.GetHeight() ); } - if( !NWRenderPixmapToScreen(pixmap, pixmapRect) ) - { - g_object_unref( pixmap ); - return false; - } - g_object_unref( pixmap ); + bool bRet = NWRenderPixmapToScreen( pixmap, pixmapRect ); + delete pixmap; - return true; + return bRet; } static Rectangle NWGetScrollButtonRect( SalX11Screen nScreen, ControlPart nPart, Rectangle aAreaRect ) @@ -2282,7 +2341,8 @@ bool GtkSalGraphics::NWPaintGTKSpinBox( ControlType nType, ControlPart nPart, const ImplControlValue& aValue, const OUString& rCaption ) { - GdkPixmap * pixmap; + GdkX11Pixmap * pixmap; + GdkPixmap * gdkPixmap; Rectangle pixmapRect; GtkStateType stateType; GtkShadowType shadowType; @@ -2326,9 +2386,10 @@ bool GtkSalGraphics::NWPaintGTKSpinBox( ControlType nType, ControlPart nPart, pixmap = NWGetPixmapFromScreen( pixmapRect ); if ( !pixmap ) return false; + gdkPixmap = pixmap->GetGdkPixmap(); // First render background - gtk_paint_flat_box(m_pWindow->style,pixmap,GTK_STATE_NORMAL,GTK_SHADOW_NONE,NULL,m_pWindow,"base", + gtk_paint_flat_box(m_pWindow->style,gdkPixmap,GTK_STATE_NORMAL,GTK_SHADOW_NONE,NULL,m_pWindow,"base", -pixmapRect.Left(), -pixmapRect.Top(), pixmapRect.Right(), @@ -2348,7 +2409,7 @@ bool GtkSalGraphics::NWPaintGTKSpinBox( ControlType nType, ControlPart nPart, aEditBoxRect.setX( 0 ); aEditBoxRect.setY( 0 ); - NWPaintOneEditBox( m_nXScreen, pixmap, NULL, nType, nPart, aEditBoxRect, nState, aValue, rCaption ); + NWPaintOneEditBox( m_nXScreen, gdkPixmap, NULL, nType, nPart, aEditBoxRect, nState, aValue, rCaption ); } NWSetWidgetState( gWidgetData[m_nXScreen].gSpinButtonWidget, nState, stateType ); @@ -2359,23 +2420,19 @@ bool GtkSalGraphics::NWPaintGTKSpinBox( ControlType nType, ControlPart nPart, Rectangle shadowRect( upBtnRect ); shadowRect.Union( downBtnRect ); - gtk_paint_box( gWidgetData[m_nXScreen].gSpinButtonWidget->style, pixmap, GTK_STATE_NORMAL, shadowType, NULL, + gtk_paint_box( gWidgetData[m_nXScreen].gSpinButtonWidget->style, gdkPixmap, GTK_STATE_NORMAL, shadowType, NULL, gWidgetData[m_nXScreen].gSpinButtonWidget, "spinbutton", (shadowRect.Left() - pixmapRect.Left()), (shadowRect.Top() - pixmapRect.Top()), shadowRect.GetWidth(), shadowRect.GetHeight() ); } - NWPaintOneSpinButton( m_nXScreen, pixmap, nType, upBtnPart, pixmapRect, upBtnState, aValue, rCaption ); - NWPaintOneSpinButton( m_nXScreen, pixmap, nType, downBtnPart, pixmapRect, downBtnState, aValue, rCaption ); + NWPaintOneSpinButton( m_nXScreen, gdkPixmap, nType, upBtnPart, pixmapRect, upBtnState, aValue, rCaption ); + NWPaintOneSpinButton( m_nXScreen, gdkPixmap, nType, downBtnPart, pixmapRect, downBtnState, aValue, rCaption ); - if( !NWRenderPixmapToScreen(pixmap, pixmapRect) ) - { - g_object_unref( pixmap ); - return false; - } + bool bRet = NWRenderPixmapToScreen( pixmap, pixmapRect ); + delete pixmap; - g_object_unref( pixmap ); - return true; + return bRet; } static Rectangle NWGetSpinButtonRect( SalX11Screen nScreen, @@ -2609,7 +2666,8 @@ bool GtkSalGraphics::NWPaintGTKTabItem( ControlType nType, ControlPart, const OUString& ) { OSL_ASSERT( nType != CTRL_TAB_ITEM || aValue.getType() == CTRL_TAB_ITEM ); - GdkPixmap * pixmap; + GdkX11Pixmap * pixmap; + GdkPixmap * gdkPixmap; Rectangle pixmapRect; Rectangle tabRect; GtkStateType stateType; @@ -2681,14 +2739,15 @@ bool GtkSalGraphics::NWPaintGTKTabItem( ControlType nType, ControlPart, return NWRenderPixmapToScreen( pixmap, pixmapRect ); } - pixmap = gdk_pixmap_new( NULL, pixmapRect.GetWidth(), pixmapRect.GetHeight(), - GetGenericData()->GetSalDisplay()->GetVisual( m_nXScreen ).GetDepth() ); + pixmap = new GdkX11Pixmap( pixmapRect.GetWidth(), pixmapRect.GetHeight(), + GetGenericData()->GetSalDisplay()->GetVisual( m_nXScreen ).GetDepth() ); + gdkPixmap = pixmap->GetGdkPixmap(); GdkRectangle paintRect; paintRect.x = paintRect.y = 0; paintRect.width = pixmapRect.GetWidth(); paintRect.height = pixmapRect.GetHeight(); - gtk_paint_flat_box( m_pWindow->style, pixmap, GTK_STATE_NORMAL, + gtk_paint_flat_box( m_pWindow->style, gdkPixmap, GTK_STATE_NORMAL, GTK_SHADOW_NONE, &paintRect, m_pWindow, "base", -rControlRectangle.Left(), -rControlRectangle.Top(), @@ -2703,7 +2762,7 @@ bool GtkSalGraphics::NWPaintGTKTabItem( ControlType nType, ControlPart, break; case CTRL_TAB_PANE: - gtk_paint_box_gap( gWidgetData[m_nXScreen].gNotebookWidget->style, pixmap, GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, gWidgetData[m_nXScreen].gNotebookWidget, + gtk_paint_box_gap( gWidgetData[m_nXScreen].gNotebookWidget->style, gdkPixmap, GTK_STATE_NORMAL, GTK_SHADOW_OUT, NULL, gWidgetData[m_nXScreen].gNotebookWidget, (char *)"notebook", 0, 0, pixmapRect.GetWidth(), pixmapRect.GetHeight(), GTK_POS_TOP, 0, 0 ); break; @@ -2712,7 +2771,7 @@ bool GtkSalGraphics::NWPaintGTKTabItem( ControlType nType, ControlPart, stateType = ( nState & CTRL_STATE_SELECTED ) ? GTK_STATE_NORMAL : GTK_STATE_ACTIVE; // First draw the background - gtk_paint_flat_box(gWidgetData[m_nXScreen].gNotebookWidget->style, pixmap, + gtk_paint_flat_box(gWidgetData[m_nXScreen].gNotebookWidget->style, gdkPixmap, GTK_STATE_NORMAL, GTK_SHADOW_NONE, NULL, m_pWindow, "base", -rControlRectangle.Left(), -rControlRectangle.Top(), @@ -2721,17 +2780,17 @@ bool GtkSalGraphics::NWPaintGTKTabItem( ControlType nType, ControlPart, // Now the tab itself if( nState & CTRL_STATE_ROLLOVER ) - g_object_set_data(G_OBJECT(pixmap),tabPrelitDataName,reinterpret_cast<gpointer>(TRUE)); + g_object_set_data(G_OBJECT(gdkPixmap),tabPrelitDataName,reinterpret_cast<gpointer>(TRUE)); - gtk_paint_extension( gWidgetData[m_nXScreen].gNotebookWidget->style, pixmap, stateType, GTK_SHADOW_OUT, NULL, gWidgetData[m_nXScreen].gNotebookWidget, + gtk_paint_extension( gWidgetData[m_nXScreen].gNotebookWidget->style, gdkPixmap, stateType, GTK_SHADOW_OUT, NULL, gWidgetData[m_nXScreen].gNotebookWidget, (char *)"tab", (tabRect.Left() - pixmapRect.Left()), (tabRect.Top() - pixmapRect.Top()), tabRect.GetWidth(), tabRect.GetHeight(), GTK_POS_BOTTOM ); - g_object_steal_data(G_OBJECT(pixmap),tabPrelitDataName); + g_object_steal_data(G_OBJECT(gdkPixmap),tabPrelitDataName); if ( nState & CTRL_STATE_SELECTED ) { - gtk_paint_flat_box( m_pWindow->style, pixmap, stateType, GTK_SHADOW_NONE, NULL, m_pWindow, + gtk_paint_flat_box( m_pWindow->style, gdkPixmap, stateType, GTK_SHADOW_NONE, NULL, m_pWindow, "base", 0, (pixmapRect.GetHeight() - 1), pixmapRect.GetWidth(), 1 ); } break; @@ -2747,8 +2806,7 @@ bool GtkSalGraphics::NWPaintGTKTabItem( ControlType nType, ControlPart, else aCachePage.Fill( nType, nState, pixmapRect, pixmap ); - bool bSuccess = NWRenderPixmapToScreen(pixmap, pixmapRect); - g_object_unref( pixmap ); + bool bSuccess = NWRenderPixmapToScreen( pixmap, pixmapRect ); return bSuccess; } @@ -3324,11 +3382,11 @@ bool GtkSalGraphics::NWPaintGTKListNode( break; } - GdkPixmap* pixmap = NWGetPixmapFromScreen( aRect ); + GdkX11Pixmap* pixmap = NWGetPixmapFromScreen( aRect ); if( ! pixmap ) return false; - GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap ); + GdkDrawable* const &pixDrawable = pixmap->GetGdkDrawable(); gtk_paint_expander( gWidgetData[m_nXScreen].gTreeView->style, pixDrawable, stateType, @@ -3339,7 +3397,7 @@ bool GtkSalGraphics::NWPaintGTKListNode( eStyle ); bool bRet = NWRenderPixmapToScreen( pixmap, aRect ); - g_object_unref( pixmap ); + delete pixmap; return bRet; } @@ -3360,11 +3418,11 @@ bool GtkSalGraphics::NWPaintGTKProgress( long nProgressWidth = rValue.getNumericVal(); - GdkPixmap* pixmap = NWGetPixmapFromScreen( Rectangle( Point( 0, 0 ), Size( w, h ) ) ); + GdkX11Pixmap* pixmap = NWGetPixmapFromScreen( Rectangle( Point( 0, 0 ), Size( w, h ) ) ); if( ! pixmap ) return false; - GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap ); + GdkDrawable* const &pixDrawable = pixmap->GetGdkDrawable(); // paint background gtk_paint_flat_box(gWidgetData[m_nXScreen].gProgressBar->style, pixDrawable, @@ -3408,7 +3466,7 @@ bool GtkSalGraphics::NWPaintGTKProgress( } bool bRet = NWRenderPixmapToScreen( pixmap, rControlRectangle ); - g_object_unref( pixmap ); + delete pixmap; return bRet; } @@ -3430,11 +3488,11 @@ bool GtkSalGraphics::NWPaintGTKSlider( const SliderValue* pVal = static_cast<const SliderValue*>(&rValue); - GdkPixmap* pixmap = NWGetPixmapFromScreen( rControlRectangle ); + GdkX11Pixmap* pixmap = NWGetPixmapFromScreen( rControlRectangle ); if( ! pixmap ) return false; - GdkDrawable* const &pixDrawable = GDK_DRAWABLE( pixmap ); + GdkDrawable* const &pixDrawable = pixmap->GetGdkDrawable(); GtkWidget* pWidget = (nPart == PART_TRACK_HORZ_AREA) ? GTK_WIDGET(gWidgetData[m_nXScreen].gHScale) : GTK_WIDGET(gWidgetData[m_nXScreen].gVScale); @@ -3496,7 +3554,7 @@ bool GtkSalGraphics::NWPaintGTKSlider( } bool bRet = NWRenderPixmapToScreen( pixmap, rControlRectangle ); - g_object_unref( pixmap ); + delete pixmap; return bRet; } @@ -4070,62 +4128,28 @@ void GtkSalGraphics::updateSettings( AllSettings& rSettings ) * Create a GdkPixmap filled with the contents of an area of an Xlib window ************************************************************************/ -GdkPixmap* GtkSalGraphics::NWGetPixmapFromScreen( Rectangle srcRect ) +GdkX11Pixmap* GtkSalGraphics::NWGetPixmapFromScreen( Rectangle srcRect ) { - // Create a new pixmap to hold the composite of the window background and the control - GdkPixmap * pPixmap = gdk_pixmap_new( GDK_DRAWABLE(GetGdkWindow()), srcRect.GetWidth(), srcRect.GetHeight(), -1 ); - GdkGC * pPixmapGC = gdk_gc_new( pPixmap ); - - if( !pPixmap || !pPixmapGC ) - { - if ( pPixmap ) - g_object_unref( pPixmap ); - if ( pPixmapGC ) - g_object_unref( pPixmapGC ); - std::fprintf( stderr, "salnativewidgets-gtk.cxx: could not get valid pixmap from screen\n" ); - return( NULL ); - } - - // Copy the background of the screen into a composite pixmap - CopyScreenArea( GetXDisplay(), - GetDrawable(), GetScreenNumber(), GetVisual().GetDepth(), - gdk_x11_drawable_get_xid(pPixmap), - SalX11Screen( gdk_screen_get_number( gdk_drawable_get_screen( GDK_DRAWABLE(pPixmap) ) ) ), - gdk_drawable_get_depth( GDK_DRAWABLE( pPixmap ) ), - gdk_x11_gc_get_xgc(pPixmapGC), - srcRect.Left(), srcRect.Top(), srcRect.GetWidth(), srcRect.GetHeight(), 0, 0 ); - - g_object_unref( pPixmapGC ); - return( pPixmap ); + X11Pixmap* pPixmap; + GdkX11Pixmap* pResult; + + pPixmap = GetPixmapFromScreen( srcRect ); + if( pPixmap == NULL ) + return NULL; + + pResult = new GdkX11Pixmap( *pPixmap, GetGdkWindow() ); + delete pPixmap; + + return pResult; } /************************************************************************ * Copy an alpha pixmap to screen using a gc with clipping ************************************************************************/ -bool GtkSalGraphics::NWRenderPixmapToScreen( GdkPixmap* pPixmap, Rectangle dstRect ) +bool GtkSalGraphics::NWRenderPixmapToScreen( GdkX11Pixmap* pPixmap, Rectangle dstRect ) { - // The GC can't be null, otherwise we'd have no clip region - GC aFontGC = GetFontGC(); - if( aFontGC == NULL ) - { - std::fprintf(stderr, "salnativewidgets.cxx: no valid GC\n" ); - return false; - } - - if ( !pPixmap ) - return false; - - // Copy the background of the screen into a composite pixmap - CopyScreenArea( GetXDisplay(), - GDK_DRAWABLE_XID(pPixmap), - SalX11Screen( gdk_screen_get_number( gdk_drawable_get_screen( GDK_DRAWABLE(pPixmap) ) ) ), - gdk_drawable_get_depth( GDK_DRAWABLE(pPixmap) ), - GetDrawable(), m_nXScreen, GetVisual().GetDepth(), - aFontGC, - 0, 0, dstRect.GetWidth(), dstRect.GetHeight(), dstRect.Left(), dstRect.Top() ); - - return true; + return RenderPixmapToScreen( pPixmap, dstRect.Left(), dstRect.Top() ); } /************************************************************************ diff --git a/vcl/unx/gtk/window/gtksalframe.cxx b/vcl/unx/gtk/window/gtksalframe.cxx index b39875f99d2a..03cf9df414ce 100644 --- a/vcl/unx/gtk/window/gtksalframe.cxx +++ b/vcl/unx/gtk/window/gtksalframe.cxx @@ -4508,4 +4508,9 @@ Size GtkSalDisplay::GetScreenSize( int nDisplayScreen ) return Size( aRect.GetWidth(), aRect.GetHeight() ); } +Window GtkSalFrame::GetX11Window() +{ + return widget_get_xid(m_pWindow); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/source/gdi/gdiimpl.cxx b/vcl/win/source/gdi/gdiimpl.cxx new file mode 100644 index 000000000000..453033fa5efb --- /dev/null +++ b/vcl/win/source/gdi/gdiimpl.cxx @@ -0,0 +1,2371 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "gdiimpl.hxx" + +#include <stdio.h> +#include <string.h> +#include <svsys.h> +#include <rtl/strbuf.hxx> +#include <tools/debug.hxx> +#include <tools/poly.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <win/wincomp.hxx> +#include <win/saldata.hxx> +#include <win/salgdi.h> +#include "win/salbmp.h" +#include <vcl/salbtype.hxx> +#include <win/salframe.h> +#include <basegfx/matrix/b2dhommatrixtools.hxx> + +#include "outdata.hxx" +#include "win/salids.hrc" + +#if defined _MSC_VER +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#endif + +#if defined _MSC_VER +#pragma warning(push, 1) +#endif + +#ifdef __MINGW32__ +#ifdef GetObject +#undef GetObject +#endif +#endif + +#include <gdiplus.h> +#include <gdiplusenums.h> +#include <gdipluscolor.h> + +#if defined _MSC_VER +#pragma warning(pop) +#endif + +#include <basegfx/polygon/b2dpolygon.hxx> + +#define SAL_POLYPOLYCOUNT_STACKBUF 8 +#define SAL_POLYPOLYPOINTS_STACKBUF 64 + +#define DITHER_PAL_DELTA 51 +#define DITHER_PAL_STEPS 6 +#define DITHER_PAL_COUNT (DITHER_PAL_STEPS*DITHER_PAL_STEPS*DITHER_PAL_STEPS) +#define DITHER_MAX_SYSCOLOR 16 +#define DITHER_EXTRA_COLORS 1 +#define DMAP( _def_nVal, _def_nThres ) ((pDitherDiff[_def_nVal]>(_def_nThres))?pDitherHigh[_def_nVal]:pDitherLow[_def_nVal]) + +#define SAL_POLY_STACKBUF 32 +#define USE_GDI_BEZIERS + +namespace { + +// #100127# draw an array of points which might also contain bezier control points +void ImplRenderPath( HDC hdc, sal_uLong nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry ) +{ + if( nPoints ) + { + sal_uInt16 i; + // TODO: profile whether the following options are faster: + // a) look ahead and draw consecutive bezier or line segments by PolyBezierTo/PolyLineTo resp. + // b) convert our flag array to window's and use PolyDraw + + MoveToEx( hdc, pPtAry->mnX, pPtAry->mnY, NULL ); + ++pPtAry; ++pFlgAry; + + for( i=1; i<nPoints; ++i, ++pPtAry, ++pFlgAry ) + { + if( *pFlgAry != POLY_CONTROL ) + { + LineTo( hdc, pPtAry->mnX, pPtAry->mnY ); + } + else if( nPoints - i > 2 ) + { + PolyBezierTo( hdc, reinterpret_cast<const POINT*>(pPtAry), 3 ); + i += 2; pPtAry += 2; pFlgAry += 2; + } + } + } +} + +// #100127# Fill point and flag memory from array of points which +// might also contain bezier control points for the PolyDraw() GDI method +// Make sure pWinPointAry and pWinFlagAry are big enough +void ImplPreparePolyDraw( bool bCloseFigures, + sal_uLong nPoly, + const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, + const BYTE* const* pFlgAry, + POINT* pWinPointAry, + BYTE* pWinFlagAry ) +{ + sal_uLong nCurrPoly; + for( nCurrPoly=0; nCurrPoly<nPoly; ++nCurrPoly ) + { + const POINT* pCurrPoint = reinterpret_cast<const POINT*>( *pPtAry++ ); + const BYTE* pCurrFlag = *pFlgAry++; + const sal_uInt32 nCurrPoints = *pPoints++; + const bool bHaveFlagArray( pCurrFlag ); + sal_uLong nCurrPoint; + + if( nCurrPoints ) + { + // start figure + *pWinPointAry++ = *pCurrPoint++; + *pWinFlagAry++ = PT_MOVETO; + ++pCurrFlag; + + for( nCurrPoint=1; nCurrPoint<nCurrPoints; ) + { + // #102067# Check existence of flag array + if( bHaveFlagArray && + ( nCurrPoint + 2 ) < nCurrPoints ) + { + BYTE P4( pCurrFlag[ 2 ] ); + + if( ( POLY_CONTROL == pCurrFlag[ 0 ] ) && + ( POLY_CONTROL == pCurrFlag[ 1 ] ) && + ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) ) + { + // control point one + *pWinPointAry++ = *pCurrPoint++; + *pWinFlagAry++ = PT_BEZIERTO; + + // control point two + *pWinPointAry++ = *pCurrPoint++; + *pWinFlagAry++ = PT_BEZIERTO; + + // end point + *pWinPointAry++ = *pCurrPoint++; + *pWinFlagAry++ = PT_BEZIERTO; + + nCurrPoint += 3; + pCurrFlag += 3; + continue; + } + } + + // regular line point + *pWinPointAry++ = *pCurrPoint++; + *pWinFlagAry++ = PT_LINETO; + ++pCurrFlag; + ++nCurrPoint; + } + + // end figure? + if( bCloseFigures ) + pWinFlagAry[-1] |= PT_CLOSEFIGURE; + } + } +} + + +static PALETTEENTRY aImplSalSysPalEntryAry[ DITHER_MAX_SYSCOLOR ] = +{ +{ 0, 0, 0, 0 }, +{ 0, 0, 0x80, 0 }, +{ 0, 0x80, 0, 0 }, +{ 0, 0x80, 0x80, 0 }, +{ 0x80, 0, 0, 0 }, +{ 0x80, 0, 0x80, 0 }, +{ 0x80, 0x80, 0, 0 }, +{ 0x80, 0x80, 0x80, 0 }, +{ 0xC0, 0xC0, 0xC0, 0 }, +{ 0, 0, 0xFF, 0 }, +{ 0, 0xFF, 0, 0 }, +{ 0, 0xFF, 0xFF, 0 }, +{ 0xFF, 0, 0, 0 }, +{ 0xFF, 0, 0xFF, 0 }, +{ 0xFF, 0xFF, 0, 0 }, +{ 0xFF, 0xFF, 0xFF, 0 } +}; + +static PALETTEENTRY aImplExtraColor1 = +{ + 0, 184, 255, 0 +}; + +static BYTE aOrdDither8Bit[8][8] = +{ + { 0, 38, 9, 48, 2, 40, 12, 50 }, + { 25, 12, 35, 22, 28, 15, 37, 24 }, + { 6, 44, 3, 41, 8, 47, 5, 44 }, + { 32, 19, 28, 16, 34, 21, 31, 18 }, + { 1, 40, 11, 49, 0, 39, 10, 48 }, + { 27, 14, 36, 24, 26, 13, 36, 23 }, + { 8, 46, 4, 43, 7, 45, 4, 42 }, + { 33, 20, 30, 17, 32, 20, 29, 16 } +}; + +static BYTE aOrdDither16Bit[8][8] = +{ + { 0, 6, 1, 7, 0, 6, 1, 7 }, + { 4, 2, 5, 3, 4, 2, 5, 3 }, + { 1, 7, 0, 6, 1, 7, 0, 6 }, + { 5, 3, 4, 2, 5, 3, 4, 2 }, + { 0, 6, 1, 7, 0, 6, 1, 7 }, + { 4, 2, 5, 3, 4, 2, 5, 3 }, + { 1, 7, 0, 6, 1, 7, 0, 6 }, + { 5, 3, 4, 2, 5, 3, 4, 2 } +}; + +SalColor ImplGetROPSalColor( SalROPColor nROPColor ) +{ + SalColor nSalColor; + if ( nROPColor == SAL_ROP_0 ) + nSalColor = MAKE_SALCOLOR( 0, 0, 0 ); + else + nSalColor = MAKE_SALCOLOR( 255, 255, 255 ); + return nSalColor; +} + +int ImplIsPaletteEntry( BYTE nRed, BYTE nGreen, BYTE nBlue ) +{ + // dither color? + if ( !(nRed % DITHER_PAL_DELTA) && !(nGreen % DITHER_PAL_DELTA) && !(nBlue % DITHER_PAL_DELTA) ) + return TRUE; + + PALETTEENTRY* pPalEntry = aImplSalSysPalEntryAry; + + // standard palette color? + for ( sal_uInt16 i = 0; i < DITHER_MAX_SYSCOLOR; i++, pPalEntry++ ) + { + if( pPalEntry->peRed == nRed && pPalEntry->peGreen == nGreen && pPalEntry->peBlue == nBlue ) + return TRUE; + } + + // extra color? + if ( aImplExtraColor1.peRed == nRed && + aImplExtraColor1.peGreen == nGreen && + aImplExtraColor1.peBlue == nBlue ) + { + return TRUE; + } + + return FALSE; +} + +} + +WinSalGraphicsImpl::WinSalGraphicsImpl(WinSalGraphics& rParent): + mrParent(rParent), + mbXORMode(false), + mhPen(0), + mhBrush(0) +{ +} + +WinSalGraphicsImpl::~WinSalGraphicsImpl() +{ + if ( mhPen ) + { + if ( !mbStockPen ) + DeletePen( mhPen ); + } + + if ( mhBrush ) + { + if ( !mbStockBrush ) + DeleteBrush( mhBrush ); + } + +} + +void WinSalGraphicsImpl::freeResources() +{ +} + +bool WinSalGraphicsImpl::drawEPS(long, long, long, long, void*, sal_uLong) +{ + return false; +} + +void WinSalGraphicsImpl::copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) +{ + HDC hSrcDC; + DWORD nRop; + + if ( pSrcGraphics ) + hSrcDC = static_cast<WinSalGraphics*>(pSrcGraphics)->getHDC(); + else + hSrcDC = mrParent.getHDC(); + + if ( mbXORMode ) + nRop = SRCINVERT; + else + nRop = SRCCOPY; + + if ( (rPosAry.mnSrcWidth == rPosAry.mnDestWidth) && + (rPosAry.mnSrcHeight == rPosAry.mnDestHeight) ) + { + BitBlt( mrParent.getHDC(), + (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, + (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, + hSrcDC, + (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY, + nRop ); + } + else + { + int nOldStretchMode = SetStretchBltMode( mrParent.getHDC(), STRETCH_DELETESCANS ); + StretchBlt( mrParent.getHDC(), + (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, + (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, + hSrcDC, + (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY, + (int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight, + nRop ); + SetStretchBltMode( mrParent.getHDC(), nOldStretchMode ); + } +} + +void ImplCalcOutSideRgn( const RECT& rSrcRect, + int nLeft, int nTop, int nRight, int nBottom, + HRGN& rhInvalidateRgn ) +{ + HRGN hTempRgn; + + // calculate area outside the visible region + if ( rSrcRect.left < nLeft ) + { + if ( !rhInvalidateRgn ) + rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect ); + hTempRgn = CreateRectRgn( -31999, 0, nLeft, 31999 ); + CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF ); + DeleteRegion( hTempRgn ); + } + if ( rSrcRect.top < nTop ) + { + if ( !rhInvalidateRgn ) + rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect ); + hTempRgn = CreateRectRgn( 0, -31999, 31999, nTop ); + CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF ); + DeleteRegion( hTempRgn ); + } + if ( rSrcRect.right > nRight ) + { + if ( !rhInvalidateRgn ) + rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect ); + hTempRgn = CreateRectRgn( nRight, 0, 31999, 31999 ); + CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF ); + DeleteRegion( hTempRgn ); + } + if ( rSrcRect.bottom > nBottom ) + { + if ( !rhInvalidateRgn ) + rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect ); + hTempRgn = CreateRectRgn( 0, nBottom, 31999, 31999 ); + CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF ); + DeleteRegion( hTempRgn ); + } +} + +void WinSalGraphicsImpl::copyArea( long nDestX, long nDestY, + long nSrcX, long nSrcY, + long nSrcWidth, long nSrcHeight, + sal_uInt16 nFlags ) +{ + bool bRestoreClipRgn = false; + HRGN hOldClipRgn = 0; + int nOldClipRgnType = ERROR; + HRGN hInvalidateRgn = 0; + + // do we have to invalidate also the overlapping regions? + if ( (nFlags & SAL_COPYAREA_WINDOWINVALIDATE) && mrParent.isWindow() ) + { + // compute and invalidate those parts that were either off-screen or covered by other windows + // while performing the above BitBlt + // those regions then have to be invalidated as they contain useless/wrong data + RECT aSrcRect; + RECT aClipRect; + RECT aTempRect; + RECT aTempRect2; + HRGN hTempRgn; + HWND hWnd; + + // restrict srcRect to this window (calc intersection) + aSrcRect.left = (int)nSrcX; + aSrcRect.top = (int)nSrcY; + aSrcRect.right = aSrcRect.left+(int)nSrcWidth; + aSrcRect.bottom = aSrcRect.top+(int)nSrcHeight; + GetClientRect( mrParent.gethWnd(), &aClipRect ); + if ( IntersectRect( &aSrcRect, &aSrcRect, &aClipRect ) ) + { + // transform srcRect to screen coordinates + POINT aPt; + aPt.x = 0; + aPt.y = 0; + ClientToScreen( mrParent.gethWnd(), &aPt ); + aSrcRect.left += aPt.x; + aSrcRect.top += aPt.y; + aSrcRect.right += aPt.x; + aSrcRect.bottom += aPt.y; + hInvalidateRgn = 0; + + // compute the parts that are off screen (ie invisible) + RECT theScreen; + ImplSalGetWorkArea( NULL, &theScreen, NULL ); // find the screen area taking multiple monitors into account + ImplCalcOutSideRgn( aSrcRect, theScreen.left, theScreen.top, theScreen.right, theScreen.bottom, hInvalidateRgn ); + + // calculate regions that are covered by other windows + HRGN hTempRgn2 = 0; + HWND hWndTopWindow = mrParent.gethWnd(); + // Find the TopLevel Window, because only Windows which are in + // in the foreground of our TopLevel window must be considered + if ( GetWindowStyle( hWndTopWindow ) & WS_CHILD ) + { + RECT aTempRect3 = aSrcRect; + do + { + hWndTopWindow = ::GetParent( hWndTopWindow ); + + // Test if the Parent clips our window + GetClientRect( hWndTopWindow, &aTempRect ); + POINT aPt2; + aPt2.x = 0; + aPt2.y = 0; + ClientToScreen( hWndTopWindow, &aPt2 ); + aTempRect.left += aPt2.x; + aTempRect.top += aPt2.y; + aTempRect.right += aPt2.x; + aTempRect.bottom += aPt2.y; + IntersectRect( &aTempRect3, &aTempRect3, &aTempRect ); + } + while ( GetWindowStyle( hWndTopWindow ) & WS_CHILD ); + + // If one or more Parents clip our window, than we must + // calculate the outside area + if ( !EqualRect( &aSrcRect, &aTempRect3 ) ) + { + ImplCalcOutSideRgn( aSrcRect, + aTempRect3.left, aTempRect3.top, + aTempRect3.right, aTempRect3.bottom, + hInvalidateRgn ); + } + } + // retrieve the top-most (z-order) child window + hWnd = GetWindow( GetDesktopWindow(), GW_CHILD ); + while ( hWnd ) + { + if ( hWnd == hWndTopWindow ) + break; + if ( IsWindowVisible( hWnd ) && !IsIconic( hWnd ) ) + { + GetWindowRect( hWnd, &aTempRect ); + if ( IntersectRect( &aTempRect2, &aSrcRect, &aTempRect ) ) + { + // hWnd covers part or all of aSrcRect + if ( !hInvalidateRgn ) + hInvalidateRgn = CreateRectRgnIndirect( &aSrcRect ); + + // get full bounding box of hWnd + hTempRgn = CreateRectRgnIndirect( &aTempRect ); + + // get region of hWnd (the window may be shaped) + if ( !hTempRgn2 ) + hTempRgn2 = CreateRectRgn( 0, 0, 0, 0 ); + int nRgnType = GetWindowRgn( hWnd, hTempRgn2 ); + if ( (nRgnType != ERROR) && (nRgnType != NULLREGION) ) + { + // convert window region to screen coordinates + OffsetRgn( hTempRgn2, aTempRect.left, aTempRect.top ); + // and intersect with the window's bounding box + CombineRgn( hTempRgn, hTempRgn, hTempRgn2, RGN_AND ); + } + // finally compute that part of aSrcRect which is not covered by any parts of hWnd + CombineRgn( hInvalidateRgn, hInvalidateRgn, hTempRgn, RGN_DIFF ); + DeleteRegion( hTempRgn ); + } + } + // retrieve the next window in the z-order, i.e. the window below hwnd + hWnd = GetWindow( hWnd, GW_HWNDNEXT ); + } + if ( hTempRgn2 ) + DeleteRegion( hTempRgn2 ); + if ( hInvalidateRgn ) + { + // hInvalidateRgn contains the fully visible parts of the original srcRect + hTempRgn = CreateRectRgnIndirect( &aSrcRect ); + // substract it from the original rect to get the occluded parts + int nRgnType = CombineRgn( hInvalidateRgn, hTempRgn, hInvalidateRgn, RGN_DIFF ); + DeleteRegion( hTempRgn ); + + if ( (nRgnType != ERROR) && (nRgnType != NULLREGION) ) + { + // move the occluded parts to the destination pos + int nOffX = (int)(nDestX-nSrcX); + int nOffY = (int)(nDestY-nSrcY); + OffsetRgn( hInvalidateRgn, nOffX-aPt.x, nOffY-aPt.y ); + + // by excluding hInvalidateRgn from the system's clip region + // we will prevent bitblt from copying useless data + // epsecially now shadows from overlapping windows will appear (#i36344) + hOldClipRgn = CreateRectRgn( 0, 0, 0, 0 ); + nOldClipRgnType = GetClipRgn( mrParent.getHDC(), hOldClipRgn ); + + bRestoreClipRgn = TRUE; // indicate changed clipregion and force invalidate + ExtSelectClipRgn( mrParent.getHDC(), hInvalidateRgn, RGN_DIFF ); + } + } + } + } + + BitBlt( mrParent.getHDC(), + (int)nDestX, (int)nDestY, + (int)nSrcWidth, (int)nSrcHeight, + mrParent.getHDC(), + (int)nSrcX, (int)nSrcY, + SRCCOPY ); + + if( bRestoreClipRgn ) + { + // restore old clip region + if( nOldClipRgnType != ERROR ) + SelectClipRgn( mrParent.getHDC(), hOldClipRgn); + DeleteRegion( hOldClipRgn ); + + // invalidate regions that were not copied + bool bInvalidate = true; + + // Combine Invalidate vcl::Region with existing ClipRegion + HRGN hTempRgn = CreateRectRgn( 0, 0, 0, 0 ); + if ( GetClipRgn( mrParent.getHDC(), hTempRgn ) == 1 ) + { + int nRgnType = CombineRgn( hInvalidateRgn, hTempRgn, hInvalidateRgn, RGN_AND ); + if ( (nRgnType == ERROR) || (nRgnType == NULLREGION) ) + bInvalidate = false; + } + DeleteRegion( hTempRgn ); + + if ( bInvalidate ) + { + InvalidateRgn( mrParent.gethWnd(), hInvalidateRgn, TRUE ); + // here we only initiate an update if this is the MainThread, + // so that there is no deadlock when handling the Paint event, + // as the SolarMutex is already held by this Thread + SalData* pSalData = GetSalData(); + DWORD nCurThreadId = GetCurrentThreadId(); + if ( pSalData->mnAppThreadId == nCurThreadId ) + UpdateWindow( mrParent.gethWnd() ); + } + + DeleteRegion( hInvalidateRgn ); + } + +} + +namespace { + +void ImplDrawBitmap( HDC hDC, const SalTwoRect& rPosAry, const WinSalBitmap& rSalBitmap, + bool bPrinter, int nDrawMode ) +{ + if( hDC ) + { + HGLOBAL hDrawDIB; + HBITMAP hDrawDDB = rSalBitmap.ImplGethDDB(); + WinSalBitmap* pTmpSalBmp = NULL; + bool bPrintDDB = ( bPrinter && hDrawDDB ); + + if( bPrintDDB ) + { + pTmpSalBmp = new WinSalBitmap; + pTmpSalBmp->Create( rSalBitmap, rSalBitmap.GetBitCount() ); + hDrawDIB = pTmpSalBmp->ImplGethDIB(); + } + else + hDrawDIB = rSalBitmap.ImplGethDIB(); + + if( hDrawDIB ) + { + PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDrawDIB ); + PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI; + PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI + + rSalBitmap.ImplGetDIBColorCount( hDrawDIB ) * sizeof( RGBQUAD ); + const int nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS ); + + StretchDIBits( hDC, + (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, + (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, + (int)rPosAry.mnSrcX, (int)(pBIH->biHeight - rPosAry.mnSrcHeight - rPosAry.mnSrcY), + (int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight, + pBits, pBI, DIB_RGB_COLORS, nDrawMode ); + + GlobalUnlock( hDrawDIB ); + SetStretchBltMode( hDC, nOldStretchMode ); + } + else if( hDrawDDB && !bPrintDDB ) + { + HDC hBmpDC = ImplGetCachedDC( CACHED_HDC_DRAW, hDrawDDB ); + COLORREF nOldBkColor = RGB(0xFF,0xFF,0xFF); + COLORREF nOldTextColor = RGB(0,0,0); + bool bMono = ( rSalBitmap.GetBitCount() == 1 ); + + if( bMono ) + { + COLORREF nBkColor = RGB( 0xFF, 0xFF, 0xFF ); + COLORREF nTextColor = RGB( 0x00, 0x00, 0x00 ); + //fdo#33455 handle 1 bit depth pngs with palette entries + //to set fore/back colors + if (const BitmapBuffer* pBitmapBuffer = const_cast<WinSalBitmap&>(rSalBitmap).AcquireBuffer(true)) + { + const BitmapPalette& rPalette = pBitmapBuffer->maPalette; + if (rPalette.GetEntryCount() == 2) + { + SalColor nCol; + nCol = ImplColorToSal(rPalette[0]); + nTextColor = RGB( SALCOLOR_RED(nCol), SALCOLOR_GREEN(nCol), SALCOLOR_BLUE(nCol) ); + nCol = ImplColorToSal(rPalette[1]); + nBkColor = RGB( SALCOLOR_RED(nCol), SALCOLOR_GREEN(nCol), SALCOLOR_BLUE(nCol) ); + } + } + nOldBkColor = SetBkColor( hDC, nBkColor ); + nOldTextColor = ::SetTextColor( hDC, nTextColor ); + } + + if ( (rPosAry.mnSrcWidth == rPosAry.mnDestWidth) && + (rPosAry.mnSrcHeight == rPosAry.mnDestHeight) ) + { + BitBlt( hDC, + (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, + (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, + hBmpDC, + (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY, + nDrawMode ); + } + else + { + const int nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS ); + + StretchBlt( hDC, + (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, + (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, + hBmpDC, + (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY, + (int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight, + nDrawMode ); + + SetStretchBltMode( hDC, nOldStretchMode ); + } + + if( bMono ) + { + SetBkColor( hDC, nOldBkColor ); + ::SetTextColor( hDC, nOldTextColor ); + } + + ImplReleaseCachedDC( CACHED_HDC_DRAW ); + } + + if( bPrintDDB ) + delete pTmpSalBmp; + } +} + +} + +void WinSalGraphicsImpl::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap) +{ + bool bTryDirectPaint(!mrParent.isPrinter() && !mbXORMode); + + if(bTryDirectPaint) + { + // only paint direct when no scaling and no MapMode, else the + // more expensive conversions may be done for short-time Bitmap/BitmapEx + // used for buffering only + if(rPosAry.mnSrcWidth == rPosAry.mnDestWidth && rPosAry.mnSrcHeight == rPosAry.mnDestHeight) + { + bTryDirectPaint = false; + } + } + + // try to draw using GdiPlus directly + if(bTryDirectPaint && tryDrawBitmapGdiPlus(rPosAry, rSalBitmap)) + { + return; + } + + // fall back old stuff + ImplDrawBitmap(mrParent.getHDC(), rPosAry, static_cast<const WinSalBitmap&>(rSalBitmap), + mrParent.isPrinter(), + mbXORMode ? SRCINVERT : SRCCOPY ); +} + +void WinSalGraphicsImpl::drawBitmap( const SalTwoRect& rPosAry, + const SalBitmap& rSSalBitmap, + SalColor nTransparentColor ) +{ + DBG_ASSERT( !mrParent.isPrinter(), "No transparency print possible!" ); + + const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap); + + WinSalBitmap* pMask = new WinSalBitmap; + const Point aPoint; + const Size aSize( rSalBitmap.GetSize() ); + HBITMAP hMaskBitmap = CreateBitmap( (int) aSize.Width(), (int) aSize.Height(), 1, 1, NULL ); + HDC hMaskDC = ImplGetCachedDC( CACHED_HDC_1, hMaskBitmap ); + const BYTE cRed = SALCOLOR_RED( nTransparentColor ); + const BYTE cGreen = SALCOLOR_GREEN( nTransparentColor ); + const BYTE cBlue = SALCOLOR_BLUE( nTransparentColor ); + + if( rSalBitmap.ImplGethDDB() ) + { + HDC hSrcDC = ImplGetCachedDC( CACHED_HDC_2, rSalBitmap.ImplGethDDB() ); + COLORREF aOldCol = SetBkColor( hSrcDC, RGB( cRed, cGreen, cBlue ) ); + + BitBlt( hMaskDC, 0, 0, (int) aSize.Width(), (int) aSize.Height(), hSrcDC, 0, 0, SRCCOPY ); + + SetBkColor( hSrcDC, aOldCol ); + ImplReleaseCachedDC( CACHED_HDC_2 ); + } + else + { + WinSalBitmap* pTmpSalBmp = new WinSalBitmap; + + if( pTmpSalBmp->Create( rSalBitmap, &mrParent ) ) + { + HDC hSrcDC = ImplGetCachedDC( CACHED_HDC_2, pTmpSalBmp->ImplGethDDB() ); + COLORREF aOldCol = SetBkColor( hSrcDC, RGB( cRed, cGreen, cBlue ) ); + + BitBlt( hMaskDC, 0, 0, (int) aSize.Width(), (int) aSize.Height(), hSrcDC, 0, 0, SRCCOPY ); + + SetBkColor( hSrcDC, aOldCol ); + ImplReleaseCachedDC( CACHED_HDC_2 ); + } + + delete pTmpSalBmp; + } + + ImplReleaseCachedDC( CACHED_HDC_1 ); + + // hMaskBitmap is destroyed by new SalBitmap 'pMask' ( bDIB==FALSE, bCopy == FALSE ) + if( pMask->Create( hMaskBitmap, FALSE, FALSE ) ) + drawBitmap( rPosAry, rSalBitmap, *pMask ); + + delete pMask; +} + +void WinSalGraphicsImpl::drawBitmap( const SalTwoRect& rPosAry, + const SalBitmap& rSSalBitmap, + const SalBitmap& rSTransparentBitmap ) +{ + DBG_ASSERT( !mrParent.isPrinter(), "No transparency print possible!" ); + bool bTryDirectPaint(!mrParent.isPrinter() && !mbXORMode); + + if(bTryDirectPaint) + { + // only paint direct when no scaling and no MapMode, else the + // more expensive conversions may be done for short-time Bitmap/BitmapEx + // used for buffering only + if(rPosAry.mnSrcWidth == rPosAry.mnDestWidth && rPosAry.mnSrcHeight == rPosAry.mnDestHeight) + { + bTryDirectPaint = false; + } + } + + // try to draw using GdiPlus directly + if(bTryDirectPaint && drawAlphaBitmap(rPosAry, rSSalBitmap, rSTransparentBitmap)) + { + return; + } + + const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap); + const WinSalBitmap& rTransparentBitmap = static_cast<const WinSalBitmap&>(rSTransparentBitmap); + + SalTwoRect aPosAry = rPosAry; + int nDstX = (int)aPosAry.mnDestX; + int nDstY = (int)aPosAry.mnDestY; + int nDstWidth = (int)aPosAry.mnDestWidth; + int nDstHeight = (int)aPosAry.mnDestHeight; + HDC hDC = mrParent.getHDC(); + HBITMAP hMemBitmap = 0; + HBITMAP hMaskBitmap = 0; + + if( ( nDstWidth > CACHED_HDC_DEFEXT ) || ( nDstHeight > CACHED_HDC_DEFEXT ) ) + { + hMemBitmap = CreateCompatibleBitmap( hDC, nDstWidth, nDstHeight ); + hMaskBitmap = CreateCompatibleBitmap( hDC, nDstWidth, nDstHeight ); + } + + HDC hMemDC = ImplGetCachedDC( CACHED_HDC_1, hMemBitmap ); + HDC hMaskDC = ImplGetCachedDC( CACHED_HDC_2, hMaskBitmap ); + + aPosAry.mnDestX = aPosAry.mnDestY = 0; + BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hDC, nDstX, nDstY, SRCCOPY ); + + // WIN/WNT seems to have a minor problem mapping the correct color of the + // mask to the palette if we draw the DIB directly ==> draw DDB + if( ( GetBitCount() <= 8 ) && rTransparentBitmap.ImplGethDIB() && rTransparentBitmap.GetBitCount() == 1 ) + { + WinSalBitmap aTmp; + + if( aTmp.Create( rTransparentBitmap, &mrParent ) ) + ImplDrawBitmap( hMaskDC, aPosAry, aTmp, FALSE, SRCCOPY ); + } + else + ImplDrawBitmap( hMaskDC, aPosAry, rTransparentBitmap, FALSE, SRCCOPY ); + + // now MemDC contains background, MaskDC the transparency mask + + // #105055# Respect XOR mode + if( mbXORMode ) + { + ImplDrawBitmap( hMaskDC, aPosAry, rSalBitmap, FALSE, SRCERASE ); + // now MaskDC contains the bitmap area with black background + BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCINVERT ); + // now MemDC contains background XORed bitmap area ontop + } + else + { + BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCAND ); + // now MemDC contains background with masked-out bitmap area + ImplDrawBitmap( hMaskDC, aPosAry, rSalBitmap, FALSE, SRCERASE ); + // now MaskDC contains the bitmap area with black background + BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCPAINT ); + // now MemDC contains background and bitmap merged together + } + // copy to output DC + BitBlt( hDC, nDstX, nDstY, nDstWidth, nDstHeight, hMemDC, 0, 0, SRCCOPY ); + + ImplReleaseCachedDC( CACHED_HDC_1 ); + ImplReleaseCachedDC( CACHED_HDC_2 ); + + // hMemBitmap != 0 ==> hMaskBitmap != 0 + if( hMemBitmap ) + { + DeleteObject( hMemBitmap ); + DeleteObject( hMaskBitmap ); + } +} + +bool WinSalGraphicsImpl::drawAlphaRect( long nX, long nY, long nWidth, + long nHeight, sal_uInt8 nTransparency ) +{ + if( mbPen || !mbBrush || mbXORMode ) + return false; // can only perform solid fills without XOR. + + HDC hMemDC = ImplGetCachedDC( CACHED_HDC_1, 0 ); + SetPixel( hMemDC, (int)0, (int)0, mnBrushColor ); + + BLENDFUNCTION aFunc = { + AC_SRC_OVER, + 0, + sal::static_int_cast<sal_uInt8>(255 - 255L*nTransparency/100), + 0 + }; + + // hMemDC contains a 1x1 bitmap of the right color - stretch-blit + // that to dest hdc + bool bRet = AlphaBlend( mrParent.getHDC(), nX, nY, nWidth, nHeight, + hMemDC, 0,0,1,1, + aFunc ) == TRUE; + + ImplReleaseCachedDC( CACHED_HDC_1 ); + + return bRet; +} + +void WinSalGraphicsImpl::drawMask( const SalTwoRect& rPosAry, + const SalBitmap& rSSalBitmap, + SalColor nMaskColor ) +{ + DBG_ASSERT( !mrParent.isPrinter(), "No transparency print possible!" ); + + const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap); + + SalTwoRect aPosAry = rPosAry; + const BYTE cRed = SALCOLOR_RED( nMaskColor ); + const BYTE cGreen = SALCOLOR_GREEN( nMaskColor ); + const BYTE cBlue = SALCOLOR_BLUE( nMaskColor ); + HDC hDC = mrParent.getHDC(); + HBRUSH hMaskBrush = CreateSolidBrush( RGB( cRed, cGreen, cBlue ) ); + HBRUSH hOldBrush = SelectBrush( hDC, hMaskBrush ); + + // WIN/WNT seems to have a minor problem mapping the correct color of the + // mask to the palette if we draw the DIB directly ==> draw DDB + if( ( GetBitCount() <= 8 ) && rSalBitmap.ImplGethDIB() && rSalBitmap.GetBitCount() == 1 ) + { + WinSalBitmap aTmp; + + if( aTmp.Create( rSalBitmap, &mrParent ) ) + ImplDrawBitmap( hDC, aPosAry, aTmp, FALSE, 0x00B8074AUL ); + } + else + ImplDrawBitmap( hDC, aPosAry, rSalBitmap, FALSE, 0x00B8074AUL ); + + SelectBrush( hDC, hOldBrush ); + DeleteBrush( hMaskBrush ); +} + +SalBitmap* WinSalGraphicsImpl::getBitmap( long nX, long nY, long nDX, long nDY ) +{ + DBG_ASSERT( !mrParent.isPrinter(), "No ::GetBitmap() from printer possible!" ); + + WinSalBitmap* pSalBitmap = NULL; + + nDX = labs( nDX ); + nDY = labs( nDY ); + + HDC hDC = mrParent.getHDC(); + HBITMAP hBmpBitmap = CreateCompatibleBitmap( hDC, nDX, nDY ); + HDC hBmpDC = ImplGetCachedDC( CACHED_HDC_1, hBmpBitmap ); + bool bRet; + + bRet = BitBlt( hBmpDC, 0, 0, (int) nDX, (int) nDY, hDC, (int) nX, (int) nY, SRCCOPY ) ? TRUE : FALSE; + ImplReleaseCachedDC( CACHED_HDC_1 ); + + if( bRet ) + { + pSalBitmap = new WinSalBitmap; + + if( !pSalBitmap->Create( hBmpBitmap, FALSE, FALSE ) ) + { + delete pSalBitmap; + pSalBitmap = NULL; + } + } + else + { + // #124826# avoid resource leak ! happens when runing without desktop access (remote desktop, service, may be screensavers) + DeleteBitmap( hBmpBitmap ); + } + + return pSalBitmap; +} + +SalColor WinSalGraphicsImpl::getPixel( long nX, long nY ) +{ + COLORREF aWinCol = ::GetPixel( mrParent.getHDC(), (int) nX, (int) nY ); + + if ( CLR_INVALID == aWinCol ) + return MAKE_SALCOLOR( 0, 0, 0 ); + else + return MAKE_SALCOLOR( GetRValue( aWinCol ), + GetGValue( aWinCol ), + GetBValue( aWinCol ) ); +} + +void WinSalGraphicsImpl::invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags ) +{ + if ( nFlags & SAL_INVERT_TRACKFRAME ) + { + HPEN hDotPen = CreatePen( PS_DOT, 0, 0 ); + HPEN hOldPen = SelectPen( mrParent.getHDC(), hDotPen ); + HBRUSH hOldBrush = SelectBrush( mrParent.getHDC(), GetStockBrush( NULL_BRUSH ) ); + int nOldROP = SetROP2( mrParent.getHDC(), R2_NOT ); + + WIN_Rectangle( mrParent.getHDC(), (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) ); + + SetROP2( mrParent.getHDC(), nOldROP ); + SelectPen( mrParent.getHDC(), hOldPen ); + SelectBrush( mrParent.getHDC(), hOldBrush ); + DeletePen( hDotPen ); + } + else if ( nFlags & SAL_INVERT_50 ) + { + SalData* pSalData = GetSalData(); + if ( !pSalData->mh50Brush ) + { + if ( !pSalData->mh50Bmp ) + pSalData->mh50Bmp = ImplLoadSalBitmap( SAL_RESID_BITMAP_50 ); + pSalData->mh50Brush = CreatePatternBrush( pSalData->mh50Bmp ); + } + + COLORREF nOldTextColor = ::SetTextColor( mrParent.getHDC(), 0 ); + HBRUSH hOldBrush = SelectBrush( mrParent.getHDC(), pSalData->mh50Brush ); + PatBlt( mrParent.getHDC(), nX, nY, nWidth, nHeight, PATINVERT ); + ::SetTextColor( mrParent.getHDC(), nOldTextColor ); + SelectBrush( mrParent.getHDC(), hOldBrush ); + } + else + { + RECT aRect; + aRect.left = (int)nX; + aRect.top = (int)nY; + aRect.right = (int)nX+nWidth; + aRect.bottom = (int)nY+nHeight; + ::InvertRect( mrParent.getHDC(), &aRect ); + } +} + +void WinSalGraphicsImpl::invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nSalFlags ) +{ + HPEN hPen; + HPEN hOldPen; + HBRUSH hBrush; + HBRUSH hOldBrush = 0; + COLORREF nOldTextColor RGB(0,0,0); + int nOldROP = SetROP2( mrParent.getHDC(), R2_NOT ); + + if ( nSalFlags & SAL_INVERT_TRACKFRAME ) + hPen = CreatePen( PS_DOT, 0, 0 ); + else + { + + if ( nSalFlags & SAL_INVERT_50 ) + { + SalData* pSalData = GetSalData(); + if ( !pSalData->mh50Brush ) + { + if ( !pSalData->mh50Bmp ) + pSalData->mh50Bmp = ImplLoadSalBitmap( SAL_RESID_BITMAP_50 ); + pSalData->mh50Brush = CreatePatternBrush( pSalData->mh50Bmp ); + } + + hBrush = pSalData->mh50Brush; + } + else + hBrush = GetStockBrush( BLACK_BRUSH ); + + hPen = GetStockPen( NULL_PEN ); + nOldTextColor = ::SetTextColor( mrParent.getHDC(), 0 ); + hOldBrush = SelectBrush( mrParent.getHDC(), hBrush ); + } + hOldPen = SelectPen( mrParent.getHDC(), hPen ); + + POINT* pWinPtAry; + // for NT, we can handover the array directly + DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), + "WinSalGraphicsImpl::DrawPolyLine(): POINT != SalPoint" ); + + pWinPtAry = (POINT*)pPtAry; + // for Windows 95 and its maximum number of points + if ( nSalFlags & SAL_INVERT_TRACKFRAME ) + { + if ( !Polyline( mrParent.getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) ) + Polyline( mrParent.getHDC(), pWinPtAry, MAX_64KSALPOINTS ); + } + else + { + if ( !WIN_Polygon( mrParent.getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) ) + WIN_Polygon( mrParent.getHDC(), pWinPtAry, MAX_64KSALPOINTS ); + } + + SetROP2( mrParent.getHDC(), nOldROP ); + SelectPen( mrParent.getHDC(), hOldPen ); + + if ( nSalFlags & SAL_INVERT_TRACKFRAME ) + DeletePen( hPen ); + else + { + ::SetTextColor( mrParent.getHDC(), nOldTextColor ); + SelectBrush( mrParent.getHDC(), hOldBrush ); + } +} + +sal_uInt16 WinSalGraphicsImpl::GetBitCount() const +{ + return (sal_uInt16)GetDeviceCaps( mrParent.getHDC(), BITSPIXEL ); +} + +long WinSalGraphicsImpl::GetGraphicsWidth() const +{ + if( mrParent.gethWnd() && IsWindow( mrParent.gethWnd() ) ) + { + WinSalFrame* pFrame = GetWindowPtr( mrParent.gethWnd() ); + if( pFrame ) + { + if( pFrame->maGeometry.nWidth ) + return pFrame->maGeometry.nWidth; + else + { + // TODO: perhaps not needed, maGeometry should always be up-to-date + RECT aRect; + GetClientRect( mrParent.gethWnd(), &aRect ); + return aRect.right; + } + } + } + + return 0; +} + +void WinSalGraphicsImpl::ResetClipRegion() +{ + if ( mrParent.mhRegion ) + { + DeleteRegion( mrParent.mhRegion ); + mrParent.mhRegion = 0; + } + + SelectClipRgn( mrParent.getHDC(), 0 ); +} + +bool WinSalGraphicsImpl::setClipRegion( const vcl::Region& i_rClip ) +{ + if ( mrParent.mhRegion ) + { + DeleteRegion( mrParent.mhRegion ); + mrParent.mhRegion = 0; + } + + bool bUsePolygon(i_rClip.HasPolyPolygonOrB2DPolyPolygon()); + static bool bTryToAvoidPolygon(true); + + // #i122149# try to avoid usage of tools::PolyPolygon ClipRegions when tools::PolyPolygon is no curve + // and only contains horizontal/vertical edges. In that case, use the fallback + // in GetRegionRectangles which will use vcl::Region::GetAsRegionBand() which will do + // the correct polygon-to-RegionBand transformation. + // Background is that when using the same Rectangle as rectangle or as Polygon + // clip region will lead to different results; the polygon-based one will be + // one pixel less to the right and down (see GDI docu for CreatePolygonRgn). This + // again is because of the polygon-nature and it's classic handling when filling. + // This also means that all cases which use a 'true' polygon-based incarnation of + // a vcl::Region should know what they do - it may lead to repaint errors. + if(bUsePolygon && bTryToAvoidPolygon) + { + const basegfx::B2DPolyPolygon aPolyPolygon( i_rClip.GetAsB2DPolyPolygon() ); + + if(!aPolyPolygon.areControlPointsUsed()) + { + if(basegfx::tools::containsOnlyHorizontalAndVerticalEdges(aPolyPolygon)) + { + bUsePolygon = false; + } + } + } + + if(bUsePolygon) + { + // #i122149# check the comment above to know that this may lead to potential repaint + // problems. It may be solved (if needed) by scaling the polygon by one in X + // and Y. Currently the workaround to only use it if really unavoidable will + // solve most cases. When someone is really using polygon-based Regions he + // should know what he is doing. + // Added code to do that scaling to check if it works, testing it. + const basegfx::B2DPolyPolygon aPolyPolygon( i_rClip.GetAsB2DPolyPolygon() ); + const sal_uInt32 nCount(aPolyPolygon.count()); + + if( nCount ) + { + std::vector< POINT > aPolyPoints; + aPolyPoints.reserve( 1024 ); + std::vector< INT > aPolyCounts( nCount, 0 ); + basegfx::B2DHomMatrix aExpand; + static bool bExpandByOneInXandY(true); + + if(bExpandByOneInXandY) + { + const basegfx::B2DRange aRangeS(aPolyPolygon.getB2DRange()); + const basegfx::B2DRange aRangeT(aRangeS.getMinimum(), aRangeS.getMaximum() + basegfx::B2DTuple(1.0, 1.0)); + aExpand = basegfx::B2DHomMatrix(basegfx::tools::createSourceRangeTargetRangeTransform(aRangeS, aRangeT)); + } + + for(sal_uInt32 a(0); a < nCount; a++) + { + const basegfx::B2DPolygon aPoly( + basegfx::tools::adaptiveSubdivideByDistance( + aPolyPolygon.getB2DPolygon(a), + 1)); + const sal_uInt32 nPoints(aPoly.count()); + aPolyCounts[a] = nPoints; + + for( sal_uInt32 b = 0; b < nPoints; b++ ) + { + basegfx::B2DPoint aPt(aPoly.getB2DPoint(b)); + + if(bExpandByOneInXandY) + { + aPt = aExpand * aPt; + } + + POINT aPOINT; + // #i122149# do correct rounding + aPOINT.x = basegfx::fround(aPt.getX()); + aPOINT.y = basegfx::fround(aPt.getY()); + aPolyPoints.push_back( aPOINT ); + } + } + + mrParent.mhRegion = CreatePolyPolygonRgn( &aPolyPoints[0], &aPolyCounts[0], nCount, ALTERNATE ); + } + } + else + { + RectangleVector aRectangles; + i_rClip.GetRegionRectangles(aRectangles); + + sal_uLong nRectBufSize = sizeof(RECT)*aRectangles.size(); + if ( aRectangles.size() < SAL_CLIPRECT_COUNT ) + { + if ( !mrParent.mpStdClipRgnData ) + mrParent.mpStdClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+(SAL_CLIPRECT_COUNT*sizeof(RECT))]; + mrParent.mpClipRgnData = mrParent.mpStdClipRgnData; + } + else + mrParent.mpClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+nRectBufSize]; + mrParent.mpClipRgnData->rdh.dwSize = sizeof( RGNDATAHEADER ); + mrParent.mpClipRgnData->rdh.iType = RDH_RECTANGLES; + mrParent.mpClipRgnData->rdh.nCount = aRectangles.size(); + mrParent.mpClipRgnData->rdh.nRgnSize = nRectBufSize; + RECT* pBoundRect = &(mrParent.mpClipRgnData->rdh.rcBound); + SetRectEmpty( pBoundRect ); + RECT* pNextClipRect = (RECT*)(&(mrParent.mpClipRgnData->Buffer)); + bool bFirstClipRect = true; + + for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter) + { + const long nW(aRectIter->GetWidth()); + const long nH(aRectIter->GetHeight()); + + if(nW && nH) + { + const long nRight(aRectIter->Left() + nW); + const long nBottom(aRectIter->Top() + nH); + + if(bFirstClipRect) + { + pBoundRect->left = aRectIter->Left(); + pBoundRect->top = aRectIter->Top(); + pBoundRect->right = nRight; + pBoundRect->bottom = nBottom; + bFirstClipRect = false; + } + else + { + if(aRectIter->Left() < pBoundRect->left) + { + pBoundRect->left = (int)aRectIter->Left(); + } + + if(aRectIter->Top() < pBoundRect->top) + { + pBoundRect->top = (int)aRectIter->Top(); + } + + if(nRight > pBoundRect->right) + { + pBoundRect->right = (int)nRight; + } + + if(nBottom > pBoundRect->bottom) + { + pBoundRect->bottom = (int)nBottom; + } + } + + pNextClipRect->left = (int)aRectIter->Left(); + pNextClipRect->top = (int)aRectIter->Top(); + pNextClipRect->right = (int)nRight; + pNextClipRect->bottom = (int)nBottom; + pNextClipRect++; + } + else + { + mrParent.mpClipRgnData->rdh.nCount--; + mrParent.mpClipRgnData->rdh.nRgnSize -= sizeof( RECT ); + } + } + + // create clip region from ClipRgnData + if(0 == mrParent.mpClipRgnData->rdh.nCount) + { + // #i123585# region is empty; this may happen when e.g. a tools::PolyPolygon is given + // that contains no polygons or only empty ones (no width/height). This is + // perfectly fine and we are done, except setting it (see end of method) + } + else if(1 == mrParent.mpClipRgnData->rdh.nCount) + { + RECT* pRect = &(mrParent.mpClipRgnData->rdh.rcBound); + mrParent.mhRegion = CreateRectRgn( pRect->left, pRect->top, + pRect->right, pRect->bottom ); + } + else if(mrParent.mpClipRgnData->rdh.nCount > 1) + { + sal_uLong nSize = mrParent.mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER); + mrParent.mhRegion = ExtCreateRegion( NULL, nSize, mrParent.mpClipRgnData ); + + // if ExtCreateRegion(...) is not supported + if( !mrParent.mhRegion ) + { + RGNDATAHEADER* pHeader = (RGNDATAHEADER*) mrParent.mpClipRgnData; + + if( pHeader->nCount ) + { + RECT* pRect = (RECT*) mrParent.mpClipRgnData->Buffer; + mrParent.mhRegion = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom ); + pRect++; + + for( sal_uLong n = 1; n < pHeader->nCount; n++, pRect++ ) + { + HRGN hRgn = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom ); + CombineRgn( mrParent.mhRegion, mrParent.mhRegion, hRgn, RGN_OR ); + DeleteRegion( hRgn ); + } + } + } + + if ( mrParent.mpClipRgnData != mrParent.mpStdClipRgnData ) + delete [] mrParent.mpClipRgnData; + } + } + + if( mrParent.mhRegion ) + { + SelectClipRgn( mrParent.getHDC(), mrParent.mhRegion ); + + // debug code if you weant to check range of the newly applied ClipRegion + //RECT aBound; + //const int aRegionType = GetRgnBox(mrParent.mhRegion, &aBound); + + //bool bBla = true; + } + else + { + // #i123585# See above, this is a valid case, execute it + SelectClipRgn( mrParent.getHDC(), 0 ); + } + + // #i123585# retval no longer dependent of mrParent.mhRegion, see TaskId comments above + return true; +} + +void WinSalGraphicsImpl::SetLineColor() +{ + // create and select new pen + HPEN hNewPen = GetStockPen( NULL_PEN ); + HPEN hOldPen = SelectPen( mrParent.getHDC(), hNewPen ); + + // destroy or save old pen + if ( mhPen ) + { + if ( !mbStockPen ) + DeletePen( mhPen ); + } + else + mrParent.mhDefPen = hOldPen; + + // set new data + mhPen = hNewPen; + mbPen = FALSE; + mbStockPen = TRUE; +} + +void WinSalGraphicsImpl::SetLineColor( SalColor nSalColor ) +{ + maLineColor = nSalColor; + COLORREF nPenColor = PALETTERGB( SALCOLOR_RED( nSalColor ), + SALCOLOR_GREEN( nSalColor ), + SALCOLOR_BLUE( nSalColor ) ); + HPEN hNewPen = 0; + bool bStockPen = FALSE; + + // search for stock pen (only screen, because printer have problems, + // when we use stock objects) + if ( !mrParent.isPrinter() ) + { + SalData* pSalData = GetSalData(); + for ( sal_uInt16 i = 0; i < pSalData->mnStockPenCount; i++ ) + { + if ( nPenColor == pSalData->maStockPenColorAry[i] ) + { + hNewPen = pSalData->mhStockPenAry[i]; + bStockPen = TRUE; + break; + } + } + } + + // create new pen + if ( !hNewPen ) + { + if ( !mrParent.isPrinter() ) + { + if ( GetSalData()->mhDitherPal && ImplIsSysColorEntry( nSalColor ) ) + nPenColor = PALRGB_TO_RGB( nPenColor ); + } + + hNewPen = CreatePen( PS_SOLID, mrParent.mnPenWidth, nPenColor ); + bStockPen = FALSE; + } + + // select new pen + HPEN hOldPen = SelectPen( mrParent.getHDC(), hNewPen ); + + // destroy or save old pen + if ( mhPen ) + { + if ( !mbStockPen ) + DeletePen( mhPen ); + } + else + mrParent.mhDefPen = hOldPen; + + // set new data + mnPenColor = nPenColor; + mhPen = hNewPen; + mbPen = TRUE; + mbStockPen = bStockPen; +} + +void WinSalGraphicsImpl::SetFillColor() +{ + // create and select new brush + HBRUSH hNewBrush = GetStockBrush( NULL_BRUSH ); + HBRUSH hOldBrush = SelectBrush( mrParent.getHDC(), hNewBrush ); + + // destroy or save old brush + if ( mhBrush ) + { + if ( !mbStockBrush ) + DeleteBrush( mhBrush ); + } + else + mrParent.mhDefBrush = hOldBrush; + + // set new data + mhBrush = hNewBrush; + mbBrush = FALSE; + mbStockBrush = TRUE; +} + +void WinSalGraphicsImpl::SetFillColor( SalColor nSalColor ) +{ + maFillColor = nSalColor; + SalData* pSalData = GetSalData(); + BYTE nRed = SALCOLOR_RED( nSalColor ); + BYTE nGreen = SALCOLOR_GREEN( nSalColor ); + BYTE nBlue = SALCOLOR_BLUE( nSalColor ); + COLORREF nBrushColor = PALETTERGB( nRed, nGreen, nBlue ); + HBRUSH hNewBrush = 0; + bool bStockBrush = FALSE; + + // search for stock brush (only screen, because printer have problems, + // when we use stock objects) + if ( !mrParent.isPrinter() ) + { + for ( sal_uInt16 i = 0; i < pSalData->mnStockBrushCount; i++ ) + { + if ( nBrushColor == pSalData->maStockBrushColorAry[ i ] ) + { + hNewBrush = pSalData->mhStockBrushAry[i]; + bStockBrush = TRUE; + break; + } + } + } + + // create new brush + if ( !hNewBrush ) + { + if ( mrParent.isPrinter() || !pSalData->mhDitherDIB ) + hNewBrush = CreateSolidBrush( nBrushColor ); + else + { + if ( 24 == ((BITMAPINFOHEADER*)pSalData->mpDitherDIB)->biBitCount ) + { + BYTE* pTmp = pSalData->mpDitherDIBData; + long* pDitherDiff = pSalData->mpDitherDiff; + BYTE* pDitherLow = pSalData->mpDitherLow; + BYTE* pDitherHigh = pSalData->mpDitherHigh; + + for( long nY = 0L; nY < 8L; nY++ ) + { + for( long nX = 0L; nX < 8L; nX++ ) + { + const long nThres = aOrdDither16Bit[ nY ][ nX ]; + *pTmp++ = DMAP( nBlue, nThres ); + *pTmp++ = DMAP( nGreen, nThres ); + *pTmp++ = DMAP( nRed, nThres ); + } + } + + hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_RGB_COLORS ); + } + else if ( ImplIsSysColorEntry( nSalColor ) ) + { + nBrushColor = PALRGB_TO_RGB( nBrushColor ); + hNewBrush = CreateSolidBrush( nBrushColor ); + } + else if ( ImplIsPaletteEntry( nRed, nGreen, nBlue ) ) + hNewBrush = CreateSolidBrush( nBrushColor ); + else + { + BYTE* pTmp = pSalData->mpDitherDIBData; + long* pDitherDiff = pSalData->mpDitherDiff; + BYTE* pDitherLow = pSalData->mpDitherLow; + BYTE* pDitherHigh = pSalData->mpDitherHigh; + + for ( long nY = 0L; nY < 8L; nY++ ) + { + for ( long nX = 0L; nX < 8L; nX++ ) + { + const long nThres = aOrdDither8Bit[ nY ][ nX ]; + *pTmp = DMAP( nRed, nThres ) + DMAP( nGreen, nThres ) * 6 + DMAP( nBlue, nThres ) * 36; + pTmp++; + } + } + + hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_PAL_COLORS ); + } + } + + bStockBrush = FALSE; + } + + // select new brush + HBRUSH hOldBrush = SelectBrush( mrParent.getHDC(), hNewBrush ); + + // destroy or save old brush + if ( mhBrush ) + { + if ( !mbStockBrush ) + DeleteBrush( mhBrush ); + } + else + mrParent.mhDefBrush = hOldBrush; + + // set new data + mnBrushColor = nBrushColor; + mhBrush = hNewBrush; + mbBrush = TRUE; + mbStockBrush = bStockBrush; +} + +void WinSalGraphicsImpl::SetXORMode( bool bSet, bool ) +{ + mbXORMode = bSet; + ::SetROP2( mrParent.getHDC(), bSet ? R2_XORPEN : R2_COPYPEN ); +} + +void WinSalGraphicsImpl::SetROPLineColor( SalROPColor nROPColor ) +{ + SetLineColor( ImplGetROPSalColor( nROPColor ) ); +} + +void WinSalGraphicsImpl::SetROPFillColor( SalROPColor nROPColor ) +{ + SetFillColor( ImplGetROPSalColor( nROPColor ) ); +} + +void WinSalGraphicsImpl::drawPixel( long nX, long nY ) +{ + if ( mbXORMode ) + { + HBRUSH hBrush = CreateSolidBrush( mnPenColor ); + HBRUSH hOldBrush = SelectBrush( mrParent.getHDC(), hBrush ); + PatBlt( mrParent.getHDC(), (int)nX, (int)nY, (int)1, (int)1, PATINVERT ); + SelectBrush( mrParent.getHDC(), hOldBrush ); + DeleteBrush( hBrush ); + } + else + SetPixel( mrParent.getHDC(), (int)nX, (int)nY, mnPenColor ); +} + +void WinSalGraphicsImpl::drawPixel( long nX, long nY, SalColor nSalColor ) +{ + COLORREF nCol = PALETTERGB( SALCOLOR_RED( nSalColor ), + SALCOLOR_GREEN( nSalColor ), + SALCOLOR_BLUE( nSalColor ) ); + + if ( !mrParent.isPrinter() && + GetSalData()->mhDitherPal && + ImplIsSysColorEntry( nSalColor ) ) + nCol = PALRGB_TO_RGB( nCol ); + + if ( mbXORMode ) + { + HBRUSH hBrush = CreateSolidBrush( nCol ); + HBRUSH hOldBrush = SelectBrush( mrParent.getHDC(), hBrush ); + PatBlt( mrParent.getHDC(), (int)nX, (int)nY, (int)1, (int)1, PATINVERT ); + SelectBrush( mrParent.getHDC(), hOldBrush ); + DeleteBrush( hBrush ); + } + else + ::SetPixel( mrParent.getHDC(), (int)nX, (int)nY, nCol ); +} + +void WinSalGraphicsImpl::drawLine( long nX1, long nY1, long nX2, long nY2 ) +{ + MoveToEx( mrParent.getHDC(), (int)nX1, (int)nY1, NULL ); + + // we must paint the endpoint + int bPaintEnd = TRUE; + if ( nX1 == nX2 ) + { + bPaintEnd = FALSE; + if ( nY1 <= nY2 ) + nY2++; + else + nY2--; + } + if ( nY1 == nY2 ) + { + bPaintEnd = FALSE; + if ( nX1 <= nX2 ) + nX2++; + else + nX2--; + } + + LineTo( mrParent.getHDC(), (int)nX2, (int)nY2 ); + + if ( bPaintEnd && !mrParent.isPrinter() ) + { + if ( mbXORMode ) + { + HBRUSH hBrush = CreateSolidBrush( mnPenColor ); + HBRUSH hOldBrush = SelectBrush( mrParent.getHDC(), hBrush ); + PatBlt( mrParent.getHDC(), (int)nX2, (int)nY2, (int)1, (int)1, PATINVERT ); + SelectBrush( mrParent.getHDC(), hOldBrush ); + DeleteBrush( hBrush ); + } + else + SetPixel( mrParent.getHDC(), (int)nX2, (int)nY2, mnPenColor ); + } +} + +void WinSalGraphicsImpl::drawRect( long nX, long nY, long nWidth, long nHeight ) +{ + if ( !mbPen ) + { + if ( !mrParent.isPrinter() ) + { + PatBlt( mrParent.getHDC(), (int)nX, (int)nY, (int)nWidth, (int)nHeight, + mbXORMode ? PATINVERT : PATCOPY ); + } + else + { + RECT aWinRect; + aWinRect.left = nX; + aWinRect.top = nY; + aWinRect.right = nX+nWidth; + aWinRect.bottom = nY+nHeight; + ::FillRect( mrParent.getHDC(), &aWinRect, mhBrush ); + } + } + else + WIN_Rectangle( mrParent.getHDC(), (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) ); +} + +void WinSalGraphicsImpl::drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) +{ + // for NT, we can handover the array directly + DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), + "WinSalGraphicsImpl::DrawPolyLine(): POINT != SalPoint" ); + + POINT* pWinPtAry = (POINT*)pPtAry; + + // we assume there are at least 2 points (Polyline requres at least 2 point, see MSDN) + // we must paint the endpoint for last line + BOOL bPaintEnd = TRUE; + if ( pWinPtAry[nPoints-2].x == pWinPtAry[nPoints-1].x ) + { + bPaintEnd = FALSE; + if ( pWinPtAry[nPoints-2].y <= pWinPtAry[nPoints-1].y ) + pWinPtAry[nPoints-1].y++; + else + pWinPtAry[nPoints-1].y--; + } + if ( pWinPtAry[nPoints-2].y == pWinPtAry[nPoints-1].y ) + { + bPaintEnd = FALSE; + if ( pWinPtAry[nPoints-2].x <= pWinPtAry[nPoints-1].x ) + pWinPtAry[nPoints-1].x++; + else + pWinPtAry[nPoints-1].x--; + } + + // for Windows 95 and its maximum number of points + if ( !Polyline( mrParent.getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) ) + Polyline( mrParent.getHDC(), pWinPtAry, MAX_64KSALPOINTS ); + + if ( bPaintEnd && !mrParent.isPrinter() ) + { + if ( mbXORMode ) + { + HBRUSH hBrush = CreateSolidBrush( mnPenColor ); + HBRUSH hOldBrush = SelectBrush( mrParent.getHDC(), hBrush ); + PatBlt( mrParent.getHDC(), (int)(pWinPtAry[nPoints-1].x), (int)(pWinPtAry[nPoints-1].y), (int)1, (int)1, PATINVERT ); + SelectBrush( mrParent.getHDC(), hOldBrush ); + DeleteBrush( hBrush ); + } + else + SetPixel( mrParent.getHDC(), (int)(pWinPtAry[nPoints-1].x), (int)(pWinPtAry[nPoints-1].y), mnPenColor ); + } +} + +void WinSalGraphicsImpl::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) +{ + // for NT, we can handover the array directly + DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), + "WinSalGraphicsImpl::DrawPolygon(): POINT != SalPoint" ); + + POINT* pWinPtAry = (POINT*)pPtAry; + // for Windows 95 and its maximum number of points + if ( !WIN_Polygon( mrParent.getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) ) + WIN_Polygon( mrParent.getHDC(), pWinPtAry, MAX_64KSALPOINTS ); +} + +void WinSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, + PCONSTSALPOINT* pPtAry ) +{ + UINT aWinPointAry[SAL_POLYPOLYCOUNT_STACKBUF]; + UINT* pWinPointAry; + UINT nPolyPolyPoints = 0; + UINT nPoints; + UINT i; + + if ( nPoly <= SAL_POLYPOLYCOUNT_STACKBUF ) + pWinPointAry = aWinPointAry; + else + pWinPointAry = new UINT[nPoly]; + + for ( i = 0; i < (UINT)nPoly; i++ ) + { + nPoints = (UINT)pPoints[i]+1; + pWinPointAry[i] = nPoints; + nPolyPolyPoints += nPoints; + } + + POINT aWinPointAryAry[SAL_POLYPOLYPOINTS_STACKBUF]; + POINT* pWinPointAryAry; + if ( nPolyPolyPoints <= SAL_POLYPOLYPOINTS_STACKBUF ) + pWinPointAryAry = aWinPointAryAry; + else + pWinPointAryAry = new POINT[nPolyPolyPoints]; + // for NT, we can handover the array directly + DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), + "WinSalGraphicsImpl::DrawPolyPolygon(): POINT != SalPoint" ); + const SalPoint* pPolyAry; + UINT n = 0; + for ( i = 0; i < (UINT)nPoly; i++ ) + { + nPoints = pWinPointAry[i]; + pPolyAry = pPtAry[i]; + memcpy( pWinPointAryAry+n, pPolyAry, (nPoints-1)*sizeof(POINT) ); + pWinPointAryAry[n+nPoints-1] = pWinPointAryAry[n]; + n += nPoints; + } + + if ( !WIN_PolyPolygon( mrParent.getHDC(), pWinPointAryAry, (int*)pWinPointAry, (UINT)nPoly ) && + (nPolyPolyPoints > MAX_64KSALPOINTS) ) + { + nPolyPolyPoints = 0; + nPoly = 0; + do + { + nPolyPolyPoints += pWinPointAry[(UINT)nPoly]; + nPoly++; + } + while ( nPolyPolyPoints < MAX_64KSALPOINTS ); + nPoly--; + if ( pWinPointAry[(UINT)nPoly] > MAX_64KSALPOINTS ) + pWinPointAry[(UINT)nPoly] = MAX_64KSALPOINTS; + if ( nPoly == 1 ) + WIN_Polygon( mrParent.getHDC(), pWinPointAryAry, *pWinPointAry ); + else + WIN_PolyPolygon( mrParent.getHDC(), pWinPointAryAry, (int*)pWinPointAry, nPoly ); + } + + if ( pWinPointAry != aWinPointAry ) + delete [] pWinPointAry; + if ( pWinPointAryAry != aWinPointAryAry ) + delete [] pWinPointAryAry; +} + +bool WinSalGraphicsImpl::drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry ) +{ +#ifdef USE_GDI_BEZIERS + // for NT, we can handover the array directly + DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), + "WinSalGraphicsImpl::DrawPolyLineBezier(): POINT != SalPoint" ); + + ImplRenderPath( mrParent.getHDC(), nPoints, pPtAry, pFlgAry ); + + return true; +#else + return false; +#endif +} + +bool WinSalGraphicsImpl::drawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry ) +{ +#ifdef USE_GDI_BEZIERS + // for NT, we can handover the array directly + DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), + "WinSalGraphicsImpl::DrawPolygonBezier(): POINT != SalPoint" ); + + POINT aStackAry1[SAL_POLY_STACKBUF]; + BYTE aStackAry2[SAL_POLY_STACKBUF]; + POINT* pWinPointAry; + BYTE* pWinFlagAry; + if( nPoints > SAL_POLY_STACKBUF ) + { + pWinPointAry = new POINT[ nPoints ]; + pWinFlagAry = new BYTE[ nPoints ]; + } + else + { + pWinPointAry = aStackAry1; + pWinFlagAry = aStackAry2; + } + + sal_uInt32 nPoints_i32(nPoints); + ImplPreparePolyDraw(true, 1, &nPoints_i32, &pPtAry, &pFlgAry, pWinPointAry, pWinFlagAry); + + bool bRet( false ); + + if( BeginPath( mrParent.getHDC() ) ) + { + PolyDraw(mrParent.getHDC(), pWinPointAry, pWinFlagAry, nPoints); + + if( EndPath( mrParent.getHDC() ) ) + { + if( StrokeAndFillPath( mrParent.getHDC() ) ) + bRet = true; + } + } + + if( pWinPointAry != aStackAry1 ) + { + delete [] pWinPointAry; + delete [] pWinFlagAry; + } + + return bRet; +#else + return false; +#endif +} + +bool WinSalGraphicsImpl::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, const BYTE* const* pFlgAry ) +{ +#ifdef USE_GDI_BEZIERS + // for NT, we can handover the array directly + DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), + "WinSalGraphicsImpl::DrawPolyPolygonBezier(): POINT != SalPoint" ); + + sal_uLong nCurrPoly, nTotalPoints; + const sal_uInt32* pCurrPoints = pPoints; + for( nCurrPoly=0, nTotalPoints=0; nCurrPoly<nPoly; ++nCurrPoly ) + nTotalPoints += *pCurrPoints++; + + POINT aStackAry1[SAL_POLY_STACKBUF]; + BYTE aStackAry2[SAL_POLY_STACKBUF]; + POINT* pWinPointAry; + BYTE* pWinFlagAry; + if( nTotalPoints > SAL_POLY_STACKBUF ) + { + pWinPointAry = new POINT[ nTotalPoints ]; + pWinFlagAry = new BYTE[ nTotalPoints ]; + } + else + { + pWinPointAry = aStackAry1; + pWinFlagAry = aStackAry2; + } + + ImplPreparePolyDraw(true, nPoly, pPoints, pPtAry, pFlgAry, pWinPointAry, pWinFlagAry); + + bool bRet( false ); + + if( BeginPath( mrParent.getHDC() ) ) + { + PolyDraw(mrParent.getHDC(), pWinPointAry, pWinFlagAry, nTotalPoints); + + if( EndPath( mrParent.getHDC() ) ) + { + if( StrokeAndFillPath( mrParent.getHDC() ) ) + bRet = true; + } + } + + if( pWinPointAry != aStackAry1 ) + { + delete [] pWinPointAry; + delete [] pWinFlagAry; + } + + return bRet; +#else + return false; +#endif +} + +void impAddB2DPolygonToGDIPlusGraphicsPathReal(Gdiplus::GpPath *pPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin) +{ + sal_uInt32 nCount(rPolygon.count()); + + if(nCount) + { + const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1); + const bool bControls(rPolygon.areControlPointsUsed()); + basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0)); + + for(sal_uInt32 a(0); a < nEdgeCount; a++) + { + const sal_uInt32 nNextIndex((a + 1) % nCount); + const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex)); + + if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex))) + { + const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a)); + const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex)); + + Gdiplus::DllExports::GdipAddPathBezier(pPath, + aCurr.getX(), aCurr.getY(), + aCa.getX(), aCa.getY(), + aCb.getX(), aCb.getY(), + aNext.getX(), aNext.getY()); + } + else + { + Gdiplus::DllExports::GdipAddPathLine(pPath, aCurr.getX(), aCurr.getY(), aNext.getX(), aNext.getY()); + } + + if(a + 1 < nEdgeCount) + { + aCurr = aNext; + + if(bNoLineJoin) + { + Gdiplus::DllExports::GdipStartPathFigure(pPath); + } + } + } + } +} + +void impAddB2DPolygonToGDIPlusGraphicsPathInteger(Gdiplus::GpPath *pPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin) +{ + sal_uInt32 nCount(rPolygon.count()); + + if(nCount) + { + const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1); + const bool bControls(rPolygon.areControlPointsUsed()); + basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0)); + + for(sal_uInt32 a(0); a < nEdgeCount; a++) + { + const sal_uInt32 nNextIndex((a + 1) % nCount); + const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex)); + + if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex))) + { + const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a)); + const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex)); + + Gdiplus::DllExports::GdipAddPathBezier( + pPath, + aCurr.getX(), aCurr.getY(), + aCa.getX(), aCa.getY(), + aCb.getX(), aCb.getY(), + aNext.getX(), aNext.getY()); + } + else + { + Gdiplus::DllExports::GdipAddPathLine(pPath, aCurr.getX(), aCurr.getY(), aNext.getX(), aNext.getY()); + } + + if(a + 1 < nEdgeCount) + { + aCurr = aNext; + + if(bNoLineJoin) + { + Gdiplus::DllExports::GdipStartPathFigure(pPath); + } + } + } + } +} + +bool WinSalGraphicsImpl::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency) +{ + const sal_uInt32 nCount(rPolyPolygon.count()); + + if(mbBrush && nCount && (fTransparency >= 0.0 && fTransparency < 1.0)) + { + Gdiplus::GpGraphics *pGraphics = NULL; + Gdiplus::DllExports::GdipCreateFromHDC(mrParent.getHDC(), &pGraphics); + const sal_uInt8 aTrans((sal_uInt8)255 - (sal_uInt8)basegfx::fround(fTransparency * 255.0)); + Gdiplus::Color aTestColor(aTrans, SALCOLOR_RED(maFillColor), SALCOLOR_GREEN(maFillColor), SALCOLOR_BLUE(maFillColor)); + Gdiplus::GpSolidFill *pTestBrush; + Gdiplus::DllExports::GdipCreateSolidFill(aTestColor.GetValue(), &pTestBrush); + Gdiplus::GpPath *pPath = NULL; + Gdiplus::DllExports::GdipCreatePath(Gdiplus::FillModeAlternate, &pPath); + + for(sal_uInt32 a(0); a < nCount; a++) + { + if(0 != a) + { + Gdiplus::DllExports::GdipStartPathFigure(pPath); // #i101491# not needed for first run + } + + impAddB2DPolygonToGDIPlusGraphicsPathReal(pPath, rPolyPolygon.getB2DPolygon(a), false); + Gdiplus::DllExports::GdipClosePathFigure(pPath); + } + + if(mrParent.getAntiAliasB2DDraw()) + { + Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics, Gdiplus::SmoothingModeAntiAlias); + } + else + { + Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics, Gdiplus::SmoothingModeNone); + } + + if(mrParent.isPrinter()) + { + // #i121591# + // Normally GdiPlus should not be used for printing at all since printers cannot + // print transparent filled polygon geometry and normally this does not happen + // since OutputDevice::RemoveTransparenciesFromMetaFile is used as preparation + // and no transparent parts should remain for printing. But this can be overridden + // by the user and thus happens. This call can only come (currently) from + // OutputDevice::DrawTransparent, see comments there with the same TaskID. + // If it is used, the mapping for the printer is wrong and needs to be corrected. I + // checked that there is *no* transformation set and estimated that a stable factor + // dependent of the printer's DPI is used. Create and set a transformation here to + // correct this. + Gdiplus::REAL aDpiX; + Gdiplus::DllExports::GdipGetDpiX(pGraphics, &aDpiX); + Gdiplus::REAL aDpiY; + Gdiplus::DllExports::GdipGetDpiY(pGraphics, &aDpiY); + + Gdiplus::DllExports::GdipResetWorldTransform(pGraphics); + Gdiplus::DllExports::GdipScaleWorldTransform(pGraphics, Gdiplus::REAL(100.0) / aDpiX, Gdiplus::REAL(100.0) / aDpiY, Gdiplus::MatrixOrderAppend); + } + + Gdiplus::DllExports::GdipFillPath(pGraphics, pTestBrush, pPath); + + Gdiplus::DllExports::GdipDeletePath(pPath); + Gdiplus::DllExports::GdipDeleteGraphics(pGraphics); + } + + return true; +} + +bool WinSalGraphicsImpl::drawPolyLine( + const basegfx::B2DPolygon& rPolygon, + double fTransparency, + const basegfx::B2DVector& rLineWidths, + basegfx::B2DLineJoin eLineJoin, + com::sun::star::drawing::LineCap eLineCap) +{ + const sal_uInt32 nCount(rPolygon.count()); + + if(mbPen && nCount) + { + Gdiplus::GpGraphics *pGraphics = NULL; + Gdiplus::DllExports::GdipCreateFromHDC(mrParent.getHDC(), &pGraphics); + const sal_uInt8 aTrans = (sal_uInt8)basegfx::fround( 255 * (1.0 - fTransparency) ); + Gdiplus::Color aTestColor(aTrans, SALCOLOR_RED(maLineColor), SALCOLOR_GREEN(maLineColor), SALCOLOR_BLUE(maLineColor)); + Gdiplus::GpPen *pTestPen = NULL; + Gdiplus::DllExports::GdipCreatePen1(aTestColor.GetValue(), Gdiplus::REAL(rLineWidths.getX()), Gdiplus::UnitWorld, &pTestPen); + Gdiplus::GpPath *pPath; + Gdiplus::DllExports::GdipCreatePath(Gdiplus::FillModeAlternate, &pPath); + bool bNoLineJoin(false); + + switch(eLineJoin) + { + default : // basegfx::B2DLINEJOIN_NONE : + { + if(basegfx::fTools::more(rLineWidths.getX(), 0.0)) + { + bNoLineJoin = true; + } + break; + } + case basegfx::B2DLINEJOIN_BEVEL : + { + Gdiplus::DllExports::GdipSetPenLineJoin(pTestPen, Gdiplus::LineJoinBevel); + break; + } + case basegfx::B2DLINEJOIN_MIDDLE : + case basegfx::B2DLINEJOIN_MITER : + { + const Gdiplus::REAL aMiterLimit(15.0); + Gdiplus::DllExports::GdipSetPenMiterLimit(pTestPen, aMiterLimit); + Gdiplus::DllExports::GdipSetPenLineJoin(pTestPen, Gdiplus::LineJoinMiter); + break; + } + case basegfx::B2DLINEJOIN_ROUND : + { + Gdiplus::DllExports::GdipSetPenLineJoin(pTestPen, Gdiplus::LineJoinRound); + break; + } + } + + switch(eLineCap) + { + default: /*com::sun::star::drawing::LineCap_BUTT*/ + { + // nothing to do + break; + } + case com::sun::star::drawing::LineCap_ROUND: + { + Gdiplus::DllExports::GdipSetPenStartCap(pTestPen, Gdiplus::LineCapRound); + Gdiplus::DllExports::GdipSetPenEndCap(pTestPen, Gdiplus::LineCapRound); + break; + } + case com::sun::star::drawing::LineCap_SQUARE: + { + Gdiplus::DllExports::GdipSetPenStartCap(pTestPen, Gdiplus::LineCapSquare); + Gdiplus::DllExports::GdipSetPenEndCap(pTestPen, Gdiplus::LineCapSquare); + break; + } + } + + if(nCount > 250 && basegfx::fTools::more(rLineWidths.getX(), 1.5)) + { + impAddB2DPolygonToGDIPlusGraphicsPathInteger(pPath, rPolygon, bNoLineJoin); + } + else + { + impAddB2DPolygonToGDIPlusGraphicsPathReal(pPath, rPolygon, bNoLineJoin); + } + + if(rPolygon.isClosed() && !bNoLineJoin) + { + // #i101491# needed to create the correct line joins + Gdiplus::DllExports::GdipClosePathFigure(pPath); + } + + if(mrParent.getAntiAliasB2DDraw()) + { + Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics, Gdiplus::SmoothingModeAntiAlias); + } + else + { + Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics, Gdiplus::SmoothingModeNone); + } + + Gdiplus::DllExports::GdipDrawPath(pGraphics, pTestPen, pPath); + + Gdiplus::DllExports::GdipDeletePath(pPath); + Gdiplus::DllExports::GdipDeletePen(pTestPen); + Gdiplus::DllExports::GdipDeleteGraphics(pGraphics); + } + + return true; +} + +void paintToGdiPlus( + Gdiplus::Graphics& rGraphics, + const SalTwoRect& rTR, + Gdiplus::Bitmap& rBitmap) +{ + // only parts of source are used + Gdiplus::PointF aDestPoints[3]; + Gdiplus::ImageAttributes aAttributes; + + // define target region as paralellogram + aDestPoints[0].X = Gdiplus::REAL(rTR.mnDestX); + aDestPoints[0].Y = Gdiplus::REAL(rTR.mnDestY); + aDestPoints[1].X = Gdiplus::REAL(rTR.mnDestX + rTR.mnDestWidth); + aDestPoints[1].Y = Gdiplus::REAL(rTR.mnDestY); + aDestPoints[2].X = Gdiplus::REAL(rTR.mnDestX); + aDestPoints[2].Y = Gdiplus::REAL(rTR.mnDestY + rTR.mnDestHeight); + + aAttributes.SetWrapMode(Gdiplus::WrapModeTileFlipXY); + + rGraphics.DrawImage( + &rBitmap, + aDestPoints, + 3, + Gdiplus::REAL(rTR.mnSrcX), + Gdiplus::REAL(rTR.mnSrcY), + Gdiplus::REAL(rTR.mnSrcWidth), + Gdiplus::REAL(rTR.mnSrcHeight), + Gdiplus::UnitPixel, + &aAttributes, + 0, + 0); +} + +void setInterpolationMode( + Gdiplus::Graphics& rGraphics, + const long& rSrcWidth, + const long& rDestWidth, + const long& rSrcHeight, + const long& rDestHeight) +{ + const bool bSameWidth(rSrcWidth == rDestWidth); + const bool bSameHeight(rSrcHeight == rDestHeight); + + if(bSameWidth && bSameHeight) + { +#ifdef __MINGW32__ + //Gdiplus::InterpolationModeInvalid is missing on mingw + rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeDefault); +#else + rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeInvalid); +#endif + } + else if(rDestWidth > rSrcWidth && rDestHeight > rSrcHeight) + { + rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeDefault); + } + else if(rDestWidth < rSrcWidth && rDestHeight < rSrcHeight) + { + rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeBicubic); + } + else + { + rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeDefault); + } +} + +bool WinSalGraphicsImpl::tryDrawBitmapGdiPlus(const SalTwoRect& rTR, const SalBitmap& rSrcBitmap) +{ + if(rTR.mnSrcWidth && rTR.mnSrcHeight && rTR.mnDestWidth && rTR.mnDestHeight) + { + const WinSalBitmap& rSalBitmap = static_cast< const WinSalBitmap& >(rSrcBitmap); + GdiPlusBmpPtr aARGB(rSalBitmap.ImplGetGdiPlusBitmap()); + + if(aARGB.get()) + { + Gdiplus::Graphics aGraphics(mrParent.getHDC()); + + setInterpolationMode( + aGraphics, + rTR.mnSrcWidth, + rTR.mnDestWidth, + rTR.mnSrcHeight, + rTR.mnDestHeight); + + paintToGdiPlus( + aGraphics, + rTR, + *aARGB.get()); + + return true; + } + } + + return false; +} + +bool WinSalGraphicsImpl::drawAlphaBitmap( + const SalTwoRect& rTR, + const SalBitmap& rSrcBitmap, + const SalBitmap& rAlphaBmp) +{ + if(rTR.mnSrcWidth && rTR.mnSrcHeight && rTR.mnDestWidth && rTR.mnDestHeight) + { + const WinSalBitmap& rSalBitmap = static_cast< const WinSalBitmap& >(rSrcBitmap); + const WinSalBitmap& rSalAlpha = static_cast< const WinSalBitmap& >(rAlphaBmp); + GdiPlusBmpPtr aARGB(rSalBitmap.ImplGetGdiPlusBitmap(&rSalAlpha)); + + if(aARGB.get()) + { + Gdiplus::Graphics aGraphics(mrParent.getHDC()); + + setInterpolationMode( + aGraphics, + rTR.mnSrcWidth, + rTR.mnDestWidth, + rTR.mnSrcHeight, + rTR.mnDestHeight); + + paintToGdiPlus( + aGraphics, + rTR, + *aARGB.get()); + + return true; + } + } + + return false; +} + +bool WinSalGraphicsImpl::drawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) +{ + const WinSalBitmap& rSalBitmap = static_cast< const WinSalBitmap& >(rSourceBitmap); + const WinSalBitmap* pSalAlpha = static_cast< const WinSalBitmap* >(pAlphaBitmap); + GdiPlusBmpPtr aARGB(rSalBitmap.ImplGetGdiPlusBitmap(pSalAlpha)); + + if(aARGB.get()) + { + const long nSrcWidth(aARGB->GetWidth()); + const long nSrcHeight(aARGB->GetHeight()); + + if(nSrcWidth && nSrcHeight) + { + const long nDestWidth(basegfx::fround(basegfx::B2DVector(rX - rNull).getLength())); + const long nDestHeight(basegfx::fround(basegfx::B2DVector(rY - rNull).getLength())); + + if(nDestWidth && nDestHeight) + { + Gdiplus::Graphics aGraphics(mrParent.getHDC()); + Gdiplus::PointF aDestPoints[3]; + Gdiplus::ImageAttributes aAttributes; + + setInterpolationMode( + aGraphics, + nSrcWidth, + nDestWidth, + nSrcHeight, + nDestHeight); + + // this mode is only capable of drawing the whole bitmap to a paralellogram + aDestPoints[0].X = Gdiplus::REAL(rNull.getX()); + aDestPoints[0].Y = Gdiplus::REAL(rNull.getY()); + aDestPoints[1].X = Gdiplus::REAL(rX.getX()); + aDestPoints[1].Y = Gdiplus::REAL(rX.getY()); + aDestPoints[2].X = Gdiplus::REAL(rY.getX()); + aDestPoints[2].Y = Gdiplus::REAL(rY.getY()); + + aAttributes.SetWrapMode(Gdiplus::WrapModeTileFlipXY); + + aGraphics.DrawImage( + aARGB.get(), + aDestPoints, + 3, + Gdiplus::REAL(0.0), + Gdiplus::REAL(0.0), + Gdiplus::REAL(nSrcWidth), + Gdiplus::REAL(nSrcHeight), + Gdiplus::UnitPixel, + &aAttributes, + 0, + 0); + } + } + + return true; + } + + return false; +} + +bool WinSalGraphicsImpl::drawGradient(const tools::PolyPolygon& /*rPolygon*/, + const Gradient& /*rGradient*/) +{ + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/source/gdi/gdiimpl.hxx b/vcl/win/source/gdi/gdiimpl.hxx new file mode 100644 index 000000000000..2a0780f21738 --- /dev/null +++ b/vcl/win/source/gdi/gdiimpl.hxx @@ -0,0 +1,218 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "salgdiimpl.hxx" + +#include <vcl/gradient.hxx> + +#include "svsys.h" + +class WinSalGraphics; + +class WinSalGraphicsImpl : public SalGraphicsImpl +{ +private: + + WinSalGraphics& mrParent; + bool mbXORMode : 1; // _every_ output with RasterOp XOR + bool mbPen : 1; // is Pen (FALSE == NULL_PEN) + HPEN mhPen; // Pen + bool mbStockPen : 1; // is Pen a stockpen + bool mbBrush : 1; // is Brush (FALSE == NULL_BRUSH) + bool mbStockBrush : 1; // is Brush a stcokbrush + HBRUSH mhBrush; // Brush + COLORREF mnPenColor; // PenColor + COLORREF mnBrushColor; // BrushColor + + // remember RGB values for SetLineColor/SetFillColor + SalColor maLineColor; + SalColor maFillColor; + + bool tryDrawBitmapGdiPlus(const SalTwoRect& rTR, const SalBitmap& rSrcBitmap); + +public: + + WinSalGraphicsImpl(WinSalGraphics& rParent); + + virtual ~WinSalGraphicsImpl(); + + virtual void freeResources() SAL_OVERRIDE; + + virtual bool setClipRegion( const vcl::Region& ) SAL_OVERRIDE; + // + // get the depth of the device + virtual sal_uInt16 GetBitCount() const SAL_OVERRIDE; + + // get the width of the device + virtual long GetGraphicsWidth() const SAL_OVERRIDE; + + // set the clip region to empty + virtual void ResetClipRegion() SAL_OVERRIDE; + + // set the line color to transparent (= don't draw lines) + + virtual void SetLineColor() SAL_OVERRIDE; + + // set the line color to a specific color + virtual void SetLineColor( SalColor nSalColor ) SAL_OVERRIDE; + + // set the fill color to transparent (= don't fill) + virtual void SetFillColor() SAL_OVERRIDE; + + // set the fill color to a specific color, shapes will be + // filled accordingly + virtual void SetFillColor( SalColor nSalColor ) SAL_OVERRIDE; + + // enable/disable XOR drawing + virtual void SetXORMode( bool bSet, bool bInvertOnly ) SAL_OVERRIDE; + + // set line color for raster operations + virtual void SetROPLineColor( SalROPColor nROPColor ) SAL_OVERRIDE; + + // set fill color for raster operations + virtual void SetROPFillColor( SalROPColor nROPColor ) SAL_OVERRIDE; + + // draw --> LineColor and FillColor and RasterOp and ClipRegion + virtual void drawPixel( long nX, long nY ) SAL_OVERRIDE; + virtual void drawPixel( long nX, long nY, SalColor nSalColor ) SAL_OVERRIDE; + + virtual void drawLine( long nX1, long nY1, long nX2, long nY2 ) SAL_OVERRIDE; + + virtual void drawRect( long nX, long nY, long nWidth, long nHeight ) SAL_OVERRIDE; + + virtual void drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) SAL_OVERRIDE; + + virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) SAL_OVERRIDE; + + virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) SAL_OVERRIDE; + virtual bool drawPolyPolygon( const ::basegfx::B2DPolyPolygon&, double fTransparency ) SAL_OVERRIDE; + + virtual bool drawPolyLine( + const ::basegfx::B2DPolygon&, + double fTransparency, + const ::basegfx::B2DVector& rLineWidths, + basegfx::B2DLineJoin, + com::sun::star::drawing::LineCap) SAL_OVERRIDE; + + virtual bool drawPolyLineBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const sal_uInt8* pFlgAry ) SAL_OVERRIDE; + + virtual bool drawPolygonBezier( + sal_uInt32 nPoints, + const SalPoint* pPtAry, + const sal_uInt8* pFlgAry ) SAL_OVERRIDE; + + virtual bool drawPolyPolygonBezier( + sal_uInt32 nPoly, + const sal_uInt32* pPoints, + const SalPoint* const* pPtAry, + const sal_uInt8* const* pFlgAry ) SAL_OVERRIDE; + + // CopyArea --> No RasterOp, but ClipRegion + virtual void copyArea( + long nDestX, long nDestY, + long nSrcX, long nSrcY, + long nSrcWidth, long nSrcHeight, + sal_uInt16 nFlags ) SAL_OVERRIDE; + + // CopyBits and DrawBitmap --> RasterOp and ClipRegion + // CopyBits() --> pSrcGraphics == NULL, then CopyBits on same Graphics + virtual void copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) SAL_OVERRIDE; + + virtual void drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap ) SAL_OVERRIDE; + + virtual void drawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + SalColor nTransparentColor ) SAL_OVERRIDE; + + virtual void drawBitmap( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + const SalBitmap& rMaskBitmap ) SAL_OVERRIDE; + + virtual void drawMask( + const SalTwoRect& rPosAry, + const SalBitmap& rSalBitmap, + SalColor nMaskColor ) SAL_OVERRIDE; + + virtual SalBitmap* getBitmap( long nX, long nY, long nWidth, long nHeight ) SAL_OVERRIDE; + + virtual SalColor getPixel( long nX, long nY ) SAL_OVERRIDE; + + // invert --> ClipRegion (only Windows or VirDevs) + virtual void invert( + long nX, long nY, + long nWidth, long nHeight, + SalInvert nFlags) SAL_OVERRIDE; + + virtual void invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nFlags ) SAL_OVERRIDE; + + virtual bool drawEPS( + long nX, long nY, + long nWidth, long nHeight, + void* pPtr, + sal_uLong nSize ) SAL_OVERRIDE; + + /** Render bitmap with alpha channel + + @param rSourceBitmap + Source bitmap to blit + + @param rAlphaBitmap + Alpha channel to use for blitting + + @return true, if the operation succeeded, and false + otherwise. In this case, clients should try to emulate alpha + compositing themselves + */ + virtual bool drawAlphaBitmap( + const SalTwoRect&, + const SalBitmap& rSourceBitmap, + const SalBitmap& rAlphaBitmap ) SAL_OVERRIDE; + + /** draw transformed bitmap (maybe with alpha) where Null, X, Y define the coordinate system */ + virtual bool drawTransformedBitmap( + const basegfx::B2DPoint& rNull, + const basegfx::B2DPoint& rX, + const basegfx::B2DPoint& rY, + const SalBitmap& rSourceBitmap, + const SalBitmap* pAlphaBitmap) SAL_OVERRIDE; + + /** Render solid rectangle with given transparency + + @param nTransparency + Transparency value (0-255) to use. 0 blits and opaque, 255 a + fully transparent rectangle + */ + virtual bool drawAlphaRect( + long nX, long nY, + long nWidth, long nHeight, + sal_uInt8 nTransparency ) SAL_OVERRIDE; + + + virtual bool drawGradient(const tools::PolyPolygon& rPolygon, + const Gradient& rGradient) SAL_OVERRIDE; + + virtual bool swapBuffers() SAL_OVERRIDE { return false; } +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/source/gdi/salbmp.cxx b/vcl/win/source/gdi/salbmp.cxx index 912144401069..0f8906c84bc0 100644 --- a/vcl/win/source/gdi/salbmp.cxx +++ b/vcl/win/source/gdi/salbmp.cxx @@ -1076,4 +1076,9 @@ bool WinSalBitmap::GetSystemData( BitmapSystemData& rData ) return bRet; } +bool WinSalBitmap::Scale( const double& /*rScaleX*/, const double& /*rScaleY*/, sal_uInt32 /*nScaleFlag*/ ) +{ + return false; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/source/gdi/salgdi.cxx b/vcl/win/source/gdi/salgdi.cxx index 80ce1fdd317c..4e3b76f93455 100644 --- a/vcl/win/source/gdi/salgdi.cxx +++ b/vcl/win/source/gdi/salgdi.cxx @@ -32,8 +32,13 @@ #include <win/salframe.h> #include <basegfx/matrix/b2dhommatrixtools.hxx> -// comment out to prevent use of beziers on GDI functions -#define USE_GDI_BEZIERS +#include "salgdiimpl.hxx" +#include "gdiimpl.hxx" +#include "opengl/win/gdiimpl.hxx" + +#include <vcl/opengl/OpenGLHelper.hxx> + +#include <officecfg/Office/Common.hxx> #define DITHER_PAL_DELTA 51 #define DITHER_PAL_STEPS 6 @@ -106,9 +111,6 @@ static BYTE aOrdDither16Bit[8][8] = // complex is set #define GSL_PEN_WIDTH 1 -#define SAL_POLYPOLYCOUNT_STACKBUF 8 -#define SAL_POLYPOLYPOINTS_STACKBUF 64 - void ImplInitSalGDI() { SalData* pSalData = GetSalData(); @@ -365,6 +367,23 @@ void ImplFreeSalGDI() pSalData->mbResourcesAlreadyFreed = true; } +int ImplIsSysColorEntry( SalColor nSalColor ) +{ + SysColorEntry* pEntry = pFirstSysColor; + const DWORD nTestRGB = (DWORD)RGB( SALCOLOR_RED( nSalColor ), + SALCOLOR_GREEN( nSalColor ), + SALCOLOR_BLUE( nSalColor ) ); + + while ( pEntry ) + { + if ( pEntry->nRGB == nTestRGB ) + return TRUE; + pEntry = pEntry->pNext; + } + + return FALSE; +} + static int ImplIsPaletteEntry( BYTE nRed, BYTE nGreen, BYTE nBlue ) { // dither color? @@ -391,23 +410,6 @@ static int ImplIsPaletteEntry( BYTE nRed, BYTE nGreen, BYTE nBlue ) return FALSE; } -int ImplIsSysColorEntry( SalColor nSalColor ) -{ - SysColorEntry* pEntry = pFirstSysColor; - const DWORD nTestRGB = (DWORD)RGB( SALCOLOR_RED( nSalColor ), - SALCOLOR_GREEN( nSalColor ), - SALCOLOR_BLUE( nSalColor ) ); - - while ( pEntry ) - { - if ( pEntry->nRGB == nTestRGB ) - return TRUE; - pEntry = pEntry->pNext; - } - - return FALSE; -} - static void ImplInsertSysColorEntry( int nSysIndex ) { const DWORD nRGB = GetSysColor( nSysIndex ); @@ -466,44 +468,42 @@ void ImplUpdateSysColorEntries() ImplInsertSysColorEntry( COLOR_INACTIVECAPTIONTEXT ); } -static SalColor ImplGetROPSalColor( SalROPColor nROPColor ) -{ - SalColor nSalColor; - if ( nROPColor == SAL_ROP_0 ) - nSalColor = MAKE_SALCOLOR( 0, 0, 0 ); - else - nSalColor = MAKE_SALCOLOR( 255, 255, 255 ); - return nSalColor; -} - -void ImplSalInitGraphics( WinSalGraphics* pData ) +void WinSalGraphics::InitGraphics() { // calculate the minimal line width for the printer - if ( pData->mbPrinter ) + if ( isPrinter() ) { - int nDPIX = GetDeviceCaps( pData->getHDC(), LOGPIXELSX ); + int nDPIX = GetDeviceCaps( getHDC(), LOGPIXELSX ); if ( nDPIX <= 300 ) - pData->mnPenWidth = 0; + mnPenWidth = 0; else - pData->mnPenWidth = nDPIX/300; + mnPenWidth = nDPIX/300; } - ::SetTextAlign( pData->getHDC(), TA_BASELINE | TA_LEFT | TA_NOUPDATECP ); - ::SetBkMode( pData->getHDC(), WIN32_TRANSPARENT ); - ::SetROP2( pData->getHDC(), R2_COPYPEN ); + ::SetTextAlign( getHDC(), TA_BASELINE | TA_LEFT | TA_NOUPDATECP ); + ::SetBkMode( getHDC(), WIN32_TRANSPARENT ); + ::SetROP2( getHDC(), R2_COPYPEN ); + + OpenGLSalGraphicsImpl* pImpl = dynamic_cast<OpenGLSalGraphicsImpl*>(mpImpl.get()); + if (pImpl) + { + if (mbVirDev) + pImpl->GetOpenGLContext().requestVirtualDevice(); + pImpl->GetOpenGLContext().init(mhLocalDC, mhWnd); + } } -void ImplSalDeInitGraphics( WinSalGraphics* pData ) +void WinSalGraphics::DeInitGraphics() { // clear clip region - SelectClipRgn( pData->getHDC(), 0 ); + SelectClipRgn( getHDC(), 0 ); // select default objects - if ( pData->mhDefPen ) - SelectPen( pData->getHDC(), pData->mhDefPen ); - if ( pData->mhDefBrush ) - SelectBrush( pData->getHDC(), pData->mhDefBrush ); - if ( pData->mhDefFont ) - SelectFont( pData->getHDC(), pData->mhDefFont ); + if ( mhDefPen ) + SelectPen( getHDC(), mhDefPen ); + if ( mhDefBrush ) + SelectBrush( getHDC(), mhDefBrush ); + if ( mhDefFont ) + SelectFont( getHDC(), mhDefFont ); } HDC ImplGetCachedDC( sal_uLong nID, HBITMAP hBmp ) @@ -566,107 +566,36 @@ void ImplClearHDCCache( SalData* pData ) } } -// #100127# Fill point and flag memory from array of points which -// might also contain bezier control points for the PolyDraw() GDI method -// Make sure pWinPointAry and pWinFlagAry are big enough -void ImplPreparePolyDraw( bool bCloseFigures, - sal_uLong nPoly, - const sal_uInt32* pPoints, - const SalPoint* const* pPtAry, - const BYTE* const* pFlgAry, - POINT* pWinPointAry, - BYTE* pWinFlagAry ) +WinSalGraphics::WinSalGraphics(WinSalGraphics::Type eType, bool bScreen, HWND hWnd): + mhLocalDC(0), + mbPrinter(eType == WinSalGraphics::PRINTER), + mbVirDev(eType == WinSalGraphics::VIRTUAL_DEVICE), + mbWindow(eType == WinSalGraphics::WINDOW), + mhWnd(hWnd), + mbScreen(bScreen), + mfCurrentFontScale(1.0), + mhRegion(0), + mhDefPen(0), + mhDefBrush(0), + mhDefFont(0), + mhDefPal(0), + mpStdClipRgnData(NULL), + mpLogFont(NULL), + mpFontCharSets(NULL), + mpFontAttrCache(NULL), + mnFontCharSetCount(0), + mpFontKernPairs(NULL), + mnFontKernPairCount(0), + mbFontKernInit(false), + mnPenWidth(GSL_PEN_WIDTH) { - sal_uLong nCurrPoly; - for( nCurrPoly=0; nCurrPoly<nPoly; ++nCurrPoly ) - { - const POINT* pCurrPoint = reinterpret_cast<const POINT*>( *pPtAry++ ); - const BYTE* pCurrFlag = *pFlgAry++; - const sal_uInt32 nCurrPoints = *pPoints++; - const bool bHaveFlagArray( pCurrFlag ); - sal_uLong nCurrPoint; - - if( nCurrPoints ) - { - // start figure - *pWinPointAry++ = *pCurrPoint++; - *pWinFlagAry++ = PT_MOVETO; - ++pCurrFlag; - - for( nCurrPoint=1; nCurrPoint<nCurrPoints; ) - { - // #102067# Check existence of flag array - if( bHaveFlagArray && - ( nCurrPoint + 2 ) < nCurrPoints ) - { - BYTE P4( pCurrFlag[ 2 ] ); - - if( ( POLY_CONTROL == pCurrFlag[ 0 ] ) && - ( POLY_CONTROL == pCurrFlag[ 1 ] ) && - ( POLY_NORMAL == P4 || POLY_SMOOTH == P4 || POLY_SYMMTR == P4 ) ) - { - // control point one - *pWinPointAry++ = *pCurrPoint++; - *pWinFlagAry++ = PT_BEZIERTO; - - // control point two - *pWinPointAry++ = *pCurrPoint++; - *pWinFlagAry++ = PT_BEZIERTO; - - // end point - *pWinPointAry++ = *pCurrPoint++; - *pWinFlagAry++ = PT_BEZIERTO; - - nCurrPoint += 3; - pCurrFlag += 3; - continue; - } - } - - // regular line point - *pWinPointAry++ = *pCurrPoint++; - *pWinFlagAry++ = PT_LINETO; - ++pCurrFlag; - ++nCurrPoint; - } - - // end figure? - if( bCloseFigures ) - pWinFlagAry[-1] |= PT_CLOSEFIGURE; - } - } -} - -// #100127# draw an array of points which might also contain bezier control points -void ImplRenderPath( HDC hdc, sal_uLong nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry ) -{ - if( nPoints ) - { - sal_uInt16 i; - // TODO: profile whether the following options are faster: - // a) look ahead and draw consecutive bezier or line segments by PolyBezierTo/PolyLineTo resp. - // b) convert our flag array to window's and use PolyDraw - - MoveToEx( hdc, pPtAry->mnX, pPtAry->mnY, NULL ); - ++pPtAry; ++pFlgAry; - - for( i=1; i<nPoints; ++i, ++pPtAry, ++pFlgAry ) - { - if( *pFlgAry != POLY_CONTROL ) - { - LineTo( hdc, pPtAry->mnX, pPtAry->mnY ); - } - else if( nPoints - i > 2 ) - { - PolyBezierTo( hdc, reinterpret_cast<const POINT*>(pPtAry), 3 ); - i += 2; pPtAry += 2; pFlgAry += 2; - } - } - } -} + static bool bOpenGLPossible = OpenGLHelper::supportsVCLOpenGL(); + bool bUseOpenGL = bOpenGLPossible && mbWindow ? officecfg::Office::Common::VCL::UseOpenGL::get() : false; + if (bUseOpenGL) + mpImpl.reset(new WinOpenGLSalGraphicsImpl(*this)); + else + mpImpl.reset(new WinSalGraphicsImpl(*this)); -WinSalGraphics::WinSalGraphics() -{ for( int i = 0; i < MAX_FALLBACK; ++i ) { mhFonts[ i ] = 0; @@ -674,44 +603,12 @@ WinSalGraphics::WinSalGraphics() mpWinFontEntry[ i ] = NULL; mfFontScale[ i ] = 1.0; } - - mfCurrentFontScale = 1.0; - - mhLocalDC = 0; - mhPen = 0; - mhBrush = 0; - mhRegion = 0; - mhDefPen = 0; - mhDefBrush = 0; - mhDefFont = 0; - mhDefPal = 0; - mpStdClipRgnData = NULL; - mpLogFont = NULL; - mpFontCharSets = NULL; - mpFontAttrCache = NULL; - mnFontCharSetCount = 0; - mpFontKernPairs = NULL; - mnFontKernPairCount = 0; - mbFontKernInit = FALSE; - mbXORMode = FALSE; - mnPenWidth = GSL_PEN_WIDTH; } WinSalGraphics::~WinSalGraphics() { // free obsolete GDI objects - ReleaseFonts(); - - if ( mhPen ) - { - if ( !mbStockPen ) - DeletePen( mhPen ); - } - if ( mhBrush ) - { - if ( !mbStockBrush ) - DeleteBrush( mhBrush ); - } + ReleaseFonts(); if ( mhRegion ) { @@ -720,8 +617,7 @@ WinSalGraphics::~WinSalGraphics() } // delete cache data - if ( mpStdClipRgnData ) - delete [] mpStdClipRgnData; + delete [] mpStdClipRgnData; delete mpLogFont; @@ -730,6 +626,51 @@ WinSalGraphics::~WinSalGraphics() delete mpFontKernPairs; } +bool WinSalGraphics::isPrinter() const +{ + return mbPrinter; +} + +bool WinSalGraphics::isVirtualDevice() const +{ + return mbVirDev; +} + +bool WinSalGraphics::isWindow() const +{ + return mbWindow; +} + +bool WinSalGraphics::isScreen() const +{ + return mbScreen; +} + +HWND WinSalGraphics::gethWnd() +{ + return mhWnd; +} + +void WinSalGraphics::setHWND(HWND hWnd) +{ + mhWnd = hWnd; +} + +HPALETTE WinSalGraphics::getDefPal() const +{ + return mhDefPal; +} + +void WinSalGraphics::setDefPal(HPALETTE hDefPal) +{ + mhDefPal = hDefPal; +} + +HRGN WinSalGraphics::getRegion() const +{ + return mhRegion; +} + void WinSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY ) { rDPIX = GetDeviceCaps( getHDC(), LOGPIXELSX ); @@ -744,839 +685,111 @@ void WinSalGraphics::GetResolution( sal_Int32& rDPIX, sal_Int32& rDPIY ) sal_uInt16 WinSalGraphics::GetBitCount() const { - return (sal_uInt16)GetDeviceCaps( getHDC(), BITSPIXEL ); + return mpImpl->GetBitCount(); } long WinSalGraphics::GetGraphicsWidth() const { - if( mhWnd && IsWindow( mhWnd ) ) - { - WinSalFrame* pFrame = GetWindowPtr( mhWnd ); - if( pFrame ) - { - if( pFrame->maGeometry.nWidth ) - return pFrame->maGeometry.nWidth; - else - { - // TODO: perhaps not needed, maGeometry should always be up-to-date - RECT aRect; - GetClientRect( mhWnd, &aRect ); - return aRect.right; - } - } - } - - return 0; + return mpImpl->GetGraphicsWidth(); } void WinSalGraphics::ResetClipRegion() { - if ( mhRegion ) - { - DeleteRegion( mhRegion ); - mhRegion = 0; - } - - SelectClipRgn( getHDC(), 0 ); + mpImpl->ResetClipRegion(); } bool WinSalGraphics::setClipRegion( const vcl::Region& i_rClip ) { - if ( mhRegion ) - { - DeleteRegion( mhRegion ); - mhRegion = 0; - } - - bool bUsePolygon(i_rClip.HasPolyPolygonOrB2DPolyPolygon()); - static bool bTryToAvoidPolygon(true); - - // #i122149# try to avoid usage of tools::PolyPolygon ClipRegions when tools::PolyPolygon is no curve - // and only contains horizontal/vertical edges. In that case, use the fallback - // in GetRegionRectangles which will use vcl::Region::GetAsRegionBand() which will do - // the correct polygon-to-RegionBand transformation. - // Background is that when using the same Rectangle as rectangle or as Polygon - // clip region will lead to different results; the polygon-based one will be - // one pixel less to the right and down (see GDI docu for CreatePolygonRgn). This - // again is because of the polygon-nature and it's classic handling when filling. - // This also means that all cases which use a 'true' polygon-based incarnation of - // a vcl::Region should know what they do - it may lead to repaint errors. - if(bUsePolygon && bTryToAvoidPolygon) - { - const basegfx::B2DPolyPolygon aPolyPolygon( i_rClip.GetAsB2DPolyPolygon() ); - - if(!aPolyPolygon.areControlPointsUsed()) - { - if(basegfx::tools::containsOnlyHorizontalAndVerticalEdges(aPolyPolygon)) - { - bUsePolygon = false; - } - } - } - - if(bUsePolygon) - { - // #i122149# check the comment above to know that this may lead to potential repaint - // problems. It may be solved (if needed) by scaling the polygon by one in X - // and Y. Currently the workaround to only use it if really unavoidable will - // solve most cases. When someone is really using polygon-based Regions he - // should know what he is doing. - // Added code to do that scaling to check if it works, testing it. - const basegfx::B2DPolyPolygon aPolyPolygon( i_rClip.GetAsB2DPolyPolygon() ); - const sal_uInt32 nCount(aPolyPolygon.count()); - - if( nCount ) - { - std::vector< POINT > aPolyPoints; - aPolyPoints.reserve( 1024 ); - std::vector< INT > aPolyCounts( nCount, 0 ); - basegfx::B2DHomMatrix aExpand; - static bool bExpandByOneInXandY(true); - - if(bExpandByOneInXandY) - { - const basegfx::B2DRange aRangeS(aPolyPolygon.getB2DRange()); - const basegfx::B2DRange aRangeT(aRangeS.getMinimum(), aRangeS.getMaximum() + basegfx::B2DTuple(1.0, 1.0)); - aExpand = basegfx::B2DHomMatrix(basegfx::tools::createSourceRangeTargetRangeTransform(aRangeS, aRangeT)); - } - - for(sal_uInt32 a(0); a < nCount; a++) - { - const basegfx::B2DPolygon aPoly( - basegfx::tools::adaptiveSubdivideByDistance( - aPolyPolygon.getB2DPolygon(a), - 1)); - const sal_uInt32 nPoints(aPoly.count()); - aPolyCounts[a] = nPoints; - - for( sal_uInt32 b = 0; b < nPoints; b++ ) - { - basegfx::B2DPoint aPt(aPoly.getB2DPoint(b)); - - if(bExpandByOneInXandY) - { - aPt = aExpand * aPt; - } - - POINT aPOINT; - // #i122149# do correct rounding - aPOINT.x = basegfx::fround(aPt.getX()); - aPOINT.y = basegfx::fround(aPt.getY()); - aPolyPoints.push_back( aPOINT ); - } - } - - mhRegion = CreatePolyPolygonRgn( &aPolyPoints[0], &aPolyCounts[0], nCount, ALTERNATE ); - } - } - else - { - RectangleVector aRectangles; - i_rClip.GetRegionRectangles(aRectangles); - - sal_uLong nRectBufSize = sizeof(RECT)*aRectangles.size(); - if ( aRectangles.size() < SAL_CLIPRECT_COUNT ) - { - if ( !mpStdClipRgnData ) - mpStdClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+(SAL_CLIPRECT_COUNT*sizeof(RECT))]; - mpClipRgnData = mpStdClipRgnData; - } - else - mpClipRgnData = (RGNDATA*)new BYTE[sizeof(RGNDATA)-1+nRectBufSize]; - mpClipRgnData->rdh.dwSize = sizeof( RGNDATAHEADER ); - mpClipRgnData->rdh.iType = RDH_RECTANGLES; - mpClipRgnData->rdh.nCount = aRectangles.size(); - mpClipRgnData->rdh.nRgnSize = nRectBufSize; - RECT* pBoundRect = &(mpClipRgnData->rdh.rcBound); - SetRectEmpty( pBoundRect ); - RECT* pNextClipRect = (RECT*)(&(mpClipRgnData->Buffer)); - bool bFirstClipRect = true; - - for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter) - { - const long nW(aRectIter->GetWidth()); - const long nH(aRectIter->GetHeight()); - - if(nW && nH) - { - const long nRight(aRectIter->Left() + nW); - const long nBottom(aRectIter->Top() + nH); - - if(bFirstClipRect) - { - pBoundRect->left = aRectIter->Left(); - pBoundRect->top = aRectIter->Top(); - pBoundRect->right = nRight; - pBoundRect->bottom = nBottom; - bFirstClipRect = false; - } - else - { - if(aRectIter->Left() < pBoundRect->left) - { - pBoundRect->left = (int)aRectIter->Left(); - } - - if(aRectIter->Top() < pBoundRect->top) - { - pBoundRect->top = (int)aRectIter->Top(); - } - - if(nRight > pBoundRect->right) - { - pBoundRect->right = (int)nRight; - } - - if(nBottom > pBoundRect->bottom) - { - pBoundRect->bottom = (int)nBottom; - } - } - - pNextClipRect->left = (int)aRectIter->Left(); - pNextClipRect->top = (int)aRectIter->Top(); - pNextClipRect->right = (int)nRight; - pNextClipRect->bottom = (int)nBottom; - pNextClipRect++; - } - else - { - mpClipRgnData->rdh.nCount--; - mpClipRgnData->rdh.nRgnSize -= sizeof( RECT ); - } - } - - // create clip region from ClipRgnData - if(0 == mpClipRgnData->rdh.nCount) - { - // #i123585# region is empty; this may happen when e.g. a tools::PolyPolygon is given - // that contains no polygons or only empty ones (no width/height). This is - // perfectly fine and we are done, except setting it (see end of method) - } - else if(1 == mpClipRgnData->rdh.nCount) - { - RECT* pRect = &(mpClipRgnData->rdh.rcBound); - mhRegion = CreateRectRgn( pRect->left, pRect->top, - pRect->right, pRect->bottom ); - } - else if(mpClipRgnData->rdh.nCount > 1) - { - sal_uLong nSize = mpClipRgnData->rdh.nRgnSize+sizeof(RGNDATAHEADER); - mhRegion = ExtCreateRegion( NULL, nSize, mpClipRgnData ); - - // if ExtCreateRegion(...) is not supported - if( !mhRegion ) - { - RGNDATAHEADER* pHeader = (RGNDATAHEADER*) mpClipRgnData; - - if( pHeader->nCount ) - { - RECT* pRect = (RECT*) mpClipRgnData->Buffer; - mhRegion = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom ); - pRect++; - - for( sal_uLong n = 1; n < pHeader->nCount; n++, pRect++ ) - { - HRGN hRgn = CreateRectRgn( pRect->left, pRect->top, pRect->right, pRect->bottom ); - CombineRgn( mhRegion, mhRegion, hRgn, RGN_OR ); - DeleteRegion( hRgn ); - } - } - } - - if ( mpClipRgnData != mpStdClipRgnData ) - delete [] mpClipRgnData; - } - } - - if( mhRegion ) - { - SelectClipRgn( getHDC(), mhRegion ); - - // debug code if you weant to check range of the newly applied ClipRegion - //RECT aBound; - //const int aRegionType = GetRgnBox(mhRegion, &aBound); - - //bool bBla = true; - } - else - { - // #i123585# See above, this is a valid case, execute it - SelectClipRgn( getHDC(), 0 ); - } - - // #i123585# retval no longer dependent of mhRegion, see TaskId comments above - return true; + return mpImpl->setClipRegion( i_rClip ); } void WinSalGraphics::SetLineColor() { - // create and select new pen - HPEN hNewPen = GetStockPen( NULL_PEN ); - HPEN hOldPen = SelectPen( getHDC(), hNewPen ); - - // destroy or save old pen - if ( mhPen ) - { - if ( !mbStockPen ) - DeletePen( mhPen ); - } - else - mhDefPen = hOldPen; - - // set new data - mhPen = hNewPen; - mbPen = FALSE; - mbStockPen = TRUE; + mpImpl->SetLineColor(); } void WinSalGraphics::SetLineColor( SalColor nSalColor ) { - maLineColor = nSalColor; - COLORREF nPenColor = PALETTERGB( SALCOLOR_RED( nSalColor ), - SALCOLOR_GREEN( nSalColor ), - SALCOLOR_BLUE( nSalColor ) ); - HPEN hNewPen = 0; - bool bStockPen = FALSE; - - // search for stock pen (only screen, because printer have problems, - // when we use stock objects) - if ( !mbPrinter ) - { - SalData* pSalData = GetSalData(); - for ( sal_uInt16 i = 0; i < pSalData->mnStockPenCount; i++ ) - { - if ( nPenColor == pSalData->maStockPenColorAry[i] ) - { - hNewPen = pSalData->mhStockPenAry[i]; - bStockPen = TRUE; - break; - } - } - } - - // create new pen - if ( !hNewPen ) - { - if ( !mbPrinter ) - { - if ( GetSalData()->mhDitherPal && ImplIsSysColorEntry( nSalColor ) ) - nPenColor = PALRGB_TO_RGB( nPenColor ); - } - - hNewPen = CreatePen( PS_SOLID, mnPenWidth, nPenColor ); - bStockPen = FALSE; - } - - // select new pen - HPEN hOldPen = SelectPen( getHDC(), hNewPen ); - - // destroy or save old pen - if ( mhPen ) - { - if ( !mbStockPen ) - DeletePen( mhPen ); - } - else - mhDefPen = hOldPen; - - // set new data - mnPenColor = nPenColor; - mhPen = hNewPen; - mbPen = TRUE; - mbStockPen = bStockPen; + mpImpl->SetLineColor( nSalColor ); } void WinSalGraphics::SetFillColor() { - // create and select new brush - HBRUSH hNewBrush = GetStockBrush( NULL_BRUSH ); - HBRUSH hOldBrush = SelectBrush( getHDC(), hNewBrush ); - - // destroy or save old brush - if ( mhBrush ) - { - if ( !mbStockBrush ) - DeleteBrush( mhBrush ); - } - else - mhDefBrush = hOldBrush; - - // set new data - mhBrush = hNewBrush; - mbBrush = FALSE; - mbStockBrush = TRUE; + mpImpl->SetFillColor(); } void WinSalGraphics::SetFillColor( SalColor nSalColor ) { - maFillColor = nSalColor; - SalData* pSalData = GetSalData(); - BYTE nRed = SALCOLOR_RED( nSalColor ); - BYTE nGreen = SALCOLOR_GREEN( nSalColor ); - BYTE nBlue = SALCOLOR_BLUE( nSalColor ); - COLORREF nBrushColor = PALETTERGB( nRed, nGreen, nBlue ); - HBRUSH hNewBrush = 0; - bool bStockBrush = FALSE; - - // search for stock brush (only screen, because printer have problems, - // when we use stock objects) - if ( !mbPrinter ) - { - for ( sal_uInt16 i = 0; i < pSalData->mnStockBrushCount; i++ ) - { - if ( nBrushColor == pSalData->maStockBrushColorAry[ i ] ) - { - hNewBrush = pSalData->mhStockBrushAry[i]; - bStockBrush = TRUE; - break; - } - } - } - - // create new brush - if ( !hNewBrush ) - { - if ( mbPrinter || !pSalData->mhDitherDIB ) - hNewBrush = CreateSolidBrush( nBrushColor ); - else - { - if ( 24 == ((BITMAPINFOHEADER*)pSalData->mpDitherDIB)->biBitCount ) - { - BYTE* pTmp = pSalData->mpDitherDIBData; - long* pDitherDiff = pSalData->mpDitherDiff; - BYTE* pDitherLow = pSalData->mpDitherLow; - BYTE* pDitherHigh = pSalData->mpDitherHigh; - - for( long nY = 0L; nY < 8L; nY++ ) - { - for( long nX = 0L; nX < 8L; nX++ ) - { - const long nThres = aOrdDither16Bit[ nY ][ nX ]; - *pTmp++ = DMAP( nBlue, nThres ); - *pTmp++ = DMAP( nGreen, nThres ); - *pTmp++ = DMAP( nRed, nThres ); - } - } - - hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_RGB_COLORS ); - } - else if ( ImplIsSysColorEntry( nSalColor ) ) - { - nBrushColor = PALRGB_TO_RGB( nBrushColor ); - hNewBrush = CreateSolidBrush( nBrushColor ); - } - else if ( ImplIsPaletteEntry( nRed, nGreen, nBlue ) ) - hNewBrush = CreateSolidBrush( nBrushColor ); - else - { - BYTE* pTmp = pSalData->mpDitherDIBData; - long* pDitherDiff = pSalData->mpDitherDiff; - BYTE* pDitherLow = pSalData->mpDitherLow; - BYTE* pDitherHigh = pSalData->mpDitherHigh; - - for ( long nY = 0L; nY < 8L; nY++ ) - { - for ( long nX = 0L; nX < 8L; nX++ ) - { - const long nThres = aOrdDither8Bit[ nY ][ nX ]; - *pTmp = DMAP( nRed, nThres ) + DMAP( nGreen, nThres ) * 6 + DMAP( nBlue, nThres ) * 36; - pTmp++; - } - } - - hNewBrush = CreateDIBPatternBrush( pSalData->mhDitherDIB, DIB_PAL_COLORS ); - } - } - - bStockBrush = FALSE; - } - - // select new brush - HBRUSH hOldBrush = SelectBrush( getHDC(), hNewBrush ); - - // destroy or save old brush - if ( mhBrush ) - { - if ( !mbStockBrush ) - DeleteBrush( mhBrush ); - } - else - mhDefBrush = hOldBrush; - - // set new data - mnBrushColor = nBrushColor; - mhBrush = hNewBrush; - mbBrush = TRUE; - mbStockBrush = bStockBrush; + mpImpl->SetFillColor( nSalColor ); } -void WinSalGraphics::SetXORMode( bool bSet, bool ) +void WinSalGraphics::SetXORMode( bool bSet, bool bInvertOnly ) { - mbXORMode = bSet; - ::SetROP2( getHDC(), bSet ? R2_XORPEN : R2_COPYPEN ); + mpImpl->SetXORMode( bSet, bInvertOnly ); } void WinSalGraphics::SetROPLineColor( SalROPColor nROPColor ) { - SetLineColor( ImplGetROPSalColor( nROPColor ) ); + mpImpl->SetROPLineColor( nROPColor ); } void WinSalGraphics::SetROPFillColor( SalROPColor nROPColor ) { - SetFillColor( ImplGetROPSalColor( nROPColor ) ); + mpImpl->SetROPFillColor( nROPColor ); } void WinSalGraphics::drawPixel( long nX, long nY ) { - if ( mbXORMode ) - { - HBRUSH hBrush = CreateSolidBrush( mnPenColor ); - HBRUSH hOldBrush = SelectBrush( getHDC(), hBrush ); - PatBlt( getHDC(), (int)nX, (int)nY, (int)1, (int)1, PATINVERT ); - SelectBrush( getHDC(), hOldBrush ); - DeleteBrush( hBrush ); - } - else - SetPixel( getHDC(), (int)nX, (int)nY, mnPenColor ); + mpImpl->drawPixel( nX, nY ); } void WinSalGraphics::drawPixel( long nX, long nY, SalColor nSalColor ) { - COLORREF nCol = PALETTERGB( SALCOLOR_RED( nSalColor ), - SALCOLOR_GREEN( nSalColor ), - SALCOLOR_BLUE( nSalColor ) ); - - if ( !mbPrinter && - GetSalData()->mhDitherPal && - ImplIsSysColorEntry( nSalColor ) ) - nCol = PALRGB_TO_RGB( nCol ); - - if ( mbXORMode ) - { - HBRUSH hBrush = CreateSolidBrush( nCol ); - HBRUSH hOldBrush = SelectBrush( getHDC(), hBrush ); - PatBlt( getHDC(), (int)nX, (int)nY, (int)1, (int)1, PATINVERT ); - SelectBrush( getHDC(), hOldBrush ); - DeleteBrush( hBrush ); - } - else - ::SetPixel( getHDC(), (int)nX, (int)nY, nCol ); + mpImpl->drawPixel( nX, nY, nSalColor ); } void WinSalGraphics::drawLine( long nX1, long nY1, long nX2, long nY2 ) { - MoveToEx( getHDC(), (int)nX1, (int)nY1, NULL ); - - // we must paint the endpoint - int bPaintEnd = TRUE; - if ( nX1 == nX2 ) - { - bPaintEnd = FALSE; - if ( nY1 <= nY2 ) - nY2++; - else - nY2--; - } - if ( nY1 == nY2 ) - { - bPaintEnd = FALSE; - if ( nX1 <= nX2 ) - nX2++; - else - nX2--; - } - - LineTo( getHDC(), (int)nX2, (int)nY2 ); - - if ( bPaintEnd && !mbPrinter ) - { - if ( mbXORMode ) - { - HBRUSH hBrush = CreateSolidBrush( mnPenColor ); - HBRUSH hOldBrush = SelectBrush( getHDC(), hBrush ); - PatBlt( getHDC(), (int)nX2, (int)nY2, (int)1, (int)1, PATINVERT ); - SelectBrush( getHDC(), hOldBrush ); - DeleteBrush( hBrush ); - } - else - SetPixel( getHDC(), (int)nX2, (int)nY2, mnPenColor ); - } + mpImpl->drawLine( nX1, nY1, nX2, nY2 ); } void WinSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight ) { - if ( !mbPen ) - { - if ( !mbPrinter ) - { - PatBlt( getHDC(), (int)nX, (int)nY, (int)nWidth, (int)nHeight, - mbXORMode ? PATINVERT : PATCOPY ); - } - else - { - RECT aWinRect; - aWinRect.left = nX; - aWinRect.top = nY; - aWinRect.right = nX+nWidth; - aWinRect.bottom = nY+nHeight; - ::FillRect( getHDC(), &aWinRect, mhBrush ); - } - } - else - WIN_Rectangle( getHDC(), (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) ); + mpImpl->drawRect( nX, nY, nWidth, nHeight ); } void WinSalGraphics::drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) { - // for NT, we can handover the array directly - DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), - "WinSalGraphics::DrawPolyLine(): POINT != SalPoint" ); - - POINT* pWinPtAry = (POINT*)pPtAry; - - // we assume there are at least 2 points (Polyline requres at least 2 point, see MSDN) - // we must paint the endpoint for last line - BOOL bPaintEnd = TRUE; - if ( pWinPtAry[nPoints-2].x == pWinPtAry[nPoints-1].x ) - { - bPaintEnd = FALSE; - if ( pWinPtAry[nPoints-2].y <= pWinPtAry[nPoints-1].y ) - pWinPtAry[nPoints-1].y++; - else - pWinPtAry[nPoints-1].y--; - } - if ( pWinPtAry[nPoints-2].y == pWinPtAry[nPoints-1].y ) - { - bPaintEnd = FALSE; - if ( pWinPtAry[nPoints-2].x <= pWinPtAry[nPoints-1].x ) - pWinPtAry[nPoints-1].x++; - else - pWinPtAry[nPoints-1].x--; - } - - // for Windows 95 and its maximum number of points - if ( !Polyline( getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) ) - Polyline( getHDC(), pWinPtAry, MAX_64KSALPOINTS ); - - if ( bPaintEnd && !mbPrinter ) - { - if ( mbXORMode ) - { - HBRUSH hBrush = CreateSolidBrush( mnPenColor ); - HBRUSH hOldBrush = SelectBrush( getHDC(), hBrush ); - PatBlt( getHDC(), (int)(pWinPtAry[nPoints-1].x), (int)(pWinPtAry[nPoints-1].y), (int)1, (int)1, PATINVERT ); - SelectBrush( getHDC(), hOldBrush ); - DeleteBrush( hBrush ); - } - else - SetPixel( getHDC(), (int)(pWinPtAry[nPoints-1].x), (int)(pWinPtAry[nPoints-1].y), mnPenColor ); - } + mpImpl->drawPolyLine( nPoints, pPtAry ); } void WinSalGraphics::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) { - // for NT, we can handover the array directly - DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), - "WinSalGraphics::DrawPolygon(): POINT != SalPoint" ); - - POINT* pWinPtAry = (POINT*)pPtAry; - // for Windows 95 and its maximum number of points - if ( !WIN_Polygon( getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) ) - WIN_Polygon( getHDC(), pWinPtAry, MAX_64KSALPOINTS ); + mpImpl->drawPolygon( nPoints, pPtAry ); } void WinSalGraphics::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) { - UINT aWinPointAry[SAL_POLYPOLYCOUNT_STACKBUF]; - UINT* pWinPointAry; - UINT nPolyPolyPoints = 0; - UINT nPoints; - UINT i; - - if ( nPoly <= SAL_POLYPOLYCOUNT_STACKBUF ) - pWinPointAry = aWinPointAry; - else - pWinPointAry = new UINT[nPoly]; - - for ( i = 0; i < (UINT)nPoly; i++ ) - { - nPoints = (UINT)pPoints[i]+1; - pWinPointAry[i] = nPoints; - nPolyPolyPoints += nPoints; - } - - POINT aWinPointAryAry[SAL_POLYPOLYPOINTS_STACKBUF]; - POINT* pWinPointAryAry; - if ( nPolyPolyPoints <= SAL_POLYPOLYPOINTS_STACKBUF ) - pWinPointAryAry = aWinPointAryAry; - else - pWinPointAryAry = new POINT[nPolyPolyPoints]; - // for NT, we can handover the array directly - DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), - "WinSalGraphics::DrawPolyPolygon(): POINT != SalPoint" ); - const SalPoint* pPolyAry; - UINT n = 0; - for ( i = 0; i < (UINT)nPoly; i++ ) - { - nPoints = pWinPointAry[i]; - pPolyAry = pPtAry[i]; - memcpy( pWinPointAryAry+n, pPolyAry, (nPoints-1)*sizeof(POINT) ); - pWinPointAryAry[n+nPoints-1] = pWinPointAryAry[n]; - n += nPoints; - } - - if ( !WIN_PolyPolygon( getHDC(), pWinPointAryAry, (int*)pWinPointAry, (UINT)nPoly ) && - (nPolyPolyPoints > MAX_64KSALPOINTS) ) - { - nPolyPolyPoints = 0; - nPoly = 0; - do - { - nPolyPolyPoints += pWinPointAry[(UINT)nPoly]; - nPoly++; - } - while ( nPolyPolyPoints < MAX_64KSALPOINTS ); - nPoly--; - if ( pWinPointAry[(UINT)nPoly] > MAX_64KSALPOINTS ) - pWinPointAry[(UINT)nPoly] = MAX_64KSALPOINTS; - if ( nPoly == 1 ) - WIN_Polygon( getHDC(), pWinPointAryAry, *pWinPointAry ); - else - WIN_PolyPolygon( getHDC(), pWinPointAryAry, (int*)pWinPointAry, nPoly ); - } - - if ( pWinPointAry != aWinPointAry ) - delete [] pWinPointAry; - if ( pWinPointAryAry != aWinPointAryAry ) - delete [] pWinPointAryAry; + mpImpl->drawPolyPolygon( nPoly, pPoints, pPtAry ); } -#define SAL_POLY_STACKBUF 32 - bool WinSalGraphics::drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry ) { -#ifdef USE_GDI_BEZIERS - // for NT, we can handover the array directly - DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), - "WinSalGraphics::DrawPolyLineBezier(): POINT != SalPoint" ); - - ImplRenderPath( getHDC(), nPoints, pPtAry, pFlgAry ); - - return true; -#else - return false; -#endif + return mpImpl->drawPolyLineBezier( nPoints, pPtAry, pFlgAry ); } bool WinSalGraphics::drawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const BYTE* pFlgAry ) { -#ifdef USE_GDI_BEZIERS - // for NT, we can handover the array directly - DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), - "WinSalGraphics::DrawPolygonBezier(): POINT != SalPoint" ); - - POINT aStackAry1[SAL_POLY_STACKBUF]; - BYTE aStackAry2[SAL_POLY_STACKBUF]; - POINT* pWinPointAry; - BYTE* pWinFlagAry; - if( nPoints > SAL_POLY_STACKBUF ) - { - pWinPointAry = new POINT[ nPoints ]; - pWinFlagAry = new BYTE[ nPoints ]; - } - else - { - pWinPointAry = aStackAry1; - pWinFlagAry = aStackAry2; - } - - sal_uInt32 nPoints_i32(nPoints); - ImplPreparePolyDraw(true, 1, &nPoints_i32, &pPtAry, &pFlgAry, pWinPointAry, pWinFlagAry); - - bool bRet( false ); - - if( BeginPath( getHDC() ) ) - { - PolyDraw(getHDC(), pWinPointAry, pWinFlagAry, nPoints); - - if( EndPath( getHDC() ) ) - { - if( StrokeAndFillPath( getHDC() ) ) - bRet = true; - } - } - - if( pWinPointAry != aStackAry1 ) - { - delete [] pWinPointAry; - delete [] pWinFlagAry; - } - - return bRet; -#else - return false; -#endif + return mpImpl->drawPolygonBezier( nPoints, pPtAry, pFlgAry ); } bool WinSalGraphics::drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, const SalPoint* const* pPtAry, const BYTE* const* pFlgAry ) { -#ifdef USE_GDI_BEZIERS - // for NT, we can handover the array directly - DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), - "WinSalGraphics::DrawPolyPolygonBezier(): POINT != SalPoint" ); - - sal_uLong nCurrPoly, nTotalPoints; - const sal_uInt32* pCurrPoints = pPoints; - for( nCurrPoly=0, nTotalPoints=0; nCurrPoly<nPoly; ++nCurrPoly ) - nTotalPoints += *pCurrPoints++; - - POINT aStackAry1[SAL_POLY_STACKBUF]; - BYTE aStackAry2[SAL_POLY_STACKBUF]; - POINT* pWinPointAry; - BYTE* pWinFlagAry; - if( nTotalPoints > SAL_POLY_STACKBUF ) - { - pWinPointAry = new POINT[ nTotalPoints ]; - pWinFlagAry = new BYTE[ nTotalPoints ]; - } - else - { - pWinPointAry = aStackAry1; - pWinFlagAry = aStackAry2; - } - - ImplPreparePolyDraw(true, nPoly, pPoints, pPtAry, pFlgAry, pWinPointAry, pWinFlagAry); - - bool bRet( false ); - - if( BeginPath( getHDC() ) ) - { - PolyDraw(getHDC(), pWinPointAry, pWinFlagAry, nTotalPoints); - - if( EndPath( getHDC() ) ) - { - if( StrokeAndFillPath( getHDC() ) ) - bRet = true; - } - } - - if( pWinPointAry != aStackAry1 ) - { - delete [] pWinPointAry; - delete [] pWinFlagAry; - } - - return bRet; -#else - return false; -#endif + return mpImpl->drawPolyPolygonBezier( nPoly, pPoints, pPtAry, pFlgAry ); } -#define POSTSCRIPT_BUFSIZE 0x4000 // MAXIMUM BUFSIZE EQ 0xFFFF - static BYTE* ImplSearchEntry( BYTE* pSource, BYTE* pDest, sal_uLong nComp, sal_uLong nSize ) { while ( nComp-- >= nSize ) @@ -1656,9 +869,11 @@ static bool ImplGetBoundingBox( double* nNumb, BYTE* pSource, sal_uLong nSize ) return bRetValue; } +#define POSTSCRIPT_BUFSIZE 0x4000 // MAXIMUM BUFSIZE EQ 0xFFFF + bool WinSalGraphics::drawEPS( long nX, long nY, long nWidth, long nHeight, void* pPtr, sal_uLong nSize ) { - bool bRetValue = FALSE; + bool bRetValue = false; if ( mbPrinter ) { @@ -1814,4 +1029,9 @@ SystemGraphicsData WinSalGraphics::GetGraphicsData() const return aRes; } +bool WinSalGraphics::SwapBuffers() +{ + return mpImpl->swapBuffers(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/source/gdi/salgdi2.cxx b/vcl/win/source/gdi/salgdi2.cxx index 16f262fa41c6..f00945164f3e 100644 --- a/vcl/win/source/gdi/salgdi2.cxx +++ b/vcl/win/source/gdi/salgdi2.cxx @@ -33,6 +33,7 @@ #include "vcl/salbtype.hxx" #include "vcl/bmpacc.hxx" #include "outdata.hxx" +#include "salgdiimpl.hxx" bool WinSalGraphics::supportsOperation( OutDevSupportType eType ) const { @@ -56,82 +57,7 @@ bool WinSalGraphics::supportsOperation( OutDevSupportType eType ) const void WinSalGraphics::copyBits( const SalTwoRect& rPosAry, SalGraphics* pSrcGraphics ) { - HDC hSrcDC; - DWORD nRop; - - if ( pSrcGraphics ) - hSrcDC = static_cast<WinSalGraphics*>(pSrcGraphics)->getHDC(); - else - hSrcDC = getHDC(); - - if ( mbXORMode ) - nRop = SRCINVERT; - else - nRop = SRCCOPY; - - if ( (rPosAry.mnSrcWidth == rPosAry.mnDestWidth) && - (rPosAry.mnSrcHeight == rPosAry.mnDestHeight) ) - { - BitBlt( getHDC(), - (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, - (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, - hSrcDC, - (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY, - nRop ); - } - else - { - int nOldStretchMode = SetStretchBltMode( getHDC(), STRETCH_DELETESCANS ); - StretchBlt( getHDC(), - (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, - (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, - hSrcDC, - (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY, - (int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight, - nRop ); - SetStretchBltMode( getHDC(), nOldStretchMode ); - } -} - -void ImplCalcOutSideRgn( const RECT& rSrcRect, - int nLeft, int nTop, int nRight, int nBottom, - HRGN& rhInvalidateRgn ) -{ - HRGN hTempRgn; - - // calculate area outside the visible region - if ( rSrcRect.left < nLeft ) - { - if ( !rhInvalidateRgn ) - rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect ); - hTempRgn = CreateRectRgn( -31999, 0, nLeft, 31999 ); - CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF ); - DeleteRegion( hTempRgn ); - } - if ( rSrcRect.top < nTop ) - { - if ( !rhInvalidateRgn ) - rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect ); - hTempRgn = CreateRectRgn( 0, -31999, 31999, nTop ); - CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF ); - DeleteRegion( hTempRgn ); - } - if ( rSrcRect.right > nRight ) - { - if ( !rhInvalidateRgn ) - rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect ); - hTempRgn = CreateRectRgn( nRight, 0, 31999, 31999 ); - CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF ); - DeleteRegion( hTempRgn ); - } - if ( rSrcRect.bottom > nBottom ) - { - if ( !rhInvalidateRgn ) - rhInvalidateRgn = CreateRectRgnIndirect( &rSrcRect ); - hTempRgn = CreateRectRgn( 0, nBottom, 31999, 31999 ); - CombineRgn( rhInvalidateRgn, rhInvalidateRgn, hTempRgn, RGN_DIFF ); - DeleteRegion( hTempRgn ); - } + mpImpl->copyBits( rPosAry, pSrcGraphics ); } void WinSalGraphics::copyArea( long nDestX, long nDestY, @@ -139,688 +65,60 @@ void WinSalGraphics::copyArea( long nDestX, long nDestY, long nSrcWidth, long nSrcHeight, sal_uInt16 nFlags ) { - bool bRestoreClipRgn = false; - HRGN hOldClipRgn = 0; - int nOldClipRgnType = ERROR; - HRGN hInvalidateRgn = 0; - - // do we have to invalidate also the overlapping regions? - if ( (nFlags & SAL_COPYAREA_WINDOWINVALIDATE) && mbWindow ) - { - // compute and invalidate those parts that were either off-screen or covered by other windows - // while performing the above BitBlt - // those regions then have to be invalidated as they contain useless/wrong data - RECT aSrcRect; - RECT aClipRect; - RECT aTempRect; - RECT aTempRect2; - HRGN hTempRgn; - HWND hWnd; - - // restrict srcRect to this window (calc intersection) - aSrcRect.left = (int)nSrcX; - aSrcRect.top = (int)nSrcY; - aSrcRect.right = aSrcRect.left+(int)nSrcWidth; - aSrcRect.bottom = aSrcRect.top+(int)nSrcHeight; - GetClientRect( mhWnd, &aClipRect ); - if ( IntersectRect( &aSrcRect, &aSrcRect, &aClipRect ) ) - { - // transform srcRect to screen coordinates - POINT aPt; - aPt.x = 0; - aPt.y = 0; - ClientToScreen( mhWnd, &aPt ); - aSrcRect.left += aPt.x; - aSrcRect.top += aPt.y; - aSrcRect.right += aPt.x; - aSrcRect.bottom += aPt.y; - hInvalidateRgn = 0; - - // compute the parts that are off screen (ie invisible) - RECT theScreen; - ImplSalGetWorkArea( NULL, &theScreen, NULL ); // find the screen area taking multiple monitors into account - ImplCalcOutSideRgn( aSrcRect, theScreen.left, theScreen.top, theScreen.right, theScreen.bottom, hInvalidateRgn ); - - // calculate regions that are covered by other windows - HRGN hTempRgn2 = 0; - HWND hWndTopWindow = mhWnd; - // Find the TopLevel Window, because only Windows which are in - // in the foreground of our TopLevel window must be considered - if ( GetWindowStyle( hWndTopWindow ) & WS_CHILD ) - { - RECT aTempRect3 = aSrcRect; - do - { - hWndTopWindow = ::GetParent( hWndTopWindow ); - - // Test if the Parent clips our window - GetClientRect( hWndTopWindow, &aTempRect ); - POINT aPt2; - aPt2.x = 0; - aPt2.y = 0; - ClientToScreen( hWndTopWindow, &aPt2 ); - aTempRect.left += aPt2.x; - aTempRect.top += aPt2.y; - aTempRect.right += aPt2.x; - aTempRect.bottom += aPt2.y; - IntersectRect( &aTempRect3, &aTempRect3, &aTempRect ); - } - while ( GetWindowStyle( hWndTopWindow ) & WS_CHILD ); - - // If one or more Parents clip our window, than we must - // calculate the outside area - if ( !EqualRect( &aSrcRect, &aTempRect3 ) ) - { - ImplCalcOutSideRgn( aSrcRect, - aTempRect3.left, aTempRect3.top, - aTempRect3.right, aTempRect3.bottom, - hInvalidateRgn ); - } - } - // retrieve the top-most (z-order) child window - hWnd = GetWindow( GetDesktopWindow(), GW_CHILD ); - while ( hWnd ) - { - if ( hWnd == hWndTopWindow ) - break; - if ( IsWindowVisible( hWnd ) && !IsIconic( hWnd ) ) - { - GetWindowRect( hWnd, &aTempRect ); - if ( IntersectRect( &aTempRect2, &aSrcRect, &aTempRect ) ) - { - // hWnd covers part or all of aSrcRect - if ( !hInvalidateRgn ) - hInvalidateRgn = CreateRectRgnIndirect( &aSrcRect ); - - // get full bounding box of hWnd - hTempRgn = CreateRectRgnIndirect( &aTempRect ); - - // get region of hWnd (the window may be shaped) - if ( !hTempRgn2 ) - hTempRgn2 = CreateRectRgn( 0, 0, 0, 0 ); - int nRgnType = GetWindowRgn( hWnd, hTempRgn2 ); - if ( (nRgnType != ERROR) && (nRgnType != NULLREGION) ) - { - // convert window region to screen coordinates - OffsetRgn( hTempRgn2, aTempRect.left, aTempRect.top ); - // and intersect with the window's bounding box - CombineRgn( hTempRgn, hTempRgn, hTempRgn2, RGN_AND ); - } - // finally compute that part of aSrcRect which is not covered by any parts of hWnd - CombineRgn( hInvalidateRgn, hInvalidateRgn, hTempRgn, RGN_DIFF ); - DeleteRegion( hTempRgn ); - } - } - // retrieve the next window in the z-order, i.e. the window below hwnd - hWnd = GetWindow( hWnd, GW_HWNDNEXT ); - } - if ( hTempRgn2 ) - DeleteRegion( hTempRgn2 ); - if ( hInvalidateRgn ) - { - // hInvalidateRgn contains the fully visible parts of the original srcRect - hTempRgn = CreateRectRgnIndirect( &aSrcRect ); - // substract it from the original rect to get the occluded parts - int nRgnType = CombineRgn( hInvalidateRgn, hTempRgn, hInvalidateRgn, RGN_DIFF ); - DeleteRegion( hTempRgn ); - - if ( (nRgnType != ERROR) && (nRgnType != NULLREGION) ) - { - // move the occluded parts to the destination pos - int nOffX = (int)(nDestX-nSrcX); - int nOffY = (int)(nDestY-nSrcY); - OffsetRgn( hInvalidateRgn, nOffX-aPt.x, nOffY-aPt.y ); - - // by excluding hInvalidateRgn from the system's clip region - // we will prevent bitblt from copying useless data - // epsecially now shadows from overlapping windows will appear (#i36344) - hOldClipRgn = CreateRectRgn( 0, 0, 0, 0 ); - nOldClipRgnType = GetClipRgn( getHDC(), hOldClipRgn ); - - bRestoreClipRgn = TRUE; // indicate changed clipregion and force invalidate - ExtSelectClipRgn( getHDC(), hInvalidateRgn, RGN_DIFF ); - } - } - } - } - - BitBlt( getHDC(), - (int)nDestX, (int)nDestY, - (int)nSrcWidth, (int)nSrcHeight, - getHDC(), - (int)nSrcX, (int)nSrcY, - SRCCOPY ); - - if( bRestoreClipRgn ) - { - // restore old clip region - if( nOldClipRgnType != ERROR ) - SelectClipRgn( getHDC(), hOldClipRgn); - DeleteRegion( hOldClipRgn ); - - // invalidate regions that were not copied - bool bInvalidate = true; - - // Combine Invalidate vcl::Region with existing ClipRegion - HRGN hTempRgn = CreateRectRgn( 0, 0, 0, 0 ); - if ( GetClipRgn( getHDC(), hTempRgn ) == 1 ) - { - int nRgnType = CombineRgn( hInvalidateRgn, hTempRgn, hInvalidateRgn, RGN_AND ); - if ( (nRgnType == ERROR) || (nRgnType == NULLREGION) ) - bInvalidate = false; - } - DeleteRegion( hTempRgn ); - - if ( bInvalidate ) - { - InvalidateRgn( mhWnd, hInvalidateRgn, TRUE ); - // here we only initiate an update if this is the MainThread, - // so that there is no deadlock when handling the Paint event, - // as the SolarMutex is already held by this Thread - SalData* pSalData = GetSalData(); - DWORD nCurThreadId = GetCurrentThreadId(); - if ( pSalData->mnAppThreadId == nCurThreadId ) - UpdateWindow( mhWnd ); - } - - DeleteRegion( hInvalidateRgn ); - } - -} - -void ImplDrawBitmap( HDC hDC, - const SalTwoRect& rPosAry, const WinSalBitmap& rSalBitmap, - bool bPrinter, int nDrawMode ) -{ - if( hDC ) - { - HGLOBAL hDrawDIB; - HBITMAP hDrawDDB = rSalBitmap.ImplGethDDB(); - WinSalBitmap* pTmpSalBmp = NULL; - bool bPrintDDB = ( bPrinter && hDrawDDB ); - - if( bPrintDDB ) - { - pTmpSalBmp = new WinSalBitmap; - pTmpSalBmp->Create( rSalBitmap, rSalBitmap.GetBitCount() ); - hDrawDIB = pTmpSalBmp->ImplGethDIB(); - } - else - hDrawDIB = rSalBitmap.ImplGethDIB(); - - if( hDrawDIB ) - { - PBITMAPINFO pBI = (PBITMAPINFO) GlobalLock( hDrawDIB ); - PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER) pBI; - PBYTE pBits = (PBYTE) pBI + *(DWORD*) pBI + - rSalBitmap.ImplGetDIBColorCount( hDrawDIB ) * sizeof( RGBQUAD ); - const int nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS ); - - StretchDIBits( hDC, - (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, - (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, - (int)rPosAry.mnSrcX, (int)(pBIH->biHeight - rPosAry.mnSrcHeight - rPosAry.mnSrcY), - (int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight, - pBits, pBI, DIB_RGB_COLORS, nDrawMode ); - - GlobalUnlock( hDrawDIB ); - SetStretchBltMode( hDC, nOldStretchMode ); - } - else if( hDrawDDB && !bPrintDDB ) - { - HDC hBmpDC = ImplGetCachedDC( CACHED_HDC_DRAW, hDrawDDB ); - COLORREF nOldBkColor = RGB(0xFF,0xFF,0xFF); - COLORREF nOldTextColor = RGB(0,0,0); - bool bMono = ( rSalBitmap.GetBitCount() == 1 ); - - if( bMono ) - { - COLORREF nBkColor = RGB( 0xFF, 0xFF, 0xFF ); - COLORREF nTextColor = RGB( 0x00, 0x00, 0x00 ); - //fdo#33455 handle 1 bit depth pngs with palette entries - //to set fore/back colors - if (const BitmapBuffer* pBitmapBuffer = const_cast<WinSalBitmap&>(rSalBitmap).AcquireBuffer(true)) - { - const BitmapPalette& rPalette = pBitmapBuffer->maPalette; - if (rPalette.GetEntryCount() == 2) - { - SalColor nCol; - nCol = ImplColorToSal(rPalette[0]); - nTextColor = RGB( SALCOLOR_RED(nCol), SALCOLOR_GREEN(nCol), SALCOLOR_BLUE(nCol) ); - nCol = ImplColorToSal(rPalette[1]); - nBkColor = RGB( SALCOLOR_RED(nCol), SALCOLOR_GREEN(nCol), SALCOLOR_BLUE(nCol) ); - } - } - nOldBkColor = SetBkColor( hDC, nBkColor ); - nOldTextColor = ::SetTextColor( hDC, nTextColor ); - } - - if ( (rPosAry.mnSrcWidth == rPosAry.mnDestWidth) && - (rPosAry.mnSrcHeight == rPosAry.mnDestHeight) ) - { - BitBlt( hDC, - (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, - (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, - hBmpDC, - (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY, - nDrawMode ); - } - else - { - const int nOldStretchMode = SetStretchBltMode( hDC, STRETCH_DELETESCANS ); - - StretchBlt( hDC, - (int)rPosAry.mnDestX, (int)rPosAry.mnDestY, - (int)rPosAry.mnDestWidth, (int)rPosAry.mnDestHeight, - hBmpDC, - (int)rPosAry.mnSrcX, (int)rPosAry.mnSrcY, - (int)rPosAry.mnSrcWidth, (int)rPosAry.mnSrcHeight, - nDrawMode ); - - SetStretchBltMode( hDC, nOldStretchMode ); - } - - if( bMono ) - { - SetBkColor( hDC, nOldBkColor ); - ::SetTextColor( hDC, nOldTextColor ); - } - - ImplReleaseCachedDC( CACHED_HDC_DRAW ); - } - - if( bPrintDDB ) - delete pTmpSalBmp; - } + mpImpl->copyArea( nDestX, nDestY, nSrcX, nSrcY, + nSrcWidth, nSrcHeight, nFlags ); } void WinSalGraphics::drawBitmap(const SalTwoRect& rPosAry, const SalBitmap& rSalBitmap) { - bool bTryDirectPaint(!mbPrinter && !mbXORMode); - - if(bTryDirectPaint) - { - // only paint direct when no scaling and no MapMode, else the - // more expensive conversions may be done for short-time Bitmap/BitmapEx - // used for buffering only - if(rPosAry.mnSrcWidth == rPosAry.mnDestWidth && rPosAry.mnSrcHeight == rPosAry.mnDestHeight) - { - bTryDirectPaint = false; - } - } - - // try to draw using GdiPlus directly - if(bTryDirectPaint && tryDrawBitmapGdiPlus(rPosAry, rSalBitmap)) - { - return; - } - - // fall back old stuff - ImplDrawBitmap(getHDC(), rPosAry, static_cast<const WinSalBitmap&>(rSalBitmap), - mbPrinter, - mbXORMode ? SRCINVERT : SRCCOPY ); + mpImpl->drawBitmap( rPosAry, rSalBitmap ); } void WinSalGraphics::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSSalBitmap, SalColor nTransparentColor ) { - DBG_ASSERT( !mbPrinter, "No transparency print possible!" ); - - const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap); - - WinSalBitmap* pMask = new WinSalBitmap; - const Point aPoint; - const Size aSize( rSalBitmap.GetSize() ); - HBITMAP hMaskBitmap = CreateBitmap( (int) aSize.Width(), (int) aSize.Height(), 1, 1, NULL ); - HDC hMaskDC = ImplGetCachedDC( CACHED_HDC_1, hMaskBitmap ); - const BYTE cRed = SALCOLOR_RED( nTransparentColor ); - const BYTE cGreen = SALCOLOR_GREEN( nTransparentColor ); - const BYTE cBlue = SALCOLOR_BLUE( nTransparentColor ); - - if( rSalBitmap.ImplGethDDB() ) - { - HDC hSrcDC = ImplGetCachedDC( CACHED_HDC_2, rSalBitmap.ImplGethDDB() ); - COLORREF aOldCol = SetBkColor( hSrcDC, RGB( cRed, cGreen, cBlue ) ); - - BitBlt( hMaskDC, 0, 0, (int) aSize.Width(), (int) aSize.Height(), hSrcDC, 0, 0, SRCCOPY ); - - SetBkColor( hSrcDC, aOldCol ); - ImplReleaseCachedDC( CACHED_HDC_2 ); - } - else - { - WinSalBitmap* pTmpSalBmp = new WinSalBitmap; - - if( pTmpSalBmp->Create( rSalBitmap, this ) ) - { - HDC hSrcDC = ImplGetCachedDC( CACHED_HDC_2, pTmpSalBmp->ImplGethDDB() ); - COLORREF aOldCol = SetBkColor( hSrcDC, RGB( cRed, cGreen, cBlue ) ); - - BitBlt( hMaskDC, 0, 0, (int) aSize.Width(), (int) aSize.Height(), hSrcDC, 0, 0, SRCCOPY ); - - SetBkColor( hSrcDC, aOldCol ); - ImplReleaseCachedDC( CACHED_HDC_2 ); - } - - delete pTmpSalBmp; - } - - ImplReleaseCachedDC( CACHED_HDC_1 ); - - // hMaskBitmap is destroyed by new SalBitmap 'pMask' ( bDIB==FALSE, bCopy == FALSE ) - if( pMask->Create( hMaskBitmap, FALSE, FALSE ) ) - drawBitmap( rPosAry, rSalBitmap, *pMask ); - - delete pMask; + mpImpl->drawBitmap( rPosAry, rSSalBitmap, nTransparentColor ); } void WinSalGraphics::drawBitmap( const SalTwoRect& rPosAry, const SalBitmap& rSSalBitmap, const SalBitmap& rSTransparentBitmap ) { - DBG_ASSERT( !mbPrinter, "No transparency print possible!" ); - bool bTryDirectPaint(!mbPrinter && !mbXORMode); - - if(bTryDirectPaint) - { - // only paint direct when no scaling and no MapMode, else the - // more expensive conversions may be done for short-time Bitmap/BitmapEx - // used for buffering only - if(rPosAry.mnSrcWidth == rPosAry.mnDestWidth && rPosAry.mnSrcHeight == rPosAry.mnDestHeight) - { - bTryDirectPaint = false; - } - } - - // try to draw using GdiPlus directly - if(bTryDirectPaint && drawAlphaBitmap(rPosAry, rSSalBitmap, rSTransparentBitmap)) - { - return; - } - - const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap); - const WinSalBitmap& rTransparentBitmap = static_cast<const WinSalBitmap&>(rSTransparentBitmap); - - SalTwoRect aPosAry = rPosAry; - int nDstX = (int)aPosAry.mnDestX; - int nDstY = (int)aPosAry.mnDestY; - int nDstWidth = (int)aPosAry.mnDestWidth; - int nDstHeight = (int)aPosAry.mnDestHeight; - HDC hDC = getHDC(); - HBITMAP hMemBitmap = 0; - HBITMAP hMaskBitmap = 0; - - if( ( nDstWidth > CACHED_HDC_DEFEXT ) || ( nDstHeight > CACHED_HDC_DEFEXT ) ) - { - hMemBitmap = CreateCompatibleBitmap( hDC, nDstWidth, nDstHeight ); - hMaskBitmap = CreateCompatibleBitmap( hDC, nDstWidth, nDstHeight ); - } - - HDC hMemDC = ImplGetCachedDC( CACHED_HDC_1, hMemBitmap ); - HDC hMaskDC = ImplGetCachedDC( CACHED_HDC_2, hMaskBitmap ); - - aPosAry.mnDestX = aPosAry.mnDestY = 0; - BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hDC, nDstX, nDstY, SRCCOPY ); - - // WIN/WNT seems to have a minor problem mapping the correct color of the - // mask to the palette if we draw the DIB directly ==> draw DDB - if( ( GetBitCount() <= 8 ) && rTransparentBitmap.ImplGethDIB() && rTransparentBitmap.GetBitCount() == 1 ) - { - WinSalBitmap aTmp; - - if( aTmp.Create( rTransparentBitmap, this ) ) - ImplDrawBitmap( hMaskDC, aPosAry, aTmp, FALSE, SRCCOPY ); - } - else - ImplDrawBitmap( hMaskDC, aPosAry, rTransparentBitmap, FALSE, SRCCOPY ); - - // now MemDC contains background, MaskDC the transparency mask - - // #105055# Respect XOR mode - if( mbXORMode ) - { - ImplDrawBitmap( hMaskDC, aPosAry, rSalBitmap, FALSE, SRCERASE ); - // now MaskDC contains the bitmap area with black background - BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCINVERT ); - // now MemDC contains background XORed bitmap area ontop - } - else - { - BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCAND ); - // now MemDC contains background with masked-out bitmap area - ImplDrawBitmap( hMaskDC, aPosAry, rSalBitmap, FALSE, SRCERASE ); - // now MaskDC contains the bitmap area with black background - BitBlt( hMemDC, 0, 0, nDstWidth, nDstHeight, hMaskDC, 0, 0, SRCPAINT ); - // now MemDC contains background and bitmap merged together - } - // copy to output DC - BitBlt( hDC, nDstX, nDstY, nDstWidth, nDstHeight, hMemDC, 0, 0, SRCCOPY ); - - ImplReleaseCachedDC( CACHED_HDC_1 ); - ImplReleaseCachedDC( CACHED_HDC_2 ); - - // hMemBitmap != 0 ==> hMaskBitmap != 0 - if( hMemBitmap ) - { - DeleteObject( hMemBitmap ); - DeleteObject( hMaskBitmap ); - } + mpImpl->drawBitmap( rPosAry, rSSalBitmap, rSTransparentBitmap ); } bool WinSalGraphics::drawAlphaRect( long nX, long nY, long nWidth, long nHeight, sal_uInt8 nTransparency ) { - if( mbPen || !mbBrush || mbXORMode ) - return false; // can only perform solid fills without XOR. - - HDC hMemDC = ImplGetCachedDC( CACHED_HDC_1, 0 ); - SetPixel( hMemDC, (int)0, (int)0, mnBrushColor ); - - BLENDFUNCTION aFunc = { - AC_SRC_OVER, - 0, - sal::static_int_cast<sal_uInt8>(255 - 255L*nTransparency/100), - 0 - }; - - // hMemDC contains a 1x1 bitmap of the right color - stretch-blit - // that to dest hdc - bool bRet = AlphaBlend( getHDC(), nX, nY, nWidth, nHeight, - hMemDC, 0,0,1,1, - aFunc ) == TRUE; - - ImplReleaseCachedDC( CACHED_HDC_1 ); - - return bRet; + return mpImpl->drawAlphaRect( nX, nY, nWidth, nHeight, nTransparency ); } void WinSalGraphics::drawMask( const SalTwoRect& rPosAry, const SalBitmap& rSSalBitmap, SalColor nMaskColor ) { - DBG_ASSERT( !mbPrinter, "No transparency print possible!" ); - - const WinSalBitmap& rSalBitmap = static_cast<const WinSalBitmap&>(rSSalBitmap); - - SalTwoRect aPosAry = rPosAry; - const BYTE cRed = SALCOLOR_RED( nMaskColor ); - const BYTE cGreen = SALCOLOR_GREEN( nMaskColor ); - const BYTE cBlue = SALCOLOR_BLUE( nMaskColor ); - HDC hDC = getHDC(); - HBRUSH hMaskBrush = CreateSolidBrush( RGB( cRed, cGreen, cBlue ) ); - HBRUSH hOldBrush = SelectBrush( hDC, hMaskBrush ); - - // WIN/WNT seems to have a minor problem mapping the correct color of the - // mask to the palette if we draw the DIB directly ==> draw DDB - if( ( GetBitCount() <= 8 ) && rSalBitmap.ImplGethDIB() && rSalBitmap.GetBitCount() == 1 ) - { - WinSalBitmap aTmp; - - if( aTmp.Create( rSalBitmap, this ) ) - ImplDrawBitmap( hDC, aPosAry, aTmp, FALSE, 0x00B8074AUL ); - } - else - ImplDrawBitmap( hDC, aPosAry, rSalBitmap, FALSE, 0x00B8074AUL ); - - SelectBrush( hDC, hOldBrush ); - DeleteBrush( hMaskBrush ); + mpImpl->drawMask( rPosAry, rSSalBitmap, nMaskColor ); } SalBitmap* WinSalGraphics::getBitmap( long nX, long nY, long nDX, long nDY ) { - DBG_ASSERT( !mbPrinter, "No ::GetBitmap() from printer possible!" ); - - WinSalBitmap* pSalBitmap = NULL; - - nDX = labs( nDX ); - nDY = labs( nDY ); - - HDC hDC = getHDC(); - HBITMAP hBmpBitmap = CreateCompatibleBitmap( hDC, nDX, nDY ); - HDC hBmpDC = ImplGetCachedDC( CACHED_HDC_1, hBmpBitmap ); - bool bRet; - - bRet = BitBlt( hBmpDC, 0, 0, (int) nDX, (int) nDY, hDC, (int) nX, (int) nY, SRCCOPY ) ? TRUE : FALSE; - ImplReleaseCachedDC( CACHED_HDC_1 ); - - if( bRet ) - { - pSalBitmap = new WinSalBitmap; - - if( !pSalBitmap->Create( hBmpBitmap, FALSE, FALSE ) ) - { - delete pSalBitmap; - pSalBitmap = NULL; - } - } - else - { - // #124826# avoid resource leak ! happens when runing without desktop access (remote desktop, service, may be screensavers) - DeleteBitmap( hBmpBitmap ); - } - - return pSalBitmap; + return mpImpl->getBitmap( nX, nY, nDX, nDY ); } SalColor WinSalGraphics::getPixel( long nX, long nY ) { - COLORREF aWinCol = ::GetPixel( getHDC(), (int) nX, (int) nY ); - - if ( CLR_INVALID == aWinCol ) - return MAKE_SALCOLOR( 0, 0, 0 ); - else - return MAKE_SALCOLOR( GetRValue( aWinCol ), - GetGValue( aWinCol ), - GetBValue( aWinCol ) ); + return mpImpl->getPixel( nX, nY ); } void WinSalGraphics::invert( long nX, long nY, long nWidth, long nHeight, SalInvert nFlags ) { - if ( nFlags & SAL_INVERT_TRACKFRAME ) - { - HPEN hDotPen = CreatePen( PS_DOT, 0, 0 ); - HPEN hOldPen = SelectPen( getHDC(), hDotPen ); - HBRUSH hOldBrush = SelectBrush( getHDC(), GetStockBrush( NULL_BRUSH ) ); - int nOldROP = SetROP2( getHDC(), R2_NOT ); - - WIN_Rectangle( getHDC(), (int)nX, (int)nY, (int)(nX+nWidth), (int)(nY+nHeight) ); - - SetROP2( getHDC(), nOldROP ); - SelectPen( getHDC(), hOldPen ); - SelectBrush( getHDC(), hOldBrush ); - DeletePen( hDotPen ); - } - else if ( nFlags & SAL_INVERT_50 ) - { - SalData* pSalData = GetSalData(); - if ( !pSalData->mh50Brush ) - { - if ( !pSalData->mh50Bmp ) - pSalData->mh50Bmp = ImplLoadSalBitmap( SAL_RESID_BITMAP_50 ); - pSalData->mh50Brush = CreatePatternBrush( pSalData->mh50Bmp ); - } - - COLORREF nOldTextColor = ::SetTextColor( getHDC(), 0 ); - HBRUSH hOldBrush = SelectBrush( getHDC(), pSalData->mh50Brush ); - PatBlt( getHDC(), nX, nY, nWidth, nHeight, PATINVERT ); - ::SetTextColor( getHDC(), nOldTextColor ); - SelectBrush( getHDC(), hOldBrush ); - } - else - { - RECT aRect; - aRect.left = (int)nX; - aRect.top = (int)nY; - aRect.right = (int)nX+nWidth; - aRect.bottom = (int)nY+nHeight; - ::InvertRect( getHDC(), &aRect ); - } + mpImpl->invert( nX, nY, nWidth, nHeight, nFlags ); } void WinSalGraphics::invert( sal_uInt32 nPoints, const SalPoint* pPtAry, SalInvert nSalFlags ) { - HPEN hPen; - HPEN hOldPen; - HBRUSH hBrush; - HBRUSH hOldBrush = 0; - COLORREF nOldTextColor RGB(0,0,0); - int nOldROP = SetROP2( getHDC(), R2_NOT ); - - if ( nSalFlags & SAL_INVERT_TRACKFRAME ) - hPen = CreatePen( PS_DOT, 0, 0 ); - else - { - - if ( nSalFlags & SAL_INVERT_50 ) - { - SalData* pSalData = GetSalData(); - if ( !pSalData->mh50Brush ) - { - if ( !pSalData->mh50Bmp ) - pSalData->mh50Bmp = ImplLoadSalBitmap( SAL_RESID_BITMAP_50 ); - pSalData->mh50Brush = CreatePatternBrush( pSalData->mh50Bmp ); - } - - hBrush = pSalData->mh50Brush; - } - else - hBrush = GetStockBrush( BLACK_BRUSH ); - - hPen = GetStockPen( NULL_PEN ); - nOldTextColor = ::SetTextColor( getHDC(), 0 ); - hOldBrush = SelectBrush( getHDC(), hBrush ); - } - hOldPen = SelectPen( getHDC(), hPen ); - - POINT* pWinPtAry; - // for NT, we can handover the array directly - DBG_ASSERT( sizeof( POINT ) == sizeof( SalPoint ), - "WinSalGraphics::DrawPolyLine(): POINT != SalPoint" ); - - pWinPtAry = (POINT*)pPtAry; - // for Windows 95 and its maximum number of points - if ( nSalFlags & SAL_INVERT_TRACKFRAME ) - { - if ( !Polyline( getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) ) - Polyline( getHDC(), pWinPtAry, MAX_64KSALPOINTS ); - } - else - { - if ( !WIN_Polygon( getHDC(), pWinPtAry, (int)nPoints ) && (nPoints > MAX_64KSALPOINTS) ) - WIN_Polygon( getHDC(), pWinPtAry, MAX_64KSALPOINTS ); - } - - SetROP2( getHDC(), nOldROP ); - SelectPen( getHDC(), hOldPen ); - - if ( nSalFlags & SAL_INVERT_TRACKFRAME ) - DeletePen( hPen ); - else - { - ::SetTextColor( getHDC(), nOldTextColor ); - SelectBrush( getHDC(), hOldBrush ); - } + mpImpl->invert( nPoints, pPtAry, nSalFlags ); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/source/gdi/salgdi_gdiplus.cxx b/vcl/win/source/gdi/salgdi_gdiplus.cxx index 1dc4f05a088a..65dbdd84acec 100644 --- a/vcl/win/source/gdi/salgdi_gdiplus.cxx +++ b/vcl/win/source/gdi/salgdi_gdiplus.cxx @@ -25,195 +25,11 @@ #include <win/salgdi.h> #include <win/salbmp.h> -#if defined _MSC_VER -#ifndef min -#define min(a,b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif -#endif - -#if defined _MSC_VER -#pragma warning(push, 1) -#endif - -#ifdef __MINGW32__ -#ifdef GetObject -#undef GetObject -#endif -#define GetObject GetObjectA -#endif - -#include <gdiplus.h> -#include <gdiplusenums.h> -#include <gdipluscolor.h> - -#ifdef __MINGW32__ -#ifdef GetObject -#undef GetObject -#endif -#endif - -#if defined _MSC_VER -#pragma warning(pop) -#endif - -#include <basegfx/polygon/b2dpolygon.hxx> - -void impAddB2DPolygonToGDIPlusGraphicsPathReal(Gdiplus::GpPath *pPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin) -{ - sal_uInt32 nCount(rPolygon.count()); - - if(nCount) - { - const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1); - const bool bControls(rPolygon.areControlPointsUsed()); - basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0)); - - for(sal_uInt32 a(0); a < nEdgeCount; a++) - { - const sal_uInt32 nNextIndex((a + 1) % nCount); - const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex)); - - if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex))) - { - const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a)); - const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex)); - - Gdiplus::DllExports::GdipAddPathBezier(pPath, - aCurr.getX(), aCurr.getY(), - aCa.getX(), aCa.getY(), - aCb.getX(), aCb.getY(), - aNext.getX(), aNext.getY()); - } - else - { - Gdiplus::DllExports::GdipAddPathLine(pPath, aCurr.getX(), aCurr.getY(), aNext.getX(), aNext.getY()); - } - - if(a + 1 < nEdgeCount) - { - aCurr = aNext; - - if(bNoLineJoin) - { - Gdiplus::DllExports::GdipStartPathFigure(pPath); - } - } - } - } -} - -void impAddB2DPolygonToGDIPlusGraphicsPathInteger(Gdiplus::GpPath *pPath, const basegfx::B2DPolygon& rPolygon, bool bNoLineJoin) -{ - sal_uInt32 nCount(rPolygon.count()); - - if(nCount) - { - const sal_uInt32 nEdgeCount(rPolygon.isClosed() ? nCount : nCount - 1); - const bool bControls(rPolygon.areControlPointsUsed()); - basegfx::B2DPoint aCurr(rPolygon.getB2DPoint(0)); - - for(sal_uInt32 a(0); a < nEdgeCount; a++) - { - const sal_uInt32 nNextIndex((a + 1) % nCount); - const basegfx::B2DPoint aNext(rPolygon.getB2DPoint(nNextIndex)); - - if(bControls && (rPolygon.isNextControlPointUsed(a) || rPolygon.isPrevControlPointUsed(nNextIndex))) - { - const basegfx::B2DPoint aCa(rPolygon.getNextControlPoint(a)); - const basegfx::B2DPoint aCb(rPolygon.getPrevControlPoint(nNextIndex)); - - Gdiplus::DllExports::GdipAddPathBezier( - pPath, - aCurr.getX(), aCurr.getY(), - aCa.getX(), aCa.getY(), - aCb.getX(), aCb.getY(), - aNext.getX(), aNext.getY()); - } - else - { - Gdiplus::DllExports::GdipAddPathLine(pPath, aCurr.getX(), aCurr.getY(), aNext.getX(), aNext.getY()); - } - - if(a + 1 < nEdgeCount) - { - aCurr = aNext; - - if(bNoLineJoin) - { - Gdiplus::DllExports::GdipStartPathFigure(pPath); - } - } - } - } -} +#include "gdiimpl.hxx" bool WinSalGraphics::drawPolyPolygon( const ::basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency) { - const sal_uInt32 nCount(rPolyPolygon.count()); - - if(mbBrush && nCount && (fTransparency >= 0.0 && fTransparency < 1.0)) - { - Gdiplus::GpGraphics *pGraphics = NULL; - Gdiplus::DllExports::GdipCreateFromHDC(getHDC(), &pGraphics); - const sal_uInt8 aTrans((sal_uInt8)255 - (sal_uInt8)basegfx::fround(fTransparency * 255.0)); - Gdiplus::Color aTestColor(aTrans, SALCOLOR_RED(maFillColor), SALCOLOR_GREEN(maFillColor), SALCOLOR_BLUE(maFillColor)); - Gdiplus::GpSolidFill *pTestBrush; - Gdiplus::DllExports::GdipCreateSolidFill(aTestColor.GetValue(), &pTestBrush); - Gdiplus::GpPath *pPath = NULL; - Gdiplus::DllExports::GdipCreatePath(Gdiplus::FillModeAlternate, &pPath); - - for(sal_uInt32 a(0); a < nCount; a++) - { - if(0 != a) - { - Gdiplus::DllExports::GdipStartPathFigure(pPath); // #i101491# not needed for first run - } - - impAddB2DPolygonToGDIPlusGraphicsPathReal(pPath, rPolyPolygon.getB2DPolygon(a), false); - Gdiplus::DllExports::GdipClosePathFigure(pPath); - } - - if(getAntiAliasB2DDraw()) - { - Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics, Gdiplus::SmoothingModeAntiAlias); - } - else - { - Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics, Gdiplus::SmoothingModeNone); - } - - if(mbPrinter) - { - // #i121591# - // Normally GdiPlus should not be used for printing at all since printers cannot - // print transparent filled polygon geometry and normally this does not happen - // since OutputDevice::RemoveTransparenciesFromMetaFile is used as preparation - // and no transparent parts should remain for printing. But this can be overridden - // by the user and thus happens. This call can only come (currently) from - // OutputDevice::DrawTransparent, see comments there with the same TaskID. - // If it is used, the mapping for the printer is wrong and needs to be corrected. I - // checked that there is *no* transformation set and estimated that a stable factor - // dependent of the printer's DPI is used. Create and set a transformation here to - // correct this. - Gdiplus::REAL aDpiX; - Gdiplus::DllExports::GdipGetDpiX(pGraphics, &aDpiX); - Gdiplus::REAL aDpiY; - Gdiplus::DllExports::GdipGetDpiY(pGraphics, &aDpiY); - - Gdiplus::DllExports::GdipResetWorldTransform(pGraphics); - Gdiplus::DllExports::GdipScaleWorldTransform(pGraphics, Gdiplus::REAL(100.0) / aDpiX, Gdiplus::REAL(100.0) / aDpiY, Gdiplus::MatrixOrderAppend); - } - - Gdiplus::DllExports::GdipFillPath(pGraphics, pTestBrush, pPath); - - Gdiplus::DllExports::GdipDeletePath(pPath); - Gdiplus::DllExports::GdipDeleteGraphics(pGraphics); - } - - return true; + return mpImpl->drawPolyPolygon( rPolyPolygon, fTransparency ); } bool WinSalGraphics::drawPolyLine( @@ -223,199 +39,8 @@ bool WinSalGraphics::drawPolyLine( basegfx::B2DLineJoin eLineJoin, com::sun::star::drawing::LineCap eLineCap) { - const sal_uInt32 nCount(rPolygon.count()); - - if(mbPen && nCount) - { - Gdiplus::GpGraphics *pGraphics = NULL; - Gdiplus::DllExports::GdipCreateFromHDC(getHDC(), &pGraphics); - const sal_uInt8 aTrans = (sal_uInt8)basegfx::fround( 255 * (1.0 - fTransparency) ); - Gdiplus::Color aTestColor(aTrans, SALCOLOR_RED(maLineColor), SALCOLOR_GREEN(maLineColor), SALCOLOR_BLUE(maLineColor)); - Gdiplus::GpPen *pTestPen = NULL; - Gdiplus::DllExports::GdipCreatePen1(aTestColor.GetValue(), Gdiplus::REAL(rLineWidths.getX()), Gdiplus::UnitWorld, &pTestPen); - Gdiplus::GpPath *pPath; - Gdiplus::DllExports::GdipCreatePath(Gdiplus::FillModeAlternate, &pPath); - bool bNoLineJoin(false); - - switch(eLineJoin) - { - default : // basegfx::B2DLINEJOIN_NONE : - { - if(basegfx::fTools::more(rLineWidths.getX(), 0.0)) - { - bNoLineJoin = true; - } - break; - } - case basegfx::B2DLINEJOIN_BEVEL : - { - Gdiplus::DllExports::GdipSetPenLineJoin(pTestPen, Gdiplus::LineJoinBevel); - break; - } - case basegfx::B2DLINEJOIN_MIDDLE : - case basegfx::B2DLINEJOIN_MITER : - { - const Gdiplus::REAL aMiterLimit(15.0); - Gdiplus::DllExports::GdipSetPenMiterLimit(pTestPen, aMiterLimit); - Gdiplus::DllExports::GdipSetPenLineJoin(pTestPen, Gdiplus::LineJoinMiter); - break; - } - case basegfx::B2DLINEJOIN_ROUND : - { - Gdiplus::DllExports::GdipSetPenLineJoin(pTestPen, Gdiplus::LineJoinRound); - break; - } - } - - switch(eLineCap) - { - default: /*com::sun::star::drawing::LineCap_BUTT*/ - { - // nothing to do - break; - } - case com::sun::star::drawing::LineCap_ROUND: - { - Gdiplus::DllExports::GdipSetPenStartCap(pTestPen, Gdiplus::LineCapRound); - Gdiplus::DllExports::GdipSetPenEndCap(pTestPen, Gdiplus::LineCapRound); - break; - } - case com::sun::star::drawing::LineCap_SQUARE: - { - Gdiplus::DllExports::GdipSetPenStartCap(pTestPen, Gdiplus::LineCapSquare); - Gdiplus::DllExports::GdipSetPenEndCap(pTestPen, Gdiplus::LineCapSquare); - break; - } - } - - if(nCount > 250 && basegfx::fTools::more(rLineWidths.getX(), 1.5)) - { - impAddB2DPolygonToGDIPlusGraphicsPathInteger(pPath, rPolygon, bNoLineJoin); - } - else - { - impAddB2DPolygonToGDIPlusGraphicsPathReal(pPath, rPolygon, bNoLineJoin); - } - - if(rPolygon.isClosed() && !bNoLineJoin) - { - // #i101491# needed to create the correct line joins - Gdiplus::DllExports::GdipClosePathFigure(pPath); - } - - if(getAntiAliasB2DDraw()) - { - Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics, Gdiplus::SmoothingModeAntiAlias); - } - else - { - Gdiplus::DllExports::GdipSetSmoothingMode(pGraphics, Gdiplus::SmoothingModeNone); - } - - Gdiplus::DllExports::GdipDrawPath(pGraphics, pTestPen, pPath); - - Gdiplus::DllExports::GdipDeletePath(pPath); - Gdiplus::DllExports::GdipDeletePen(pTestPen); - Gdiplus::DllExports::GdipDeleteGraphics(pGraphics); - } - - return true; -} - -void paintToGdiPlus( - Gdiplus::Graphics& rGraphics, - const SalTwoRect& rTR, - Gdiplus::Bitmap& rBitmap) -{ - // only parts of source are used - Gdiplus::PointF aDestPoints[3]; - Gdiplus::ImageAttributes aAttributes; - - // define target region as paralellogram - aDestPoints[0].X = Gdiplus::REAL(rTR.mnDestX); - aDestPoints[0].Y = Gdiplus::REAL(rTR.mnDestY); - aDestPoints[1].X = Gdiplus::REAL(rTR.mnDestX + rTR.mnDestWidth); - aDestPoints[1].Y = Gdiplus::REAL(rTR.mnDestY); - aDestPoints[2].X = Gdiplus::REAL(rTR.mnDestX); - aDestPoints[2].Y = Gdiplus::REAL(rTR.mnDestY + rTR.mnDestHeight); - - aAttributes.SetWrapMode(Gdiplus::WrapModeTileFlipXY); - - rGraphics.DrawImage( - &rBitmap, - aDestPoints, - 3, - Gdiplus::REAL(rTR.mnSrcX), - Gdiplus::REAL(rTR.mnSrcY), - Gdiplus::REAL(rTR.mnSrcWidth), - Gdiplus::REAL(rTR.mnSrcHeight), - Gdiplus::UnitPixel, - &aAttributes, - 0, - 0); -} - -void setInterpolationMode( - Gdiplus::Graphics& rGraphics, - const long& rSrcWidth, - const long& rDestWidth, - const long& rSrcHeight, - const long& rDestHeight) -{ - const bool bSameWidth(rSrcWidth == rDestWidth); - const bool bSameHeight(rSrcHeight == rDestHeight); - - if(bSameWidth && bSameHeight) - { -#ifdef __MINGW32__ - //Gdiplus::InterpolationModeInvalid is missing on mingw - rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeDefault); -#else - rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeInvalid); -#endif - } - else if(rDestWidth > rSrcWidth && rDestHeight > rSrcHeight) - { - rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeDefault); - } - else if(rDestWidth < rSrcWidth && rDestHeight < rSrcHeight) - { - rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeBicubic); - } - else - { - rGraphics.SetInterpolationMode(Gdiplus::InterpolationModeDefault); - } -} - -bool WinSalGraphics::tryDrawBitmapGdiPlus(const SalTwoRect& rTR, const SalBitmap& rSrcBitmap) -{ - if(rTR.mnSrcWidth && rTR.mnSrcHeight && rTR.mnDestWidth && rTR.mnDestHeight) - { - const WinSalBitmap& rSalBitmap = static_cast< const WinSalBitmap& >(rSrcBitmap); - GdiPlusBmpPtr aARGB(rSalBitmap.ImplGetGdiPlusBitmap()); - - if(aARGB.get()) - { - Gdiplus::Graphics aGraphics(getHDC()); - - setInterpolationMode( - aGraphics, - rTR.mnSrcWidth, - rTR.mnDestWidth, - rTR.mnSrcHeight, - rTR.mnDestHeight); - - paintToGdiPlus( - aGraphics, - rTR, - *aARGB.get()); - - return true; - } - } - - return false; + return mpImpl->drawPolyLine(rPolygon, fTransparency, rLineWidths, + eLineJoin, eLineCap); } bool WinSalGraphics::drawAlphaBitmap( @@ -423,33 +48,7 @@ bool WinSalGraphics::drawAlphaBitmap( const SalBitmap& rSrcBitmap, const SalBitmap& rAlphaBmp) { - if(rTR.mnSrcWidth && rTR.mnSrcHeight && rTR.mnDestWidth && rTR.mnDestHeight) - { - const WinSalBitmap& rSalBitmap = static_cast< const WinSalBitmap& >(rSrcBitmap); - const WinSalBitmap& rSalAlpha = static_cast< const WinSalBitmap& >(rAlphaBmp); - GdiPlusBmpPtr aARGB(rSalBitmap.ImplGetGdiPlusBitmap(&rSalAlpha)); - - if(aARGB.get()) - { - Gdiplus::Graphics aGraphics(getHDC()); - - setInterpolationMode( - aGraphics, - rTR.mnSrcWidth, - rTR.mnDestWidth, - rTR.mnSrcHeight, - rTR.mnDestHeight); - - paintToGdiPlus( - aGraphics, - rTR, - *aARGB.get()); - - return true; - } - } - - return false; + return mpImpl->drawAlphaBitmap(rTR, rSrcBitmap, rAlphaBmp); } bool WinSalGraphics::drawTransformedBitmap( @@ -459,62 +58,8 @@ bool WinSalGraphics::drawTransformedBitmap( const SalBitmap& rSourceBitmap, const SalBitmap* pAlphaBitmap) { - const WinSalBitmap& rSalBitmap = static_cast< const WinSalBitmap& >(rSourceBitmap); - const WinSalBitmap* pSalAlpha = static_cast< const WinSalBitmap* >(pAlphaBitmap); - GdiPlusBmpPtr aARGB(rSalBitmap.ImplGetGdiPlusBitmap(pSalAlpha)); - - if(aARGB.get()) - { - const long nSrcWidth(aARGB->GetWidth()); - const long nSrcHeight(aARGB->GetHeight()); - - if(nSrcWidth && nSrcHeight) - { - const long nDestWidth(basegfx::fround(basegfx::B2DVector(rX - rNull).getLength())); - const long nDestHeight(basegfx::fround(basegfx::B2DVector(rY - rNull).getLength())); - - if(nDestWidth && nDestHeight) - { - Gdiplus::Graphics aGraphics(getHDC()); - Gdiplus::PointF aDestPoints[3]; - Gdiplus::ImageAttributes aAttributes; - - setInterpolationMode( - aGraphics, - nSrcWidth, - nDestWidth, - nSrcHeight, - nDestHeight); - - // this mode is only capable of drawing the whole bitmap to a paralellogram - aDestPoints[0].X = Gdiplus::REAL(rNull.getX()); - aDestPoints[0].Y = Gdiplus::REAL(rNull.getY()); - aDestPoints[1].X = Gdiplus::REAL(rX.getX()); - aDestPoints[1].Y = Gdiplus::REAL(rX.getY()); - aDestPoints[2].X = Gdiplus::REAL(rY.getX()); - aDestPoints[2].Y = Gdiplus::REAL(rY.getY()); - - aAttributes.SetWrapMode(Gdiplus::WrapModeTileFlipXY); - - aGraphics.DrawImage( - aARGB.get(), - aDestPoints, - 3, - Gdiplus::REAL(0.0), - Gdiplus::REAL(0.0), - Gdiplus::REAL(nSrcWidth), - Gdiplus::REAL(nSrcHeight), - Gdiplus::UnitPixel, - &aAttributes, - 0, - 0); - } - } - - return true; - } - - return false; + return mpImpl->drawTransformedBitmap(rNull, rX, rY, + rSourceBitmap, pAlphaBitmap); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/source/gdi/salprn.cxx b/vcl/win/source/gdi/salprn.cxx index 6d6b8ea49f01..ad22b4e817a2 100644 --- a/vcl/win/source/gdi/salprn.cxx +++ b/vcl/win/source/gdi/salprn.cxx @@ -1045,15 +1045,10 @@ static HDC ImplCreateSalPrnIC( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetup static WinSalGraphics* ImplCreateSalPrnGraphics( HDC hDC ) { - WinSalGraphics* pGraphics = new WinSalGraphics; + WinSalGraphics* pGraphics = new WinSalGraphics(WinSalGraphics::PRINTER, false, 0); pGraphics->SetLayout( 0 ); pGraphics->setHDC(hDC); - pGraphics->mhWnd = 0; - pGraphics->mbPrinter = TRUE; - pGraphics->mbVirDev = FALSE; - pGraphics->mbWindow = FALSE; - pGraphics->mbScreen = FALSE; - ImplSalInitGraphics( pGraphics ); + pGraphics->InitGraphics(); return pGraphics; } @@ -1065,7 +1060,7 @@ static bool ImplUpdateSalPrnIC( WinSalInfoPrinter* pPrinter, ImplJobSetup* pSetu if ( pPrinter->mpGraphics ) { - ImplSalDeInitGraphics( pPrinter->mpGraphics ); + pPrinter->mpGraphics->DeInitGraphics(); DeleteDC( pPrinter->mpGraphics->getHDC() ); delete pPrinter->mpGraphics; } @@ -1129,7 +1124,7 @@ WinSalInfoPrinter::~WinSalInfoPrinter() { if ( mpGraphics ) { - ImplSalDeInitGraphics( mpGraphics ); + mpGraphics->DeInitGraphics(); DeleteDC( mpGraphics->getHDC() ); delete mpGraphics; } @@ -1412,7 +1407,7 @@ WinSalPrinter::~WinSalPrinter() { if ( mpGraphics ) { - ImplSalDeInitGraphics( mpGraphics ); + mpGraphics->DeInitGraphics(); delete mpGraphics; } @@ -1587,7 +1582,7 @@ bool WinSalPrinter::EndJob() { if ( mpGraphics ) { - ImplSalDeInitGraphics( mpGraphics ); + mpGraphics->DeInitGraphics(); delete mpGraphics; mpGraphics = NULL; } @@ -1650,7 +1645,7 @@ void ImplSalPrinterAbortJobAsync( HDC hPrnDC ) { if ( pPrinter->mpGraphics ) { - ImplSalDeInitGraphics( pPrinter->mpGraphics ); + pPrinter->mpGraphics->DeInitGraphics(); delete pPrinter->mpGraphics; pPrinter->mpGraphics = NULL; } @@ -1710,7 +1705,7 @@ bool WinSalPrinter::EndPage() HDC hDC = mhDC; if ( hDC && mpGraphics ) { - ImplSalDeInitGraphics( mpGraphics ); + mpGraphics->DeInitGraphics(); delete mpGraphics; mpGraphics = NULL; } diff --git a/vcl/win/source/gdi/salvd.cxx b/vcl/win/source/gdi/salvd.cxx index fec719b1aaa1..2269debcd1a8 100644 --- a/vcl/win/source/gdi/salvd.cxx +++ b/vcl/win/source/gdi/salvd.cxx @@ -104,20 +104,15 @@ SalVirtualDevice* WinSalInstance::CreateVirtualDevice( SalGraphics* pSGraphics, { WinSalVirtualDevice* pVDev = new WinSalVirtualDevice; SalData* pSalData = GetSalData(); - WinSalGraphics* pVirGraphics = new WinSalGraphics; + WinSalGraphics* pVirGraphics = new WinSalGraphics(WinSalGraphics::VIRTUAL_DEVICE, pGraphics->isScreen(), 0); pVirGraphics->SetLayout( 0 ); // by default no! mirroring for VirtualDevices, can be enabled with EnableRTL() pVirGraphics->setHDC(hDC); - pVirGraphics->mhWnd = 0; - pVirGraphics->mbPrinter = FALSE; - pVirGraphics->mbVirDev = TRUE; - pVirGraphics->mbWindow = FALSE; - pVirGraphics->mbScreen = pGraphics->mbScreen; - if ( pSalData->mhDitherPal && pVirGraphics->mbScreen ) + if ( pSalData->mhDitherPal && pVirGraphics->isScreen() ) { - pVirGraphics->mhDefPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE ); + pVirGraphics->setDefPal(SelectPalette( hDC, pSalData->mhDitherPal, TRUE )); RealizePalette( hDC ); } - ImplSalInitGraphics( pVirGraphics ); + pVirGraphics->InitGraphics(); pVDev->setHDC(hDC); pVDev->mhBmp = hBmp; @@ -168,9 +163,9 @@ WinSalVirtualDevice::~WinSalVirtualDevice() *ppVirDev = mpNext; // destroy saved DC - if( mpGraphics->mhDefPal ) - SelectPalette( mpGraphics->getHDC(), mpGraphics->mhDefPal, TRUE ); - ImplSalDeInitGraphics( mpGraphics ); + if( mpGraphics->getDefPal() ) + SelectPalette( mpGraphics->getHDC(), mpGraphics->getDefPal(), TRUE ); + mpGraphics->InitGraphics(); if( mhDefBmp ) SelectBitmap( mpGraphics->getHDC(), mhDefBmp ); if( !mbForeignDC ) diff --git a/vcl/win/source/window/salframe.cxx b/vcl/win/source/window/salframe.cxx index 2de8d5855a73..9dd008bb5261 100644 --- a/vcl/win/source/window/salframe.cxx +++ b/vcl/win/source/window/salframe.cxx @@ -932,9 +932,9 @@ WinSalFrame::~WinSalFrame() // destroy saved DC if ( mpGraphics ) { - if ( mpGraphics->mhDefPal ) - SelectPalette( mpGraphics->getHDC(), mpGraphics->mhDefPal, TRUE ); - ImplSalDeInitGraphics( mpGraphics ); + if ( mpGraphics->getDefPal() ) + SelectPalette( mpGraphics->getHDC(), mpGraphics->getDefPal(), TRUE ); + mpGraphics->DeInitGraphics(); ReleaseDC( mhWnd, mpGraphics->getHDC() ); delete mpGraphics; mpGraphics = NULL; @@ -983,13 +983,8 @@ SalGraphics* WinSalFrame::AcquireGraphics() if ( !mpGraphics2 ) { - mpGraphics2 = new WinSalGraphics; + mpGraphics2 = new WinSalGraphics(WinSalGraphics::WINDOW, true, mhWnd); mpGraphics2->setHDC(0); - mpGraphics2->mhWnd = mhWnd; - mpGraphics2->mbPrinter = FALSE; - mpGraphics2->mbVirDev = FALSE; - mpGraphics2->mbWindow = TRUE; - mpGraphics2->mbScreen = TRUE; } HDC hDC = (HDC)(sal_IntPtr)SendMessageW( pSalData->mpFirstInstance->mhComWnd, @@ -1000,10 +995,10 @@ SalGraphics* WinSalFrame::AcquireGraphics() mpGraphics2->setHDC(hDC); if ( pSalData->mhDitherPal ) { - mpGraphics2->mhDefPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE ); + mpGraphics2->setDefPal(SelectPalette( hDC, pSalData->mhDitherPal, TRUE )); RealizePalette( hDC ); } - ImplSalInitGraphics( mpGraphics2 ); + mpGraphics2->InitGraphics(); mbGraphics = TRUE; pSalData->mnCacheDCInUse++; @@ -1019,19 +1014,14 @@ SalGraphics* WinSalFrame::AcquireGraphics() HDC hDC = GetDC( mhWnd ); if ( hDC ) { - mpGraphics = new WinSalGraphics; + mpGraphics = new WinSalGraphics(WinSalGraphics::WINDOW, true, mhWnd); mpGraphics->setHDC(hDC); - mpGraphics->mhWnd = mhWnd; - mpGraphics->mbPrinter = FALSE; - mpGraphics->mbVirDev = FALSE; - mpGraphics->mbWindow = TRUE; - mpGraphics->mbScreen = TRUE; if ( pSalData->mhDitherPal ) { - mpGraphics->mhDefPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE ); + mpGraphics->setDefPal(SelectPalette( hDC, pSalData->mhDitherPal, TRUE )); RealizePalette( hDC ); } - ImplSalInitGraphics( mpGraphics ); + mpGraphics->InitGraphics(); mbGraphics = TRUE; } } @@ -1049,9 +1039,9 @@ void WinSalFrame::ReleaseGraphics( SalGraphics* pGraphics ) if ( mpGraphics2->getHDC() ) { SalData* pSalData = GetSalData(); - if ( mpGraphics2->mhDefPal ) - SelectPalette( mpGraphics2->getHDC(), mpGraphics2->mhDefPal, TRUE ); - ImplSalDeInitGraphics( mpGraphics2 ); + if ( mpGraphics2->getDefPal() ) + SelectPalette( mpGraphics2->getHDC(), mpGraphics2->getDefPal(), TRUE ); + mpGraphics2->InitGraphics(); SendMessageW( pSalData->mpFirstInstance->mhComWnd, SAL_MSG_RELEASEDC, (WPARAM)mhWnd, @@ -1499,9 +1489,9 @@ static void ImplSetParentFrame( WinSalFrame* pThis, HWND hNewParentWnd, bool bAs // destroy saved DC if ( pThis->mpGraphics ) { - if ( pThis->mpGraphics->mhDefPal ) - SelectPalette( pThis->mpGraphics->getHDC(), pThis->mpGraphics->mhDefPal, TRUE ); - ImplSalDeInitGraphics( pThis->mpGraphics ); + if ( pThis->mpGraphics->getDefPal() ) + SelectPalette( pThis->mpGraphics->getHDC(), pThis->mpGraphics->getDefPal(), TRUE ); + pThis->mpGraphics->InitGraphics(); ReleaseDC( pThis->mhWnd, pThis->mpGraphics->getHDC() ); } @@ -1520,7 +1510,7 @@ static void ImplSetParentFrame( WinSalFrame* pThis, HWND hNewParentWnd, bool bAs { if( pThis->mpGraphics2 ) { - pThis->mpGraphics2->mhWnd = hWnd; + pThis->mpGraphics2->setHWND(hWnd); if( bNeedCacheDC ) { @@ -1533,10 +1523,10 @@ static void ImplSetParentFrame( WinSalFrame* pThis, HWND hNewParentWnd, bool bAs pThis->mpGraphics2->setHDC(hDC); if ( pSalData->mhDitherPal ) { - pThis->mpGraphics2->mhDefPal = SelectPalette( hDC, pSalData->mhDitherPal, TRUE ); + pThis->mpGraphics2->setDefPal(SelectPalette( hDC, pSalData->mhDitherPal, TRUE )); RealizePalette( hDC ); } - ImplSalInitGraphics( pThis->mpGraphics2 ); + pThis->mpGraphics2->InitGraphics(); // re-select saved gdi objects if( hFont ) @@ -1558,14 +1548,14 @@ static void ImplSetParentFrame( WinSalFrame* pThis, HWND hNewParentWnd, bool bAs if( pThis->mpGraphics ) { // re-create DC - pThis->mpGraphics->mhWnd = hWnd; + pThis->mpGraphics->setHWND(hWnd); pThis->mpGraphics->setHDC( GetDC( hWnd ) ); if ( GetSalData()->mhDitherPal ) { - pThis->mpGraphics->mhDefPal = SelectPalette( pThis->mpGraphics->getHDC(), GetSalData()->mhDitherPal, TRUE ); + pThis->mpGraphics->setDefPal(SelectPalette( pThis->mpGraphics->getHDC(), GetSalData()->mhDitherPal, TRUE )); RealizePalette( pThis->mpGraphics->getHDC() ); } - ImplSalInitGraphics( pThis->mpGraphics ); + pThis->mpGraphics->InitGraphics(); pThis->mbGraphics = TRUE; } } @@ -3763,7 +3753,7 @@ static bool ImplHandlePaintMsg( HWND hWnd ) { // clip-region must be reset, as we do not get a proper // bounding-rectangle otherwise - if ( pFrame->mpGraphics && pFrame->mpGraphics->mhRegion ) + if ( pFrame->mpGraphics && pFrame->mpGraphics->getRegion() ) SelectClipRgn( pFrame->mpGraphics->getHDC(), 0 ); // according to Window-Documentation one shall check first if @@ -3779,10 +3769,10 @@ static bool ImplHandlePaintMsg( HWND hWnd ) // Paint // reset ClipRegion - if ( pFrame->mpGraphics && pFrame->mpGraphics->mhRegion ) + if ( pFrame->mpGraphics && pFrame->mpGraphics->getRegion() ) { SelectClipRgn( pFrame->mpGraphics->getHDC(), - pFrame->mpGraphics->mhRegion ); + pFrame->mpGraphics->getRegion() ); } if ( bMutex ) @@ -3801,10 +3791,10 @@ static bool ImplHandlePaintMsg( HWND hWnd ) else { // reset ClipRegion - if ( pFrame->mpGraphics && pFrame->mpGraphics->mhRegion ) + if ( pFrame->mpGraphics && pFrame->mpGraphics->getRegion() ) { SelectClipRgn( pFrame->mpGraphics->getHDC(), - pFrame->mpGraphics->mhRegion ); + pFrame->mpGraphics->getRegion() ); } } } @@ -4157,7 +4147,7 @@ static void ImplHandleForcePalette( HWND hWnd ) if ( pFrame && pFrame->mpGraphics ) { WinSalGraphics* pGraphics = pFrame->mpGraphics; - if ( pGraphics && pGraphics->mhDefPal ) + if ( pGraphics && pGraphics->getDefPal() ) { SelectPalette( pGraphics->getHDC(), hPal, FALSE ); if ( RealizePalette( pGraphics->getHDC() ) ) @@ -4220,10 +4210,10 @@ static LRESULT ImplHandlePalette( bool bFrame, HWND hWnd, UINT nMsg, while ( pTempVD ) { pGraphics = pTempVD->mpGraphics; - if ( pGraphics->mhDefPal ) + if ( pGraphics->getDefPal() ) { SelectPalette( pGraphics->getHDC(), - pGraphics->mhDefPal, + pGraphics->getDefPal(), TRUE ); } pTempVD = pTempVD->mpNext; @@ -4232,10 +4222,10 @@ static LRESULT ImplHandlePalette( bool bFrame, HWND hWnd, UINT nMsg, while ( pTempFrame ) { pGraphics = pTempFrame->mpGraphics; - if ( pGraphics && pGraphics->mhDefPal ) + if ( pGraphics && pGraphics->getDefPal() ) { SelectPalette( pGraphics->getHDC(), - pGraphics->mhDefPal, + pGraphics->getDefPal(), TRUE ); } pTempFrame = pTempFrame->mpNextFrame; @@ -4270,7 +4260,7 @@ static LRESULT ImplHandlePalette( bool bFrame, HWND hWnd, UINT nMsg, while ( pTempVD ) { pGraphics = pTempVD->mpGraphics; - if ( pGraphics->mhDefPal ) + if ( pGraphics->getDefPal() ) { SelectPalette( pGraphics->getHDC(), hPal, TRUE ); RealizePalette( pGraphics->getHDC() ); @@ -4283,7 +4273,7 @@ static LRESULT ImplHandlePalette( bool bFrame, HWND hWnd, UINT nMsg, if ( pTempFrame != pFrame ) { pGraphics = pTempFrame->mpGraphics; - if ( pGraphics && pGraphics->mhDefPal ) + if ( pGraphics && pGraphics->getDefPal() ) { SelectPalette( pGraphics->getHDC(), hPal, TRUE ); if ( RealizePalette( pGraphics->getHDC() ) ) @@ -4300,7 +4290,7 @@ static LRESULT ImplHandlePalette( bool bFrame, HWND hWnd, UINT nMsg, while ( pTempFrame ) { pGraphics = pTempFrame->mpGraphics; - if ( pGraphics && pGraphics->mhDefPal ) + if ( pGraphics && pGraphics->getDefPal() ) { InvalidateRect( pTempFrame->mhWnd, NULL, FALSE ); UpdateWindow( pTempFrame->mhWnd ); diff --git a/vcl/workben/icontest.cxx b/vcl/workben/icontest.cxx index 543d1c7fad91..39c36865f13c 100644 --- a/vcl/workben/icontest.cxx +++ b/vcl/workben/icontest.cxx @@ -81,21 +81,6 @@ public: virtual void Resize() SAL_OVERRIDE; }; -class MyOpenGLWorkWindow : public MyWorkWindow -{ -public: - bool mbHaveTexture; - OpenGLWindow *mpOpenGLWindow; - GLuint mnTextureName; - float mnTextureAspect; - - void LoadTexture(); - - MyOpenGLWorkWindow( vcl::Window* pParent, WinBits nWinStyle ); - - virtual void Paint( const Rectangle& rRect ) SAL_OVERRIDE; -}; - MyWorkWindow::MyWorkWindow( vcl::Window* pParent, WinBits nWinStyle ) : WorkWindow(pParent, nWinStyle) , mpBitmap(NULL) @@ -146,165 +131,6 @@ void MyWorkWindow::Paint( const Rectangle& rRect ) Invalidate( INVALIDATE_CHILDREN ); } -MyOpenGLWorkWindow::MyOpenGLWorkWindow( vcl::Window* pParent, WinBits nWinStyle ) - : MyWorkWindow(pParent, nWinStyle) - , mnTextureName(0) - , mnTextureAspect(0) -{ - mbHaveTexture = false; - mpOpenGLWindow = new OpenGLWindow( this ); - mpOpenGLWindow->SetSizePixel( Size( WIDTH, HEIGHT ) ); - mpOpenGLWindow->Show(); - mpOpenGLWindow->EnableInput(); -} - -void MyOpenGLWorkWindow::LoadTexture() -{ - mbHaveTexture = true; - - glEnable(GL_TEXTURE_2D); - CHECK_GL_ERROR(); - - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - CHECK_GL_ERROR(); - - glGenTextures( 1, &mnTextureName ); - CHECK_GL_ERROR(); - - glBindTexture(GL_TEXTURE_2D, mnTextureName); - CHECK_GL_ERROR(); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - CHECK_GL_ERROR(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - CHECK_GL_ERROR(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - CHECK_GL_ERROR(); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - CHECK_GL_ERROR(); - - BitmapEx aBitmap( maGraphic.GetBitmapEx( ) ); - Size aBitmapSize( aBitmap.GetSizePixel() ); - - GLint maxTexSize; - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTexSize); - CHECK_GL_ERROR(); - - SAL_INFO("vcl.icontest", "GL_MAX_TEXTURE_SIZE: " << maxTexSize); - - if (aBitmapSize.Width() > maxTexSize || aBitmapSize.Height() > maxTexSize) - { - Size aNewSize(aBitmapSize); - if (aNewSize.Width() > maxTexSize) - { - aNewSize.setHeight(aNewSize.Height() * (((float) maxTexSize) / aNewSize.Width())); - aNewSize.setWidth(maxTexSize); - } - if (aNewSize.Height() > maxTexSize) - { - aNewSize.setWidth(aNewSize.Width() * (((float) maxTexSize) / aNewSize.Height())); - aNewSize.setHeight(maxTexSize); - } - SAL_INFO("vcl.icontest", "Scaling to " << aNewSize); - aBitmap.Scale(aNewSize, BMP_SCALE_SUPER); - aBitmapSize = aNewSize; - } - - SAL_INFO("vcl.icontest", "GLEW_ARB_texture_non_power_of_two: " << (GLEW_ARB_texture_non_power_of_two ? "YES" : "NO")); - - GLsizei texWidth(aBitmapSize.Width()), texHeight(aBitmapSize.Height()); - - mnTextureAspect = ((float) aBitmapSize.Width()) / aBitmapSize.Height(); - - if (!GLEW_ARB_texture_non_power_of_two) - { - texWidth = texHeight = std::max(aBitmapSize.Width(), aBitmapSize.Height()); - if (!glm::isPowerOfTwo(texWidth)) - { - texWidth = glm::powerOfTwoAbove(texWidth); - texHeight = texWidth; - } - - aBitmap.Expand(texWidth - aBitmapSize.Width(), texHeight - aBitmapSize.Height()); - - mnTextureAspect = 1; - } - - SAL_INFO("vcl.icontest", "Texture size: " << texWidth << "x" << texHeight); - - GLubyte *buffer = new GLubyte[texWidth * texHeight * 4]; - OpenGLHelper::ConvertBitmapExToRGBATextureBuffer( aBitmap, buffer, true ); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, - texWidth, texHeight, - 0, GL_RGBA, GL_UNSIGNED_BYTE, - buffer); - CHECK_GL_ERROR(); - - delete[] buffer; -} - -void MyOpenGLWorkWindow::Paint( const Rectangle& ) -{ - std::cout << "==> Paint! "<< mnPaintCount++ << " (OpenGL) " << GetSizePixel() << " " << getTimeNow() - mnStartTime << std::endl; - OpenGLContext& aCtx = mpOpenGLWindow->getContext(); - aCtx.requestLegacyContext(); - CHECK_GL_ERROR(); - - if (!mbHaveTexture) - LoadTexture(); - - aCtx.setWinSize( Size( WIDTH+1, HEIGHT+1 ) ); - CHECK_GL_ERROR(); - - aCtx.makeCurrent(); - CHECK_GL_ERROR(); - - glViewport( 0, 0, WIDTH, HEIGHT ); - CHECK_GL_ERROR(); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - CHECK_GL_ERROR(); - - glBindTexture(GL_TEXTURE_2D, mnTextureName); - CHECK_GL_ERROR(); - - glPushMatrix(); - CHECK_GL_ERROR(); - - glTranslatef(-1, -1, 0); - glScalef(2, 2, 2); - - if (mnTextureAspect >= ((float) WIDTH) / HEIGHT) - glScalef(1, 1/mnTextureAspect, 1); - else - glScalef(1*mnTextureAspect, 1, 1); - CHECK_GL_ERROR(); - - glBegin(GL_QUADS); - glTexCoord2f(0, 0); - glVertex3f(0, 0, 0); - glTexCoord2f(0, 1); - glVertex3f(0, 1 + (0.1*sin(mnPaintCount/50.)), 0); - glTexCoord2f(1, 1); - glVertex3f(1 + (0.1*sin(mnPaintCount/60.)), 1 + (0.1*sin(mnPaintCount/50.)), 0); - glTexCoord2f(1, 0); - glVertex3f(1 + (0.1*sin(mnPaintCount/60.)), 0, 0); - glEnd(); - CHECK_GL_ERROR(); - - glPopMatrix(); - CHECK_GL_ERROR(); - - aCtx.swapBuffers(); - CHECK_GL_ERROR(); - - if (mnPaintCount == 100) - Application::Quit(); - - Invalidate( INVALIDATE_CHILDREN ); -} - void MyWorkWindow::Resize() { SAL_INFO("vcl.icontest", "Resize " << GetSizePixel()); @@ -345,18 +171,13 @@ void IconTestApp::Init() int IconTestApp::Main() { - if (GetCommandLineParamCount() != 2 || - (GetCommandLineParam(0) != "vcl" && - GetCommandLineParam(0) != "opengl")) + if (GetCommandLineParamCount() != 1) { - fprintf(stderr, "Usage: imagetest [vcl|opengl] image\n"); + fprintf(stderr, "Usage: imagetest <image>\n"); return EXIT_FAILURE; } - OUString sImageFile( GetCommandLineParam( 1 ) ); - if (GetCommandLineParam(0) == "vcl") - DoItWithVcl( sImageFile ); - else - DoItWithOpenGL( sImageFile ); + OUString sImageFile( GetCommandLineParam( 0 ) ); + DoItWithVcl( sImageFile ); return nRet; } @@ -391,37 +212,6 @@ void IconTestApp::DoItWithVcl( const OUString& sImageFile) } } -void IconTestApp::DoItWithOpenGL(const OUString& sImageFile) -{ - try - { - MyOpenGLWorkWindow *pWindow = new MyOpenGLWorkWindow( NULL, WB_APP | WB_STDWORK | WB_SIZEABLE | WB_CLOSEABLE | WB_CLIPCHILDREN ); - - pWindow->SetText(OUString("OpenGL Image Test")); - - pWindow->LoadGraphic( sImageFile ); - - Size aGraphicSize( pWindow->maGraphic.GetSizePixel() ); - float aspect = ((float) aGraphicSize.Width()) / aGraphicSize.Height(); - SAL_INFO("vcl.icontest", sImageFile << ": size: " << aGraphicSize << " aspect: " << aspect); - - pWindow->Hide(); - pWindow->Show(); - - Execute(); - } - catch (const uno::Exception &e) - { - fprintf(stderr, "fatal error: %s\n", OUStringToOString(e.Message, osl_getThreadTextEncoding()).getStr()); - nRet = EXIT_FAILURE; - } - catch (const std::exception &e) - { - fprintf(stderr, "fatal error: %s\n", e.what()); - nRet = EXIT_FAILURE; - } -} - void vclmain::createApplication() { static IconTestApp aApp; diff --git a/vcl/workben/outdevgrind.cxx b/vcl/workben/outdevgrind.cxx index 9b99ee3c1fa5..66763e0ad765 100644 --- a/vcl/workben/outdevgrind.cxx +++ b/vcl/workben/outdevgrind.cxx @@ -17,17 +17,16 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -// bootstrap stuff -#include <rtl/bootstrap.hxx> -#include <rtl/ustring.hxx> -#include <comphelper/processfactory.hxx> -#include <cppuhelper/servicefactory.hxx> +#include <sal/main.h> +#include <tools/extendapplicationenvironment.hxx> + #include <cppuhelper/bootstrap.hxx> +#include <comphelper/processfactory.hxx> #include <com/sun/star/lang/XMultiServiceFactory.hpp> -#include <com/sun/star/lang/XInitialization.hpp> -#include <com/sun/star/registry/XSimpleRegistry.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> #include <vcl/svapp.hxx> +#include <vcl/window.hxx> #include <vcl/dialog.hxx> #include <vcl/outdev.hxx> #include <vcl/virdev.hxx> @@ -41,13 +40,14 @@ #include <vcl/gradient.hxx> #include <vcl/lineinfo.hxx> +#include <rtl/bootstrap.hxx> + #include <osl/time.h> #include <boost/function.hpp> #include <boost/bind.hpp> #include <stdio.h> -#include <unistd.h> using namespace ::com::sun::star; @@ -110,6 +110,7 @@ void setupMethodStubs( functor_vector_type& res ) const OUString aString("This is a test"); const LineInfo aLineInfo(LINE_SOLID,5); +#ifdef FIXME_VDEV // unfortunately, VDevs have inaccessible copy constructors static VirtualDevice aVDev; static VirtualDevice aVDevBW(1); @@ -121,6 +122,18 @@ void setupMethodStubs( functor_vector_type& res ) const Bitmap aBitmap( aVDev.GetBitmap(aPt1,aVDevSize) ); const Bitmap aBitmapBW( aVDevBW.GetBitmap(aPt1,aVDevSize) ); const Bitmap aBitmapAlien( aVDevSize, 8 ); +#else + BitmapEx aIntro; + rtl::Bootstrap::set("BRAND_BASE_DIR", "."); + if (Application::LoadBrandBitmap ("intro", aIntro)) + Application::Abort( "Failed to load intro image, run inside program/" ); + + const Bitmap aBitmap( aIntro.GetBitmap() ); + Bitmap aBitmapBW( aBitmap ); + aBitmapBW.Filter( BMP_FILTER_EMBOSS_GREY ); + Bitmap aBitmapAlien( Size( 100, 100 ), 8 ); + aBitmapAlien.Erase( COL_RED ); +#endif const BitmapEx aBitmapEx( aBitmap, aBitmapBW ); const BitmapEx aBitmapExBW( aBitmapBW, aBitmapBW ); @@ -137,12 +150,14 @@ void setupMethodStubs( functor_vector_type& res ) aMtf.AddAction( new MetaFillColorAction(Color(COL_RED),true) ); aMtf.AddAction( new MetaRectAction(aRect) ); +#ifdef FIXME_NEEDS_LOVE add(res, "DrawTextArray", boost::bind( &OutputDevice::DrawTextArray, _1, aPt1, aString, (const sal_Int32*)0, (sal_uInt16)0, aString.getLength() )); +#endif /* void DrawPixel( const Point& rPt, const Color& rColor ); */ add(res, @@ -283,6 +298,7 @@ void setupMethodStubs( functor_vector_type& res ) aRect2.TopLeft(), aRect2.GetSize(), aRect.TopLeft(), aRect.GetSize())); +#ifdef FIXME_VDEV /* void DrawOutDev( const Point& rDestPt, const Size& rDestSize, const Point& rSrcPt, const Size& rSrcSize, const OutputDevice& rOutDev ); @@ -314,6 +330,7 @@ void setupMethodStubs( functor_vector_type& res ) aRect2.TopLeft(), aRect2.GetSize(), aRect.TopLeft(), aRect.GetSize(), boost::cref(aVDev) )); +#endif /* void CopyArea( const Point& rDestPt, const Point& rSrcPt, const Size& rSrcSize, @@ -326,6 +343,7 @@ void setupMethodStubs( functor_vector_type& res ) _1, aPt1,aPt3,aRect2.GetSize(),(sal_uInt16)0 )); +#ifdef NEEDS_QUALIY_PARAMTER /* void DrawBitmap( const Point& rDestPt, const Bitmap& rBitmap ); */ @@ -376,6 +394,7 @@ void setupMethodStubs( functor_vector_type& res ) _1, aPt1,aRect.GetSize(),aBitmap )); +#if 0 /* void DrawBitmap( const Point& rDestPt, const Size& rDestSize, const Point& rSrcPtPixel, const Size& rSrcSizePixel, const Bitmap& rBitmap ); @@ -391,6 +410,7 @@ void setupMethodStubs( functor_vector_type& res ) &OutputDevice::DrawBitmap), _1, aPt1,aRect.GetSize(),aPt3,aRect2.GetSize(),aBitmapAlien )); +#endif /* void DrawBitmap( const Point& rDestPt, const Size& rDestSize, const Point& rSrcPtPixel, const Size& rSrcSizePixel, @@ -687,6 +707,8 @@ void setupMethodStubs( functor_vector_type& res ) _1, aPt1,aRect.GetSize(),aImage,(sal_uInt16)0 )); +#endif // NEEDS_QUALITY_PARAMATER + /* void DrawGradient( const Rectangle& rRect, const Gradient& rGradient ); */ add(res, "DrawGradient", @@ -721,6 +743,7 @@ void setupMethodStubs( functor_vector_type& res ) _1, aRect2,aWallpaper )); +#ifdef FIXME_HAVE_WAVE_NORMAL /* void DrawWaveLine( const Point& rStartPos, const Point& rEndPos, sal_uInt16 nStyle ); */ add(res, "DrawWaveLine", @@ -728,6 +751,7 @@ void setupMethodStubs( functor_vector_type& res ) &OutputDevice::DrawWaveLine, _1, aPt1,aPt2,(sal_uInt16)WAVE_NORMAL )); +#endif /* void DrawGrid( const Rectangle& rRect, const Size& rDist, sal_uLong nFlags ); */ add(res, @@ -783,7 +807,7 @@ void grindFunc( OutputDevice& rTarget, iter->second(&rTarget); if( rTarget.GetOutDevType() == OUTDEV_WINDOW ) - static_cast<Window&>(rTarget).Sync(); + static_cast< vcl::Window & >( rTarget ).Sync(); fprintf( stdout, "Duration: %d ms (%d repetitions)\tOperation: %s\tSetup: %s\n", @@ -824,13 +848,13 @@ void outDevGrind( OutputDevice& rTarget, sal_Int32 nTurns=100 ) rTarget.SetLineColor( Color(COL_BLACK) ); rTarget.SetFillColor( Color(COL_GREEN) ); rTarget.SetRasterOp( ROP_OVERPAINT ); - rTarget.SetClipRegion( aClipRect ); + rTarget.SetClipRegion( vcl::Region( aClipRect ) ); grindFunc( rTarget, iter, nTurns, "with rect clip, w/o xor" ); rTarget.SetLineColor( Color(COL_BLACK) ); rTarget.SetFillColor( Color(COL_GREEN) ); rTarget.SetRasterOp( ROP_OVERPAINT ); - rTarget.SetClipRegion( aClipPoly ); + rTarget.SetClipRegion( vcl::Region( aClipPoly ) ); grindFunc( rTarget, iter, nTurns, "with complex clip, w/o xor" ); rTarget.SetLineColor( Color(COL_BLACK) ); @@ -842,13 +866,13 @@ void outDevGrind( OutputDevice& rTarget, sal_Int32 nTurns=100 ) rTarget.SetLineColor( Color(COL_BLACK) ); rTarget.SetFillColor( Color(COL_GREEN) ); rTarget.SetRasterOp( ROP_XOR ); - rTarget.SetClipRegion( aClipRect ); + rTarget.SetClipRegion( vcl::Region( aClipRect ) ); grindFunc( rTarget, iter, nTurns, "with rect clip, with xor" ); rTarget.SetLineColor( Color(COL_BLACK) ); rTarget.SetFillColor( Color(COL_GREEN) ); rTarget.SetRasterOp( ROP_XOR ); - rTarget.SetClipRegion( aClipPoly ); + rTarget.SetClipRegion( vcl::Region( aClipPoly ) ); grindFunc( rTarget, iter, nTurns, "with complex clip, with xor" ); ++iter; @@ -874,11 +898,21 @@ sal_uInt16 GrindApp::Exception( sal_uInt16 nError ) int GrindApp::Main() { + TestWindow aWindow; + aWindow.Execute(); + return 0; +} + +} // namespace + + +SAL_IMPLEMENT_MAIN() +{ bool bHelp = false; - for( sal_uInt16 i = 0; i < GetCommandLineParamCount(); i++ ) + for( sal_uInt16 i = 0; i < Application::GetCommandLineParamCount(); i++ ) { - OUString aParam = GetCommandLineParam( i ); + OUString aParam = Application::GetCommandLineParam( i ); if( aParam == "--help" || aParam == "-h" ) bHelp = true; @@ -890,35 +924,24 @@ int GrindApp::Main() return EXIT_SUCCESS; } - // create the global service-manager - uno::Reference< lang::XMultiServiceFactory > xFactory; - try - { - uno::Reference< uno::XComponentContext > xCtx = ::cppu::defaultBootstrap_InitialComponentContext(); - xFactory = uno::Reference< lang::XMultiServiceFactory >( xCtx->getServiceManager(), - uno::UNO_QUERY ); - if( xFactory.is() ) - ::comphelper::setProcessServiceFactory( xFactory ); - } - catch( uno::Exception& ) - { - } + tools::extendApplicationEnvironment(); - if( !xFactory.is() ) - { - fprintf( stderr, - "Could not bootstrap UNO, installation must be in disorder. Exiting.\n" ); - exit( 1 ); - } + uno::Reference< uno::XComponentContext > xContext = cppu::defaultBootstrap_InitialComponentContext(); + uno::Reference< lang::XMultiServiceFactory > xServiceManager( xContext->getServiceManager(), uno::UNO_QUERY ); - TestWindow pWindow; - pWindow.Execute(); + if( !xServiceManager.is() ) + Application::Abort( "Failed to bootstrap" ); - return EXIT_SUCCESS; -} + comphelper::setProcessServiceFactory( xServiceManager ); -} // namespace + InitVCL(); + + GrindApp aGrindApp; + aGrindApp.Main(); -GrindApp aGrindApp; + DeInitVCL(); + + return EXIT_SUCCESS; +} /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/workben/vcldemo.cxx b/vcl/workben/vcldemo.cxx index 7fe1b2d09fb7..daa877f95385 100644 --- a/vcl/workben/vcldemo.cxx +++ b/vcl/workben/vcldemo.cxx @@ -5,152 +5,362 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include <sal/main.h> -#include <tools/extendapplicationenvironment.hxx> - -#include <cppuhelper/bootstrap.hxx> +#include <rtl/bootstrap.hxx> #include <comphelper/processfactory.hxx> - +#include <cppuhelper/bootstrap.hxx> #include <com/sun/star/lang/XMultiServiceFactory.hpp> -#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/registry/XSimpleRegistry.hpp> +#include <com/sun/star/ucb/UniversalContentBroker.hpp> + +#include <vcl/vclmain.hxx> -#include <vcl/event.hxx> +#include <tools/urlobj.hxx> +#include <tools/stream.hxx> #include <vcl/svapp.hxx> +#include <vcl/pngread.hxx> #include <vcl/wrkwin.hxx> -#include <vcl/msgbox.hxx> +#include <vcl/virdev.hxx> +#include <vcl/graphicfilter.hxx> -#include <unistd.h> -#include <stdio.h> +# define FIXME_ALPHA_WORKING +# define FIXME_ROUNDED_RECT_WORKING +# define FIXME_DRAW_TRANSPARENT_WORKING +#if 0 +#endif -using namespace ::com::sun::star::uno; -using namespace ::com::sun::star::lang; -using namespace cppu; +using namespace css; -// Forward declaration -void Main(); +class DemoBase : + public WorkWindow // hide OutputDevice if necessary +{ +public: + DemoBase() : WorkWindow( NULL, WB_APP | WB_STDWORK) + { + } + OutputDevice &getOutDev() { return *this; } +}; -SAL_IMPLEMENT_MAIN() +class DemoWin : public DemoBase { - try + Bitmap maIntroBW; + BitmapEx maIntro; + +public: + DemoWin() : DemoBase() + { + // Needed to find images + OUString aPath; + rtl::Bootstrap::get("SYSBINDIR", aPath); +#ifdef FIXME_THIS_FAILS + rtl::Bootstrap::set("BRAND_BASE_DIR", aPath + "/.."); + if (Application::LoadBrandBitmap("intro", maIntro)) + Application::Abort("Failed to load intro image"); +#else + aPath = aPath + "/intro.png"; + SvFileStream aFileStream( aPath, STREAM_READ ); + GraphicFilter aGraphicFilter(false); + Graphic aGraphic; + if (aGraphicFilter.ImportGraphic(aGraphic, aPath, aFileStream) != 0) + Application::Abort("Failed to load intro image: " + aPath); + maIntro = aGraphic.GetBitmapEx(); +#endif + maIntroBW = maIntro.GetBitmap(); + maIntroBW.Filter( BMP_FILTER_EMBOSS_GREY ); + } + + void drawToDevice(OutputDevice &r, bool bVdev); + + virtual void Paint( const Rectangle& rRect ) SAL_OVERRIDE + { + fprintf(stderr, "DemoWin::Paint(%ld,%ld,%ld,%ld)\n", rRect.getX(), rRect.getY(), rRect.getWidth(), rRect.getHeight()); + drawToDevice(getOutDev(), false); + } + + std::vector<Rectangle> partitionAndClear(OutputDevice &rDev, + int nX, int nY); + + void drawBackground(OutputDevice &rDev) + { + Rectangle r(Point(0,0), rDev.GetOutputSizePixel()); + Gradient aGradient; + aGradient.SetStartColor(COL_BLUE); + aGradient.SetEndColor(COL_GREEN); + aGradient.SetStyle(GradientStyle_LINEAR); +// aGradient.SetBorder(r.GetSize().Width()/20); + rDev.DrawGradient(r, aGradient); + } + + void drawRadialLines(OutputDevice &rDev, Rectangle r) { - tools::extendApplicationEnvironment(); + rDev.SetFillColor(Color(COL_LIGHTRED)); + rDev.SetLineColor(Color(COL_BLACK)); + rDev.DrawRect( r ); - Reference< XComponentContext > xContext = defaultBootstrap_InitialComponentContext(); - Reference< XMultiServiceFactory > xServiceManager( xContext->getServiceManager(), UNO_QUERY ); + // FIXME: notice these appear reflected at the bottom not the top. + for(int i=0; i<r.GetHeight(); i+=15) + rDev.DrawLine( Point(r.Left(), r.Top()+i), Point(r.Right(), r.Bottom()-i) ); + for(int i=0; i<r.GetWidth(); i+=15) + rDev.DrawLine( Point(r.Left()+i, r.Bottom()), Point(r.Right()-i, r.Top()) ); - if( !xServiceManager.is() ) - Application::Abort( "Failed to bootstrap" ); + // Should draw a white-line across the middle + Color aLastPixel( COL_WHITE ); + Point aCenter((r.Left() + r.Right())/2 - 4, + (r.Top() + r.Bottom())/2 - 4); + for(int i=0; i<8; i++) + { + rDev.DrawPixel(aCenter, aLastPixel); + aLastPixel = rDev.GetPixel(aCenter); + aCenter.Move(1,1); + } + } - comphelper::setProcessServiceFactory( xServiceManager ); + void drawText(OutputDevice &rDev, Rectangle r) - InitVCL(); - ::Main(); - DeInitVCL(); + { + rDev.SetTextColor( Color( COL_BLACK ) ); + vcl::Font aFont( OUString( "Times" ), Size( 0, 25 ) ); + rDev.SetFont( aFont ); + rDev.DrawText( r, OUString( "Just a simple text" ) ); } - catch (const Exception& e) + + void drawPoly(OutputDevice &rDev, Rectangle r) + // pretty { - SAL_WARN("vcl.app", "Fatal exception: " << e.Message); - return 1; + drawCheckered(rDev, r); + + long nDx = r.GetWidth()/20; + long nDy = r.GetHeight()/20; + Rectangle aShrunk(r); + aShrunk.Move(nDx, nDy); + aShrunk.SetSize(Size(r.GetWidth()-nDx*2, + r.GetHeight()-nDy*2)); + Polygon aPoly(aShrunk); + tools::PolyPolygon aPPoly(aPoly); + rDev.SetLineColor(Color(COL_RED)); + rDev.SetFillColor(Color(COL_RED)); + // This hits the optional 'drawPolyPolygon' code-path + rDev.DrawTransparent(aPPoly, 64); } + void drawEllipse(OutputDevice &rDev, Rectangle r) - return 0; -} + { + rDev.SetLineColor(Color(COL_RED)); + rDev.SetFillColor(Color(COL_GREEN)); + rDev.DrawEllipse(r); + } + void drawCheckered(OutputDevice &rDev, Rectangle r) -class MyWin : public WorkWindow -{ -public: - MyWin( vcl::Window* pParent, WinBits nWinStyle ); - - virtual void MouseMove( const MouseEvent& rMEvt ) SAL_OVERRIDE; - virtual void MouseButtonDown( const MouseEvent& rMEvt ) SAL_OVERRIDE; - virtual void MouseButtonUp( const MouseEvent& rMEvt ) SAL_OVERRIDE; - virtual void KeyInput( const KeyEvent& rKEvt ) SAL_OVERRIDE; - virtual void KeyUp( const KeyEvent& rKEvt ) SAL_OVERRIDE; - virtual void Paint( const Rectangle& rRect ) SAL_OVERRIDE; - virtual void Resize() SAL_OVERRIDE; + { + rDev.DrawCheckered(r.TopLeft(), r.GetSize()); + } + void drawGradient(OutputDevice &rDev, Rectangle r) + + { + Gradient aGradient; + aGradient.SetStartColor(COL_YELLOW); + aGradient.SetEndColor(COL_RED); +// aGradient.SetAngle(45); + aGradient.SetStyle(GradientStyle_RECT); + aGradient.SetBorder(r.GetSize().Width()/20); + rDev.DrawGradient(r, aGradient); + } + void drawBitmap(OutputDevice &rDev, Rectangle r) + + { + Bitmap aBitmap(maIntroBW); + aBitmap.Scale(r.GetSize(), BMP_SCALE_BESTQUALITY); + rDev.DrawBitmap(r.TopLeft(), aBitmap); + } + void drawBitmapEx(OutputDevice &rDev, Rectangle r) + + { + drawCheckered(rDev, r); + + BitmapEx aBitmap(maIntro); + aBitmap.Scale(r.GetSize(), BMP_SCALE_BESTQUALITY); +#ifdef FIXME_ALPHA_WORKING + AlphaMask aSemiTransp(aBitmap.GetSizePixel()); + aSemiTransp.Erase(64); + rDev.DrawBitmapEx(r.TopLeft(), BitmapEx(aBitmap.GetBitmap(), + aSemiTransp)); +#else + rDev.DrawBitmapEx(r.TopLeft(), aBitmap); +#endif + } + void drawPolyPolgons(OutputDevice &rDev, Rectangle r) + + { + struct { + double nX, nY; + } aPoints[] = { { 0.1, 0.1 }, { 0.9, 0.9 }, + { 0.9, 0.1 }, { 0.1, 0.9 }, + { 0.1, 0.1 } }; + + tools::PolyPolygon aPolyPoly; + // Render 4x polygons & aggregate into another PolyPolygon + for (int x = 0; x < 2; x++) + { + for (int y = 0; y < 2; y++) + { + Rectangle aSubRect(r); + aSubRect.Move(x * r.GetWidth()/3, y * r.GetHeight()/3); + aSubRect.SetSize(Size(r.GetWidth()/2, r.GetHeight()/4)); + Polygon aPoly(SAL_N_ELEMENTS(aPoints)); + for (size_t v = 0; v < SAL_N_ELEMENTS(aPoints); v++) + { + aPoly.SetPoint(Point(aSubRect.Left() + + aSubRect.GetWidth() * aPoints[v].nX, + aSubRect.Top() + + aSubRect.GetHeight() * aPoints[v].nY), + v); + } + rDev.SetLineColor(Color(COL_YELLOW)); + rDev.SetFillColor(Color(COL_BLACK)); + rDev.DrawPolygon(aPoly); + + // now move and add to the polypolygon + aPoly.Move(0, r.GetHeight()/2); + aPolyPoly.Insert(aPoly); + } + } + rDev.SetLineColor(Color(COL_LIGHTRED)); + rDev.SetFillColor(Color(COL_GREEN)); +#ifdef FIXME_DRAW_TRANSPARENT_WORKING + rDev.DrawTransparent(aPolyPoly, 50); +#else + rDev.DrawPolyPolygon(aPolyPoly); +#endif + } + void drawToVirtualDevice(OutputDevice &rDev, Rectangle r) + { + VirtualDevice aNested; + aNested.SetOutputSize(r.GetSize()); + Rectangle aWhole(Point(0,0), r.GetSize()); + // mini me + drawToDevice(aNested, true); + + Bitmap aBitmap(aNested.GetBitmap(Point(0,0),aWhole.GetSize())); + rDev.DrawBitmap(r.TopLeft(), aBitmap); + } + + void fetchDrawBitmap(OutputDevice &rDev, Rectangle r) + { + // FIXME: should work ... + Bitmap aBitmap(GetBitmap(Point(0,0),rDev.GetOutputSizePixel())); + aBitmap.Scale(r.GetSize(), BMP_SCALE_BESTQUALITY); + rDev.DrawBitmap(r.TopLeft(), aBitmap); + } }; -void Main() +std::vector<Rectangle> DemoWin::partitionAndClear(OutputDevice &rDev, int nX, int nY) { - MyWin aMainWin( NULL, WB_APP | WB_STDWORK ); - aMainWin.SetText( OUString( "VCLDemo - VCL Workbench" ) ); - aMainWin.Show(); + Rectangle r; + std::vector<Rectangle> aRegions; - Application::Execute(); -} + // Make small cleared area for these guys + Size aSize(rDev.GetOutputSizePixel()); + long nBorderSize = aSize.Width() / 32; + long nBoxWidth = (aSize.Width() - nBorderSize*(nX+1)) / nX; + long nBoxHeight = (aSize.Height() - nBorderSize*(nY+1)) / nY; + for (int y = 0; y < nY; y++ ) + { + for (int x = 0; x < nX; x++ ) + { + r.SetPos(Point(nBorderSize + (nBorderSize + nBoxWidth) * x, + nBorderSize + (nBorderSize + nBoxHeight) * y)); + r.SetSize(Size(nBoxWidth, nBoxHeight)); -MyWin::MyWin( vcl::Window* pParent, WinBits nWinStyle ) : - WorkWindow( pParent, nWinStyle ) -{ -} + // knock up a nice little border + rDev.SetLineColor(COL_GRAY); + rDev.SetFillColor(COL_LIGHTGRAY); + if ((x + y) % 2) + rDev.DrawRect(r); + else + { +#ifdef FIXME_ROUNDED_RECT_WORKING + rDev.DrawRect(r, nBorderSize, nBorderSize); +#else + rDev.DrawRect(r); +#endif + } -void MyWin::MouseMove( const MouseEvent& rMEvt ) -{ - WorkWindow::MouseMove( rMEvt ); -} + aRegions.push_back(r); + } + } -void MyWin::MouseButtonDown( const MouseEvent& rMEvt ) -{ - Rectangle aRect(0,0,4,4); - aRect.SetPos( rMEvt.GetPosPixel() ); - SetFillColor(Color(COL_RED)); - DrawRect( aRect ); + return aRegions; } -void MyWin::MouseButtonUp( const MouseEvent& rMEvt ) +void DemoWin::drawToDevice(OutputDevice &rDev, bool bVdev) { - WorkWindow::MouseButtonUp( rMEvt ); -} + drawBackground(rDev); -void MyWin::KeyInput( const KeyEvent& rKEvt ) -{ - WorkWindow::KeyInput( rKEvt ); -} + std::vector<Rectangle> aRegions(partitionAndClear(rDev, 4, 3)); -void MyWin::KeyUp( const KeyEvent& rKEvt ) -{ - WorkWindow::KeyUp( rKEvt ); + drawRadialLines(rDev, aRegions[0]); + drawText(rDev, aRegions[1]); + drawPoly(rDev, aRegions[2]); + drawEllipse(rDev, aRegions[3]); + drawCheckered(rDev, aRegions[4]); + drawBitmapEx(rDev, aRegions[5]); + drawBitmap(rDev, aRegions[6]); + drawGradient(rDev, aRegions[7]); + drawPolyPolgons(rDev, aRegions[8]); + if (!bVdev) + drawToVirtualDevice(rDev, aRegions[9]); + // last - thumbnail all the above + fetchDrawBitmap(rDev, aRegions[10]); } -void MyWin::Paint( const Rectangle& rRect ) +class DemoApp : public Application { - fprintf(stderr, "MyWin::Paint(%ld,%ld,%ld,%ld)\n", rRect.getX(), rRect.getY(), rRect.getWidth(), rRect.getHeight()); - - Size aSz(GetSizePixel()); - Point aPt; - Rectangle r(aPt, aSz); - - SetFillColor(Color(COL_BLUE)); - SetLineColor(Color(COL_YELLOW)); +public: + DemoApp() {} - DrawRect( r ); + virtual int Main() SAL_OVERRIDE + { + DemoWin aMainWin; + aMainWin.SetText( "Interactive VCL demo" ); + aMainWin.Show(); + Application::Execute(); + return 0; + } - for(int i=0; i<aSz.Height(); i+=15) - DrawLine( Point(r.Left(), r.Top()+i), Point(r.Right(), r.Bottom()-i) ); - for(int i=0; i<aSz.Width(); i+=15) - DrawLine( Point(r.Left()+i, r.Bottom()), Point(r.Right()-i, r.Top()) ); +protected: + uno::Reference<lang::XMultiServiceFactory> xMSF; + void Init() SAL_OVERRIDE + { + try + { + uno::Reference<uno::XComponentContext> xComponentContext + = ::cppu::defaultBootstrap_InitialComponentContext(); + xMSF = uno::Reference<lang::XMultiServiceFactory> + ( xComponentContext->getServiceManager(), uno::UNO_QUERY ); + if( !xMSF.is() ) + Application::Abort("Bootstrap failure - no service manager"); - SetTextColor( Color( COL_WHITE ) ); - vcl::Font aFont( OUString( "Times" ), Size( 0, 25 ) ); - SetFont( aFont ); - DrawText( Point( 20, 30 ), OUString( "Just a simple test text" ) ); -} + ::comphelper::setProcessServiceFactory( xMSF ); + } + catch (const uno::Exception &e) + { + Application::Abort("Bootstrap exception " + e.Message); + } + } + void DeInit() SAL_OVERRIDE + { + uno::Reference< lang::XComponent >( + comphelper::getProcessComponentContext(), + uno::UNO_QUERY_THROW )-> dispose(); + ::comphelper::setProcessServiceFactory( NULL ); + } +}; -void MyWin::Resize() +void vclmain::createApplication() { - WorkWindow::Resize(); + static DemoApp aApp; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |