diff options
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: */ |