diff options
author | Jan Holesovsky <kendy@suse.cz> | 2013-01-01 22:48:32 +0100 |
---|---|---|
committer | Jan Holesovsky <kendy@suse.cz> | 2013-01-04 22:02:50 +0100 |
commit | 255c03d6ad4ed13c456ee621e0af765684a475d2 (patch) | |
tree | 082de8822a61ce4fa9079e8355b11f25b927ad5e /vcl | |
parent | d7524b9e8bff832b305ca9ec735664607c50224f (diff) |
Move GraphicFilter class to vcl.
Change-Id: I2318eeda59cee1cfdb074f9a90fd7d8d80aab19f
Diffstat (limited to 'vcl')
105 files changed, 24429 insertions, 0 deletions
diff --git a/vcl/CppunitTest_vcl_filters_test.mk b/vcl/CppunitTest_vcl_filters_test.mk new file mode 100644 index 000000000000..b6db6efc463f --- /dev/null +++ b/vcl/CppunitTest_vcl_filters_test.mk @@ -0,0 +1,62 @@ +# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*- +# Version: MPL 1.1 / GPLv3+ / LGPLv3+ +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License or as specified alternatively below. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# Major Contributor(s): +# Copyright (C) 2011 Red Hat, Inc., Caolán McNamara <caolanm@redhat.com> +# (initial developer) +# +# All Rights Reserved. +# +# For minor contributions see the git repository. +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 3 or later (the "GPLv3+"), or +# the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"), +# in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable +# instead of those above. + +$(eval $(call gb_CppunitTest_CppunitTest,svtools_filters_test)) + +$(eval $(call gb_CppunitTest_add_exception_objects,svtools_filters_test, \ + svtools/qa/cppunit/filters-test \ +)) + +$(eval $(call gb_CppunitTest_use_libraries,svtools_filters_test, \ + comphelper \ + cppu \ + cppuhelper \ + sal \ + svt \ + test \ + tl \ + unotest \ + vcl \ + $(gb_UWINAPI) \ +)) + +$(eval $(call gb_CppunitTest_use_api,svtools_filters_test,\ + udkapi \ + offapi \ +)) + +$(eval $(call gb_CppunitTest_use_ure,svtools_filters_test)) + +$(eval $(call gb_CppunitTest_use_components,svtools_filters_test,\ + configmgr/source/configmgr \ + i18npool/util/i18npool \ + ucb/source/core/ucb1 \ +)) + +$(eval $(call gb_CppunitTest_use_configuration,svtools_filters_test)) + +# vim: set noet sw=4 ts=4: diff --git a/vcl/inc/vcl/FilterConfigItem.hxx b/vcl/inc/vcl/FilterConfigItem.hxx new file mode 100644 index 000000000000..e20ebf8dbf16 --- /dev/null +++ b/vcl/inc/vcl/FilterConfigItem.hxx @@ -0,0 +1,86 @@ +/* -*- 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 _FILTER_CONFIG_ITEM_HXX_ +#define _FILTER_CONFIG_ITEM_HXX_ + +#include "svtools/svtdllapi.h" +#include <tools/string.hxx> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/uno/Any.h> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyAccess.hpp> +#include <com/sun/star/task/XStatusIndicator.hpp> + +class SVT_DLLPUBLIC FilterConfigItem +{ + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xUpdatableView; + ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet > xPropSet; + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > aFilterData; + + sal_Bool bModified; + + SVT_DLLPRIVATE sal_Bool ImplGetPropertyValue( ::com::sun::star::uno::Any& rAny, + const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySet >& rXPropSet, + const ::rtl::OUString& rPropName, + sal_Bool bTestPropertyAvailability ); + + SVT_DLLPRIVATE void ImpInitTree( const String& rTree ); + + + SVT_DLLPRIVATE static ::com::sun::star::beans::PropertyValue* GetPropertyValue( + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rPropSeq, + const ::rtl::OUString& rName ); + SVT_DLLPRIVATE static sal_Bool WritePropertyValue( + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >& rPropSeq, + const ::com::sun::star::beans::PropertyValue& rPropValue ); + + public : + + FilterConfigItem( const ::rtl::OUString& rSubTree ); + FilterConfigItem( ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData ); + FilterConfigItem( const ::rtl::OUString& rSubTree, ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData ); + ~FilterConfigItem(); + + // all read methods are trying to return values in following order: + // 1. FilterData PropertySequence + // 2. configuration + // 3. given default + sal_Bool ReadBool( const ::rtl::OUString& rKey, sal_Bool bDefault ); + sal_Int32 ReadInt32( const ::rtl::OUString& rKey, sal_Int32 nDefault ); + ::rtl::OUString + ReadString( const ::rtl::OUString& rKey, const ::rtl::OUString& rDefault ); + + // try to store to configuration + // and always stores into the FilterData sequence + void WriteBool( const ::rtl::OUString& rKey, sal_Bool bValue ); + void WriteInt32( const ::rtl::OUString& rKey, sal_Int32 nValue ); + + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > GetFilterData() const; + + // GetStatusIndicator is returning the "StatusIndicator" property of the FilterData sequence + ::com::sun::star::uno::Reference< ::com::sun::star::task::XStatusIndicator > GetStatusIndicator() const; +}; + +#endif // _FILTER_CONFIG_ITEM_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/vcl/graphicfilter.hxx b/vcl/inc/vcl/graphicfilter.hxx new file mode 100644 index 000000000000..23d0c7204737 --- /dev/null +++ b/vcl/inc/vcl/graphicfilter.hxx @@ -0,0 +1,360 @@ +/* -*- 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 _FILTER_HXX +#define _FILTER_HXX + +#include <svtools/fltcall.hxx> +#include "svtools/svtdllapi.h" +#include <tools/stream.hxx> +#include <vcl/graph.hxx> +#include <tools/gen.hxx> +#include <tools/urlobj.hxx> +#include <vcl/field.hxx> +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/beans/PropertyValue.hpp> + +struct WMF_EXTERNALHEADER; +// ----------------------- +// - GraphicFilter-Types - +// ----------------------- + +struct ImplDirEntryHelper +{ + static sal_Bool Exists( const INetURLObject& rObj ); + static void Kill( const String& rStr ); +}; + +class Window; +class Graphic; + +#define OPT_FILTERSECTION "Graphic" + +#define GRFILTER_OK 0 +#define GRFILTER_OPENERROR 1 +#define GRFILTER_IOERROR 2 +#define GRFILTER_FORMATERROR 3 +#define GRFILTER_VERSIONERROR 4 +#define GRFILTER_FILTERERROR 5 +#define GRFILTER_ABORT 6 +#define GRFILTER_TOOBIG 7 + +#define GRFILTER_OUTHINT_GREY 1 + +#define GRFILTER_FORMAT_NOTFOUND ((sal_uInt16)0xFFFF) +#define GRFILTER_FORMAT_DONTKNOW ((sal_uInt16)0xFFFF) + +#define GRFILTER_I_FLAGS_SET_LOGSIZE_FOR_JPEG 00000001 +#define GRFILTER_I_FLAGS_DONT_SET_LOGSIZE_FOR_JPEG 00000002 +#define GRFILTER_I_FLAGS_FOR_PREVIEW 00000004 +#define GRFILTER_I_FLAGS_ALLOW_PARTIAL_STREAMREAD 00000010 + +#define IMP_BMP "SVBMP" +#define IMP_SVMETAFILE "SVMETAFILE" +#define IMP_WMF "SVWMF" +#define IMP_EMF "SVEMF" +#define IMP_SVSGF "SVSGF" +#define IMP_SVSGV "SVSGV" +#define IMP_GIF "SVIGIF" +#define IMP_PNG "SVIPNG" +#define IMP_JPEG "SVIJPEG" +#define IMP_XBM "SVIXBM" +#define IMP_XPM "SVIXPM" +#define IMP_SVG "SVISVG" +#define EXP_BMP "SVBMP" +#define EXP_SVMETAFILE "SVMETAFILE" +#define EXP_WMF "SVWMF" +#define EXP_EMF "SVEMF" +#define EXP_JPEG "SVEJPEG" +#define EXP_SVG "SVESVG" +#define EXP_PNG "SVEPNG" + +#define BMP_SHORTNAME "BMP" +#define GIF_SHORTNAME "GIF" +#define JPG_SHORTNAME "JPG" +#define MET_SHORTNAME "MET" +#define PCT_SHORTNAME "PCT" +#define PNG_SHORTNAME "PNG" +#define SVM_SHORTNAME "SVM" +#define TIF_SHORTNAME "TIF" +#define WMF_SHORTNAME "WMF" +#define EMF_SHORTNAME "EMF" +#define SVG_SHORTNAME "SVG" + +// ------------------------------------ +// - Info-Klasse fuer alle von uns +// unterstuetzten Grafik-Fileformate +// ------------------------------------ + +#define GFF_NOT ( (sal_uInt16)0x0000 ) +#define GFF_BMP ( (sal_uInt16)0x0001 ) +#define GFF_GIF ( (sal_uInt16)0x0002 ) +#define GFF_JPG ( (sal_uInt16)0x0003 ) +#define GFF_PCD ( (sal_uInt16)0x0004 ) +#define GFF_PCX ( (sal_uInt16)0x0005 ) +#define GFF_PNG ( (sal_uInt16)0x0006 ) +#define GFF_TIF ( (sal_uInt16)0x0007 ) +#define GFF_XBM ( (sal_uInt16)0x0008 ) +#define GFF_XPM ( (sal_uInt16)0x0009 ) +#define GFF_PBM ( (sal_uInt16)0x000a ) +#define GFF_PGM ( (sal_uInt16)0x000b ) +#define GFF_PPM ( (sal_uInt16)0x000c ) +#define GFF_RAS ( (sal_uInt16)0x000d ) +#define GFF_TGA ( (sal_uInt16)0x000e ) +#define GFF_PSD ( (sal_uInt16)0x000f ) +#define GFF_EPS ( (sal_uInt16)0x0010 ) +#define GFF_DXF ( (sal_uInt16)0x00f1 ) +#define GFF_MET ( (sal_uInt16)0x00f2 ) +#define GFF_PCT ( (sal_uInt16)0x00f3 ) +#define GFF_SGF ( (sal_uInt16)0x00f4 ) +#define GFF_SVM ( (sal_uInt16)0x00f5 ) +#define GFF_WMF ( (sal_uInt16)0x00f6 ) +#define GFF_SGV ( (sal_uInt16)0x00f7 ) +#define GFF_EMF ( (sal_uInt16)0x00f8 ) +#define GFF_SVG ( (sal_uInt16)0x00f9 ) +#define GFF_XXX ( (sal_uInt16)0xffff ) + +// --------------------- +// - GraphicDescriptor - +// --------------------- + +class SVT_DLLPUBLIC GraphicDescriptor +{ + SvStream* pFileStm; + + String aPathExt; + Size aPixSize; + Size aLogSize; + sal_uInt16 nBitsPerPixel; + sal_uInt16 nPlanes; + sal_uInt16 nFormat; + sal_Bool bCompressed; + sal_Bool bOwnStream; + + void ImpConstruct(); + + sal_Bool ImpDetectBMP( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectGIF( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectJPG( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectPCD( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectPCX( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectPNG( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectTIF( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectXBM( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectXPM( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectPBM( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectPGM( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectPPM( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectRAS( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectTGA( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectPSD( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectEPS( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectDXF( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectMET( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectPCT( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectSGF( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectSVM( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectWMF( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectSGV( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectEMF( SvStream& rStm, sal_Bool bExtendedInfo ); + sal_Bool ImpDetectSVG( SvStream& rStm, sal_Bool bExtendedInfo ); + GraphicDescriptor( const GraphicDescriptor& ); + GraphicDescriptor& operator=( const GraphicDescriptor& ); + +public: + + // Ctor, um einen Filenamen zu setzen. Es muss ::Detect() gerufen werden, + // um das File zu identifizieren; + // wenn das File keinen eindeutigen Header besitzt ( Mtf's ) wird das + // Format anhand der Extension bestimmt + GraphicDescriptor( const INetURLObject& rPath ); + + // Ctor, um einen Stream zu setzen. Es muss ::Detect() gerufen werden, + // um das File zu identifizieren; + // da einige Formate ( Mtf's ) keinen eindeutigen Header besitzen, + // ist es sinnvoll den Filenamen (inkl. Ext. ) mitanzugeben, + // da so das Format ueber die Extension ermittelt werden kann + GraphicDescriptor( SvStream& rInStream, const String* pPath = NULL ); + + // Dtor + virtual ~GraphicDescriptor(); + + // Startet die Detektion; + // bei bExtendedInfo == sal_True werden soweit wie moeglich + // Daten aus dem jeweiligen FileHeader ermittelt + // ( Groesse, Farbtiefe usw. ) + virtual sal_Bool Detect( sal_Bool bExtendedInfo = sal_False ); + + // liefert das Fileformat nach erfolgreicher Detektion zurueck; + // wenn kein Format erkannt wurde, ist das Formart GFF_NOT + sal_uInt16 GetFileFormat() const { return nFormat; } + + // liefert die Pixel-Bildgroesse oder 0-Size zurueck + const Size& GetSizePixel() const { return (Size&) aPixSize; } + + // liefert die logische Bildgroesse in 1/100mm oder 0-Size zurueck + const Size& GetSize_100TH_MM() const { return (Size&) aLogSize; } + + // liefert die Bits/Pixel oder 0 zurueck + sal_uInt16 GetBitsPerPixel() const { return nBitsPerPixel; } + + // liefert die Anzahl der Planes oder 0 zurueck + sal_uInt16 GetPlanes() const { return nPlanes; } + + // zeigt an, ob das Bild evtl. komprimiert (wie auch immer) ist + sal_Bool IsCompressed() const { return bCompressed; } + + // gibt die Filternummer des Filters zurueck, + // der im GraphicFilter zum Lesen dieses Formats + // benoetigt wird + static String GetImportFormatShortName( sal_uInt16 nFormat ); +}; + +// ----------------- +// - GraphicFilter - +// ----------------- + +struct FilterErrorEx +{ + sal_uLong nFilterError; + sal_uLong nStreamError; + + FilterErrorEx() : nFilterError( 0UL ), nStreamError( 0UL ) {} +}; + +// ----------------------------------------------------------------------------- + +struct ConvertData; +class FilterConfigCache; +class SVT_DLLPUBLIC GraphicFilter +{ + friend class SvFilterOptionsDialog; + +private: + + void ImplInit(); + sal_uLong ImplSetError( sal_uLong nError, const SvStream* pStm = NULL ); + sal_uInt16 ImpTestOrFindFormat( const String& rPath, SvStream& rStream, sal_uInt16& rFormat ); + + DECL_LINK( FilterCallback, ConvertData* pData ); + +protected: + + rtl::OUString aFilterPath; + FilterConfigCache* pConfig; + FilterErrorEx* pErrorEx; + sal_Bool bAbort; + sal_Bool bUseConfig; + long nExpGraphHint; + +public: + + GraphicFilter( sal_Bool bUseConfig = sal_True ); + ~GraphicFilter(); + + void SetFilterPath( const rtl::OUString& rFilterPath ) { aFilterPath = rFilterPath; }; + + sal_uInt16 GetImportFormatCount(); + sal_uInt16 GetImportFormatNumber( const String& rFormatName ); + sal_uInt16 GetImportFormatNumberForMediaType( const String& rMediaType ); + sal_uInt16 GetImportFormatNumberForShortName( const String& rShortName ); + sal_uInt16 GetImportFormatNumberForTypeName( const String& rType ); + String GetImportFormatName( sal_uInt16 nFormat ); + String GetImportFormatTypeName( sal_uInt16 nFormat ); + String GetImportFormatMediaType( sal_uInt16 nFormat ); + String GetImportFormatShortName( sal_uInt16 nFormat ); + String GetImportOSFileType( sal_uInt16 nFormat ); + String GetImportWildcard( sal_uInt16 nFormat, sal_Int32 nEntry = 0 ); + sal_Bool IsImportPixelFormat( sal_uInt16 nFormat ); + + sal_uInt16 GetExportFormatCount(); + sal_uInt16 GetExportFormatNumber( const String& rFormatName ); + sal_uInt16 GetExportFormatNumberForMediaType( const String& rShortName ); + sal_uInt16 GetExportFormatNumberForShortName( const String& rShortName ); + sal_uInt16 GetExportFormatNumberForTypeName( const String& rType ); + String GetExportFormatName( sal_uInt16 nFormat ); + String GetExportFormatTypeName( sal_uInt16 nFormat ); + String GetExportFormatMediaType( sal_uInt16 nFormat ); + String GetExportFormatShortName( sal_uInt16 nFormat ); + String GetExportOSFileType( sal_uInt16 nFormat ); + String GetExportWildcard( sal_uInt16 nFormat, sal_Int32 nEntry = 0 ); + sal_Bool IsExportPixelFormat( sal_uInt16 nFormat ); + + sal_Bool HasExportDialog( sal_uInt16 nFormat ); + sal_Bool DoExportDialog( Window* pWindow, sal_uInt16 nFormat ); + sal_Bool DoExportDialog( Window* pWindow, sal_uInt16 nFormat, FieldUnit eFieldUnit ); + + sal_uInt16 ExportGraphic( const Graphic& rGraphic, const INetURLObject& rPath, + sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW, + const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >* pFilterData = NULL ); + sal_uInt16 ExportGraphic( const Graphic& rGraphic, const String& rPath, + SvStream& rOStm, sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW, + const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >* pFilterData = NULL ); + long GetExportGraphicHint() const { return nExpGraphHint; } + + sal_uInt16 CanImportGraphic( const INetURLObject& rPath, + sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW, + sal_uInt16 * pDeterminedFormat = NULL); + + sal_uInt16 ImportGraphic( Graphic& rGraphic, const INetURLObject& rPath, + sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW, + sal_uInt16 * pDeterminedFormat = NULL, sal_uInt32 nImportFlags = 0 ); + + sal_uInt16 CanImportGraphic( const String& rPath, SvStream& rStream, + sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW, + sal_uInt16 * pDeterminedFormat = NULL); + + sal_uInt16 ImportGraphic( Graphic& rGraphic, const String& rPath, + SvStream& rStream, + sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW, + sal_uInt16 * pDeterminedFormat = NULL, sal_uInt32 nImportFlags = 0, + WMF_EXTERNALHEADER *pExtHeader = NULL ); + + sal_uInt16 ImportGraphic( Graphic& rGraphic, const String& rPath, + SvStream& rStream, + sal_uInt16 nFormat, + sal_uInt16 * pDeterminedFormat, sal_uInt32 nImportFlags, + com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >* pFilterData, + WMF_EXTERNALHEADER *pExtHeader = NULL ); + + sal_Bool Setup( sal_uInt16 nFormat ); + + void Abort() { bAbort = sal_True; } + + const FilterErrorEx& GetLastError() const; + void ResetLastError(); + + const Link GetFilterCallback() const; + static GraphicFilter& GetGraphicFilter(); + static int LoadGraphic( const String& rPath, const String& rFilter, + Graphic& rGraphic, + GraphicFilter* pFilter = NULL, + sal_uInt16* pDeterminedFormat = NULL ); +}; + +// ------------------------------------ +// - Windows Metafile Lesen/Schreiben - +// ------------------------------------ + +SVT_DLLPUBLIC sal_Bool ReadWindowMetafile( SvStream& rStream, GDIMetaFile& rMTF, FilterConfigItem* pConfigItem ); +SVT_DLLPUBLIC sal_Bool WriteWindowMetafileBits( SvStream& rStream, const GDIMetaFile& rMTF ); + +#endif //_FILTER_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/inc/vcl/wmf.hxx b/vcl/inc/vcl/wmf.hxx new file mode 100644 index 000000000000..66e2dcac589d --- /dev/null +++ b/vcl/inc/vcl/wmf.hxx @@ -0,0 +1,67 @@ +/* -*- 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 _WMF_HXX +#define _WMF_HXX + +#include "svtools/svtdllapi.h" +#include <svtools/fltcall.hxx> + +struct WMF_EXTERNALHEADER +{ + sal_uInt16 xExt; + sal_uInt16 yExt; + + /** One of the following values: + <ul> + <li>MM_TEXT</li> + <li>MM_LOMETRIC</li> + <li>MM_HIMETRIC</li> + <li>MM_LOENGLISH</li> + <li>MM_HIENGLISH</li> + <li>MM_TWIPS</li> + <li>MM_ISOTROPIC</li> + <li>MM_ANISOTROPIC</li> + </ul> + If this value is 0, then no external mapmode has been defined, + the internal one should then be used. + */ + sal_uInt16 mapMode; + + WMF_EXTERNALHEADER() : + xExt( 0 ), + yExt( 0 ), + mapMode( 0 ) + { + } +}; + +sal_Bool ConvertWMFToGDIMetaFile( SvStream & rStreamWMF, GDIMetaFile & rGDIMetaFile, FilterConfigItem* pConfigItem = NULL, WMF_EXTERNALHEADER *pExtHeader = NULL ); + +SVT_DLLPUBLIC sal_Bool ReadWindowMetafile( SvStream& rStream, GDIMetaFile& rMTF, FilterConfigItem* pConfigItem ); + +SVT_DLLPUBLIC sal_Bool ConvertGDIMetaFileToWMF( const GDIMetaFile & rMTF, SvStream & rTargetStream, FilterConfigItem* pConfigItem = NULL, sal_Bool bPlaceable = sal_True ); + +sal_Bool ConvertGDIMetaFileToEMF( const GDIMetaFile & rMTF, SvStream & rTargetStream, FilterConfigItem* pConfigItem = NULL ); + +SVT_DLLPUBLIC sal_Bool WriteWindowMetafileBits( SvStream& rStream, const GDIMetaFile& rMTF ); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/graphicfilter/data/README b/vcl/qa/cppunit/graphicfilter/data/README new file mode 100644 index 000000000000..2cc9fb3cb58f --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/README @@ -0,0 +1,7 @@ +Files with the string 'CVE' in their name are encrypted to avoid +problems with virus checkers on source code download.; use: + +mdecrypt --bare -a arcfour -o hex -k 435645 -s 3 foo.doc # to unencrypt +mcrypt --bare -a arcfour -o hex -k 435645 -s 3 foo.doc # to create new tests + +to get access to the plain files for manual testing. diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/fail/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/bmp/indeterminate/.gitignore new file mode 100644 index 000000000000..583b009c7c60 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/indeterminate/.gitignore @@ -0,0 +1 @@ +*.wmf-* diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2004-0691-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2004-0691-1.bmp Binary files differnew file mode 100644 index 000000000000..d77db5782972 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2004-0691-1.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2006-0006-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2006-0006-1.bmp Binary files differnew file mode 100644 index 000000000000..4cfbdfff8358 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2006-0006-1.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2007-2244-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2007-2244-1.bmp Binary files differnew file mode 100644 index 000000000000..289cf8c0e964 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2007-2244-1.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2008-5870-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2008-5870-1.bmp new file mode 100644 index 000000000000..d223dde288b5 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/CVE-2008-5870-1.bmp @@ -0,0 +1 @@ +.GxK؝'se2~.G1-#1Y!ʢ/DV
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/bmp/pass/EDB-22680-1.bmp b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/EDB-22680-1.bmp Binary files differnew file mode 100644 index 000000000000..88b11ad57845 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/bmp/pass/EDB-22680-1.bmp diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/emf/fail/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2004-0209-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2004-0209-1.emf Binary files differnew file mode 100644 index 000000000000..a511da43add5 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2004-0209-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2008-1083-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2008-1083-1.emf Binary files differnew file mode 100644 index 000000000000..dd57d9102cd1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2008-1083-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2009-1217-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2009-1217-1.emf Binary files differnew file mode 100644 index 000000000000..8fa6e9377938 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/fail/CVE-2009-1217-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/emf/indeterminate/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/indeterminate/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/emf/pass/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-1087-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-1087-1.emf Binary files differnew file mode 100644 index 000000000000..c71739a50b99 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-1087-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-2245-1.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-2245-1.emf Binary files differnew file mode 100644 index 000000000000..746e85e847b4 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/CVE-2008-2245-1.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/emf/pass/fdo38580-3.emf b/vcl/qa/cppunit/graphicfilter/data/emf/pass/fdo38580-3.emf Binary files differnew file mode 100644 index 000000000000..0af6c749bde4 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/emf/pass/fdo38580-3.emf diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/gif/fail/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/fail/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2007-3958-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2007-3958-1.gif Binary files differnew file mode 100644 index 000000000000..7e84566e94b0 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2007-3958-1.gif diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2008-5937-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2008-5937-1.gif new file mode 100644 index 000000000000..cbefd0162510 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/fail/CVE-2008-5937-1.gif @@ -0,0 +1 @@ +&Vus؝[e21oX
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/gif/indeterminate/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/indeterminate/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/gif/pass/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2007-6715-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2007-6715-1.gif Binary files differnew file mode 100644 index 000000000000..63426f9d80c2 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2007-6715-1.gif diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2008-3013-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2008-3013-1.gif Binary files differnew file mode 100644 index 000000000000..e92a316e4b11 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2008-3013-1.gif diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2011-2131-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2011-2131-1.gif Binary files differnew file mode 100644 index 000000000000..190c7b0791a7 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2011-2131-1.gif diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2012-0282-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2012-0282-1.gif Binary files differnew file mode 100644 index 000000000000..cf4f30c21b91 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/CVE-2012-0282-1.gif diff --git a/vcl/qa/cppunit/graphicfilter/data/gif/pass/EDB-19333-1.gif b/vcl/qa/cppunit/graphicfilter/data/gif/pass/EDB-19333-1.gif new file mode 100644 index 000000000000..53d2ca01e854 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/gif/pass/EDB-19333-1.gif @@ -0,0 +1 @@ +&t};'[ek2ΐ~m1L-ha[^.!7/&VOʻBB^u2k]YnyG)ʿjkB:d#|u\#L@E
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2004-0200-1.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2004-0200-1.jpg Binary files differnew file mode 100644 index 000000000000..3d9481aca908 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2004-0200-1.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2004-0200-4.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2004-0200-4.jpg Binary files differnew file mode 100644 index 000000000000..9d26db0050bb --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2004-0200-4.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-5314-1.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-5314-1.jpg Binary files differnew file mode 100644 index 000000000000..33bbe9b5f9e1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/fail/CVE-2008-5314-1.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/jpg/indeterminate/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/indeterminate/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-2.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-2.jpg Binary files differnew file mode 100644 index 000000000000..5eb27ffb5250 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-2.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-3.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-3.jpg Binary files differnew file mode 100644 index 000000000000..4917f207f35f --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-3.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-5.jpg b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-5.jpg Binary files differnew file mode 100644 index 000000000000..bc668d3e3f31 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/jpg/pass/CVE-2004-0200-5.jpg diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/png/fail/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2004-0597-1.png b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2004-0597-1.png new file mode 100644 index 000000000000..fa90a296f9fa --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2004-0597-1.png @@ -0,0 +1,3 @@ +#Mb}o72~X.^TwB!f1s
tga2bAHb"8|eGfS$N0nI֪ +0"JGzܢ(s?d)"GEF9~}r TΝp?*ck$E"X8=2T_3v#$Hh4JKi݊J&7r=u69KjWh{$
dV[Жy\%%ǾHme+
}gXI2>*ī&
)̸6pUTjODh1-<WURK591M? +~*Nru;khX{֍Ԥ' ӏwF[KRfyO%0ihx׃wz4dT.@Xm4ipZ^yЯ`_Y? tuw4\kdJ~mg`<2ln*
kh*nw7!YIßP+hK*Ԟ`?
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2005-0633-1.png b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2005-0633-1.png Binary files differnew file mode 100644 index 000000000000..d0644d139749 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2005-0633-1.png diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2006-7210-1.png b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2006-7210-1.png Binary files differnew file mode 100644 index 000000000000..9b30cc38c7db --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2006-7210-1.png diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2007-2365-1.png b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2007-2365-1.png Binary files differnew file mode 100644 index 000000000000..b9ff67bb8b81 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2007-2365-1.png diff --git a/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2009-1511-1.png b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2009-1511-1.png new file mode 100644 index 000000000000..592fda10aa9e --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/fail/CVE-2009-1511-1.png @@ -0,0 +1 @@ +#Mb}o72͐~\._舄{'p|&F/
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/png/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/png/indeterminate/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/indeterminate/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/png/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/png/pass/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/pass/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/png/pass/black.png b/vcl/qa/cppunit/graphicfilter/data/png/pass/black.png Binary files differnew file mode 100644 index 000000000000..cbba93bedd81 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/png/pass/black.png diff --git a/vcl/qa/cppunit/graphicfilter/data/sgv/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/sgv/fail/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/sgv/fail/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/sgv/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/sgv/indeterminate/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/sgv/indeterminate/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/sgv/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/sgv/pass/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/sgv/pass/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/sgv/pass/SaveAsPicture.sgv b/vcl/qa/cppunit/graphicfilter/data/sgv/pass/SaveAsPicture.sgv Binary files differnew file mode 100755 index 000000000000..0fe908e91c98 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/sgv/pass/SaveAsPicture.sgv diff --git a/vcl/qa/cppunit/graphicfilter/data/sgv/pass/faxpfeil.sgv b/vcl/qa/cppunit/graphicfilter/data/sgv/pass/faxpfeil.sgv Binary files differnew file mode 100755 index 000000000000..c8317c62e152 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/sgv/pass/faxpfeil.sgv diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/.gitignore b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2123-1.wmf-0.009-676 b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2123-1.wmf-0.009-676 Binary files differnew file mode 100644 index 000000000000..49d3ddf28b02 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2123-1.wmf-0.009-676 diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2124-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2124-1.wmf Binary files differnew file mode 100644 index 000000000000..ac546ce5b14c --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-2124-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-4560-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-4560-1.wmf Binary files differnew file mode 100644 index 000000000000..aab34004e927 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2005-4560-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2006-0143-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2006-0143-1.wmf new file mode 100644 index 000000000000..b68b7403c338 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2006-0143-1.wmf @@ -0,0 +1 @@ +HU۬.DZ|d[e2ː~Sb&[1-kg"uZJj<we⊏
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2006-0143-2.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2006-0143-2.wmf Binary files differnew file mode 100644 index 000000000000..370abe0e249d --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/fail/CVE-2006-0143-2.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/indeterminate/.gitignore b/vcl/qa/cppunit/graphicfilter/data/wmf/indeterminate/.gitignore new file mode 100644 index 000000000000..583b009c7c60 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/indeterminate/.gitignore @@ -0,0 +1 @@ +*.wmf-* diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/.gitignore b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/.gitignore new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/.gitignore diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2005-2123-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2005-2123-1.wmf Binary files differnew file mode 100644 index 000000000000..e70664e64aa0 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2005-2123-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2006-4071-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2006-4071-1.wmf new file mode 100644 index 000000000000..cdb09c6b21e2 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2006-4071-1.wmf @@ -0,0 +1 @@ +HU۬.DZI2wɐ~._1-#f1.!0/ٸTDHN
\ No newline at end of file diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1090-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1090-1.wmf Binary files differnew file mode 100644 index 000000000000..7864da572ca2 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1090-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1238-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1238-1.wmf Binary files differnew file mode 100644 index 000000000000..10da32742570 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1238-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1245-1.wmf b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1245-1.wmf Binary files differnew file mode 100644 index 000000000000..10da32742570 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/data/wmf/pass/CVE-2007-1245-1.wmf diff --git a/vcl/qa/cppunit/graphicfilter/filters-test.cxx b/vcl/qa/cppunit/graphicfilter/filters-test.cxx new file mode 100644 index 000000000000..bdf8269575e2 --- /dev/null +++ b/vcl/qa/cppunit/graphicfilter/filters-test.cxx @@ -0,0 +1,108 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * Version: MPL 1.1 / GPLv3+ / LGPLv3+ + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Initial Developer of the Original Code is + * Caolán McNamara <caolanm@redhat.com> + * Portions created by the Initial Developer are Copyright (C) 2011 the + * Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Caolán McNamara <caolanm@redhat.com> + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 3 or later (the "GPLv3+"), or + * the GNU Lesser General Public License Version 3 or later (the "LGPLv3+"), + * in which case the provisions of the GPLv3+ or the LGPLv3+ are applicable + * instead of those above. + */ + +#include <unotest/filters-test.hxx> +#include <test/bootstrapfixture.hxx> + +#include <osl/file.hxx> +#include <osl/process.h> + +#include <svtools/filter.hxx> + +using namespace ::com::sun::star; + +/* Implementation of Filters test */ + +class SvtoolsFiltersTest + : public test::FiltersTest + , public test::BootstrapFixture +{ +public: + SvtoolsFiltersTest() : BootstrapFixture(true, false) {} + + virtual bool load(const rtl::OUString &, + const rtl::OUString &rURL, const rtl::OUString &, + unsigned int, unsigned int, unsigned int); + + /** + * Ensure CVEs remain unbroken + */ + void testCVEs(); + + CPPUNIT_TEST_SUITE(SvtoolsFiltersTest); + CPPUNIT_TEST(testCVEs); + CPPUNIT_TEST_SUITE_END(); +}; + +bool SvtoolsFiltersTest::load(const rtl::OUString &, + const rtl::OUString &rURL, const rtl::OUString &, + unsigned int, unsigned int, unsigned int) +{ + GraphicFilter aGraphicFilter(false); + SvFileStream aFileStream(rURL, STREAM_READ); + Graphic aGraphic; + return aGraphicFilter.ImportGraphic(aGraphic, rURL, aFileStream) == 0; +} + +void SvtoolsFiltersTest::testCVEs() +{ + testDir(rtl::OUString(), + getURLFromSrc("/svtools/qa/cppunit/data/wmf/"), + rtl::OUString()); + + testDir(rtl::OUString(), + getURLFromSrc("/svtools/qa/cppunit/data/emf/"), + rtl::OUString()); + + testDir(rtl::OUString(), + getURLFromSrc("/svtools/qa/cppunit/data/sgv/"), + rtl::OUString()); + + testDir(rtl::OUString(), + getURLFromSrc("/svtools/qa/cppunit/data/png/"), + rtl::OUString()); + + testDir(rtl::OUString(), + getURLFromSrc("/svtools/qa/cppunit/data/jpg/"), + rtl::OUString()); + + testDir(rtl::OUString(), + getURLFromSrc("/svtools/qa/cppunit/data/gif/"), + rtl::OUString()); + + testDir(rtl::OUString(), + getURLFromSrc("/svtools/qa/cppunit/data/bmp/"), + rtl::OUString()); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(SvtoolsFiltersTest); + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/FilterConfigCache.cxx b/vcl/source/filter/FilterConfigCache.cxx new file mode 100644 index 000000000000..dc4b7c740cdf --- /dev/null +++ b/vcl/source/filter/FilterConfigCache.cxx @@ -0,0 +1,561 @@ +/* -*- 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 "FilterConfigCache.hxx" +#include <svtools/filter.hxx> +#include <com/sun/star/uno/Any.h> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/uno/Exception.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/configuration/theDefaultProvider.hpp> + +using namespace ::com::sun::star::lang ; // XMultiServiceFactory +using namespace ::com::sun::star::container ; // XNameAccess +using namespace ::com::sun::star::uno ; // Reference +using namespace ::com::sun::star::beans ; // PropertyValue +using namespace ::com::sun::star::configuration ; +using ::rtl::OUString; + +const char* FilterConfigCache::FilterConfigCacheEntry::InternalPixelFilterNameList[] = +{ + IMP_BMP, IMP_GIF, IMP_PNG,IMP_JPEG, IMP_XBM, IMP_XPM, + EXP_BMP, EXP_JPEG, EXP_PNG, NULL +}; + +const char* FilterConfigCache::FilterConfigCacheEntry::InternalVectorFilterNameList[] = +{ + IMP_SVMETAFILE, IMP_WMF, IMP_EMF, IMP_SVSGF, IMP_SVSGV, IMP_SVG, + EXP_SVMETAFILE, EXP_WMF, EXP_EMF, EXP_SVG, NULL +}; + +const char* FilterConfigCache::FilterConfigCacheEntry::ExternalPixelFilterNameList[] = +{ + "egi", "icd", "ipd", "ipx", "ipb", "epb", "epg", + "epp", "ira", "era", "itg", "iti", "eti", "exp", NULL +}; + +sal_Bool FilterConfigCache::bInitialized = sal_False; +sal_Int32 FilterConfigCache::nIndType = -1; +sal_Int32 FilterConfigCache::nIndUIName = -1; +sal_Int32 FilterConfigCache::nIndDocumentService = -1; +sal_Int32 FilterConfigCache::nIndFilterService = -1; +sal_Int32 FilterConfigCache::nIndFlags = -1; +sal_Int32 FilterConfigCache::nIndUserData = -1; +sal_Int32 FilterConfigCache::nIndFileFormatVersion = -1; +sal_Int32 FilterConfigCache::nIndTemplateName = -1; + +sal_Bool FilterConfigCache::FilterConfigCacheEntry::CreateFilterName( const OUString& rUserDataEntry ) +{ + bIsPixelFormat = bIsInternalFilter = sal_False; + sFilterName = String( rUserDataEntry ); + const char** pPtr; + for ( pPtr = InternalPixelFilterNameList; *pPtr && ( bIsInternalFilter == sal_False ); pPtr++ ) + { + if ( sFilterName.EqualsIgnoreCaseAscii( *pPtr ) ) + { + bIsInternalFilter = sal_True; + bIsPixelFormat = sal_True; + } + } + for ( pPtr = InternalVectorFilterNameList; *pPtr && ( bIsInternalFilter == sal_False ); pPtr++ ) + { + if ( sFilterName.EqualsIgnoreCaseAscii( *pPtr ) ) + bIsInternalFilter = sal_True; + } + if ( !bIsInternalFilter ) + { + for ( pPtr = ExternalPixelFilterNameList; *pPtr && ( bIsPixelFormat == sal_False ); pPtr++ ) + { + if ( sFilterName.EqualsIgnoreCaseAscii( *pPtr ) ) + bIsPixelFormat = sal_True; + } + rtl::OUString sTemp(SVLIBRARY("?")); + sal_Int32 nIndex = sTemp.indexOf(static_cast<sal_Unicode>('?')); + sFilterName = sTemp.replaceAt(nIndex, 1, sFilterName); + } + return sFilterName.Len() != 0; +} + +String FilterConfigCache::FilterConfigCacheEntry::GetShortName() +{ + String aShortName; + if ( lExtensionList.getLength() ) + { + aShortName = lExtensionList[ 0 ]; + if ( aShortName.SearchAscii( "*.", 0 ) == 0 ) + aShortName.Erase( 0, 2 ); + } + return aShortName; +} + +/** helper to open the configuration root of the underlying + config package + + @param sPackage + specify, which config package should be opened. + Must be one of "types" or "filters" + + @return A valid object if open was successfull. The access on opened + data will be readonly. It returns NULL in case open failed. + + @throws It let pass RuntimeExceptions only. + */ +Reference< XInterface > openConfig(const char* sPackage) + throw(RuntimeException) +{ + Reference< XComponentContext > xContext( + comphelper::getProcessComponentContext() ); + Reference< XInterface > xCfg; + try + { + // get access to config API (not to file!) + Reference< XMultiServiceFactory > xConfigProvider = theDefaultProvider::get( xContext ); + + Sequence< Any > lParams(1); + PropertyValue aParam ; + + // define cfg path for open + aParam.Name = OUString( "nodepath" ); + if (rtl_str_compareIgnoreAsciiCase(sPackage, "types") == 0) + aParam.Value <<= OUString( "/org.openoffice.TypeDetection.Types/Types" ); + if (rtl_str_compareIgnoreAsciiCase(sPackage, "filters") == 0) + aParam.Value <<= OUString( "/org.openoffice.TypeDetection.GraphicFilter/Filters" ); + lParams[0] = makeAny(aParam); + + // get access to file + xCfg = xConfigProvider->createInstanceWithArguments( + OUString( "com.sun.star.configuration.ConfigurationAccess" ), lParams); + } + catch(const RuntimeException&) + { throw; } + catch(const Exception&) + { xCfg.clear(); } + + return xCfg; +} + +void FilterConfigCache::ImplInit() +{ + OUString STYPE ( "Type" ); + OUString SUINAME ( "UIName" ); + OUString SUICOMPONENT ( "UIComponent" ); + OUString SFLAGS ( "Flags" ); + OUString SMEDIATYPE ( "MediaType" ); + OUString SEXTENSIONS ( "Extensions" ); + OUString SFORMATNAME ( "FormatName" ); + OUString SREALFILTERNAME ( "RealFilterName" ); + + // get access to config + Reference< XNameAccess > xTypeAccess ( openConfig("types" ), UNO_QUERY ); + Reference< XNameAccess > xFilterAccess( openConfig("filters"), UNO_QUERY ); + + if ( xTypeAccess.is() && xFilterAccess.is() ) + { + Sequence< OUString > lAllFilter = xFilterAccess->getElementNames(); + sal_Int32 nAllFilterCount = lAllFilter.getLength(); + + for ( sal_Int32 i = 0; i < nAllFilterCount; i++ ) + { + OUString sInternalFilterName = lAllFilter[ i ]; + Reference< XPropertySet > xFilterSet; + xFilterAccess->getByName( sInternalFilterName ) >>= xFilterSet; + if (!xFilterSet.is()) + continue; + + FilterConfigCacheEntry aEntry; + + aEntry.sInternalFilterName = sInternalFilterName; + xFilterSet->getPropertyValue(STYPE) >>= aEntry.sType; + xFilterSet->getPropertyValue(SUINAME) >>= aEntry.sUIName; + xFilterSet->getPropertyValue(SREALFILTERNAME) >>= aEntry.sFilterType; + Sequence< OUString > lFlags; + xFilterSet->getPropertyValue(SFLAGS) >>= lFlags; + if (lFlags.getLength()!=1 || lFlags[0].isEmpty()) + continue; + if (lFlags[0].equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("import"))) + aEntry.nFlags = 1; + else + if (lFlags[0].equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("export"))) + aEntry.nFlags = 2; + + OUString sUIComponent; + xFilterSet->getPropertyValue(SUICOMPONENT) >>= sUIComponent; + aEntry.bHasDialog = sUIComponent.getLength(); + + ::rtl::OUString sFormatName; + xFilterSet->getPropertyValue(SFORMATNAME) >>= sFormatName; + aEntry.CreateFilterName( sFormatName ); + + Reference< XPropertySet > xTypeSet; + xTypeAccess->getByName( aEntry.sType ) >>= xTypeSet; + if (!xTypeSet.is()) + continue; + + xTypeSet->getPropertyValue(SMEDIATYPE) >>= aEntry.sMediaType; + xTypeSet->getPropertyValue(SEXTENSIONS) >>= aEntry.lExtensionList; + + // The first extension will be used + // to generate our internal FilterType ( BMP, WMF ... ) + String aExtension( aEntry.GetShortName() ); + if (aExtension.Len() != 3) + continue; + + if ( aEntry.nFlags & 1 ) + aImport.push_back( aEntry ); + if ( aEntry.nFlags & 2 ) + aExport.push_back( aEntry ); + + // bFilterEntryCreated!? + if (!( aEntry.nFlags & 3 )) + continue; //? Entry was already inserted ... but following code will be supressed?! + } + } +}; + +const char* FilterConfigCache::InternalFilterListForSvxLight[] = +{ + "bmp","1","SVBMP", + "bmp","2","SVBMP", + "dxf","1","idx", + "eps","1","ips", + "eps","2","eps", + "gif","1","SVIGIF", + "gif","2","egi", + "jpg","1","SVIJPEG", + "jpg","2","SVEJPEG", + "sgv","1","SVSGV", + "sgf","1","SVSGF", + "met","1","ime", + "met","2","eme", + "png","1","SVIPNG", + "png","2","SVEPNG", + "pct","1","ipt", + "pct","2","ept", + "pcd","1","icd", + "psd","1","ipd", + "pcx","1","ipx", + "pbm","1","ipb", + "pbm","2","epb", + "pgm","1","ipb", + "pgm","2","epg", + "ppm","1","ipb", + "ppm","2","epp", + "ras","1","ira", + "ras","2","era", + "svm","1","SVMETAFILE", + "svm","2","SVMETAFILE", + "tga","1","itg", + "tif","1","iti", + "tif","2","eti", + "emf","1","SVEMF", + "emf","2","SVEMF", + "wmf","1","SVWMF", + "wmf","2","SVWMF", + "xbm","1","SVIXBM", + "xpm","1","SVIXPM", + "xpm","2","exp", + "svg","1","SVISVG", + "svg","2","SVESVG", + NULL +}; + +void FilterConfigCache::ImplInitSmart() +{ + const char** pPtr; + for ( pPtr = InternalFilterListForSvxLight; *pPtr; pPtr++ ) + { + FilterConfigCacheEntry aEntry; + + OUString sExtension( OUString::createFromAscii( *pPtr++ ) ); + + aEntry.lExtensionList.realloc( 1 ); + aEntry.lExtensionList[ 0 ] = sExtension; + + aEntry.sType = sExtension; + aEntry.sUIName = sExtension; + + rtl::OString sFlags( *pPtr++ ); + aEntry.nFlags = sFlags.toInt32(); + + OUString sUserData( OUString::createFromAscii( *pPtr ) ); + aEntry.CreateFilterName( sUserData ); + + if ( aEntry.nFlags & 1 ) + aImport.push_back( aEntry ); + if ( aEntry.nFlags & 2 ) + aExport.push_back( aEntry ); + } +} + +// ------------------------------------------------------------------------ + +FilterConfigCache::FilterConfigCache( sal_Bool bConfig ) : + bUseConfig ( bConfig ) +{ + if ( bUseConfig ) + ImplInit(); + else + ImplInitSmart(); +} + +FilterConfigCache::~FilterConfigCache() +{ +} + +String FilterConfigCache::GetImportFilterName( sal_uInt16 nFormat ) +{ + if( nFormat < aImport.size() ) + return aImport[ nFormat ].sFilterName; + return String::EmptyString(); +} + +sal_uInt16 FilterConfigCache::GetImportFormatNumber( const String& rFormatName ) +{ + CacheVector::iterator aIter( aImport.begin() ); + while ( aIter != aImport.end() ) + { + if ( aIter->sUIName.equalsIgnoreAsciiCase( rFormatName ) ) + break; + aIter++; + } + return sal::static_int_cast< sal_uInt16 >(aIter == aImport.end() ? GRFILTER_FORMAT_NOTFOUND : aIter - aImport.begin()); +} + +sal_uInt16 FilterConfigCache::GetImportFormatNumberForMediaType( const String& rMediaType ) +{ + CacheVector::iterator aIter( aImport.begin() ); + while ( aIter != aImport.end() ) + { + if ( aIter->sMediaType.equalsIgnoreAsciiCase( rMediaType ) ) + break; + aIter++; + } + return sal::static_int_cast< sal_uInt16 >(aIter == aImport.end() ? GRFILTER_FORMAT_NOTFOUND : aIter - aImport.begin()); +} + +sal_uInt16 FilterConfigCache::GetImportFormatNumberForShortName( const String& rShortName ) +{ + CacheVector::iterator aIter( aImport.begin() ); + while ( aIter != aImport.end() ) + { + if ( aIter->GetShortName().EqualsIgnoreCaseAscii( rShortName ) ) + break; + aIter++; + } + return sal::static_int_cast< sal_uInt16 >(aIter == aImport.end() ? GRFILTER_FORMAT_NOTFOUND : aIter - aImport.begin()); +} + +sal_uInt16 FilterConfigCache::GetImportFormatNumberForTypeName( const String& rType ) +{ + CacheVector::iterator aIter( aImport.begin() ); + while ( aIter != aImport.end() ) + { + if ( aIter->sType.equalsIgnoreAsciiCase( rType ) ) + break; + aIter++; + } + return sal::static_int_cast< sal_uInt16 >(aIter == aImport.end() ? GRFILTER_FORMAT_NOTFOUND : aIter - aImport.begin()); +} + +String FilterConfigCache::GetImportFormatName( sal_uInt16 nFormat ) +{ + if( nFormat < aImport.size() ) + return aImport[ nFormat ].sUIName; + return String::EmptyString(); +} + +String FilterConfigCache::GetImportFormatMediaType( sal_uInt16 nFormat ) +{ + if( nFormat < aImport.size() ) + return aImport[ nFormat ].sMediaType; + return String::EmptyString(); +} + +String FilterConfigCache::GetImportFormatShortName( sal_uInt16 nFormat ) +{ + if( nFormat < aImport.size() ) + return aImport[ nFormat ].GetShortName(); + return String::EmptyString(); +} + +String FilterConfigCache::GetImportFormatExtension( sal_uInt16 nFormat, sal_Int32 nEntry ) +{ + if ( (nFormat < aImport.size()) && (nEntry < aImport[ nFormat ].lExtensionList.getLength()) ) + return aImport[ nFormat ].lExtensionList[ nEntry ]; + return String::EmptyString(); +} + +String FilterConfigCache::GetImportFilterType( sal_uInt16 nFormat ) +{ + if( nFormat < aImport.size() ) + return aImport[ nFormat ].sType; + return String::EmptyString(); +} + +String FilterConfigCache::GetImportFilterTypeName( sal_uInt16 nFormat ) +{ + if( nFormat < aImport.size() ) + return aImport[ nFormat ].sFilterType; + return String::EmptyString(); +} + +String FilterConfigCache::GetImportWildcard( sal_uInt16 nFormat, sal_Int32 nEntry ) +{ + String aWildcard( GetImportFormatExtension( nFormat, nEntry ) ); + if ( aWildcard.Len() ) + aWildcard.Insert( rtl::OUString("*."), 0 ); + return aWildcard; +} + +sal_Bool FilterConfigCache::IsImportInternalFilter( sal_uInt16 nFormat ) +{ + return (nFormat < aImport.size()) && aImport[ nFormat ].bIsInternalFilter; +} + +sal_Bool FilterConfigCache::IsImportPixelFormat( sal_uInt16 nFormat ) +{ + return (nFormat < aImport.size()) && aImport[ nFormat ].bIsPixelFormat; +} + +// ------------------------------------------------------------------------ + +String FilterConfigCache::GetExportFilterName( sal_uInt16 nFormat ) +{ + if( nFormat < aExport.size() ) + return aExport[ nFormat ].sFilterName; + return String::EmptyString(); +} + +sal_uInt16 FilterConfigCache::GetExportFormatNumber( const String& rFormatName ) +{ + CacheVector::iterator aIter( aExport.begin() ); + while ( aIter != aExport.end() ) + { + if ( aIter->sUIName.equalsIgnoreAsciiCase( rFormatName ) ) + break; + aIter++; + } + return sal::static_int_cast< sal_uInt16 >(aIter == aExport.end() ? GRFILTER_FORMAT_NOTFOUND : aIter - aExport.begin()); +} + +sal_uInt16 FilterConfigCache::GetExportFormatNumberForMediaType( const String& rMediaType ) +{ + CacheVector::iterator aIter( aExport.begin() ); + while ( aIter != aExport.end() ) + { + if ( aIter->sMediaType.equalsIgnoreAsciiCase( rMediaType ) ) + break; + aIter++; + } + return sal::static_int_cast< sal_uInt16 >(aIter == aExport.end() ? GRFILTER_FORMAT_NOTFOUND : aIter - aExport.begin()); +} + +sal_uInt16 FilterConfigCache::GetExportFormatNumberForShortName( const String& rShortName ) +{ + CacheVector::iterator aIter( aExport.begin() ); + while ( aIter != aExport.end() ) + { + if ( aIter->GetShortName().EqualsIgnoreCaseAscii( rShortName ) ) + break; + aIter++; + } + return sal::static_int_cast< sal_uInt16 >(aIter == aExport.end() ? GRFILTER_FORMAT_NOTFOUND : aIter - aExport.begin()); +} + +sal_uInt16 FilterConfigCache::GetExportFormatNumberForTypeName( const String& rType ) +{ + CacheVector::iterator aIter( aExport.begin() ); + while ( aIter != aExport.end() ) + { + if ( aIter->sType.equalsIgnoreAsciiCase( rType ) ) + break; + aIter++; + } + return sal::static_int_cast< sal_uInt16 >(aIter == aExport.end() ? GRFILTER_FORMAT_NOTFOUND : aIter - aExport.begin()); +} + +String FilterConfigCache::GetExportFormatName( sal_uInt16 nFormat ) +{ + if( nFormat < aExport.size() ) + return aExport[ nFormat ].sUIName; + return String::EmptyString(); +} + +String FilterConfigCache::GetExportFormatMediaType( sal_uInt16 nFormat ) +{ + if( nFormat < aExport.size() ) + return aExport[ nFormat ].sMediaType; + return String::EmptyString(); +} + +String FilterConfigCache::GetExportFormatShortName( sal_uInt16 nFormat ) +{ + if( nFormat < aExport.size() ) + return aExport[ nFormat ].GetShortName(); + return String::EmptyString(); +} + +String FilterConfigCache::GetExportFormatExtension( sal_uInt16 nFormat, sal_Int32 nEntry ) +{ + if ( (nFormat < aExport.size()) && (nEntry < aExport[ nFormat ].lExtensionList.getLength()) ) + return aExport[ nFormat ].lExtensionList[ nEntry ]; + return String::EmptyString(); +} + +String FilterConfigCache::GetExportFilterTypeName( sal_uInt16 nFormat ) +{ + if( nFormat < aExport.size() ) + return aExport[ nFormat ].sFilterType; + return String::EmptyString(); +} + +String FilterConfigCache::GetExportInternalFilterName( sal_uInt16 nFormat ) +{ + if( nFormat < aExport.size() ) + return aExport[ nFormat ].sInternalFilterName; + return String::EmptyString(); +} + +String FilterConfigCache::GetExportWildcard( sal_uInt16 nFormat, sal_Int32 nEntry ) +{ + String aWildcard( GetExportFormatExtension( nFormat, nEntry ) ); + if ( aWildcard.Len() ) + aWildcard.Insert( rtl::OUString("*."), 0 ); + return aWildcard; +} + +sal_Bool FilterConfigCache::IsExportInternalFilter( sal_uInt16 nFormat ) +{ + return (nFormat < aExport.size()) && aExport[ nFormat ].bIsInternalFilter; +} + +sal_Bool FilterConfigCache::IsExportPixelFormat( sal_uInt16 nFormat ) +{ + return (nFormat < aExport.size()) && aExport[ nFormat ].bIsPixelFormat; +} + +sal_Bool FilterConfigCache::IsExportDialog( sal_uInt16 nFormat ) +{ + return (nFormat < aExport.size()) && aExport[ nFormat ].bHasDialog; +} + +// ------------------------------------------------------------------------ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/FilterConfigCache.hxx b/vcl/source/filter/FilterConfigCache.hxx new file mode 100644 index 000000000000..b3f0022b05bb --- /dev/null +++ b/vcl/source/filter/FilterConfigCache.hxx @@ -0,0 +1,131 @@ +/* -*- 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 _FILTER_CONFIG_CACHE_HXX_ +#define _FILTER_CONFIG_CACHE_HXX_ + +#include <tools/string.hxx> +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/container/XNameAccess.hpp> + +#include <vector> + +class FilterConfigCache +{ + struct FilterConfigCacheEntry + { + ::rtl::OUString sInternalFilterName; + ::rtl::OUString sType; + ::com::sun::star::uno::Sequence< ::rtl::OUString > lExtensionList; + ::rtl::OUString sUIName; + ::rtl::OUString sDocumentService; + ::rtl::OUString sFilterService; + ::rtl::OUString sTemplateName; + + ::rtl::OUString sMediaType; + ::rtl::OUString sFilterType; + + sal_Int32 nFlags; + sal_Int32 nFileFormatVersion; + + // user data + String sFilterName; + sal_Bool bHasDialog : 1; + sal_Bool bIsInternalFilter : 1; + sal_Bool bIsPixelFormat : 1; + + sal_Bool CreateFilterName( const ::rtl::OUString& rUserDataEntry ); + String GetShortName( ); + + static const char* InternalPixelFilterNameList[]; + static const char* InternalVectorFilterNameList[]; + static const char* ExternalPixelFilterNameList[]; + }; + + typedef std::vector< FilterConfigCacheEntry > CacheVector; + + + CacheVector aImport; + CacheVector aExport; + sal_Bool bUseConfig; + + static sal_Bool bInitialized; + static sal_Int32 nIndType; + static sal_Int32 nIndUIName; + static sal_Int32 nIndDocumentService; + static sal_Int32 nIndFilterService; + static sal_Int32 nIndFlags; + static sal_Int32 nIndUserData; + static sal_Int32 nIndFileFormatVersion; + static sal_Int32 nIndTemplateName; + + static const char* InternalFilterListForSvxLight[]; + + void ImplInit(); + void ImplInitSmart(); + + public : + + sal_uInt16 GetImportFormatCount() const + { return sal::static_int_cast< sal_uInt16 >(aImport.size()); }; + sal_uInt16 GetImportFormatNumber( const String& rFormatName ); + sal_uInt16 GetImportFormatNumberForMediaType( const String& rMediaType ); + sal_uInt16 GetImportFormatNumberForShortName( const String& rShortName ); + sal_uInt16 GetImportFormatNumberForTypeName( const String& rType ); + String GetImportFilterName( sal_uInt16 nFormat ); + String GetImportFormatName( sal_uInt16 nFormat ); + String GetImportFormatExtension( sal_uInt16 nFormat, sal_Int32 nEntry = 0); + String GetImportFormatMediaType( sal_uInt16 nFormat ); + String GetImportFormatShortName( sal_uInt16 nFormat ); + String GetImportWildcard( sal_uInt16 nFormat, sal_Int32 nEntry ); + String GetImportFilterType( sal_uInt16 nFormat ); + String GetImportFilterTypeName( sal_uInt16 nFormat ); + + sal_Bool IsImportInternalFilter( sal_uInt16 nFormat ); + sal_Bool IsImportPixelFormat( sal_uInt16 nFormat ); + + sal_uInt16 GetExportFormatCount() const + { return sal::static_int_cast< sal_uInt16 >(aExport.size()); }; + sal_uInt16 GetExportFormatNumber( const String& rFormatName ); + sal_uInt16 GetExportFormatNumberForMediaType( const String& rMediaType ); + sal_uInt16 GetExportFormatNumberForShortName( const String& rShortName ); + sal_uInt16 GetExportFormatNumberForTypeName( const String& rType ); + String GetExportFilterName( sal_uInt16 nFormat ); + String GetExportFormatName( sal_uInt16 nFormat ); + String GetExportFormatExtension( sal_uInt16 nFormat, sal_Int32 nEntry = 0 ); + String GetExportFormatMediaType( sal_uInt16 nFormat ); + String GetExportFormatShortName( sal_uInt16 nFormat ); + String GetExportWildcard( sal_uInt16 nFormat, sal_Int32 nEntry ); + String GetExportFilterTypeName( sal_uInt16 nFormat ); + String GetExportInternalFilterName( sal_uInt16 nFormat ); + + sal_Bool IsExportInternalFilter( sal_uInt16 nFormat ); + sal_Bool IsExportPixelFormat( sal_uInt16 nFormat ); + sal_Bool IsExportDialog( sal_uInt16 nFormat ); + + FilterConfigCache( sal_Bool bUseConfig ); + ~FilterConfigCache(); + +}; + +#endif // _FILTER_CONFIG_CACHE_HXX_ + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/FilterConfigItem.cxx b/vcl/source/filter/FilterConfigItem.cxx new file mode 100644 index 000000000000..91310b367bed --- /dev/null +++ b/vcl/source/filter/FilterConfigItem.cxx @@ -0,0 +1,439 @@ +/* -*- 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 <svtools/FilterConfigItem.hxx> + +#include <unotools/configmgr.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/string.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/util/XChangesBatch.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/container/XHierarchicalNameAccess.hpp> + +using ::rtl::OUString; +using namespace ::utl ; // getProcessServiceFactory +using namespace ::com::sun::star::lang ; // XMultiServiceFactory +using namespace ::com::sun::star::beans ; // PropertyValue +using namespace ::com::sun::star::uno ; // Reference +using namespace ::com::sun::star::util ; // XChangesBatch +using namespace ::com::sun::star::awt ; // Size +using namespace ::com::sun::star::container ; // +using namespace ::com::sun::star::configuration; // +using namespace ::com::sun::star::task ; // XStatusIndicator + +static sal_Bool ImpIsTreeAvailable( Reference< XMultiServiceFactory >& rXCfgProv, const rtl::OUString& rTree ) +{ + sal_Bool bAvailable = !rTree.isEmpty(); + if ( bAvailable ) + { + using comphelper::string::getTokenCount; + using comphelper::string::getToken; + + sal_Int32 nTokenCount = getTokenCount(rTree, '/'); + sal_Int32 i = 0; + + if ( rTree[0] == '/' ) + ++i; + if ( rTree[rTree.getLength() - 1] == '/' ) + --nTokenCount; + + Any aAny; + aAny <<= getToken(rTree, i++, '/'); + + // creation arguments: nodepath + PropertyValue aPathArgument; + aPathArgument.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) ); + aPathArgument.Value = aAny; + + Sequence< Any > aArguments( 1 ); + aArguments[ 0 ] <<= aPathArgument; + + Reference< XInterface > xReadAccess; + try + { + xReadAccess = rXCfgProv->createInstanceWithArguments( + OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationAccess" ) ), + aArguments ); + } + catch (const ::com::sun::star::uno::Exception&) + { + bAvailable = sal_False; + } + if ( xReadAccess.is() ) + { + for ( ; bAvailable && ( i < nTokenCount ); i++ ) + { + Reference< XHierarchicalNameAccess > xHierarchicalNameAccess + ( xReadAccess, UNO_QUERY ); + + if ( !xHierarchicalNameAccess.is() ) + bAvailable = sal_False; + else + { + rtl::OUString aNode( getToken(rTree, i, '/') ); + if ( !xHierarchicalNameAccess->hasByHierarchicalName( aNode ) ) + bAvailable = sal_False; + else + { + Any a( xHierarchicalNameAccess->getByHierarchicalName( aNode ) ); + try + { + a >>= xReadAccess; + } + catch ( ::com::sun::star::uno::Exception& ) + { + bAvailable = sal_False; + } + } + } + } + } + } + return bAvailable; +} + +void FilterConfigItem::ImpInitTree( const String& rSubTree ) +{ + bModified = sal_False; + + Reference< XComponentContext > xContext( comphelper::getProcessComponentContext() ); + + Reference< XMultiServiceFactory > xCfgProv = theDefaultProvider::get( xContext ); + + OUString sTree( + OUString(RTL_CONSTASCII_USTRINGPARAM("/org.openoffice.")) + + rSubTree); + if ( ImpIsTreeAvailable(xCfgProv, sTree) ) + { + Any aAny; + // creation arguments: nodepath + PropertyValue aPathArgument; + aAny <<= sTree; + aPathArgument.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) ); + aPathArgument.Value = aAny; + + // creation arguments: commit mode + PropertyValue aModeArgument; + sal_Bool bAsyncron = sal_True; + aAny <<= bAsyncron; + aModeArgument.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "lazywrite" ) ); + aModeArgument.Value = aAny; + + Sequence< Any > aArguments( 2 ); + aArguments[ 0 ] <<= aPathArgument; + aArguments[ 1 ] <<= aModeArgument; + + try + { + xUpdatableView = xCfgProv->createInstanceWithArguments( + OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationUpdateAccess" ) ), + aArguments ); + if ( xUpdatableView.is() ) + xPropSet = Reference< XPropertySet >( xUpdatableView, UNO_QUERY ); + } + catch ( ::com::sun::star::uno::Exception& ) + { + OSL_FAIL( "FilterConfigItem::FilterConfigItem - Could not access configuration Key" ); + } + } +} + +FilterConfigItem::FilterConfigItem( const OUString& rSubTree ) +{ + ImpInitTree( rSubTree ); +} + +FilterConfigItem::FilterConfigItem( ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData ) +{ + if ( pFilterData ) + aFilterData = *pFilterData; +} + +FilterConfigItem::FilterConfigItem( const OUString& rSubTree, + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData ) +{ + ImpInitTree( rSubTree ); + + if ( pFilterData ) + aFilterData = *pFilterData; +}; + +FilterConfigItem::~FilterConfigItem() +{ + if ( xUpdatableView.is() ) + { + if ( xPropSet.is() && bModified ) + { + Reference< XChangesBatch > xUpdateControl( xUpdatableView, UNO_QUERY ); + if ( xUpdateControl.is() ) + { + try + { + xUpdateControl->commitChanges(); + } + catch ( ::com::sun::star::uno::Exception& ) + { + OSL_FAIL( "FilterConfigItem::FilterConfigItem - Could not update configuration data" ); + } + } + } + } +} + +sal_Bool FilterConfigItem::ImplGetPropertyValue( Any& rAny, const Reference< XPropertySet >& rXPropSet, const OUString& rString, sal_Bool bTestPropertyAvailability ) +{ + sal_Bool bRetValue = sal_True; + + if ( rXPropSet.is() ) + { + if ( bTestPropertyAvailability ) + { + bRetValue = sal_False; + try + { + Reference< XPropertySetInfo > + aXPropSetInfo( rXPropSet->getPropertySetInfo() ); + if ( aXPropSetInfo.is() ) + bRetValue = aXPropSetInfo->hasPropertyByName( rString ); + } + catch( ::com::sun::star::uno::Exception& ) + { + // + } + } + if ( bRetValue ) + { + try + { + rAny = rXPropSet->getPropertyValue( rString ); + if ( !rAny.hasValue() ) + bRetValue = sal_False; + } + catch( ::com::sun::star::uno::Exception& ) + { + bRetValue = sal_False; + } + } + } + else + bRetValue = sal_False; + return bRetValue; +} + + +// if property is available it returns a pointer, +// otherwise the result is null +PropertyValue* FilterConfigItem::GetPropertyValue( Sequence< PropertyValue >& rPropSeq, const OUString& rName ) +{ + PropertyValue* pPropValue = NULL; + + sal_Int32 i, nCount; + for ( i = 0, nCount = rPropSeq.getLength(); i < nCount; i++ ) + { + if ( rPropSeq[ i ].Name == rName ) + { + pPropValue = &rPropSeq[ i ]; + break; + } + } + return pPropValue; +} + +/* if PropertySequence already includes a PropertyValue using the same name, the + corresponding PropertyValue is replaced, otherwise the given PropertyValue + will be appended */ + +sal_Bool FilterConfigItem::WritePropertyValue( Sequence< PropertyValue >& rPropSeq, const PropertyValue& rPropValue ) +{ + sal_Bool bRet = sal_False; + if ( !rPropValue.Name.isEmpty() ) + { + sal_Int32 i, nCount; + for ( i = 0, nCount = rPropSeq.getLength(); i < nCount; i++ ) + { + if ( rPropSeq[ i ].Name == rPropValue.Name ) + break; + } + if ( i == nCount ) + rPropSeq.realloc( ++nCount ); + + rPropSeq[ i ] = rPropValue; + + bRet = sal_True; + } + return bRet; +} + +sal_Bool FilterConfigItem::ReadBool( const OUString& rKey, sal_Bool bDefault ) +{ + Any aAny; + sal_Bool bRetValue = bDefault; + PropertyValue* pPropVal = GetPropertyValue( aFilterData, rKey ); + if ( pPropVal ) + { + pPropVal->Value >>= bRetValue; + } + else if ( ImplGetPropertyValue( aAny, xPropSet, rKey, sal_True ) ) + { + aAny >>= bRetValue; + } + PropertyValue aBool; + aBool.Name = rKey; + aBool.Value <<= bRetValue; + WritePropertyValue( aFilterData, aBool ); + return bRetValue; +} + +sal_Int32 FilterConfigItem::ReadInt32( const OUString& rKey, sal_Int32 nDefault ) +{ + Any aAny; + sal_Int32 nRetValue = nDefault; + PropertyValue* pPropVal = GetPropertyValue( aFilterData, rKey ); + if ( pPropVal ) + { + pPropVal->Value >>= nRetValue; + } + else if ( ImplGetPropertyValue( aAny, xPropSet, rKey, sal_True ) ) + { + aAny >>= nRetValue; + } + PropertyValue aInt32; + aInt32.Name = rKey; + aInt32.Value <<= nRetValue; + WritePropertyValue( aFilterData, aInt32 ); + return nRetValue; +} + +OUString FilterConfigItem::ReadString( const OUString& rKey, const OUString& rDefault ) +{ + Any aAny; + OUString aRetValue( rDefault ); + PropertyValue* pPropVal = GetPropertyValue( aFilterData, rKey ); + if ( pPropVal ) + { + pPropVal->Value >>= aRetValue; + } + else if ( ImplGetPropertyValue( aAny, xPropSet, rKey, sal_True ) ) + { + aAny >>= aRetValue; + } + PropertyValue aString; + aString.Name = rKey; + aString.Value <<= aRetValue; + WritePropertyValue( aFilterData, aString ); + return aRetValue; +} + +void FilterConfigItem::WriteBool( const OUString& rKey, sal_Bool bNewValue ) +{ + PropertyValue aBool; + aBool.Name = rKey; + aBool.Value <<= bNewValue; + WritePropertyValue( aFilterData, aBool ); + + if ( xPropSet.is() ) + { + Any aAny; + if ( ImplGetPropertyValue( aAny, xPropSet, rKey, sal_True ) ) + { + sal_Bool bOldValue(sal_True); + if ( aAny >>= bOldValue ) + { + if ( bOldValue != bNewValue ) + { + aAny <<= bNewValue; + try + { + xPropSet->setPropertyValue( rKey, aAny ); + bModified = sal_True; + } + catch ( ::com::sun::star::uno::Exception& ) + { + OSL_FAIL( "FilterConfigItem::WriteBool - could not set PropertyValue" ); + } + } + } + } + } +} + +void FilterConfigItem::WriteInt32( const OUString& rKey, sal_Int32 nNewValue ) +{ + PropertyValue aInt32; + aInt32.Name = rKey; + aInt32.Value <<= nNewValue; + WritePropertyValue( aFilterData, aInt32 ); + + if ( xPropSet.is() ) + { + Any aAny; + + if ( ImplGetPropertyValue( aAny, xPropSet, rKey, sal_True ) ) + { + sal_Int32 nOldValue = 0; + if ( aAny >>= nOldValue ) + { + if ( nOldValue != nNewValue ) + { + aAny <<= nNewValue; + try + { + xPropSet->setPropertyValue( rKey, aAny ); + bModified = sal_True; + } + catch ( ::com::sun::star::uno::Exception& ) + { + OSL_FAIL( "FilterConfigItem::WriteInt32 - could not set PropertyValue" ); + } + } + } + } + } +} + +// ------------------------------------------------------------------------ + +Sequence< PropertyValue > FilterConfigItem::GetFilterData() const +{ + return aFilterData; +} + +// ------------------------------------------------------------------------ + +Reference< XStatusIndicator > FilterConfigItem::GetStatusIndicator() const +{ + Reference< XStatusIndicator > xStatusIndicator; + const rtl::OUString sStatusIndicator( RTL_CONSTASCII_USTRINGPARAM( "StatusIndicator" ) ); + + sal_Int32 i, nCount = aFilterData.getLength(); + for ( i = 0; i < nCount; i++ ) + { + if ( aFilterData[ i ].Name == sStatusIndicator ) + { + aFilterData[ i ].Value >>= xStatusIndicator; + break; + } + } + return xStatusIndicator; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/graphicfilter.cxx b/vcl/source/filter/graphicfilter.cxx new file mode 100644 index 000000000000..4839dfa1cc44 --- /dev/null +++ b/vcl/source/filter/graphicfilter.cxx @@ -0,0 +1,2449 @@ +/* -*- 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 <osl/mutex.hxx> +#include <comphelper/processfactory.hxx> +#include <comphelper/string.hxx> +#include <ucbhelper/content.hxx> +#include <cppuhelper/implbase1.hxx> +#include <tools/urlobj.hxx> +#include <vcl/salctype.hxx> +#include <vcl/pngread.hxx> +#include <vcl/pngwrite.hxx> +#include <vcl/svgdata.hxx> +#include <vcl/virdev.hxx> +#include <vcl/svapp.hxx> +#include <osl/file.hxx> +#include <svtools/filter.hxx> +#include "FilterConfigCache.hxx" +#include <svtools/FilterConfigItem.hxx> +#include <svtools/fltcall.hxx> +#include <svtools/wmf.hxx> +#include "gifread.hxx" +#include "jpeg.hxx" +#include "xbmread.hxx" +#include "xpmread.hxx" +#include <svl/solar.hrc> +#include <svtools/svtools.hrc> +#include "sgffilt.hxx" +#include "osl/module.hxx" +#include <com/sun/star/uno/Reference.h> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/uno/XInterface.hpp> +#include <com/sun/star/uno/XWeak.hpp> +#include <com/sun/star/uno/XAggregation.hpp> +#include <com/sun/star/lang/XTypeProvider.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/svg/XSVGWriter.hpp> +#include <com/sun/star/xml/sax/XDocumentHandler.hpp> +#include <com/sun/star/xml/sax/Writer.hpp> +#include <com/sun/star/ucb/CommandAbortedException.hpp> +#include <unotools/ucbstreamhelper.hxx> +#include <unotools/localfilehelper.hxx> +#include <rtl/bootstrap.hxx> +#include <rtl/instance.hxx> +#include <rtl/logfile.hxx> +#include <vcl/metaact.hxx> +#include <vector> + +#include "SvFilterOptionsDialog.hxx" + +#define PMGCHUNG_msOG 0x6d734f47 // Microsoft Office Animated GIF + +#define IMPORT_FUNCTION_NAME "GraphicImport" +#define EXPORT_FUNCTION_NAME "GraphicExport" + +// ----------- +// - statics - +// ----------- + +using namespace ::rtl; +using namespace ::com::sun::star; + +using comphelper::string::getTokenCount; +using comphelper::string::getToken; + +typedef ::std::vector< GraphicFilter* > FilterList_impl; +static FilterList_impl* pFilterHdlList = NULL; + +static ::osl::Mutex& getListMutex() +{ + static ::osl::Mutex s_aListProtection; + return s_aListProtection; +} + +// ------------------------- +// - ImpFilterOutputStream - +// ------------------------- + +class ImpFilterOutputStream : public ::cppu::WeakImplHelper1< ::com::sun::star::io::XOutputStream > +{ +protected: + + SvStream& mrStm; + + virtual void SAL_CALL writeBytes( const ::com::sun::star::uno::Sequence< sal_Int8 >& rData ) throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) { mrStm.Write( rData.getConstArray(), rData.getLength() ); } + virtual void SAL_CALL flush() throw (::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException) { mrStm.Flush(); } + virtual void SAL_CALL closeOutput() throw() {} + +public: + + ImpFilterOutputStream( SvStream& rStm ) : mrStm( rStm ) {} + ~ImpFilterOutputStream() {} +}; + +sal_Bool ImplDirEntryHelper::Exists( const INetURLObject& rObj ) +{ + sal_Bool bExists = sal_False; + + try + { + ::ucbhelper::Content aCnt( rObj.GetMainURL( INetURLObject::NO_DECODE ), + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >(), + comphelper::getProcessComponentContext() ); + + bExists = aCnt.isDocument(); + } + catch(const ::com::sun::star::ucb::CommandAbortedException&) + { + SAL_WARN( "svtools.filter", "CommandAbortedException" ); + } + catch(const ::com::sun::star::ucb::ContentCreationException&) + { + SAL_WARN( "svtools.filter", "ContentCreationException" ); + } + catch( ... ) + { + SAL_WARN( "svtools.filter", "Any other exception" ); + } + return bExists; +} + +// ----------------------------------------------------------------------------- + +void ImplDirEntryHelper::Kill( const String& rMainUrl ) +{ + try + { + ::ucbhelper::Content aCnt( rMainUrl, + ::com::sun::star::uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >(), + comphelper::getProcessComponentContext() ); + + aCnt.executeCommand( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "delete" )), + ::com::sun::star::uno::makeAny( sal_Bool( sal_True ) ) ); + } + catch(const ::com::sun::star::ucb::CommandAbortedException&) + { + SAL_WARN( "svtools.filter", "CommandAbortedException" ); + } + catch( ... ) + { + SAL_WARN( "svtools.filter", "Any other exception" ); + } +} + +// -------------------- +// - Helper functions - +// -------------------- + +//-------------------------------------------------------------------------- + +sal_uInt8* ImplSearchEntry( sal_uInt8* pSource, sal_uInt8* pDest, sal_uLong nComp, sal_uLong nSize ) +{ + while ( nComp-- >= nSize ) + { + sal_uLong i; + for ( i = 0; i < nSize; i++ ) + { + if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) ) + break; + } + if ( i == nSize ) + return pSource; + pSource++; + } + return NULL; +} + +//-------------------------------------------------------------------------- + +inline String ImpGetExtension( const String &rPath ) +{ + String aExt; + INetURLObject aURL( rPath ); + aExt = aURL.GetFileExtension().toAsciiUpperCase(); + return aExt; +} + +bool isPCT(SvStream& rStream, sal_uLong nStreamPos, sal_uLong nStreamLen) +{ + sal_uInt8 sBuf[3]; + // store number format + sal_uInt16 oldNumberFormat = rStream.GetNumberFormatInt(); + sal_uInt32 nOffset; // in ms documents the pict format is used without the first 512 bytes + for ( nOffset = 0; ( nOffset <= 512 ) && ( ( nStreamPos + nOffset + 14 ) <= nStreamLen ); nOffset += 512 ) + { + short y1,x1,y2,x2; + sal_Bool bdBoxOk = sal_True; + + rStream.Seek( nStreamPos + nOffset); + // size of the pict in version 1 pict ( 2bytes) : ignored + rStream.SeekRel(2); + // bounding box (bytes 2 -> 9) + rStream.SetNumberFormatInt(NUMBERFORMAT_INT_BIGENDIAN); + rStream >> y1 >> x1 >> y2 >> x2; + rStream.SetNumberFormatInt(oldNumberFormat); // reset format + + if (x1 > x2 || y1 > y2 || // bad bdbox + (x1 == x2 && y1 == y2) || // 1 pixel picture + x2-x1 > 2048 || y2-y1 > 2048 ) // picture anormaly big + bdBoxOk = sal_False; + + // read version op + rStream.Read( sBuf,3 ); + // see http://developer.apple.com/legacy/mac/library/documentation/mac/pdf/Imaging_With_QuickDraw/Appendix_A.pdf + // normal version 2 - page A23 and A24 + if ( sBuf[ 0 ] == 0x00 && sBuf[ 1 ] == 0x11 && sBuf[ 2 ] == 0x02) + return true; + // normal version 1 - page A25 + else if (sBuf[ 0 ] == 0x11 && sBuf[ 1 ] == 0x01 && bdBoxOk) + return true; + } + return false; +} + + +/************************************************************************* +|* +|* ImpPeekGraphicFormat() +|* +|* Beschreibung: +|* Diese Funktion kann zweierlei: +|* 1.) Datei anlesen, Dateiformat ermitteln +|* Eingabe-prarameter: +|* rPath - Dateipfad +|* rFormatExtension - Inhalt egal +|* bTest - setze sal_False +|* Ausgabe-parameter: +|* Funkionswert - sal_True wenn Erfolg +|* rFormatExtension - Bei Erfolg: uebliche Dateiendung +|* des Formats (Grossbuchstaben) +|* 2.) Datei anlesen, Dateiformat ueberpruefen +|* Eingabe-prarameter: +|* rPath - Dateipfad +|* rFormatExtension - uebliche Dateiendung des Formats +|* (Grossbuchstaben) +|* bTest - setze sal_True +|* Ausgabe-parameter: +|* Funkionswert - sal_False, wenn die Datei bestimmt nicht +|* vom uebgebenen Format ist. +|* sal_True, wenn die Datei WAHRSCHEINLICH von +|* dem Format ist, ODER WENN DAS FORMAT +|* DIESER FUNKTION NICHT BEKANNT IST! +|* +*************************************************************************/ + +static sal_Bool ImpPeekGraphicFormat( SvStream& rStream, String& rFormatExtension, sal_Bool bTest ) +{ + sal_uInt16 i; + sal_uInt8 sFirstBytes[ 256 ]; + sal_uLong nFirstLong,nSecondLong; + sal_uLong nStreamPos = rStream.Tell(); + + rStream.Seek( STREAM_SEEK_TO_END ); + sal_uLong nStreamLen = rStream.Tell() - nStreamPos; + rStream.Seek( nStreamPos ); + + if ( !nStreamLen ) + { + SvLockBytes* pLockBytes = rStream.GetLockBytes(); + if ( pLockBytes ) + pLockBytes->SetSynchronMode( sal_True ); + + rStream.Seek( STREAM_SEEK_TO_END ); + nStreamLen = rStream.Tell() - nStreamPos; + rStream.Seek( nStreamPos ); + } + if (!nStreamLen) + { + return false; // this prevents at least a STL assertion + } + else if (nStreamLen >= 256) + { // load first 256 bytes into a buffer + rStream.Read( sFirstBytes, 256 ); + } + else + { + rStream.Read( sFirstBytes, nStreamLen ); + + for( i = (sal_uInt16) nStreamLen; i < 256; i++ ) + sFirstBytes[ i ]=0; + } + + if( rStream.GetError() ) + return sal_False; + + // Die ersten 8 Bytes in nFirstLong, nSecondLong unterbringen, + // Big-Endian: + for( i = 0, nFirstLong = 0L, nSecondLong = 0L; i < 4; i++ ) + { + nFirstLong=(nFirstLong<<8)|(sal_uLong)sFirstBytes[i]; + nSecondLong=(nSecondLong<<8)|(sal_uLong)sFirstBytes[i+4]; + } + + // Folgende Variable ist nur bei bTest==sal_True interessant. Sie + // bleibt sal_False, wenn das Format (rFormatExtension) hier noch nicht + // einprogrammiert wurde. + sal_Bool bSomethingTested = sal_False; + + // Nun werden die verschieden Formate ueberprueft. Dabei ist die + // Reihenfolge nicht egal. Z.b. koennte eine MET-Datei auch durch + // den BMP-Test gehen, umgekehrt kann eine BMP-Datei kaum durch den + // MET-Test gehen. Also sollte MET vor BMP getestet werden. + // Theoretisch waere aber vielleicht auch eine BMP-Datei denkbar, + // die durch den MET-Test geht. + // Diese Probleme gibt es natuerlich nicht nur bei MET und BMP. + // Deshalb wird im Falle der Uberpruefung eines Formats (bTest==sal_True) + // nur genau dieses eine Format getestet. Alles andere koennte fatale + // Folgen haben, z.B. wenn der Benutzer sagt, es sei BMP-Datei (und es + // ist BMP-Datei), und hier wuerde die Datei durch den MET-Test gehen... + + //--------------------------- MET ------------------------------------ + if( !bTest || ( rFormatExtension.CompareToAscii( "MET", 3 ) == COMPARE_EQUAL ) ) + { + bSomethingTested=sal_True; + if( sFirstBytes[2] == 0xd3 ) + { + rStream.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN ); + rStream.Seek( nStreamPos ); + sal_uInt16 nFieldSize; + sal_uInt8 nMagic; + sal_Bool bOK=sal_True; + rStream >> nFieldSize >> nMagic; + for (i=0; i<3; i++) { + if (nFieldSize<6) { bOK=sal_False; break; } + if (nStreamLen < rStream.Tell() + nFieldSize ) { bOK=sal_False; break; } + rStream.SeekRel(nFieldSize-3); + rStream >> nFieldSize >> nMagic; + if (nMagic!=0xd3) { bOK=sal_False; break; } + } + rStream.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + if (bOK && !rStream.GetError()) { + rFormatExtension = rtl::OUString("MET"); + return sal_True; + } + } + } + + //--------------------------- BMP ------------------------------------ + if( !bTest || ( rFormatExtension.CompareToAscii( "BMP", 3 ) == COMPARE_EQUAL ) ) + { + sal_uInt8 nOffs; + + bSomethingTested=sal_True; + + // OS/2-Bitmaparray ('BA') koennen wir evtl. auch lesen, + // dementspr. muessen wir den Offset anpassen, + // um auf die erste Bitmap im Array zu stossen + if ( sFirstBytes[0] == 0x42 && sFirstBytes[1] == 0x41 ) + nOffs = 14; + else + nOffs = 0; + + // Jetzt testen wir zunaechst auf 'BM' + if ( sFirstBytes[0+nOffs]==0x42 && sFirstBytes[1+nOffs]==0x4d ) + { + // unter OS/2 koennen die Reserved-Flags != 0 sein + // (was sie eigentlich nicht duerften); + // in diesem Fall testen wir die Groesse des BmpInfoHeaders + if ( ( sFirstBytes[6+nOffs]==0x00 && + sFirstBytes[7+nOffs]==0x00 && + sFirstBytes[8+nOffs]==0x00 && + sFirstBytes[9+nOffs]==0x00 ) || + sFirstBytes[14+nOffs] == 0x28 || + sFirstBytes[14+nOffs] == 0x0c ) + { + rFormatExtension = rtl::OUString("BMP"); + return sal_True; + } + } + } + + //--------------------------- WMF/EMF ------------------------------------ + + if( !bTest || + ( rFormatExtension.CompareToAscii( "WMF", 3 ) == COMPARE_EQUAL ) || + ( rFormatExtension.CompareToAscii( "EMF", 3 ) == COMPARE_EQUAL ) ) + { + bSomethingTested = sal_True; + + if ( nFirstLong==0xd7cdc69a || nFirstLong==0x01000900 ) + { + rFormatExtension = rtl::OUString("WMF"); + return sal_True; + } + else if( nFirstLong == 0x01000000 && sFirstBytes[ 40 ] == 0x20 && sFirstBytes[ 41 ] == 0x45 && + sFirstBytes[ 42 ] == 0x4d && sFirstBytes[ 43 ] == 0x46 ) + { + rFormatExtension = rtl::OUString("EMF"); + return sal_True; + } + } + + //--------------------------- PCX ------------------------------------ + if( !bTest || ( rFormatExtension.CompareToAscii( "PCX", 3 ) == COMPARE_EQUAL ) ) + { + bSomethingTested=sal_True; + if (sFirstBytes[0]==0x0a) + { + sal_uInt8 nVersion=sFirstBytes[1]; + sal_uInt8 nEncoding=sFirstBytes[2]; + if( ( nVersion==0 || nVersion==2 || nVersion==3 || nVersion==5 ) && nEncoding<=1 ) + { + rFormatExtension = rtl::OUString("PCX"); + return sal_True; + } + } + } + + //--------------------------- TIF ------------------------------------ + if( !bTest || ( rFormatExtension.CompareToAscii( "TIF", 3 ) == COMPARE_EQUAL ) ) + { + bSomethingTested=sal_True; + if ( nFirstLong==0x49492a00 || nFirstLong==0x4d4d002a ) + { + rFormatExtension = rtl::OUString("TIF"); + return sal_True; + } + } + + //--------------------------- GIF ------------------------------------ + if( !bTest || ( rFormatExtension.CompareToAscii( "GIF", 3 ) == COMPARE_EQUAL ) ) + { + bSomethingTested=sal_True; + if ( nFirstLong==0x47494638 && (sFirstBytes[4]==0x37 || sFirstBytes[4]==0x39) && sFirstBytes[5]==0x61 ) + { + rFormatExtension = rtl::OUString("GIF"); + return sal_True; + } + } + + //--------------------------- PNG ------------------------------------ + if( !bTest || ( rFormatExtension.CompareToAscii( "PNG", 3 ) == COMPARE_EQUAL ) ) + { + bSomethingTested=sal_True; + if (nFirstLong==0x89504e47 && nSecondLong==0x0d0a1a0a) + { + rFormatExtension = rtl::OUString("PNG"); + return sal_True; + } + } + + //--------------------------- JPG ------------------------------------ + if( !bTest || ( rFormatExtension.CompareToAscii( "JPG", 3 ) == COMPARE_EQUAL ) ) + { + bSomethingTested=sal_True; + if ( ( nFirstLong==0xffd8ffe0 && sFirstBytes[6]==0x4a && sFirstBytes[7]==0x46 && sFirstBytes[8]==0x49 && sFirstBytes[9]==0x46 ) || + ( nFirstLong==0xffd8fffe ) || ( 0xffd8ff00 == ( nFirstLong & 0xffffff00 ) ) ) + { + rFormatExtension = rtl::OUString("JPG"); + return sal_True; + } + } + + //--------------------------- SVM ------------------------------------ + if( !bTest || ( rFormatExtension.CompareToAscii( "SVM", 3 ) == COMPARE_EQUAL ) ) + { + bSomethingTested=sal_True; + if( nFirstLong==0x53564744 && sFirstBytes[4]==0x49 ) + { + rFormatExtension = rtl::OUString("SVM"); + return sal_True; + } + else if( sFirstBytes[0]==0x56 && sFirstBytes[1]==0x43 && sFirstBytes[2]==0x4C && + sFirstBytes[3]==0x4D && sFirstBytes[4]==0x54 && sFirstBytes[5]==0x46 ) + { + rFormatExtension = rtl::OUString("SVM"); + return sal_True; + } + } + + //--------------------------- PCD ------------------------------------ + if( !bTest || ( rFormatExtension.CompareToAscii( "PCD", 3 ) == COMPARE_EQUAL ) ) + { + bSomethingTested = sal_True; + if( nStreamLen >= 2055 ) + { + char sBuf[8]; + rStream.Seek( nStreamPos + 2048 ); + rStream.Read( sBuf, 7 ); + + if( strncmp( sBuf, "PCD_IPI", 7 ) == 0 ) + { + rFormatExtension = rtl::OUString("PCD"); + return sal_True; + } + } + } + + //--------------------------- PSD ------------------------------------ + if( !bTest || ( rFormatExtension.CompareToAscii( "PSD", 3 ) == COMPARE_EQUAL ) ) + { + bSomethingTested = sal_True; + if ( ( nFirstLong == 0x38425053 ) && ( (nSecondLong >> 16 ) == 1 ) ) + { + rFormatExtension = rtl::OUString("PSD"); + return sal_True; + } + } + + //--------------------------- EPS ------------------------------------ + if( !bTest || ( rFormatExtension.CompareToAscii( "EPS", 3 ) == COMPARE_EQUAL ) ) + { + bSomethingTested = sal_True; + if ( ( nFirstLong == 0xC5D0D3C6 ) || ( ImplSearchEntry( sFirstBytes, (sal_uInt8*)"%!PS-Adobe", 10, 10 ) && + ImplSearchEntry( &sFirstBytes[15], (sal_uInt8*)"EPS", 3, 3 ) ) ) + { + rFormatExtension = rtl::OUString("EPS"); + return sal_True; + } + } + + //--------------------------- DXF ------------------------------------ + if( !bTest || ( rFormatExtension.CompareToAscii( "DXF", 3 ) == COMPARE_EQUAL ) ) + { + //Binary DXF File Format + if( strncmp( (const char*) sFirstBytes, "AutoCAD Binary DXF", 18 ) == 0 ) + { + rFormatExtension = rtl::OUString("DXF"); + return sal_True; + } + + //ASCII DXF File Format + i=0; + while (i<256 && sFirstBytes[i]<=32) + ++i; + + if (i<256 && sFirstBytes[i]=='0') + { + ++i; + + //only now do we have sufficient data to make a judgement + //based on a '0' + 'SECTION' == DXF argument + bSomethingTested=sal_True; + + while( i<256 && sFirstBytes[i]<=32 ) + ++i; + + if (i+7<256 && (strncmp((const char*)(sFirstBytes+i),"SECTION",7)==0)) + { + rFormatExtension = rtl::OUString("DXF"); + return sal_True; + } + } + + } + + //--------------------------- PCT ------------------------------------ + if( !bTest || ( rFormatExtension.CompareToAscii( "PCT", 3 ) == COMPARE_EQUAL ) ) + { + bSomethingTested = sal_True; + if (isPCT(rStream, nStreamPos, nStreamLen)) + { + rFormatExtension = rtl::OUString("PCT"); + return sal_True; + } + } + + //------------------------- PBM + PGM + PPM --------------------------- + if( !bTest || + ( rFormatExtension.CompareToAscii( "PBM", 3 ) == COMPARE_EQUAL ) || + ( rFormatExtension.CompareToAscii( "PGM", 3 ) == COMPARE_EQUAL ) || + ( rFormatExtension.CompareToAscii( "PPM", 3 ) == COMPARE_EQUAL ) ) + { + bSomethingTested=sal_True; + if ( sFirstBytes[ 0 ] == 'P' ) + { + switch( sFirstBytes[ 1 ] ) + { + case '1' : + case '4' : + rFormatExtension = rtl::OUString("PBM"); + return sal_True; + + case '2' : + case '5' : + rFormatExtension = rtl::OUString("PGM"); + return sal_True; + + case '3' : + case '6' : + rFormatExtension = rtl::OUString("PPM"); + return sal_True; + } + } + } + + //--------------------------- RAS( SUN RasterFile )------------------ + if( !bTest || ( rFormatExtension.CompareToAscii( "RAS", 3 ) == COMPARE_EQUAL ) ) + { + bSomethingTested=sal_True; + if( nFirstLong == 0x59a66a95 ) + { + rFormatExtension = rtl::OUString("RAS"); + return sal_True; + } + } + + //--------------------------- XPM ------------------------------------ + if( !bTest ) + { + bSomethingTested = sal_True; + if( ImplSearchEntry( sFirstBytes, (sal_uInt8*)"/* XPM */", 256, 9 ) ) + { + rFormatExtension = rtl::OUString("XPM"); + return sal_True; + } + } + else if( rFormatExtension.CompareToAscii( "XPM", 3 ) == COMPARE_EQUAL ) + { + bSomethingTested = sal_True; + return sal_True; + } + + //--------------------------- XBM ------------------------------------ + if( !bTest ) + { + sal_uLong nSize = ( nStreamLen > 2048 ) ? 2048 : nStreamLen; + sal_uInt8* pBuf = new sal_uInt8 [ nSize ]; + + rStream.Seek( nStreamPos ); + rStream.Read( pBuf, nSize ); + sal_uInt8* pPtr = ImplSearchEntry( pBuf, (sal_uInt8*)"#define", nSize, 7 ); + + if( pPtr ) + { + if( ImplSearchEntry( pPtr, (sal_uInt8*)"_width", pBuf + nSize - pPtr, 6 ) ) + { + rFormatExtension = rtl::OUString("XBM"); + delete[] pBuf; + return sal_True; + } + } + delete[] pBuf; + } + else if( rFormatExtension.CompareToAscii( "XBM", 3 ) == COMPARE_EQUAL ) + { + bSomethingTested = sal_True; + return sal_True; + } + + //--------------------------- SVG ------------------------------------ + if( !bTest ) + { + // check for Xml + if( ImplSearchEntry( sFirstBytes, (sal_uInt8*)"<?xml", 256, 5 ) // is it xml + && ImplSearchEntry( sFirstBytes, (sal_uInt8*)"version", 256, 7 )) // does it have a version (required for xml) + { + bool bIsSvg(false); + + // check for DOCTYPE svg combination + if( ImplSearchEntry( sFirstBytes, (sal_uInt8*)"DOCTYPE", 256, 7 ) // 'DOCTYPE' is there + && ImplSearchEntry( sFirstBytes, (sal_uInt8*)"svg", 256, 3 )) // 'svg' is there + { + bIsSvg = true; + } + + // check for svg element in 1st 256 bytes + if(!bIsSvg && ImplSearchEntry( sFirstBytes, (sal_uInt8*)"<svg", 256, 4 )) // '<svg' + { + bIsSvg = true; + } + + if(!bIsSvg) + { + // it's a xml, look for '<svg' in full file. Should not happen too + // often since the tests above will handle most cases, but can happen + // with Svg files containing big comment headers or Svg as the host + // language + const sal_uLong nSize((nStreamLen > 2048) ? 2048 : nStreamLen); + sal_uInt8* pBuf = new sal_uInt8[nSize]; + + rStream.Seek(nStreamPos); + rStream.Read(pBuf, nSize); + + if(ImplSearchEntry(pBuf, (sal_uInt8*)"<svg", nSize, 4)) // '<svg' + { + bIsSvg = true; + } + + delete[] pBuf; + } + + if(bIsSvg) + { + rFormatExtension = OUString( "SVG" ); + return sal_True; + } + } + else + { + // #119176# Svg files which have no xml header at all have shown up, + // detect those, too + bool bIsSvg(false); + + // check for svg element in 1st 256 bytes + if(ImplSearchEntry( sFirstBytes, (sal_uInt8*)"<svg", 256, 4 )) // '<svg' + { + bIsSvg = true; + } + + if(!bIsSvg) + { + // look for '<svg' in full file. Should not happen too + // often since the tests above will handle most cases, but can happen + // with Svg files containing big comment headers or Svg as the host + // language + const sal_uLong nSize((nStreamLen > 2048) ? 2048 : nStreamLen); + sal_uInt8* pBuf = new sal_uInt8[nSize]; + + rStream.Seek(nStreamPos); + rStream.Read(pBuf, nSize); + + if(ImplSearchEntry(pBuf, (sal_uInt8*)"<svg", nSize, 4)) // '<svg' + { + bIsSvg = true; + } + + delete[] pBuf; + } + + if(bIsSvg) + { + rFormatExtension = OUString( "SVG" ); + return sal_True; + } + } + } + else if( rFormatExtension.CompareToAscii( "SVG", 3 ) == COMPARE_EQUAL ) + { + bSomethingTested = sal_True; + return sal_True; + } + + //--------------------------- TGA ------------------------------------ + if( !bTest || ( rFormatExtension.CompareToAscii( "TGA", 3 ) == COMPARE_EQUAL ) ) + { + bSomethingTested = sal_True; + + // just a simple test for the extension + if( rFormatExtension.CompareToAscii( "TGA", 3 ) == COMPARE_EQUAL ) + return sal_True; + } + + //--------------------------- SGV ------------------------------------ + if( !bTest || ( rFormatExtension.CompareToAscii( "SGV", 3 ) == COMPARE_EQUAL ) ) + { + bSomethingTested = sal_True; + + // just a simple test for the extension + if( rFormatExtension.CompareToAscii( "SGV", 3 ) == COMPARE_EQUAL ) + return sal_True; + } + + //--------------------------- SGF ------------------------------------ + if( !bTest || ( rFormatExtension.CompareToAscii( "SGF", 3 ) == COMPARE_EQUAL ) ) + { + bSomethingTested=sal_True; + if( sFirstBytes[ 0 ] == 'J' && sFirstBytes[ 1 ] == 'J' ) + { + rFormatExtension = rtl::OUString("SGF"); + return sal_True; + } + } + + return bTest && !bSomethingTested; +} + +//-------------------------------------------------------------------------- + +sal_uInt16 GraphicFilter::ImpTestOrFindFormat( const String& rPath, SvStream& rStream, sal_uInt16& rFormat ) +{ + sal_uInt16 n = pConfig->GetImportFormatCount(); + + // ggf. Filter bzw. Format durch anlesen ermitteln, + // oder durch anlesen zusichern, dass das Format stimmt: + if( rFormat == GRFILTER_FORMAT_DONTKNOW ) + { + String aFormatExt; + if( ImpPeekGraphicFormat( rStream, aFormatExt, sal_False ) ) + { + for( sal_uInt16 i = 0; i < n; i++ ) + { + if( pConfig->GetImportFormatExtension( i ).EqualsIgnoreCaseAscii( aFormatExt ) ) + { + rFormat = i; + return GRFILTER_OK; + } + } + } + // ggf. Filter anhand der Datei-Endung raussuchen: + if( rPath.Len() ) + { + String aExt( ImpGetExtension( rPath ) ); + for( sal_uInt16 i = 0; i < n; i++ ) + { + if( pConfig->GetImportFormatExtension( i ).EqualsIgnoreCaseAscii( aExt ) ) + { + rFormat = i; + return GRFILTER_OK; + } + } + } + return GRFILTER_FORMATERROR; + } + else + { + String aTmpStr( pConfig->GetImportFormatExtension( rFormat ) ); + if( !ImpPeekGraphicFormat( rStream, aTmpStr.ToUpperAscii(), sal_True ) ) + return GRFILTER_FORMATERROR; + if ( pConfig->GetImportFormatExtension( rFormat ).EqualsIgnoreCaseAscii( "pcd" ) ) + { + sal_Int32 nBase = 2; // default Base0 + if ( pConfig->GetImportFilterType( rFormat ).EqualsIgnoreCaseAscii( "pcd_Photo_CD_Base4" ) ) + nBase = 1; + else if ( pConfig->GetImportFilterType( rFormat ).EqualsIgnoreCaseAscii( "pcd_Photo_CD_Base16" ) ) + nBase = 0; + String aFilterConfigPath( RTL_CONSTASCII_USTRINGPARAM( "Office.Common/Filter/Graphic/Import/PCD" ) ); + FilterConfigItem aFilterConfigItem( aFilterConfigPath ); + aFilterConfigItem.WriteInt32( String( RTL_CONSTASCII_USTRINGPARAM( "Resolution" ) ), nBase ); + } + } + + return GRFILTER_OK; +} + +//-------------------------------------------------------------------------- + +#ifndef DISABLE_EXPORT + +static Graphic ImpGetScaledGraphic( const Graphic& rGraphic, FilterConfigItem& rConfigItem ) +{ + Graphic aGraphic; + + ResMgr* pResMgr = ResMgr::CreateResMgr( "svt", Application::GetSettings().GetUILanguageTag().getLocale() ); + + sal_Int32 nLogicalWidth = rConfigItem.ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( "LogicalWidth" ) ), 0 ); + sal_Int32 nLogicalHeight = rConfigItem.ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( "LogicalHeight" ) ), 0 ); + + if ( rGraphic.GetType() != GRAPHIC_NONE ) + { + sal_Int32 nMode = rConfigItem.ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( "ExportMode" ) ), -1 ); + + if ( nMode == -1 ) // the property is not there, this is possible, if the graphic filter + { // is called via UnoGraphicExporter and not from a graphic export Dialog + nMode = 0; // then we are defaulting this mode to 0 + if ( nLogicalWidth || nLogicalHeight ) + nMode = 2; + } + + + Size aOriginalSize; + Size aPrefSize( rGraphic.GetPrefSize() ); + MapMode aPrefMapMode( rGraphic.GetPrefMapMode() ); + if ( aPrefMapMode == MAP_PIXEL ) + aOriginalSize = Application::GetDefaultDevice()->PixelToLogic( aPrefSize, MAP_100TH_MM ); + else + aOriginalSize = Application::GetDefaultDevice()->LogicToLogic( aPrefSize, aPrefMapMode, MAP_100TH_MM ); + if ( !nLogicalWidth ) + nLogicalWidth = aOriginalSize.Width(); + if ( !nLogicalHeight ) + nLogicalHeight = aOriginalSize.Height(); + if( rGraphic.GetType() == GRAPHIC_BITMAP ) + { + + // Aufloesung wird eingestellt + if( nMode == 1 ) + { + Bitmap aBitmap( rGraphic.GetBitmap() ); + MapMode aMap( MAP_100TH_INCH ); + + sal_Int32 nDPI = rConfigItem.ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( "Resolution" ) ), 75 ); + Fraction aFrac( 1, Min( Max( nDPI, sal_Int32( 75 ) ), sal_Int32( 600 ) ) ); + + aMap.SetScaleX( aFrac ); + aMap.SetScaleY( aFrac ); + + Size aOldSize = aBitmap.GetSizePixel(); + aGraphic = rGraphic; + aGraphic.SetPrefMapMode( aMap ); + aGraphic.SetPrefSize( Size( aOldSize.Width() * 100, + aOldSize.Height() * 100 ) ); + } + // Groesse wird eingestellt + else if( nMode == 2 ) + { + aGraphic = rGraphic; + aGraphic.SetPrefMapMode( MapMode( MAP_100TH_MM ) ); + aGraphic.SetPrefSize( Size( nLogicalWidth, nLogicalHeight ) ); + } + else + aGraphic = rGraphic; + + sal_Int32 nColors = rConfigItem.ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( "Color" ) ), 0 ); // #92767# + if ( nColors ) // graphic conversion necessary ? + { + BitmapEx aBmpEx( aGraphic.GetBitmapEx() ); + aBmpEx.Convert( (BmpConversion)nColors ); // the entries in the xml section have the same meaning as + aGraphic = aBmpEx; // they have in the BmpConversion enum, so it should be + } // allowed to cast them + } + else + { + if( ( nMode == 1 ) || ( nMode == 2 ) ) + { + GDIMetaFile aMtf( rGraphic.GetGDIMetaFile() ); + ::com::sun::star::awt::Size aDefaultSize( 10000, 10000 ); + Size aNewSize( OutputDevice::LogicToLogic( Size( nLogicalWidth, nLogicalHeight ), MAP_100TH_MM, aMtf.GetPrefMapMode() ) ); + + if( aNewSize.Width() && aNewSize.Height() ) + { + const Size aPreferredSize( aMtf.GetPrefSize() ); + aMtf.Scale( Fraction( aNewSize.Width(), aPreferredSize.Width() ), + Fraction( aNewSize.Height(), aPreferredSize.Height() ) ); + } + aGraphic = Graphic( aMtf ); + } + else + aGraphic = rGraphic; + } + + } + else + aGraphic = rGraphic; + + delete pResMgr; + + return aGraphic; +} + +#endif + +static String ImpCreateFullFilterPath( const String& rPath, const String& rFilterName ) +{ + ::rtl::OUString aPathURL; + + ::osl::FileBase::getFileURLFromSystemPath( rPath, aPathURL ); + aPathURL += rtl::OUString( '/' ); + + ::rtl::OUString aSystemPath; + ::osl::FileBase::getSystemPathFromFileURL( aPathURL, aSystemPath ); + aSystemPath += ::rtl::OUString( rFilterName ); + + return String( aSystemPath ); +} + + +// -------------------------- +// - ImpFilterLibCacheEntry - +// -------------------------- + +class ImpFilterLibCache; + +struct ImpFilterLibCacheEntry +{ + ImpFilterLibCacheEntry* mpNext; +#ifndef DISABLE_DYNLOADING + osl::Module maLibrary; +#endif + String maFiltername; + PFilterCall mpfnImport; + PFilterDlgCall mpfnImportDlg; + + ImpFilterLibCacheEntry( const String& rPathname, const String& rFiltername ); + int operator==( const String& rFiltername ) const { return maFiltername == rFiltername; } + + PFilterCall GetImportFunction(); +}; + +// ------------------------------------------------------------------------ + +ImpFilterLibCacheEntry::ImpFilterLibCacheEntry( const String& rPathname, const String& rFiltername ) : + mpNext ( NULL ), +#ifndef DISABLE_DYNLOADING + maLibrary ( rPathname ), +#endif + maFiltername ( rFiltername ), + mpfnImport ( NULL ), + mpfnImportDlg ( NULL ) +{ +#ifdef DISABLE_DYNLOADING + (void) rPathname; +#endif +} + +// ------------------------------------------------------------------------ + +#ifdef DISABLE_DYNLOADING + +extern "C" sal_Bool icdGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool idxGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool imeGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool ipbGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool ipdGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool ipsGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool iptGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool ipxGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool iraGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool itgGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool itiGraphicImport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); + +#endif + +PFilterCall ImpFilterLibCacheEntry::GetImportFunction() +{ + if( !mpfnImport ) + { +#ifndef DISABLE_DYNLOADING + mpfnImport = (PFilterCall) maLibrary.getFunctionSymbol(rtl::OUString(IMPORT_FUNCTION_NAME)); +#else + if( maFiltername.EqualsAscii( "icd" ) ) + mpfnImport = icdGraphicImport; + else if( maFiltername.EqualsAscii( "idx" ) ) + mpfnImport = idxGraphicImport; + else if( maFiltername.EqualsAscii( "ime" ) ) + mpfnImport = imeGraphicImport; + else if( maFiltername.EqualsAscii( "ipb" ) ) + mpfnImport = ipbGraphicImport; + else if( maFiltername.EqualsAscii( "ipd" ) ) + mpfnImport = ipdGraphicImport; + else if( maFiltername.EqualsAscii( "ips" ) ) + mpfnImport = ipsGraphicImport; + else if( maFiltername.EqualsAscii( "ipt" ) ) + mpfnImport = iptGraphicImport; + else if( maFiltername.EqualsAscii( "ipx" ) ) + mpfnImport = ipxGraphicImport; + else if( maFiltername.EqualsAscii( "ira" ) ) + mpfnImport = iraGraphicImport; + else if( maFiltername.EqualsAscii( "itg" ) ) + mpfnImport = itgGraphicImport; + else if( maFiltername.EqualsAscii( "iti" ) ) + mpfnImport = itiGraphicImport; +#endif + } + + return mpfnImport; +} + +// ------------------------------------------------------------------------ + +// --------------------- +// - ImpFilterLibCache - +// --------------------- + +class ImpFilterLibCache +{ + ImpFilterLibCacheEntry* mpFirst; + ImpFilterLibCacheEntry* mpLast; + +public: + ImpFilterLibCache(); + ~ImpFilterLibCache(); + + ImpFilterLibCacheEntry* GetFilter( const String& rFilterPath, const String& rFiltername ); +}; + +// ------------------------------------------------------------------------ + +ImpFilterLibCache::ImpFilterLibCache() : + mpFirst ( NULL ), + mpLast ( NULL ) +{ +} + +// ------------------------------------------------------------------------ + +ImpFilterLibCache::~ImpFilterLibCache() +{ + ImpFilterLibCacheEntry* pEntry = mpFirst; + while( pEntry ) + { + ImpFilterLibCacheEntry* pNext = pEntry->mpNext; + delete pEntry; + pEntry = pNext; + } +} + +// ------------------------------------------------------------------------ + +ImpFilterLibCacheEntry* ImpFilterLibCache::GetFilter( const String& rFilterPath, const String& rFilterName ) +{ + ImpFilterLibCacheEntry* pEntry = mpFirst; + + while( pEntry ) + { + if( *pEntry == rFilterName ) + break; + else + pEntry = pEntry->mpNext; + } + if( !pEntry ) + { + String aPhysicalName( ImpCreateFullFilterPath( rFilterPath, rFilterName ) ); + pEntry = new ImpFilterLibCacheEntry( aPhysicalName, rFilterName ); +#ifndef DISABLE_DYNLOADING + if ( pEntry->maLibrary.is() ) +#endif + { + if( !mpFirst ) + mpFirst = mpLast = pEntry; + else + mpLast = mpLast->mpNext = pEntry; + } +#ifndef DISABLE_DYNLOADING + else + { + delete pEntry; + pEntry = NULL; + } +#endif + } + return pEntry; +}; + +// ------------------------------------------------------------------------ + +namespace { struct Cache : public rtl::Static<ImpFilterLibCache, Cache> {}; } + +// ----------------- +// - GraphicFilter - +// ----------------- + +GraphicFilter::GraphicFilter( sal_Bool bConfig ) : + bUseConfig ( bConfig ), + nExpGraphHint ( 0 ) +{ + ImplInit(); +} + +// ------------------------------------------------------------------------ + +GraphicFilter::~GraphicFilter() +{ + { + ::osl::MutexGuard aGuard( getListMutex() ); + for( + FilterList_impl::iterator it = pFilterHdlList->begin(); + it != pFilterHdlList->end(); + ++it + ) { + if( *it == this ) + { + pFilterHdlList->erase( it ); + break; + } + } + if( pFilterHdlList->empty() ) + { + delete pFilterHdlList, pFilterHdlList = NULL; + delete pConfig; + } + } + + delete pErrorEx; +} + +// ------------------------------------------------------------------------ + +void GraphicFilter::ImplInit() +{ + { + ::osl::MutexGuard aGuard( getListMutex() ); + + if ( !pFilterHdlList ) + { + pFilterHdlList = new FilterList_impl; + pConfig = new FilterConfigCache( bUseConfig ); + } + else + pConfig = pFilterHdlList->front()->pConfig; + + pFilterHdlList->push_back( this ); + } + + if( bUseConfig ) + { + rtl::OUString url(RTL_CONSTASCII_USTRINGPARAM("$BRAND_BASE_DIR/program")); + rtl::Bootstrap::expandMacros(url); //TODO: detect failure + utl::LocalFileHelper::ConvertURLToPhysicalName(url, aFilterPath); + } + + pErrorEx = new FilterErrorEx; + bAbort = sal_False; +} + +// ------------------------------------------------------------------------ + +sal_uLong GraphicFilter::ImplSetError( sal_uLong nError, const SvStream* pStm ) +{ + pErrorEx->nFilterError = nError; + pErrorEx->nStreamError = pStm ? pStm->GetError() : ERRCODE_NONE; + return nError; +} +// ------------------------------------------------------------------------ + +sal_uInt16 GraphicFilter::GetImportFormatCount() +{ + return pConfig->GetImportFormatCount(); +} + +// ------------------------------------------------------------------------ + +sal_uInt16 GraphicFilter::GetImportFormatNumber( const String& rFormatName ) +{ + return pConfig->GetImportFormatNumber( rFormatName ); +} + +// ------------------------------------------------------------------------ + +sal_uInt16 GraphicFilter::GetImportFormatNumberForMediaType( const String& rMediaType ) +{ + return pConfig->GetImportFormatNumberForMediaType( rMediaType ); +} + +// ------------------------------------------------------------------------ + +sal_uInt16 GraphicFilter::GetImportFormatNumberForShortName( const String& rShortName ) +{ + return pConfig->GetImportFormatNumberForShortName( rShortName ); +} + +// ------------------------------------------------------------------------ + +sal_uInt16 GraphicFilter::GetImportFormatNumberForTypeName( const String& rType ) +{ + return pConfig->GetImportFormatNumberForTypeName( rType ); +} + +// ------------------------------------------------------------------------ + +String GraphicFilter::GetImportFormatName( sal_uInt16 nFormat ) +{ + return pConfig->GetImportFormatName( nFormat ); +} + +// ------------------------------------------------------------------------ + +String GraphicFilter::GetImportFormatTypeName( sal_uInt16 nFormat ) +{ + return pConfig->GetImportFilterTypeName( nFormat ); +} + +// ------------------------------------------------------------------------ + +String GraphicFilter::GetImportFormatMediaType( sal_uInt16 nFormat ) +{ + return pConfig->GetImportFormatMediaType( nFormat ); +} + +// ------------------------------------------------------------------------ + +String GraphicFilter::GetImportFormatShortName( sal_uInt16 nFormat ) +{ + return pConfig->GetImportFormatShortName( nFormat ); +} + +// ------------------------------------------------------------------------ + +String GraphicFilter::GetImportOSFileType( sal_uInt16 ) +{ + String aOSFileType; + return aOSFileType; +} + +// ------------------------------------------------------------------------ + +String GraphicFilter::GetImportWildcard( sal_uInt16 nFormat, sal_Int32 nEntry ) +{ + return pConfig->GetImportWildcard( nFormat, nEntry ); +} + +// ------------------------------------------------------------------------ + +sal_Bool GraphicFilter::IsImportPixelFormat( sal_uInt16 nFormat ) +{ + return pConfig->IsImportPixelFormat( nFormat ); +} + +// ------------------------------------------------------------------------ + +sal_uInt16 GraphicFilter::GetExportFormatCount() +{ + return pConfig->GetExportFormatCount(); +} + +// ------------------------------------------------------------------------ + +sal_uInt16 GraphicFilter::GetExportFormatNumber( const String& rFormatName ) +{ + return pConfig->GetExportFormatNumber( rFormatName ); +} + +// ------------------------------------------------------------------------ + +sal_uInt16 GraphicFilter::GetExportFormatNumberForMediaType( const String& rMediaType ) +{ + return pConfig->GetExportFormatNumberForMediaType( rMediaType ); +} + +// ------------------------------------------------------------------------ + +sal_uInt16 GraphicFilter::GetExportFormatNumberForShortName( const String& rShortName ) +{ + return pConfig->GetExportFormatNumberForShortName( rShortName ); +} + +// ------------------------------------------------------------------------ + +sal_uInt16 GraphicFilter::GetExportFormatNumberForTypeName( const String& rType ) +{ + return pConfig->GetExportFormatNumberForTypeName( rType ); +} + +// ------------------------------------------------------------------------ + +String GraphicFilter::GetExportFormatName( sal_uInt16 nFormat ) +{ + return pConfig->GetExportFormatName( nFormat ); +} + +// ------------------------------------------------------------------------ + +String GraphicFilter::GetExportFormatTypeName( sal_uInt16 nFormat ) +{ + return pConfig->GetExportFilterTypeName( nFormat ); +} + +// ------------------------------------------------------------------------ + +String GraphicFilter::GetExportFormatMediaType( sal_uInt16 nFormat ) +{ + return pConfig->GetExportFormatMediaType( nFormat ); +} + +// ------------------------------------------------------------------------ + +String GraphicFilter::GetExportFormatShortName( sal_uInt16 nFormat ) +{ + return pConfig->GetExportFormatShortName( nFormat ); +} + +// ------------------------------------------------------------------------ + +String GraphicFilter::GetExportOSFileType( sal_uInt16 ) +{ + String aOSFileType; + return aOSFileType; +} + +// ------------------------------------------------------------------------ + +String GraphicFilter::GetExportWildcard( sal_uInt16 nFormat, sal_Int32 nEntry ) +{ + return pConfig->GetExportWildcard( nFormat, nEntry ); +} + +// ------------------------------------------------------------------------ + +sal_Bool GraphicFilter::IsExportPixelFormat( sal_uInt16 nFormat ) +{ + return pConfig->IsExportPixelFormat( nFormat ); +} + +// ------------------------------------------------------------------------ + +sal_uInt16 GraphicFilter::CanImportGraphic( const INetURLObject& rPath, + sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat ) +{ + sal_uInt16 nRetValue = GRFILTER_FORMATERROR; + DBG_ASSERT( rPath.GetProtocol() != INET_PROT_NOT_VALID, "GraphicFilter::CanImportGraphic() : ProtType == INET_PROT_NOT_VALID" ); + + String aMainUrl( rPath.GetMainURL( INetURLObject::NO_DECODE ) ); + SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( aMainUrl, STREAM_READ | STREAM_SHARE_DENYNONE ); + if ( pStream ) + { + nRetValue = CanImportGraphic( aMainUrl, *pStream, nFormat, pDeterminedFormat ); + delete pStream; + } + return nRetValue; +} + +// ------------------------------------------------------------------------ + +sal_uInt16 GraphicFilter::CanImportGraphic( const String& rMainUrl, SvStream& rIStream, + sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat ) +{ + sal_uLong nStreamPos = rIStream.Tell(); + sal_uInt16 nRes = ImpTestOrFindFormat( rMainUrl, rIStream, nFormat ); + + rIStream.Seek(nStreamPos); + + if( nRes==GRFILTER_OK && pDeterminedFormat!=NULL ) + *pDeterminedFormat = nFormat; + + return (sal_uInt16) ImplSetError( nRes, &rIStream ); +} + +// ------------------------------------------------------------------------ +//SJ: TODO, we need to create a GraphicImporter component +sal_uInt16 GraphicFilter::ImportGraphic( Graphic& rGraphic, const INetURLObject& rPath, + sal_uInt16 nFormat, sal_uInt16 * pDeterminedFormat, sal_uInt32 nImportFlags ) +{ + sal_uInt16 nRetValue = GRFILTER_FORMATERROR; + DBG_ASSERT( rPath.GetProtocol() != INET_PROT_NOT_VALID, "GraphicFilter::ImportGraphic() : ProtType == INET_PROT_NOT_VALID" ); + + String aMainUrl( rPath.GetMainURL( INetURLObject::NO_DECODE ) ); + SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( aMainUrl, STREAM_READ | STREAM_SHARE_DENYNONE ); + if ( pStream ) + { + nRetValue = ImportGraphic( rGraphic, aMainUrl, *pStream, nFormat, pDeterminedFormat, nImportFlags ); + delete pStream; + } + return nRetValue; +} + +sal_uInt16 GraphicFilter::ImportGraphic( Graphic& rGraphic, const String& rPath, SvStream& rIStream, + sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat, sal_uInt32 nImportFlags, WMF_EXTERNALHEADER *pExtHeader ) +{ + return ImportGraphic( rGraphic, rPath, rIStream, nFormat, pDeterminedFormat, nImportFlags, NULL, pExtHeader ); +} + +//------------------------------------------------------------------------- + +sal_uInt16 GraphicFilter::ImportGraphic( Graphic& rGraphic, const String& rPath, SvStream& rIStream, + sal_uInt16 nFormat, sal_uInt16* pDeterminedFormat, sal_uInt32 nImportFlags, + com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >* pFilterData, + WMF_EXTERNALHEADER *pExtHeader ) +{ + String aFilterName; + sal_uLong nStmBegin; + sal_uInt16 nStatus; + GraphicReader* pContext = rGraphic.GetContext(); + GfxLinkType eLinkType = GFX_LINK_TYPE_NONE; + sal_Bool bDummyContext = ( pContext == (GraphicReader*) 1 ); + const sal_Bool bLinkSet = rGraphic.IsLink(); + FilterConfigItem* pFilterConfigItem = NULL; + + Size aPreviewSizeHint( 0, 0 ); + sal_Bool bAllowPartialStreamRead = sal_False; + sal_Bool bCreateNativeLink = sal_True; + + ResetLastError(); + + if ( pFilterData ) + { + sal_Int32 i; + for ( i = 0; i < pFilterData->getLength(); i++ ) + { + if ( (*pFilterData)[ i ].Name == "PreviewSizeHint" ) + { + awt::Size aSize; + if ( (*pFilterData)[ i ].Value >>= aSize ) + { + aPreviewSizeHint = Size( aSize.Width, aSize.Height ); + if ( aSize.Width || aSize.Height ) + nImportFlags |= GRFILTER_I_FLAGS_FOR_PREVIEW; + else + nImportFlags &=~GRFILTER_I_FLAGS_FOR_PREVIEW; + } + } + else if ( (*pFilterData)[ i ].Name == "AllowPartialStreamRead" ) + { + (*pFilterData)[ i ].Value >>= bAllowPartialStreamRead; + if ( bAllowPartialStreamRead ) + nImportFlags |= GRFILTER_I_FLAGS_ALLOW_PARTIAL_STREAMREAD; + else + nImportFlags &=~GRFILTER_I_FLAGS_ALLOW_PARTIAL_STREAMREAD; + } + else if ( (*pFilterData)[ i ].Name == "CreateNativeLink" ) + { + (*pFilterData)[ i ].Value >>= bCreateNativeLink; + } + } + } + + if( !pContext || bDummyContext ) + { + if( bDummyContext ) + { + rGraphic.SetContext( NULL ); + nStmBegin = 0; + } + else + nStmBegin = rIStream.Tell(); + + bAbort = sal_False; + nStatus = ImpTestOrFindFormat( rPath, rIStream, nFormat ); + // Falls Pending, geben wir GRFILTER_OK zurueck, + // um mehr Bytes anzufordern + if( rIStream.GetError() == ERRCODE_IO_PENDING ) + { + rGraphic.SetContext( (GraphicReader*) 1 ); + rIStream.ResetError(); + rIStream.Seek( nStmBegin ); + return (sal_uInt16) ImplSetError( GRFILTER_OK ); + } + + rIStream.Seek( nStmBegin ); + + if( ( nStatus != GRFILTER_OK ) || rIStream.GetError() ) + return (sal_uInt16) ImplSetError( ( nStatus != GRFILTER_OK ) ? nStatus : GRFILTER_OPENERROR, &rIStream ); + + if( pDeterminedFormat ) + *pDeterminedFormat = nFormat; + + aFilterName = pConfig->GetImportFilterName( nFormat ); + } + else + { + if( pContext && !bDummyContext ) + aFilterName = pContext->GetUpperFilterName(); + + nStmBegin = 0; + nStatus = GRFILTER_OK; + } + + // read graphic + if ( pConfig->IsImportInternalFilter( nFormat ) ) + { + if( aFilterName.EqualsIgnoreCaseAscii( IMP_GIF ) ) + { + if( rGraphic.GetContext() == (GraphicReader*) 1 ) + rGraphic.SetContext( NULL ); + + if( !ImportGIF( rIStream, rGraphic ) ) + nStatus = GRFILTER_FILTERERROR; + else + eLinkType = GFX_LINK_TYPE_NATIVE_GIF; + } + else if( aFilterName.EqualsIgnoreCaseAscii( IMP_PNG ) ) + { + if ( rGraphic.GetContext() == (GraphicReader*) 1 ) + rGraphic.SetContext( NULL ); + + vcl::PNGReader aPNGReader( rIStream ); + + // ignore animation for previews and set preview size + if( aPreviewSizeHint.Width() || aPreviewSizeHint.Height() ) + { + // position the stream at the end of the image if requested + if( !bAllowPartialStreamRead ) + aPNGReader.GetChunks(); + } + else + { + // check if this PNG contains a GIF chunk! + const std::vector< vcl::PNGReader::ChunkData >& rChunkData = aPNGReader.GetChunks(); + std::vector< vcl::PNGReader::ChunkData >::const_iterator aIter( rChunkData.begin() ); + std::vector< vcl::PNGReader::ChunkData >::const_iterator aEnd ( rChunkData.end() ); + while( aIter != aEnd ) + { + // Microsoft Office is storing Animated GIFs in following chunk + if ( aIter->nType == PMGCHUNG_msOG ) + { + sal_uInt32 nChunkSize = aIter->aData.size(); + if ( nChunkSize > 11 ) + { + const std::vector< sal_uInt8 >& rData = aIter->aData; + SvMemoryStream aIStrm( (void*)&rData[ 11 ], nChunkSize - 11, STREAM_READ ); + ImportGIF( aIStrm, rGraphic ); + eLinkType = GFX_LINK_TYPE_NATIVE_PNG; + break; + } + } + ++aIter; + } + } + + if ( eLinkType == GFX_LINK_TYPE_NONE ) + { + BitmapEx aBmpEx( aPNGReader.Read( aPreviewSizeHint ) ); + if ( aBmpEx.IsEmpty() ) + nStatus = GRFILTER_FILTERERROR; + else + { + rGraphic = aBmpEx; + eLinkType = GFX_LINK_TYPE_NATIVE_PNG; + } + } + } + else if( aFilterName.EqualsIgnoreCaseAscii( IMP_JPEG ) ) + { + if( rGraphic.GetContext() == (GraphicReader*) 1 ) + rGraphic.SetContext( NULL ); + + // set LOGSIZE flag always, if not explicitly disabled + // (see #90508 and #106763) + if( 0 == ( nImportFlags & GRFILTER_I_FLAGS_DONT_SET_LOGSIZE_FOR_JPEG ) ) + nImportFlags |= GRFILTER_I_FLAGS_SET_LOGSIZE_FOR_JPEG; + + if( !ImportJPEG( rIStream, rGraphic, NULL, nImportFlags ) ) + nStatus = GRFILTER_FILTERERROR; + else + eLinkType = GFX_LINK_TYPE_NATIVE_JPG; + } + else if( aFilterName.EqualsIgnoreCaseAscii( IMP_SVG ) ) + { + if( rGraphic.GetContext() == (GraphicReader*) 1 ) + rGraphic.SetContext( NULL ); + + const sal_uInt32 nStmPos(rIStream.Tell()); + const sal_uInt32 nStmLen(rIStream.Seek(STREAM_SEEK_TO_END) - nStmPos); + bool bOkay(false); + + if(nStmLen) + { + SvgDataArray aNewData(new sal_uInt8[nStmLen]); + + rIStream.Seek(nStmPos); + rIStream.Read(aNewData.get(), nStmLen); + + if(!rIStream.GetError()) + { + SvgDataPtr aSvgDataPtr( + new SvgData( + aNewData, + nStmLen, + rPath)); + + rGraphic = Graphic(aSvgDataPtr); + bOkay = true; + } + } + + if(bOkay) + { + eLinkType = GFX_LINK_TYPE_NATIVE_SVG; + } + else + { + nStatus = GRFILTER_FILTERERROR; + } + } + else if( aFilterName.EqualsIgnoreCaseAscii( IMP_XBM ) ) + { + if( rGraphic.GetContext() == (GraphicReader*) 1 ) + rGraphic.SetContext( NULL ); + + if( !ImportXBM( rIStream, rGraphic ) ) + nStatus = GRFILTER_FILTERERROR; + } + else if( aFilterName.EqualsIgnoreCaseAscii( IMP_XPM ) ) + { + if( rGraphic.GetContext() == (GraphicReader*) 1 ) + rGraphic.SetContext( NULL ); + + if( !ImportXPM( rIStream, rGraphic ) ) + nStatus = GRFILTER_FILTERERROR; + } + else if( aFilterName.EqualsIgnoreCaseAscii( IMP_BMP ) || + aFilterName.EqualsIgnoreCaseAscii( IMP_SVMETAFILE ) ) + { + // SV interne Importfilter fuer Bitmaps und MetaFiles + rIStream >> rGraphic; + if( rIStream.GetError() ) + nStatus = GRFILTER_FORMATERROR; + } + else if( aFilterName.EqualsIgnoreCaseAscii( IMP_WMF ) || + aFilterName.EqualsIgnoreCaseAscii( IMP_EMF ) ) + { + GDIMetaFile aMtf; + if( !ConvertWMFToGDIMetaFile( rIStream, aMtf, NULL, pExtHeader ) ) + nStatus = GRFILTER_FORMATERROR; + else + { + rGraphic = aMtf; + eLinkType = GFX_LINK_TYPE_NATIVE_WMF; + } + } + else if( aFilterName.EqualsIgnoreCaseAscii( IMP_SVSGF ) + || aFilterName.EqualsIgnoreCaseAscii( IMP_SVSGV ) ) + { + sal_uInt16 nVersion; + unsigned char nTyp = CheckSgfTyp( rIStream, nVersion ); + + switch( nTyp ) + { + case SGF_BITIMAGE: + { + SvMemoryStream aTempStream; + if( aTempStream.GetError() ) + return GRFILTER_OPENERROR; + + if( !SgfBMapFilter( rIStream, aTempStream ) ) + nStatus = GRFILTER_FILTERERROR; + else + { + aTempStream.Seek( 0L ); + aTempStream >> rGraphic; + + if( aTempStream.GetError() ) + nStatus = GRFILTER_FILTERERROR; + } + } + break; + + case SGF_SIMPVECT: + { + GDIMetaFile aMtf; + if( !SgfVectFilter( rIStream, aMtf ) ) + nStatus = GRFILTER_FILTERERROR; + else + rGraphic = Graphic( aMtf ); + } + break; + + case SGF_STARDRAW: + { + if( nVersion != SGV_VERSION ) + nStatus = GRFILTER_VERSIONERROR; + else + { + GDIMetaFile aMtf; + if( !SgfSDrwFilter( rIStream, aMtf, + INetURLObject(aFilterPath) ) ) + { + nStatus = GRFILTER_FILTERERROR; + } + else + rGraphic = Graphic( aMtf ); + } + } + break; + + default: + { + nStatus = GRFILTER_FORMATERROR; + } + break; + } + } + else + nStatus = GRFILTER_FILTERERROR; + } + else + { + ImpFilterLibCacheEntry* pFilter = NULL; + + // find first filter in filter paths + sal_Int32 i, nTokenCount = getTokenCount(aFilterPath, ';'); + ImpFilterLibCache &rCache = Cache::get(); + for( i = 0; ( i < nTokenCount ) && ( pFilter == NULL ); i++ ) + pFilter = rCache.GetFilter( getToken(aFilterPath, i, ';'), aFilterName ); + if( !pFilter ) + nStatus = GRFILTER_FILTERERROR; + else + { + PFilterCall pFunc = pFilter->GetImportFunction(); + + if( !pFunc ) + nStatus = GRFILTER_FILTERERROR; + else + { + String aShortName; + if( nFormat != GRFILTER_FORMAT_DONTKNOW ) + { + aShortName = GetImportFormatShortName( nFormat ).ToUpperAscii(); + if ( ( pFilterConfigItem == NULL ) && aShortName.EqualsAscii( "PCD" ) ) + { + String aFilterConfigPath( RTL_CONSTASCII_USTRINGPARAM( "Office.Common/Filter/Graphic/Import/PCD" ) ); + pFilterConfigItem = new FilterConfigItem( aFilterConfigPath ); + } + } + if( !(*pFunc)( rIStream, rGraphic, pFilterConfigItem, sal_False ) ) + nStatus = GRFILTER_FORMATERROR; + else + { + // try to set link type if format matches + if( nFormat != GRFILTER_FORMAT_DONTKNOW ) + { + if( aShortName.CompareToAscii( TIF_SHORTNAME ) == COMPARE_EQUAL ) + eLinkType = GFX_LINK_TYPE_NATIVE_TIF; + else if( aShortName.CompareToAscii( MET_SHORTNAME ) == COMPARE_EQUAL ) + eLinkType = GFX_LINK_TYPE_NATIVE_MET; + else if( aShortName.CompareToAscii( PCT_SHORTNAME ) == COMPARE_EQUAL ) + eLinkType = GFX_LINK_TYPE_NATIVE_PCT; + } + } + } + } + } + + if( nStatus == GRFILTER_OK && bCreateNativeLink && ( eLinkType != GFX_LINK_TYPE_NONE ) && !rGraphic.GetContext() && !bLinkSet ) + { + const sal_uLong nStmEnd = rIStream.Tell(); + const sal_uLong nBufSize = nStmEnd - nStmBegin; + + if( nBufSize ) + { + sal_uInt8* pBuf=0; + try + { + pBuf = new sal_uInt8[ nBufSize ]; + } + catch (const std::bad_alloc&) + { + nStatus = GRFILTER_TOOBIG; + } + + if( nStatus == GRFILTER_OK ) + { + rIStream.Seek( nStmBegin ); + rIStream.Read( pBuf, nBufSize ); + rGraphic.SetLink( GfxLink( pBuf, nBufSize, eLinkType, sal_True ) ); + } + } + } + + // Set error code or try to set native buffer + if( nStatus != GRFILTER_OK ) + { + if( bAbort ) + nStatus = GRFILTER_ABORT; + + ImplSetError( nStatus, &rIStream ); + rIStream.Seek( nStmBegin ); + rGraphic.Clear(); + } + + delete pFilterConfigItem; + return nStatus; +} + + +// ------------------------------------------------------------------------ + +sal_uInt16 GraphicFilter::ExportGraphic( const Graphic& rGraphic, const INetURLObject& rPath, + sal_uInt16 nFormat, const uno::Sequence< beans::PropertyValue >* pFilterData ) +{ +#ifdef DISABLE_EXPORT + (void) rGraphic; + (void) rPath; + (void) nFormat; + (void) pFilterData; + + return GRFILTER_FORMATERROR; +#else + RTL_LOGFILE_CONTEXT( aLog, "GraphicFilter::ExportGraphic() (thb)" ); + sal_uInt16 nRetValue = GRFILTER_FORMATERROR; + DBG_ASSERT( rPath.GetProtocol() != INET_PROT_NOT_VALID, "GraphicFilter::ExportGraphic() : ProtType == INET_PROT_NOT_VALID" ); + sal_Bool bAlreadyExists = ImplDirEntryHelper::Exists( rPath ); + + String aMainUrl( rPath.GetMainURL( INetURLObject::NO_DECODE ) ); + SvStream* pStream = ::utl::UcbStreamHelper::CreateStream( aMainUrl, STREAM_WRITE | STREAM_TRUNC ); + if ( pStream ) + { + nRetValue = ExportGraphic( rGraphic, aMainUrl, *pStream, nFormat, pFilterData ); + delete pStream; + + if( ( GRFILTER_OK != nRetValue ) && !bAlreadyExists ) + ImplDirEntryHelper::Kill( aMainUrl ); + } + return nRetValue; +#endif +} + +// ------------------------------------------------------------------------ + +#ifdef DISABLE_DYNLOADING + +#ifndef DISABLE_EXPORT + +extern "C" sal_Bool egiGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool emeGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool epbGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool epgGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool eppGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool epsGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool eptGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool eraGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool etiGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); +extern "C" sal_Bool expGraphicExport( SvStream& rStream, Graphic& rGraphic, FilterConfigItem* pConfigItem, sal_Bool ); + +#endif + +#endif + +sal_uInt16 GraphicFilter::ExportGraphic( const Graphic& rGraphic, const String& rPath, + SvStream& rOStm, sal_uInt16 nFormat, const uno::Sequence< beans::PropertyValue >* pFilterData ) +{ +#ifdef DISABLE_EXPORT + (void) rGraphic; + (void) rPath; + (void) rOStm; + (void) nFormat; + (void) pFilterData; + + return GRFILTER_FORMATERROR; +#else + RTL_LOGFILE_CONTEXT( aLog, "GraphicFilter::ExportGraphic() (thb)" ); + sal_uInt16 nFormatCount = GetExportFormatCount(); + + ResetLastError(); + nExpGraphHint = 0; + + if( nFormat == GRFILTER_FORMAT_DONTKNOW ) + { + INetURLObject aURL( rPath ); + String aExt( aURL.GetFileExtension().toAsciiUpperCase() ); + + + for( sal_uInt16 i = 0; i < nFormatCount; i++ ) + { + if ( pConfig->GetExportFormatExtension( i ).EqualsIgnoreCaseAscii( aExt ) ) + { + nFormat=i; + break; + } + } + } + if( nFormat >= nFormatCount ) + return (sal_uInt16) ImplSetError( GRFILTER_FORMATERROR ); + + FilterConfigItem aConfigItem( (uno::Sequence< beans::PropertyValue >*)pFilterData ); + String aFilterName( pConfig->GetExportFilterName( nFormat ) ); + + bAbort = sal_False; + sal_uInt16 nStatus = GRFILTER_OK; + GraphicType eType; + Graphic aGraphic( rGraphic ); + + aGraphic = ImpGetScaledGraphic( rGraphic, aConfigItem ); + eType = aGraphic.GetType(); + + if( pConfig->IsExportPixelFormat( nFormat ) ) + { + if( eType != GRAPHIC_BITMAP ) + { + Size aSizePixel; + sal_uLong nColorCount,nBitsPerPixel,nNeededMem,nMaxMem; + VirtualDevice aVirDev; + + // Maximalen Speicherbedarf fuer das Bildes holen: +// if( GetOptionsConfig() ) +// nMaxMem = (UINT32)GetOptionsConfig()->ReadKey( "VEC-TO-PIX-MAX-KB", "1024" ).ToInt32(); +// else + nMaxMem = 1024; + + nMaxMem *= 1024; // In Bytes + + // Berechnen, wie gross das Bild normalerweise werden wuerde: + aSizePixel=aVirDev.LogicToPixel(aGraphic.GetPrefSize(),aGraphic.GetPrefMapMode()); + + // Berechnen, wieviel Speicher das Bild benoetigen wuerde: + nColorCount=aVirDev.GetColorCount(); + if (nColorCount<=2) nBitsPerPixel=1; + else if (nColorCount<=4) nBitsPerPixel=2; + else if (nColorCount<=16) nBitsPerPixel=4; + else if (nColorCount<=256) nBitsPerPixel=8; + else if (nColorCount<=65536) nBitsPerPixel=16; + else nBitsPerPixel=24; + nNeededMem=((sal_uLong)aSizePixel.Width()*(sal_uLong)aSizePixel.Height()*nBitsPerPixel+7)/8; + + // ggf. Groesse des Bildes einschraenken: + if (nMaxMem<nNeededMem) + { + double fFak=sqrt(((double)nMaxMem)/((double)nNeededMem)); + aSizePixel.Width()=(sal_uLong)(((double)aSizePixel.Width())*fFak); + aSizePixel.Height()=(sal_uLong)(((double)aSizePixel.Height())*fFak); + } + + aVirDev.SetMapMode(MapMode(MAP_PIXEL)); + aVirDev.SetOutputSizePixel(aSizePixel); + Graphic aGraphic2=aGraphic; + aGraphic2.Draw(&aVirDev,Point(0,0),aSizePixel); // Gemein: dies aendert den MapMode + aVirDev.SetMapMode(MapMode(MAP_PIXEL)); + aGraphic=Graphic(aVirDev.GetBitmap(Point(0,0),aSizePixel)); + } + } + if( rOStm.GetError() ) + nStatus = GRFILTER_IOERROR; + if( GRFILTER_OK == nStatus ) + { + if ( pConfig->IsExportInternalFilter( nFormat ) ) + { + if( aFilterName.EqualsIgnoreCaseAscii( EXP_BMP ) ) + { + Bitmap aBmp( aGraphic.GetBitmap() ); + sal_Int32 nColorRes = aConfigItem.ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( "Colors" ) ), 0 ); + if ( nColorRes && ( nColorRes <= (sal_uInt16)BMP_CONVERSION_24BIT) ) + { + if( !aBmp.Convert( (BmpConversion) nColorRes ) ) + aBmp = aGraphic.GetBitmap(); + } + ResMgr* pResMgr = CREATERESMGR( svt ); + sal_Bool bRleCoding = aConfigItem.ReadBool( String( RTL_CONSTASCII_USTRINGPARAM( "RLE_Coding" ) ), sal_True ); + // Wollen wir RLE-Kodiert speichern? + aBmp.Write( rOStm, bRleCoding ); + delete pResMgr; + + if( rOStm.GetError() ) + nStatus = GRFILTER_IOERROR; + } + else if( aFilterName.EqualsIgnoreCaseAscii( EXP_SVMETAFILE ) ) + { + sal_Int32 nVersion = aConfigItem.ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( "Version" ) ), 0 ) ; + if ( nVersion ) + rOStm.SetVersion( nVersion ); + GDIMetaFile aMTF; + + if ( eType != GRAPHIC_BITMAP ) + aMTF = aGraphic.GetGDIMetaFile(); + else + { + VirtualDevice aVirDev; + + aMTF.Record( &aVirDev ); + aGraphic.Draw( &aVirDev, Point(), aGraphic.GetPrefSize() ); + aMTF.Stop(); + aMTF.SetPrefSize( aGraphic.GetPrefSize() ); + aMTF.SetPrefMapMode( aGraphic.GetPrefMapMode() ); + } + aMTF.Write( rOStm ); + if( rOStm.GetError() ) + nStatus = GRFILTER_IOERROR; + } + else if ( aFilterName.EqualsIgnoreCaseAscii( EXP_WMF ) ) + { + if( eType == GRAPHIC_GDIMETAFILE ) + { + if ( !ConvertGDIMetaFileToWMF( aGraphic.GetGDIMetaFile(), rOStm, &aConfigItem ) ) + nStatus = GRFILTER_FORMATERROR; + } + else + { + Bitmap aBmp( aGraphic.GetBitmap() ); + GDIMetaFile aMTF; + VirtualDevice aVirDev; + + aMTF.Record( &aVirDev ); + aVirDev.DrawBitmap( Point(), aBmp ); + aMTF.Stop(); + aMTF.SetPrefSize( aBmp.GetSizePixel() ); + + if( !ConvertGDIMetaFileToWMF( aMTF, rOStm, &aConfigItem ) ) + nStatus = GRFILTER_FORMATERROR; + } + if( rOStm.GetError() ) + nStatus = GRFILTER_IOERROR; + } + else if ( aFilterName.EqualsIgnoreCaseAscii( EXP_EMF ) ) + { + if( eType == GRAPHIC_GDIMETAFILE ) + { + if ( !ConvertGDIMetaFileToEMF( aGraphic.GetGDIMetaFile(), rOStm, &aConfigItem ) ) + nStatus = GRFILTER_FORMATERROR; + } + else + { + Bitmap aBmp( aGraphic.GetBitmap() ); + GDIMetaFile aMTF; + VirtualDevice aVirDev; + + aMTF.Record( &aVirDev ); + aVirDev.DrawBitmap( Point(), aBmp ); + aMTF.Stop(); + aMTF.SetPrefSize( aBmp.GetSizePixel() ); + + if( !ConvertGDIMetaFileToEMF( aMTF, rOStm, &aConfigItem ) ) + nStatus = GRFILTER_FORMATERROR; + } + if( rOStm.GetError() ) + nStatus = GRFILTER_IOERROR; + } + else if( aFilterName.EqualsIgnoreCaseAscii( EXP_JPEG ) ) + { + bool bExportedGrayJPEG = false; + if( !ExportJPEG( rOStm, aGraphic, pFilterData, &bExportedGrayJPEG ) ) + nStatus = GRFILTER_FORMATERROR; + nExpGraphHint = bExportedGrayJPEG ? GRFILTER_OUTHINT_GREY : 0; + + if( rOStm.GetError() ) + nStatus = GRFILTER_IOERROR; + } + else if ( aFilterName.EqualsIgnoreCaseAscii( EXP_PNG ) ) + { + vcl::PNGWriter aPNGWriter( aGraphic.GetBitmapEx(), pFilterData ); + if ( pFilterData ) + { + sal_Int32 k, j, i = 0; + for ( i = 0; i < pFilterData->getLength(); i++ ) + { + if ( (*pFilterData)[ i ].Name == "AdditionalChunks" ) + { + com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > aAdditionalChunkSequence; + if ( (*pFilterData)[ i ].Value >>= aAdditionalChunkSequence ) + { + for ( j = 0; j < aAdditionalChunkSequence.getLength(); j++ ) + { + if ( aAdditionalChunkSequence[ j ].Name.getLength() == 4 ) + { + sal_uInt32 nChunkType = 0; + for ( k = 0; k < 4; k++ ) + { + nChunkType <<= 8; + nChunkType |= (sal_uInt8)aAdditionalChunkSequence[ j ].Name[ k ]; + } + com::sun::star::uno::Sequence< sal_Int8 > aByteSeq; + if ( aAdditionalChunkSequence[ j ].Value >>= aByteSeq ) + { + std::vector< vcl::PNGWriter::ChunkData >& rChunkData = aPNGWriter.GetChunks(); + if ( !rChunkData.empty() ) + { + sal_uInt32 nChunkLen = aByteSeq.getLength(); + + vcl::PNGWriter::ChunkData aChunkData; + aChunkData.nType = nChunkType; + if ( nChunkLen ) + { + aChunkData.aData.resize( nChunkLen ); + memcpy( &aChunkData.aData[ 0 ], aByteSeq.getConstArray(), nChunkLen ); + } + std::vector< vcl::PNGWriter::ChunkData >::iterator aIter = rChunkData.end() - 1; + rChunkData.insert( aIter, aChunkData ); + } + } + } + } + } + } + } + } + aPNGWriter.Write( rOStm ); + + if( rOStm.GetError() ) + nStatus = GRFILTER_IOERROR; + } + else if( aFilterName.EqualsIgnoreCaseAscii( EXP_SVG ) ) + { + bool bDone(false); + + // do we have a native SVG RenderGraphic, whose data can be written directly? + const SvgDataPtr aSvgDataPtr(rGraphic.getSvgData()); + + if(aSvgDataPtr.get() && aSvgDataPtr->getSvgDataArrayLength()) + { + rOStm.Write(aSvgDataPtr->getSvgDataArray().get(), aSvgDataPtr->getSvgDataArrayLength()); + + if( rOStm.GetError() ) + { + nStatus = GRFILTER_IOERROR; + } + else + { + bDone = true; + } + } + + if( !bDone ) + { + // do the normal GDIMetaFile export instead + try + { + ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMgr( ::comphelper::getProcessServiceFactory() ); + ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); + + if( xMgr.is() ) + { + ::com::sun::star::uno::Reference< ::com::sun::star::xml::sax::XDocumentHandler > xSaxWriter( + xml::sax::Writer::create( xContext ), uno::UNO_QUERY_THROW); + + ::com::sun::star::uno::Reference< ::com::sun::star::svg::XSVGWriter > xSVGWriter( xMgr->createInstance( + ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.svg.SVGWriter" )) ), ::com::sun::star::uno::UNO_QUERY ); + + if( xSaxWriter.is() && xSVGWriter.is() ) + { + ::com::sun::star::uno::Reference< ::com::sun::star::io::XActiveDataSource > xActiveDataSource( + xSaxWriter, ::com::sun::star::uno::UNO_QUERY ); + + if( xActiveDataSource.is() ) + { + const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xStmIf( + static_cast< ::cppu::OWeakObject* >( new ImpFilterOutputStream( rOStm ) ) ); + + SvMemoryStream aMemStm( 65535, 65535 ); + + ( (GDIMetaFile&) aGraphic.GetGDIMetaFile() ).Write( aMemStm ); + + xActiveDataSource->setOutputStream( ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream >( + xStmIf, ::com::sun::star::uno::UNO_QUERY ) ); + ::com::sun::star::uno::Sequence< sal_Int8 > aMtfSeq( (sal_Int8*) aMemStm.GetData(), aMemStm.Tell() ); + xSVGWriter->write( xSaxWriter, aMtfSeq ); + } + } + } + } + catch(const ::com::sun::star::uno::Exception&) + { + nStatus = GRFILTER_IOERROR; + } + } + } + else + nStatus = GRFILTER_FILTERERROR; + } + else + { + sal_Int32 i, nTokenCount = getTokenCount(aFilterPath, ';'); + for ( i = 0; i < nTokenCount; i++ ) + { +#ifndef DISABLE_DYNLOADING + String aPhysicalName( ImpCreateFullFilterPath( getToken(aFilterPath, i, ';'), aFilterName ) ); + osl::Module aLibrary( aPhysicalName ); + + PFilterCall pFunc = (PFilterCall) aLibrary.getFunctionSymbol(rtl::OUString(EXPORT_FUNCTION_NAME)); + // Dialog in DLL ausfuehren +#else + PFilterCall pFunc = NULL; + if( aFilterName.EqualsAscii( "egi" ) ) + pFunc = egiGraphicExport; + else if( aFilterName.EqualsAscii( "eme" ) ) + pFunc = emeGraphicExport; + else if( aFilterName.EqualsAscii( "epb" ) ) + pFunc = epbGraphicExport; + else if( aFilterName.EqualsAscii( "epg" ) ) + pFunc = epgGraphicExport; + else if( aFilterName.EqualsAscii( "epp" ) ) + pFunc = eppGraphicExport; + else if( aFilterName.EqualsAscii( "eps" ) ) + pFunc = epsGraphicExport; + else if( aFilterName.EqualsAscii( "ept" ) ) + pFunc = eptGraphicExport; + else if( aFilterName.EqualsAscii( "era" ) ) + pFunc = eraGraphicExport; + else if( aFilterName.EqualsAscii( "eti" ) ) + pFunc = etiGraphicExport; + else if( aFilterName.EqualsAscii( "exp" ) ) + pFunc = expGraphicExport; +#endif + if( pFunc ) + { + if ( !(*pFunc)( rOStm, aGraphic, &aConfigItem, sal_False ) ) + nStatus = GRFILTER_FORMATERROR; + break; + } + else + nStatus = GRFILTER_FILTERERROR; + } + } + } + if( nStatus != GRFILTER_OK ) + { + if( bAbort ) + nStatus = GRFILTER_ABORT; + + ImplSetError( nStatus, &rOStm ); + } + return nStatus; +#endif +} + +// ------------------------------------------------------------------------ + +sal_Bool GraphicFilter::Setup( sal_uInt16 ) +{ + return sal_False; +} + +// ------------------------------------------------------------------------ + +sal_Bool GraphicFilter::HasExportDialog( sal_uInt16 nFormat ) +{ + return pConfig->IsExportDialog( nFormat ); +} + +// ------------------------------------------------------------------------ + +sal_Bool GraphicFilter::DoExportDialog( Window* pWindow, sal_uInt16 nFormat ) +{ + return DoExportDialog( pWindow, nFormat, FUNIT_MM ); +} + +sal_Bool GraphicFilter::DoExportDialog( Window*, sal_uInt16 nFormat, FieldUnit ) +{ +#ifdef DISABLE_EXPORT + (void) nFormat; + + return sal_False; +#else + sal_Bool bRet = sal_False; + com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > + xSMgr( ::comphelper::getProcessServiceFactory() ); + + uno::Reference< com::sun::star::uno::XInterface > xFilterOptionsDialog + ( xSMgr->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.svtools.SvFilterOptionsDialog" )) ), + com::sun::star::uno::UNO_QUERY ); + if ( xFilterOptionsDialog.is() ) + { + com::sun::star::uno::Reference< com::sun::star::ui::dialogs::XExecutableDialog > xExecutableDialog + ( xFilterOptionsDialog, ::com::sun::star::uno::UNO_QUERY ); + com::sun::star::uno::Reference< com::sun::star::beans::XPropertyAccess > xPropertyAccess + ( xFilterOptionsDialog, ::com::sun::star::uno::UNO_QUERY ); + if ( xExecutableDialog.is() && xPropertyAccess.is() ) + { + com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue > aMediaDescriptor( 1 ); + aMediaDescriptor[ 0 ].Name = String( RTL_CONSTASCII_USTRINGPARAM( "FilterName" ) ); + rtl::OUString aStr( pConfig->GetExportInternalFilterName( nFormat ) ); + aMediaDescriptor[ 0 ].Value <<= aStr; + xPropertyAccess->setPropertyValues( aMediaDescriptor ); + bRet = xExecutableDialog->execute() == com::sun::star::ui::dialogs::ExecutableDialogResults::OK; + } + } + return bRet; +#endif +} + +// ------------------------------------------------------------------------ + +const FilterErrorEx& GraphicFilter::GetLastError() const +{ + return *pErrorEx; +} + +// ------------------------------------------------------------------------ + +void GraphicFilter::ResetLastError() +{ + pErrorEx->nFilterError = pErrorEx->nStreamError = 0UL; +} + +// ------------------------------------------------------------------------ + +const Link GraphicFilter::GetFilterCallback() const +{ + const Link aLink( LINK( this, GraphicFilter, FilterCallback ) ); + return aLink; +} + +// ------------------------------------------------------------------------ + +IMPL_LINK( GraphicFilter, FilterCallback, ConvertData*, pData ) +{ + long nRet = 0L; + + if( pData ) + { + sal_uInt16 nFormat = GRFILTER_FORMAT_DONTKNOW; + rtl::OString aShortName; + switch( pData->mnFormat ) + { + case( CVT_BMP ): aShortName = BMP_SHORTNAME; break; + case( CVT_GIF ): aShortName = GIF_SHORTNAME; break; + case( CVT_JPG ): aShortName = JPG_SHORTNAME; break; + case( CVT_MET ): aShortName = MET_SHORTNAME; break; + case( CVT_PCT ): aShortName = PCT_SHORTNAME; break; + case( CVT_PNG ): aShortName = PNG_SHORTNAME; break; + case( CVT_SVM ): aShortName = SVM_SHORTNAME; break; + case( CVT_TIF ): aShortName = TIF_SHORTNAME; break; + case( CVT_WMF ): aShortName = WMF_SHORTNAME; break; + case( CVT_EMF ): aShortName = EMF_SHORTNAME; break; + case( CVT_SVG ): aShortName = SVG_SHORTNAME; break; + + default: + break; + } + if( GRAPHIC_NONE == pData->maGraphic.GetType() || pData->maGraphic.GetContext() ) // Import + { + // Import + nFormat = GetImportFormatNumberForShortName( rtl::OStringToOUString( aShortName, RTL_TEXTENCODING_UTF8) ); + nRet = ImportGraphic( pData->maGraphic, String(), pData->mrStm, nFormat ) == 0; + } +#ifndef DISABLE_EXPORT + else if( !aShortName.isEmpty() ) + { + // Export + nFormat = GetExportFormatNumberForShortName( rtl::OStringToOUString(aShortName, RTL_TEXTENCODING_UTF8) ); + nRet = ExportGraphic( pData->maGraphic, String(), pData->mrStm, nFormat ) == 0; + } +#endif + } + return nRet; +} + +namespace +{ + class StandardGraphicFilter + { + public: + StandardGraphicFilter() + { + m_aFilter.GetImportFormatCount(); + } + GraphicFilter m_aFilter; + }; + + class theGraphicFilter : public rtl::Static<StandardGraphicFilter, theGraphicFilter> {}; +} + +GraphicFilter& GraphicFilter::GetGraphicFilter() +{ + return theGraphicFilter::get().m_aFilter; +} + +int GraphicFilter::LoadGraphic( const String &rPath, const String &rFilterName, + Graphic& rGraphic, GraphicFilter* pFilter, + sal_uInt16* pDeterminedFormat ) +{ + if ( !pFilter ) + pFilter = &GetGraphicFilter(); + + const sal_uInt16 nFilter = rFilterName.Len() && pFilter->GetImportFormatCount() + ? pFilter->GetImportFormatNumber( rFilterName ) + : GRFILTER_FORMAT_DONTKNOW; + + SvStream* pStream = NULL; + INetURLObject aURL( rPath ); + + if ( aURL.HasError() || INET_PROT_NOT_VALID == aURL.GetProtocol() ) + { + aURL.SetSmartProtocol( INET_PROT_FILE ); + aURL.SetSmartURL( rPath ); + } + else if ( INET_PROT_FILE != aURL.GetProtocol() ) + { + pStream = ::utl::UcbStreamHelper::CreateStream( rPath, STREAM_READ ); + } + + int nRes = GRFILTER_OK; + if ( !pStream ) + nRes = pFilter->ImportGraphic( rGraphic, aURL, nFilter, pDeterminedFormat ); + else + nRes = pFilter->ImportGraphic( rGraphic, rPath, *pStream, nFilter, pDeterminedFormat ); + +#ifdef DBG_UTIL + if( nRes ) + DBG_WARNING2( "GrafikFehler [%d] - [%s]", nRes, rPath.GetBuffer() ); +#endif + + return nRes; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/graphicfilter2.cxx b/vcl/source/filter/graphicfilter2.cxx new file mode 100644 index 000000000000..3cf7abfef5a1 --- /dev/null +++ b/vcl/source/filter/graphicfilter2.cxx @@ -0,0 +1,1135 @@ +/* -*- 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 <string.h> +#include <stdio.h> +#include <tools/stream.hxx> +#include <vcl/outdev.hxx> +#include <svtools/filter.hxx> +#include "FilterConfigCache.hxx" +#include <unotools/ucbstreamhelper.hxx> + +#define DATA_SIZE 640 + +sal_uInt8* ImplSearchEntry( sal_uInt8* , sal_uInt8* , sal_uLong , sal_uLong ); + +GraphicDescriptor::GraphicDescriptor( const INetURLObject& rPath ) : + pFileStm( ::utl::UcbStreamHelper::CreateStream( rPath.GetMainURL( INetURLObject::NO_DECODE ), STREAM_READ ) ), + aPathExt( rPath.GetFileExtension().toAsciiLowerCase() ), + bOwnStream( sal_True ) +{ + ImpConstruct(); +} + +GraphicDescriptor::GraphicDescriptor( SvStream& rInStream, const String* pPath) : + pFileStm ( &rInStream ), + bOwnStream ( sal_False ) +{ + ImpConstruct(); + + if ( pPath ) + { + INetURLObject aURL( *pPath ); + aPathExt = aURL.GetFileExtension().toAsciiLowerCase(); + } +} + +GraphicDescriptor::~GraphicDescriptor() +{ + if ( bOwnStream ) + delete pFileStm; +} + +sal_Bool GraphicDescriptor::Detect( sal_Bool bExtendedInfo ) +{ + sal_Bool bRet = sal_False; + if ( pFileStm && !pFileStm->GetError() ) + { + SvStream& rStm = *pFileStm; + sal_uInt16 nOldFormat = rStm.GetNumberFormatInt(); + + if ( ImpDetectGIF( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectJPG( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectBMP( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectPNG( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectTIF( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectPCX( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectDXF( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectMET( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectSGF( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectSGV( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectSVM( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectWMF( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectEMF( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectSVG( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectPCT( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectXBM( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectXPM( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectPBM( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectPGM( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectPPM( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectRAS( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectTGA( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectPSD( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectEPS( rStm, bExtendedInfo ) ) bRet = sal_True; + else if ( ImpDetectPCD( rStm, bExtendedInfo ) ) bRet = sal_True; + + rStm.SetNumberFormatInt( nOldFormat ); + } + return bRet; +} + +void GraphicDescriptor::ImpConstruct() +{ + nFormat = GFF_NOT; + nBitsPerPixel = 0; + nPlanes = 0; + bCompressed = sal_False; +} + +sal_Bool GraphicDescriptor::ImpDetectBMP( SvStream& rStm, sal_Bool bExtendedInfo ) +{ + sal_uInt16 nTemp16; + sal_Bool bRet = sal_False; + sal_Int32 nStmPos = rStm.Tell(); + + rStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + rStm >> nTemp16; + + // OS/2-BitmapArray + if ( nTemp16 == 0x4142 ) + { + rStm.SeekRel( 0x0c ); + rStm >> nTemp16; + } + + // Bitmap + if ( nTemp16 == 0x4d42 ) + { + nFormat = GFF_BMP; + bRet = sal_True; + + if ( bExtendedInfo ) + { + sal_uInt32 nTemp32; + sal_uInt32 nCompression; + + // bis zur ersten Information + rStm.SeekRel( 0x10 ); + + // PixelBreite auslesen + rStm >> nTemp32; + aPixSize.Width() = nTemp32; + + // PixelHoehe auslesen + rStm >> nTemp32; + aPixSize.Height() = nTemp32; + + // Planes auslesen + rStm >> nTemp16; + nPlanes = nTemp16; + + // BitCount auslesen + rStm >> nTemp16; + nBitsPerPixel = nTemp16; + + // Compression auslesen + rStm >> nTemp32; + bCompressed = ( ( nCompression = nTemp32 ) > 0 ); + + // logische Breite + rStm.SeekRel( 4 ); + rStm >> nTemp32; + if ( nTemp32 ) + aLogSize.Width() = ( aPixSize.Width() * 100000 ) / nTemp32; + + // logische Hoehe + rStm >> nTemp32; + if ( nTemp32 ) + aLogSize.Height() = ( aPixSize.Height() * 100000 ) / nTemp32; + + // Wir wollen noch etwas feiner differenzieren und + // auf sinnvolle Werte ueberpruefen ( Bug-Id #29001 ) + if ( ( nBitsPerPixel > 24 ) || ( nCompression > 3 ) ) + { + nFormat = GFF_NOT; + bRet = sal_False; + } + } + } + rStm.Seek( nStmPos ); + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectGIF( SvStream& rStm, sal_Bool bExtendedInfo ) +{ + sal_uInt32 n32; + sal_uInt16 n16; + sal_Bool bRet = sal_False; + sal_uInt8 cByte; + + sal_Int32 nStmPos = rStm.Tell(); + rStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + rStm >> n32; + + if ( n32 == 0x38464947 ) + { + rStm >> n16; + if ( ( n16 == 0x6137 ) || ( n16 == 0x6139 ) ) + { + nFormat = GFF_GIF; + bRet = sal_True; + + if ( bExtendedInfo ) + { + sal_uInt16 nTemp16; + + // PixelBreite auslesen + rStm >> nTemp16; + aPixSize.Width() = nTemp16; + + // PixelHoehe auslesen + rStm >> nTemp16; + aPixSize.Height() = nTemp16; + + // Bits/Pixel auslesen + rStm >> cByte; + nBitsPerPixel = ( ( cByte & 112 ) >> 4 ) + 1; + } + } + } + rStm.Seek( nStmPos ); + return bRet; +} + +// returns the next jpeg marker, a return value of 0 represents an error +sal_uInt8 ImpDetectJPG_GetNextMarker( SvStream& rStm ) +{ + sal_uInt8 nByte; + do + { + do + { + rStm >> nByte; + if ( rStm.IsEof() || rStm.GetError() ) // as 0 is not allowed as marker, + return 0; // we can use it as errorcode + } + while ( nByte != 0xff ); + do + { + rStm >> nByte; + if ( rStm.IsEof() || rStm.GetError() ) + return 0; + } + while( nByte == 0xff ); + } + while( nByte == 0 ); // 0xff00 represents 0xff and not a marker, + // the marker detection has to be restartet. + return nByte; +} + +sal_Bool GraphicDescriptor::ImpDetectJPG( SvStream& rStm, sal_Bool bExtendedInfo ) +{ + sal_uInt32 nTemp32; + sal_Bool bRet = sal_False; + + sal_Int32 nStmPos = rStm.Tell(); + + rStm.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN ); + rStm >> nTemp32; + + // compare upper 24 bits + if( 0xffd8ff00 == ( nTemp32 & 0xffffff00 ) ) + { + nFormat = GFF_JPG; + bRet = sal_True; + + if ( bExtendedInfo ) + { + rStm.SeekRel( -2 ); + + sal_uInt32 nError( rStm.GetError() ); + + sal_Bool bScanFailure = sal_False; + sal_Bool bScanFinished = sal_False; + + while( !bScanFailure && !bScanFinished && !rStm.IsEof() && !rStm.GetError() ) + { + sal_uInt8 nMarker = ImpDetectJPG_GetNextMarker( rStm ); + switch( nMarker ) + { + // fixed size marker, not having a two byte length parameter + case 0xd0 : // RST0 + case 0xd1 : + case 0xd2 : + case 0xd3 : + case 0xd4 : + case 0xd5 : + case 0xd6 : + case 0xd7 : // RST7 + case 0x01 : // TEM + break; + + case 0xd8 : // SOI (has already been checked, there should not be a second one) + case 0x00 : // marker is invalid, we should stop now + bScanFailure = sal_True; + break; + + case 0xd9 : // EOI + bScanFinished = sal_True; + break; + + // per default we assume marker segments conaining a length parameter + default : + { + sal_uInt16 nLength; + rStm >> nLength; + + if ( nLength < 2 ) + bScanFailure = sal_True; + else + { + sal_uInt32 nNextMarkerPos = rStm.Tell() + nLength - 2; + switch( nMarker ) + { + case 0xe0 : // APP0 Marker + { + if ( nLength == 16 ) + { + sal_Int32 nIdentifier; + rStm >> nIdentifier; + if ( nIdentifier == 0x4a464946 ) // JFIF Identifier + { + sal_uInt8 nStringTerminator; + sal_uInt8 nMajorRevision; + sal_uInt8 nMinorRevision; + sal_uInt8 nUnits; + sal_uInt16 nHorizontalResolution; + sal_uInt16 nVerticalResolution; + sal_uInt8 nHorzThumbnailPixelCount; + sal_uInt8 nVertThumbnailPixelCount; + + rStm >> nStringTerminator + >> nMajorRevision + >> nMinorRevision + >> nUnits + >> nHorizontalResolution + >> nVerticalResolution + >> nHorzThumbnailPixelCount + >> nVertThumbnailPixelCount; + + // setting the logical size + if ( nUnits && nHorizontalResolution && nVerticalResolution ) + { + MapMode aMap; + aMap.SetMapUnit( nUnits == 1 ? MAP_INCH : MAP_CM ); + aMap.SetScaleX( Fraction( 1, nHorizontalResolution ) ); + aMap.SetScaleY( Fraction( 1, nVerticalResolution ) ); + aLogSize = OutputDevice::LogicToLogic( aPixSize, aMap, MapMode( MAP_100TH_MM ) ); + } + } + } + } + break; + + // Start of Frame Markers + case 0xc0 : // SOF0 + case 0xc1 : // SOF1 + case 0xc2 : // SOF2 + case 0xc3 : // SOF3 + case 0xc5 : // SOF5 + case 0xc6 : // SOF6 + case 0xc7 : // SOF7 + case 0xc9 : // SOF9 + case 0xca : // SOF10 + case 0xcb : // SOF11 + case 0xcd : // SOF13 + case 0xce : // SOF14 + case 0xcf : // SOF15 + { + sal_uInt8 nSamplePrecision; + sal_uInt16 nNumberOfLines; + sal_uInt16 nSamplesPerLine; + sal_uInt8 nNumberOfImageComponents; + sal_uInt8 nComponentsIdentifier; + sal_uInt8 nHorizontalSamplingFactor; + sal_uInt8 nQuantizationTableDestinationSelector; + rStm >> nSamplePrecision + >> nNumberOfLines + >> nSamplesPerLine + >> nNumberOfImageComponents + >> nComponentsIdentifier + >> nHorizontalSamplingFactor + >> nQuantizationTableDestinationSelector; + nHorizontalSamplingFactor >>= 4; + + aPixSize.Height() = nNumberOfLines; + aPixSize.Width() = nSamplesPerLine; + nBitsPerPixel = ( nNumberOfImageComponents == 3 ? 24 : nNumberOfImageComponents == 1 ? 8 : 0 ); + nPlanes = 1; + + bScanFinished = sal_True; + } + break; + } + rStm.Seek( nNextMarkerPos ); + } + } + break; + } + } + rStm.SetError( nError ); + } + } + rStm.Seek( nStmPos ); + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectPCD( SvStream& rStm, sal_Bool ) +{ + sal_Bool bRet = sal_False; + + sal_Int32 nStmPos = rStm.Tell(); + rStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + + sal_uInt32 nTemp32; + sal_uInt16 nTemp16; + sal_uInt8 cByte; + + rStm.SeekRel( 2048 ); + rStm >> nTemp32; + rStm >> nTemp16; + rStm >> cByte; + + if ( ( nTemp32 == 0x5f444350 ) && + ( nTemp16 == 0x5049 ) && + ( cByte == 0x49 ) ) + { + nFormat = GFF_PCD; + bRet = sal_True; + } + rStm.Seek( nStmPos ); + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectPCX( SvStream& rStm, sal_Bool bExtendedInfo ) +{ + // ! Because 0x0a can be interpreted as LF too ... + // we cant be shure that this special sign represent a PCX file only. + // Every Ascii file is possible here :-( + // We must detect the whole header. + bExtendedInfo = sal_True; + + sal_Bool bRet = sal_False; + sal_uInt8 cByte; + + sal_Int32 nStmPos = rStm.Tell(); + rStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + rStm >> cByte; + + if ( cByte == 0x0a ) + { + nFormat = GFF_PCX; + bRet = sal_True; + + if ( bExtendedInfo ) + { + sal_uInt16 nTemp16; + sal_uInt16 nXmin; + sal_uInt16 nXmax; + sal_uInt16 nYmin; + sal_uInt16 nYmax; + sal_uInt16 nDPIx; + sal_uInt16 nDPIy; + + + rStm.SeekRel( 1 ); + + // Kompression lesen + rStm >> cByte; + bCompressed = ( cByte > 0 ); + + bRet = (cByte==0 || cByte ==1); + + // Bits/Pixel lesen + rStm >> cByte; + nBitsPerPixel = cByte; + + // Bildabmessungen + rStm >> nTemp16; + nXmin = nTemp16; + rStm >> nTemp16; + nYmin = nTemp16; + rStm >> nTemp16; + nXmax = nTemp16; + rStm >> nTemp16; + nYmax = nTemp16; + + aPixSize.Width() = nXmax - nXmin + 1; + aPixSize.Height() = nYmax - nYmin + 1; + + // Aufloesung + rStm >> nTemp16; + nDPIx = nTemp16; + rStm >> nTemp16; + nDPIy = nTemp16; + + // logische Groesse setzen + MapMode aMap( MAP_INCH, Point(), + Fraction( 1, nDPIx ), Fraction( 1, nDPIy ) ); + aLogSize = OutputDevice::LogicToLogic( aPixSize, aMap, + MapMode( MAP_100TH_MM ) ); + + + // Anzahl Farbebenen + rStm.SeekRel( 49 ); + rStm >> cByte; + nPlanes = cByte; + + bRet = (nPlanes<=4); + } + } + + rStm.Seek( nStmPos ); + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectPNG( SvStream& rStm, sal_Bool bExtendedInfo ) +{ + sal_uInt32 nTemp32; + sal_Bool bRet = sal_False; + + sal_Int32 nStmPos = rStm.Tell(); + rStm.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN ); + rStm >> nTemp32; + + if ( nTemp32 == 0x89504e47 ) + { + rStm >> nTemp32; + if ( nTemp32 == 0x0d0a1a0a ) + { + nFormat = GFF_PNG; + bRet = sal_True; + + if ( bExtendedInfo ) + { + sal_uInt8 cByte; + + // IHDR-Chunk + rStm.SeekRel( 8 ); + + // Breite einlesen + rStm >> nTemp32; + aPixSize.Width() = nTemp32; + + // Hoehe einlesen + rStm >> nTemp32; + aPixSize.Height() = nTemp32; + + // Bits/Pixel einlesen + rStm >> cByte; + nBitsPerPixel = cByte; + + // Planes immer 1; + // Kompression immer + nPlanes = 1; + bCompressed = sal_True; + + sal_uInt32 nLen32; + + rStm.SeekRel( 8 ); + + // so lange ueberlesen, bis wir den pHYs-Chunk haben oder + // den Anfang der Bilddaten + rStm >> nLen32; + rStm >> nTemp32; + while( ( nTemp32 != 0x70485973 ) && ( nTemp32 != 0x49444154 ) ) + { + rStm.SeekRel( 4 + nLen32 ); + rStm >> nLen32; + rStm >> nTemp32; + } + + if ( nTemp32 == 0x70485973 ) + { + sal_uLong nXRes; + sal_uLong nYRes; + + // horizontale Aufloesung + rStm >> nTemp32; + nXRes = nTemp32; + + // vertikale Aufloesung + rStm >> nTemp32; + nYRes = nTemp32; + + // Unit einlesen + rStm >> cByte; + + if ( cByte ) + { + if ( nXRes ) + aLogSize.Width() = ( aPixSize.Width() * 100000 ) / + nTemp32; + + if ( nYRes ) + aLogSize.Height() = ( aPixSize.Height() * 100000 ) / + nTemp32; + } + } + } + } + } + rStm.Seek( nStmPos ); + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectTIF( SvStream& rStm, sal_Bool bExtendedInfo ) +{ + sal_Bool bDetectOk = sal_False; + sal_Bool bRet = sal_False; + sal_uInt8 cByte1; + sal_uInt8 cByte2; + + sal_Int32 nStmPos = rStm.Tell(); + rStm >> cByte1; + rStm >> cByte2; + if ( cByte1 == cByte2 ) + { + if ( cByte1 == 0x49 ) + { + rStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + bDetectOk = sal_True; + } + else if ( cByte1 == 0x4d ) + { + rStm.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN ); + bDetectOk = sal_True; + } + + if ( bDetectOk ) + { + sal_uInt16 nTemp16; + + rStm >> nTemp16; + if ( nTemp16 == 0x2a ) + { + nFormat = GFF_TIF; + bRet = sal_True; + + if ( bExtendedInfo ) + { + sal_uLong nCount; + sal_uLong nMax = DATA_SIZE - 48; + sal_uInt32 nTemp32; + sal_Bool bOk = sal_False; + + // Offset des ersten IFD einlesen + rStm >> nTemp32; + rStm.SeekRel( ( nCount = ( nTemp32 + 2 ) ) - 0x08 ); + + if ( nCount < nMax ) + { + // Tag's lesen, bis wir auf Tag256 ( Width ) treffen + // nicht mehr Bytes als DATA_SIZE lesen + rStm >> nTemp16; + while ( nTemp16 != 256 ) + { + bOk = nCount < nMax; + if ( !bOk ) + { + break; + } + rStm.SeekRel( 10 ); + rStm >> nTemp16; + nCount += 12; + } + + if ( bOk ) + { + // Breite lesen + rStm >> nTemp16; + rStm.SeekRel( 4 ); + if ( nTemp16 == 3 ) + { + rStm >> nTemp16; + aPixSize.Width() = nTemp16; + rStm.SeekRel( 2 ); + } + else + { + rStm >> nTemp32; + aPixSize.Width() = nTemp32; + } + nCount += 12; + + // Hoehe lesen + rStm.SeekRel( 2 ); + rStm >> nTemp16; + rStm.SeekRel( 4 ); + if ( nTemp16 == 3 ) + { + rStm >> nTemp16; + aPixSize.Height() = nTemp16; + rStm.SeekRel( 2 ); + } + else + { + rStm >> nTemp32; + aPixSize.Height() = nTemp32; + } + nCount += 12; + + // ggf. Bits/Pixel lesen + rStm >> nTemp16; + if ( nTemp16 == 258 ) + { + rStm.SeekRel( 6 ); + rStm >> nTemp16; + nBitsPerPixel = nTemp16; + rStm.SeekRel( 2 ); + nCount += 12; + } + else + rStm.SeekRel( -2 ); + + // ggf. Compression lesen + rStm >> nTemp16; + if ( nTemp16 == 259 ) + { + rStm.SeekRel( 6 ); + rStm >> nTemp16; + bCompressed = ( nTemp16 > 1 ); + rStm.SeekRel( 2 ); + nCount += 12; + } + else + rStm.SeekRel( -2 ); + } + } + } + } + } + } + rStm.Seek( nStmPos ); + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectXBM( SvStream&, sal_Bool ) +{ + sal_Bool bRet = aPathExt.CompareToAscii( "xbm", 3 ) == COMPARE_EQUAL; + if (bRet) + nFormat = GFF_XBM; + + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectXPM( SvStream&, sal_Bool ) +{ + sal_Bool bRet = aPathExt.CompareToAscii( "xpm", 3 ) == COMPARE_EQUAL; + if (bRet) + nFormat = GFF_XPM; + + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectPBM( SvStream& rStm, sal_Bool ) +{ + sal_Bool bRet = sal_False; + + // erst auf Datei Extension pruefen, da diese aussagekraeftiger ist + // als die 2 ID Bytes + + if ( aPathExt.CompareToAscii( "pbm", 3 ) == COMPARE_EQUAL ) + bRet = sal_True; + else + { + sal_Int32 nStmPos = rStm.Tell(); + sal_uInt8 nFirst, nSecond; + rStm >> nFirst >> nSecond; + if ( nFirst == 'P' && ( ( nSecond == '1' ) || ( nSecond == '4' ) ) ) + bRet = sal_True; + rStm.Seek( nStmPos ); + } + + if ( bRet ) + nFormat = GFF_PBM; + + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectPGM( SvStream& rStm, sal_Bool ) +{ + sal_Bool bRet = sal_False; + + if ( aPathExt.CompareToAscii( "pgm", 3 ) == COMPARE_EQUAL ) + bRet = sal_True; + else + { + sal_uInt8 nFirst, nSecond; + sal_Int32 nStmPos = rStm.Tell(); + rStm >> nFirst >> nSecond; + if ( nFirst == 'P' && ( ( nSecond == '2' ) || ( nSecond == '5' ) ) ) + bRet = sal_True; + rStm.Seek( nStmPos ); + } + + if ( bRet ) + nFormat = GFF_PGM; + + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectPPM( SvStream& rStm, sal_Bool ) +{ + sal_Bool bRet = sal_False; + + if ( aPathExt.CompareToAscii( "ppm", 3 ) == COMPARE_EQUAL ) + bRet = sal_True; + else + { + sal_uInt8 nFirst, nSecond; + sal_Int32 nStmPos = rStm.Tell(); + rStm >> nFirst >> nSecond; + if ( nFirst == 'P' && ( ( nSecond == '3' ) || ( nSecond == '6' ) ) ) + bRet = sal_True; + rStm.Seek( nStmPos ); + } + + if ( bRet ) + nFormat = GFF_PPM; + + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectRAS( SvStream& rStm, sal_Bool ) +{ + sal_uInt32 nMagicNumber; + sal_Bool bRet = sal_False; + sal_Int32 nStmPos = rStm.Tell(); + rStm.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN ); + rStm >> nMagicNumber; + if ( nMagicNumber == 0x59a66a95 ) + { + nFormat = GFF_RAS; + bRet = sal_True; + } + rStm.Seek( nStmPos ); + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectTGA( SvStream&, sal_Bool ) +{ + sal_Bool bRet = aPathExt.CompareToAscii( "tga", 3 ) == COMPARE_EQUAL; + if (bRet) + nFormat = GFF_TGA; + + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectPSD( SvStream& rStm, sal_Bool bExtendedInfo ) +{ + sal_Bool bRet = sal_False; + + sal_uInt32 nMagicNumber; + sal_Int32 nStmPos = rStm.Tell(); + rStm.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN ); + rStm >> nMagicNumber; + if ( nMagicNumber == 0x38425053 ) + { + sal_uInt16 nVersion; + rStm >> nVersion; + if ( nVersion == 1 ) + { + bRet = sal_True; + if ( bExtendedInfo ) + { + sal_uInt16 nChannels; + sal_uInt32 nRows; + sal_uInt32 nColumns; + sal_uInt16 nDepth; + sal_uInt16 nMode; + rStm.SeekRel( 6 ); // Pad + rStm >> nChannels >> nRows >> nColumns >> nDepth >> nMode; + if ( ( nDepth == 1 ) || ( nDepth == 8 ) || ( nDepth == 16 ) ) + { + nBitsPerPixel = ( nDepth == 16 ) ? 8 : nDepth; + switch ( nChannels ) + { + case 4 : + case 3 : + nBitsPerPixel = 24; + case 2 : + case 1 : + aPixSize.Width() = nColumns; + aPixSize.Height() = nRows; + break; + default: + bRet = sal_False; + } + } + else + bRet = sal_False; + } + } + } + + if ( bRet ) + nFormat = GFF_PSD; + rStm.Seek( nStmPos ); + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectEPS( SvStream& rStm, sal_Bool ) +{ + // es wird die EPS mit Vorschaubild Variante und die Extensionuebereinstimmung + // geprueft + + sal_uInt32 nFirstLong; + sal_uInt8 nFirstBytes[20]; + sal_Bool bRet = sal_False; + + sal_Int32 nStmPos = rStm.Tell(); + rStm.SetNumberFormatInt( NUMBERFORMAT_INT_BIGENDIAN ); + rStm >> nFirstLong; + rStm.SeekRel( -4 ); + rStm.Read( &nFirstBytes, 20 ); + + if ( ( nFirstLong == 0xC5D0D3C6 ) || ( aPathExt.CompareToAscii( "eps", 3 ) == COMPARE_EQUAL ) || + ( ImplSearchEntry( nFirstBytes, (sal_uInt8*)"%!PS-Adobe", 10, 10 ) + && ImplSearchEntry( &nFirstBytes[15], (sal_uInt8*)"EPS", 3, 3 ) ) ) + { + nFormat = GFF_EPS; + bRet = sal_True; + } + rStm.Seek( nStmPos ); + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectDXF( SvStream&, sal_Bool ) +{ + sal_Bool bRet = aPathExt.CompareToAscii( "dxf", 3 ) == COMPARE_EQUAL; + if (bRet) + nFormat = GFF_DXF; + + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectMET( SvStream&, sal_Bool ) +{ + sal_Bool bRet = aPathExt.CompareToAscii( "met", 3 ) == COMPARE_EQUAL; + if (bRet) + nFormat = GFF_MET; + + return bRet; +} + +extern bool isPCT(SvStream& rStream, sal_uLong nStreamPos, sal_uLong nStreamLen); + +sal_Bool GraphicDescriptor::ImpDetectPCT( SvStream& rStm, sal_Bool ) +{ + sal_Bool bRet = aPathExt.CompareToAscii( "pct", 3 ) == COMPARE_EQUAL; + if (bRet) + nFormat = GFF_PCT; + else + { + sal_Size nStreamPos = rStm.Tell(); + sal_Size nStreamLen = rStm.remainingSize(); + if (isPCT(rStm, nStreamPos, nStreamLen)) + { + bRet = sal_True; + nFormat = GFF_PCT; + } + rStm.Seek(nStreamPos); + } + + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectSGF( SvStream& rStm, sal_Bool ) +{ + sal_Bool bRet = sal_False; + if( aPathExt.CompareToAscii( "sgf", 3 ) == COMPARE_EQUAL ) + bRet = sal_True; + else + { + sal_Int32 nStmPos = rStm.Tell(); + + sal_uInt8 nFirst, nSecond; + + rStm >> nFirst >> nSecond; + + if( nFirst == 'J' && nSecond == 'J' ) + bRet = sal_True; + + rStm.Seek( nStmPos ); + } + + if( bRet ) + nFormat = GFF_SGF; + + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectSGV( SvStream&, sal_Bool ) +{ + sal_Bool bRet = aPathExt.CompareToAscii( "sgv", 3 ) == COMPARE_EQUAL; + if (bRet) + nFormat = GFF_SGV; + + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectSVM( SvStream& rStm, sal_Bool bExtendedInfo ) +{ + sal_uInt32 n32; + sal_Bool bRet = sal_False; + sal_uInt8 cByte; + + sal_Int32 nStmPos = rStm.Tell(); + rStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + rStm >> n32; + if ( n32 == 0x44475653 ) + { + rStm >> cByte; + if ( cByte == 0x49 ) + { + nFormat = GFF_SVM; + bRet = sal_True; + + if ( bExtendedInfo ) + { + sal_uInt32 nTemp32; + sal_uInt16 nTemp16; + + rStm.SeekRel( 0x04 ); + + // Breite auslesen + rStm >> nTemp32; + aLogSize.Width() = nTemp32; + + // Hoehe auslesen + rStm >> nTemp32; + aLogSize.Height() = nTemp32; + + // Map-Unit auslesen und PrefSize ermitteln + rStm >> nTemp16; + aLogSize = OutputDevice::LogicToLogic( aLogSize, + MapMode( (MapUnit) nTemp16 ), + MapMode( MAP_100TH_MM ) ); + } + } + } + else + { + rStm.SeekRel( -4L ); + rStm >> n32; + + if( n32 == 0x4D4C4356 ) + { + sal_uInt16 nTmp16; + + rStm >> nTmp16; + + if( nTmp16 == 0x4654 ) + { + nFormat = GFF_SVM; + bRet = sal_True; + + if( bExtendedInfo ) + { + MapMode aMapMode; + + rStm.SeekRel( 0x06 ); + rStm >> aMapMode; + rStm >> aLogSize; + aLogSize = OutputDevice::LogicToLogic( aLogSize, aMapMode, MapMode( MAP_100TH_MM ) ); + } + } + } + } + rStm.Seek( nStmPos ); + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectWMF( SvStream&, sal_Bool ) +{ + sal_Bool bRet = aPathExt.CompareToAscii( "wmf",3 ) == COMPARE_EQUAL; + if (bRet) + nFormat = GFF_WMF; + + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectEMF( SvStream&, sal_Bool ) +{ + sal_Bool bRet = aPathExt.CompareToAscii( "emf", 3 ) == COMPARE_EQUAL; + if (bRet) + nFormat = GFF_EMF; + + return bRet; +} + +sal_Bool GraphicDescriptor::ImpDetectSVG( SvStream& /*rStm*/, sal_Bool /*bExtendedInfo*/ ) +{ + sal_Bool bRet = aPathExt.CompareToAscii( "svg", 3 ) == COMPARE_EQUAL; + if (bRet) + nFormat = GFF_SVG; + + return bRet; +} + +String GraphicDescriptor::GetImportFormatShortName( sal_uInt16 nFormat ) +{ + const char *pKeyName = 0; + + switch( nFormat ) + { + case( GFF_BMP ) : pKeyName = "bmp"; break; + case( GFF_GIF ) : pKeyName = "gif"; break; + case( GFF_JPG ) : pKeyName = "jpg"; break; + case( GFF_PCD ) : pKeyName = "pcd"; break; + case( GFF_PCX ) : pKeyName = "pcx"; break; + case( GFF_PNG ) : pKeyName = "png"; break; + case( GFF_XBM ) : pKeyName = "xbm"; break; + case( GFF_XPM ) : pKeyName = "xpm"; break; + case( GFF_PBM ) : pKeyName = "pbm"; break; + case( GFF_PGM ) : pKeyName = "pgm"; break; + case( GFF_PPM ) : pKeyName = "ppm"; break; + case( GFF_RAS ) : pKeyName = "ras"; break; + case( GFF_TGA ) : pKeyName = "tga"; break; + case( GFF_PSD ) : pKeyName = "psd"; break; + case( GFF_EPS ) : pKeyName = "eps"; break; + case( GFF_TIF ) : pKeyName = "tif"; break; + case( GFF_DXF ) : pKeyName = "dxf"; break; + case( GFF_MET ) : pKeyName = "met"; break; + case( GFF_PCT ) : pKeyName = "pct"; break; + case( GFF_SGF ) : pKeyName = "sgf"; break; + case( GFF_SGV ) : pKeyName = "sgv"; break; + case( GFF_SVM ) : pKeyName = "svm"; break; + case( GFF_WMF ) : pKeyName = "wmf"; break; + case( GFF_EMF ) : pKeyName = "emf"; break; + case( GFF_SVG ) : pKeyName = "svg"; break; + } + + return rtl::OUString::createFromAscii(pKeyName); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/igif/decode.cxx b/vcl/source/filter/igif/decode.cxx new file mode 100644 index 000000000000..09981f6e3d28 --- /dev/null +++ b/vcl/source/filter/igif/decode.cxx @@ -0,0 +1,207 @@ +/* -*- 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 "decode.hxx" + +// ------------------------------------------------------------------------ + +struct GIFLZWTableEntry +{ + GIFLZWTableEntry* pPrev; + GIFLZWTableEntry* pFirst; + sal_uInt8 nData; +}; + +// ------------------------------------------------------------------------ + +GIFLZWDecompressor::GIFLZWDecompressor( sal_uInt8 cDataSize ) : + nInputBitsBuf ( 0 ), + nOutBufDataLen ( 0 ), + nInputBitsBufSize ( 0 ), + bEOIFound ( sal_False ), + nDataSize ( cDataSize ) +{ + pOutBuf = new sal_uInt8[ 4096 ]; + + nClearCode = 1 << nDataSize; + nEOICode = nClearCode + 1; + nTableSize = nEOICode + 1; + nCodeSize = nDataSize + 1; + nOldCode = 0xffff; + pOutBufData = pOutBuf + 4096; + + pTable = new GIFLZWTableEntry[ 4098 ]; + + for( sal_uInt16 i = 0; i < nTableSize; i++ ) + { + pTable[i].pPrev = NULL; + pTable[i].pFirst = pTable + i; + pTable[i].nData = (sal_uInt8) i; + } +} + +// ------------------------------------------------------------------------ + +GIFLZWDecompressor::~GIFLZWDecompressor() +{ + delete[] pOutBuf; + delete[] pTable; +} + +// ------------------------------------------------------------------------ + +HPBYTE GIFLZWDecompressor::DecompressBlock( HPBYTE pSrc, sal_uInt8 cBufSize, + sal_uLong& rCount, sal_Bool& rEOI ) +{ + sal_uLong nTargetSize = 4096; + sal_uLong nCount = 0; + HPBYTE pTarget = (HPBYTE) rtl_allocateMemory( nTargetSize ); + HPBYTE pTmpTarget = pTarget; + + nBlockBufSize = cBufSize; + nBlockBufPos = 0; + pBlockBuf = pSrc; + + while( ProcessOneCode() ) + { + nCount += nOutBufDataLen; + + if( nCount > nTargetSize ) + { + sal_uLong nNewSize = nTargetSize << 1; + sal_uLong nOffset = pTmpTarget - pTarget; + HPBYTE pTmp = (HPBYTE) rtl_allocateMemory( nNewSize ); + + memcpy( pTmp, pTarget, nTargetSize ); + rtl_freeMemory( pTarget ); + + nTargetSize = nNewSize; + pTmpTarget = ( pTarget = pTmp ) + nOffset; + } + + memcpy( pTmpTarget, pOutBufData, nOutBufDataLen ); + pTmpTarget += nOutBufDataLen; + pOutBufData += nOutBufDataLen; + nOutBufDataLen = 0; + + if ( bEOIFound ) + break; + } + + rCount = nCount; + rEOI = bEOIFound; + + return pTarget; +} + +// ------------------------------------------------------------------------ + +void GIFLZWDecompressor::AddToTable( sal_uInt16 nPrevCode, sal_uInt16 nCodeFirstData ) +{ + GIFLZWTableEntry* pE; + + if( nTableSize < 4096 ) + { + pE = pTable + nTableSize; + pE->pPrev = pTable + nPrevCode; + pE->pFirst = pE->pPrev->pFirst; + pE->nData = pTable[ nCodeFirstData ].pFirst->nData; + nTableSize++; + + if ( ( nTableSize == (sal_uInt16) (1 << nCodeSize) ) && ( nTableSize < 4096 ) ) + nCodeSize++; + } +} + +// ------------------------------------------------------------------------ + +sal_Bool GIFLZWDecompressor::ProcessOneCode() +{ + GIFLZWTableEntry* pE; + sal_uInt16 nCode; + sal_Bool bRet = sal_False; + sal_Bool bEndOfBlock = sal_False; + + while( nInputBitsBufSize < nCodeSize ) + { + if( nBlockBufPos >= nBlockBufSize ) + { + bEndOfBlock = sal_True; + break; + } + + nInputBitsBuf |= ( (sal_uLong) pBlockBuf[ nBlockBufPos++ ] ) << nInputBitsBufSize; + nInputBitsBufSize += 8; + } + + if ( !bEndOfBlock ) + { + // Einen Code aus dem Eingabe-Buffer holen: + nCode = sal::static_int_cast< sal_uInt16 >( + ( (sal_uInt16) nInputBitsBuf ) & ( ~( 0xffff << nCodeSize ) )); + nInputBitsBuf >>= nCodeSize; + nInputBitsBufSize = nInputBitsBufSize - nCodeSize; + + if ( nCode < nClearCode ) + { + if ( nOldCode != 0xffff ) + AddToTable( nOldCode, nCode ); + } + else if ( ( nCode > nEOICode ) && ( nCode <= nTableSize ) ) + { + if ( nCode == nTableSize ) + AddToTable( nOldCode, nOldCode ); + else + AddToTable( nOldCode, nCode ); + } + else + { + if ( nCode == nClearCode ) + { + nTableSize = nEOICode + 1; + nCodeSize = nDataSize + 1; + nOldCode = 0xffff; + nOutBufDataLen = 0; + } + else + bEOIFound = sal_True; + + return sal_True; + } + + nOldCode = nCode; + + // Zeichen(/-folge) des Codes nCode in den Ausgabe-Buffer schreiben: + pE = pTable + nCode; + do + { + nOutBufDataLen++; + *(--pOutBufData) = pE->nData; + pE = pE->pPrev; + } + while( pE ); + + bRet = sal_True; + } + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/igif/decode.hxx b/vcl/source/filter/igif/decode.hxx new file mode 100644 index 000000000000..44523e44812a --- /dev/null +++ b/vcl/source/filter/igif/decode.hxx @@ -0,0 +1,60 @@ +/* -*- 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 _DECODE_HXX +#define _DECODE_HXX + +#include <vcl/bmpacc.hxx> + +struct GIFLZWTableEntry; + +class GIFLZWDecompressor +{ + GIFLZWTableEntry* pTable; + HPBYTE pOutBuf; + HPBYTE pOutBufData; + HPBYTE pBlockBuf; + sal_uLong nInputBitsBuf; + sal_uInt16 nTableSize; + sal_uInt16 nClearCode; + sal_uInt16 nEOICode; + sal_uInt16 nCodeSize; + sal_uInt16 nOldCode; + sal_uInt16 nOutBufDataLen; + sal_uInt16 nInputBitsBufSize; + sal_Bool bEOIFound; + sal_uInt8 nDataSize; + sal_uInt8 nBlockBufSize; + sal_uInt8 nBlockBufPos; + + void AddToTable(sal_uInt16 nPrevCode, sal_uInt16 nCodeFirstData); + sal_Bool ProcessOneCode(); + + +public: + + GIFLZWDecompressor( sal_uInt8 cDataSize ); + ~GIFLZWDecompressor(); + + HPBYTE DecompressBlock( HPBYTE pSrc, sal_uInt8 cBufSize, sal_uLong& rCount, sal_Bool& rEOI ); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/igif/gifread.cxx b/vcl/source/filter/igif/gifread.cxx new file mode 100644 index 000000000000..733fd9572bc2 --- /dev/null +++ b/vcl/source/filter/igif/gifread.cxx @@ -0,0 +1,865 @@ +/* -*- 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 . + */ + + +#define _GIFPRIVATE + +#include "decode.hxx" +#include "gifread.hxx" + +// ----------- +// - Defines - +// ----------- + +#define NO_PENDING( rStm ) ( ( rStm ).GetError() != ERRCODE_IO_PENDING ) + +// ------------- +// - GIFReader - +// ------------- + +GIFReader::GIFReader( SvStream& rStm ) : + aGPalette ( 256 ), + aLPalette ( 256 ), + rIStm ( rStm ), + pAcc8 ( NULL ), + pAcc1 ( NULL ), + nLastPos ( rStm.Tell() ), + nLogWidth100 ( 0UL ), + nLogHeight100 ( 0UL ), + nGlobalWidth ( 0 ), + nGlobalHeight ( 0 ), + nImageWidth ( 0 ), + nImageHeight ( 0 ), + nLoops ( 1 ), + eActAction ( GLOBAL_HEADER_READING ), + bGCTransparent ( sal_False ), + bImGraphicReady ( sal_False ) +{ + maUpperName = rtl::OUString("SVIGIF"); + pSrcBuf = new sal_uInt8[ 256 ]; + ClearImageExtensions(); +} + +// ------------------------------------------------------------------------ + +GIFReader::~GIFReader() +{ + aImGraphic.SetContext( NULL ); + + if( pAcc1 ) + aBmp1.ReleaseAccess( pAcc1 ); + + if( pAcc8 ) + aBmp8.ReleaseAccess( pAcc8 ); + + delete[] pSrcBuf; +} + +// ------------------------------------------------------------------------ + +void GIFReader::ClearImageExtensions() +{ + nGCDisposalMethod = 0; + bGCTransparent = sal_False; + nTimer = 0; +} + +// ------------------------------------------------------------------------ + +sal_Bool GIFReader::CreateBitmaps( long nWidth, long nHeight, BitmapPalette* pPal, + sal_Bool bWatchForBackgroundColor ) +{ + const Size aSize( nWidth, nHeight ); + +#ifdef __LP64__ + // Don't bother allocating a bitmap of a size that would fail on a + // 32-bit system. We have at least one unit tests that is expected + // to fail (loading a 65535*65535 size GIF + // svtools/qa/cppunit/data/gif/fail/CVE-2008-5937-1.gif), but + // which doesn't fail on 64-bit Mac OS X at least. Why the loading + // fails on 64-bit Linux, no idea. + if (nWidth >= 64000 && nHeight >= 64000) + { + bStatus = sal_False; + return bStatus; + } +#endif + + if( bGCTransparent ) + { + const Color aWhite( COL_WHITE ); + + aBmp1 = Bitmap( aSize, 1 ); + + if( !aAnimation.Count() ) + aBmp1.Erase( aWhite ); + + pAcc1 = aBmp1.AcquireWriteAccess(); + + if( pAcc1 ) + { + cTransIndex1 = (sal_uInt8) pAcc1->GetBestPaletteIndex( aWhite ); + cNonTransIndex1 = cTransIndex1 ? 0 : 1; + } + else + bStatus = sal_False; + } + + if( bStatus ) + { + aBmp8 = Bitmap( aSize, 8, pPal ); + + if( !!aBmp8 && bWatchForBackgroundColor && aAnimation.Count() ) + aBmp8.Erase( (*pPal)[ nBackgroundColor ] ); + else + aBmp8.Erase( Color( COL_WHITE ) ); + + pAcc8 = aBmp8.AcquireWriteAccess(); + bStatus = ( pAcc8 != NULL ); + } + + return bStatus; +} + +// ------------------------------------------------------------------------ + +sal_Bool GIFReader::ReadGlobalHeader() +{ + char pBuf[ 7 ]; + sal_uInt8 nRF; + sal_uInt8 nAspect; + sal_Bool bRet = sal_False; + + rIStm.Read( pBuf, 6 ); + if( NO_PENDING( rIStm ) ) + { + pBuf[ 6 ] = 0; + if( !strcmp( pBuf, "GIF87a" ) || !strcmp( pBuf, "GIF89a" ) ) + { + rIStm.Read( pBuf, 7 ); + if( NO_PENDING( rIStm ) ) + { + SvMemoryStream aMemStm; + + aMemStm.SetBuffer( pBuf, 7, sal_False, 7 ); + aMemStm >> nGlobalWidth; + aMemStm >> nGlobalHeight; + aMemStm >> nRF; + aMemStm >> nBackgroundColor; + aMemStm >> nAspect; + + bGlobalPalette = (sal_Bool) ( nRF & 0x80 ); + + if( bGlobalPalette ) + ReadPaletteEntries( &aGPalette, 1 << ( ( nRF & 7 ) + 1 ) ); + else + nBackgroundColor = 0; + + if( NO_PENDING( rIStm ) ) + bRet = sal_True; + } + } + else + bStatus = sal_False; + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +void GIFReader::ReadPaletteEntries( BitmapPalette* pPal, sal_uLong nCount ) +{ + const sal_uLong nLen = 3UL * nCount; + sal_uInt8* pBuf = new sal_uInt8[ nLen ]; + + rIStm.Read( pBuf, nLen ); + if( NO_PENDING( rIStm ) ) + { + sal_uInt8* pTmp = pBuf; + + for( sal_uLong i = 0UL; i < nCount; ) + { + BitmapColor& rColor = (*pPal)[ (sal_uInt16) i++ ]; + + rColor.SetRed( *pTmp++ ); + rColor.SetGreen( *pTmp++ ); + rColor.SetBlue( *pTmp++ ); + } + + // nach Moeglichkeit noch einige Standardfarben unterbringen + if( nCount < 256UL ) + { + (*pPal)[ 255UL ] = Color( COL_WHITE ); + + if( nCount < 255UL ) + (*pPal)[ 254UL ] = Color( COL_BLACK ); + } + } + + delete[] pBuf; +} + +// ------------------------------------------------------------------------ + +sal_Bool GIFReader::ReadExtension() +{ + sal_uInt8 cFunction; + sal_uInt8 cSize; + sal_uInt8 cByte; + sal_Bool bRet = sal_False; + sal_Bool bOverreadDataBlocks = sal_False; + + // Extension-Label + rIStm >> cFunction; + if( NO_PENDING( rIStm ) ) + { + // Block-Laenge + rIStm >> cSize; + + switch( cFunction ) + { + // 'Graphic Control Extension' + case( 0xf9 ) : + { + sal_uInt8 cFlags; + + rIStm >> cFlags; + rIStm >> nTimer; + rIStm >> nGCTransparentIndex; + rIStm >> cByte; + + if ( NO_PENDING( rIStm ) ) + { + nGCDisposalMethod = ( cFlags >> 2) & 7; + bGCTransparent = ( cFlags & 1 ) ? sal_True : sal_False; + bStatus = ( cSize == 4 ) && ( cByte == 0 ); + bRet = sal_True; + } + } + break; + + // Application-Extension + case ( 0xff ) : + { + if ( NO_PENDING( rIStm ) ) + { + // default diese Extension ueberlesen + bOverreadDataBlocks = sal_True; + + // Appl.-Extension hat Laenge 11 + if ( cSize == 0x0b ) + { + rtl::OString aAppId = read_uInt8s_ToOString(rIStm, 8); + rtl::OString aAppCode = read_uInt8s_ToOString(rIStm, 3); + rIStm >> cSize; + + // NetScape-Extension + if( aAppId.equalsL(RTL_CONSTASCII_STRINGPARAM("NETSCAPE")) && aAppCode.equalsL(RTL_CONSTASCII_STRINGPARAM("2.0")) && cSize == 3 ) + { + rIStm >> cByte; + + // Loop-Extension + if ( cByte == 0x01 ) + { + rIStm >> cByte; + nLoops = cByte; + rIStm >> cByte; + nLoops |= ( (sal_uInt16) cByte << 8 ); + rIStm >> cByte; + + bStatus = ( cByte == 0 ); + bRet = NO_PENDING( rIStm ); + bOverreadDataBlocks = sal_False; + + // Netscape interpretiert den LoopCount + // als reine Anzahl der _Wiederholungen_; + // bei uns ist es die Gesamtanzahl der + // Durchlaeufe + if( nLoops ) + nLoops++; + } + else + rIStm.SeekRel( -1 ); + } + else if ( aAppId.equalsL(RTL_CONSTASCII_STRINGPARAM("STARDIV ")) && aAppCode.equalsL(RTL_CONSTASCII_STRINGPARAM("5.0")) && cSize == 9 ) + { + rIStm >> cByte; + + // Loop-Extension + if ( cByte == 0x01 ) + { + rIStm >> nLogWidth100 >> nLogHeight100; + rIStm >> cByte; + bStatus = ( cByte == 0 ); + bRet = NO_PENDING( rIStm ); + bOverreadDataBlocks = sal_False; + } + else + rIStm.SeekRel( -1 ); + } + + } + } + } + break; + + // alles andere ueberlesen + default: + bOverreadDataBlocks = sal_True; + break; + } + + // Sub-Blocks ueberlesen + if ( bOverreadDataBlocks ) + { + bRet = sal_True; + while( cSize && bStatus && !rIStm.IsEof() ) + { + sal_uInt16 nCount = (sal_uInt16) cSize + 1; + char* pBuffer = new char[ nCount ]; + + bRet = sal_False; + rIStm.Read( pBuffer, nCount ); + if( NO_PENDING( rIStm ) ) + { + cSize = (sal_uInt8) pBuffer[ cSize ]; + bRet = sal_True; + } + else + cSize = 0; + + delete[] pBuffer; + } + } + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +sal_Bool GIFReader::ReadLocalHeader() +{ + sal_uInt8 pBuf[ 9 ]; + sal_Bool bRet = sal_False; + + rIStm.Read( pBuf, 9 ); + if( NO_PENDING( rIStm ) ) + { + SvMemoryStream aMemStm; + BitmapPalette* pPal; + sal_uInt8 nFlags; + + aMemStm.SetBuffer( (char*) pBuf, 9, sal_False, 9 ); + aMemStm >> nImagePosX; + aMemStm >> nImagePosY; + aMemStm >> nImageWidth; + aMemStm >> nImageHeight; + aMemStm >> nFlags; + + // Falls Interlaced, ersten Startwert vorgeben + bInterlaced = ( ( nFlags & 0x40 ) == 0x40 ); + nLastInterCount = 7; + nLastImageY = 0; + + if( nFlags & 0x80 ) + { + pPal = &aLPalette; + ReadPaletteEntries( pPal, 1 << ( (nFlags & 7 ) + 1 ) ); + } + else + pPal = &aGPalette; + + // Falls alles soweit eingelesen werden konnte, kann + // nun das lokale Bild angelegt werden; + // es wird uebergeben, ob der BackgroundColorIndex evtl. + // beruecksichtigt werden soll ( wenn Globale Farbtab. und + // diese auch fuer dieses Bild gilt ) + if( NO_PENDING( rIStm ) ) + { + CreateBitmaps( nImageWidth, nImageHeight, pPal, bGlobalPalette && ( pPal == &aGPalette ) ); + bRet = sal_True; + } + } + + return bRet; +} + +// ------------------------------------------------------------------------ + +sal_uLong GIFReader::ReadNextBlock() +{ + sal_uLong nRet = 0UL; + sal_uLong nRead; + sal_uInt8 cBlockSize; + + rIStm >> cBlockSize; + + if ( rIStm.IsEof() ) + nRet = 4UL; + else if ( NO_PENDING( rIStm ) ) + { + if ( cBlockSize == 0 ) + nRet = 2UL; + else + { + rIStm.Read( pSrcBuf, cBlockSize ); + + if( NO_PENDING( rIStm ) ) + { + if( bOverreadBlock ) + nRet = 3UL; + else + { + sal_Bool bEOI; + HPBYTE pTarget = pDecomp->DecompressBlock( pSrcBuf, cBlockSize, nRead, bEOI ); + + nRet = ( bEOI ? 3 : 1 ); + + if( nRead && !bOverreadBlock ) + FillImages( pTarget, nRead ); + + rtl_freeMemory( pTarget ); + } + } + } + } + + return nRet; +} + +// ------------------------------------------------------------------------ + +void GIFReader::FillImages( HPBYTE pBytes, sal_uLong nCount ) +{ + for( sal_uLong i = 0UL; i < nCount; i++ ) + { + if( nImageX >= nImageWidth ) + { + if( bInterlaced ) + { + long nT1, nT2; + + // falls Interlaced, werden die Zeilen kopiert + if( nLastInterCount ) + { + long nMinY = Min( (long) nLastImageY + 1, (long) nImageHeight - 1 ); + long nMaxY = Min( (long) nLastImageY + nLastInterCount, (long) nImageHeight - 1 ); + + // letzte gelesene Zeile kopieren, wenn Zeilen + // nicht zusanmmenfallen ( kommt vorm wenn wir am Ende des Bildes sind ) + if( ( nMinY > nLastImageY ) && ( nLastImageY < ( nImageHeight - 1 ) ) ) + { + HPBYTE pScanline8 = pAcc8->GetScanline( nYAcc ); + sal_uLong nSize8 = pAcc8->GetScanlineSize(); + HPBYTE pScanline1 = 0; + sal_uLong nSize1 = 0; + + if( bGCTransparent ) + { + pScanline1 = pAcc1->GetScanline( nYAcc ); + nSize1 = pAcc1->GetScanlineSize(); + } + + for( long j = nMinY; j <= nMaxY; j++ ) + { + memcpy( pAcc8->GetScanline( j ), pScanline8, nSize8 ); + + if( bGCTransparent ) + memcpy( pAcc1->GetScanline( j ), pScanline1, nSize1 ); + } + } + } + + nT1 = ( ++nImageY ) << 3; + nLastInterCount = 7; + + if( nT1 >= nImageHeight ) + { + nT2 = nImageY - ( ( nImageHeight + 7 ) >> 3 ); + nT1 = ( nT2 << 3 ) + 4; + nLastInterCount = 3; + + if( nT1 >= nImageHeight ) + { + nT2 -= ( nImageHeight + 3 ) >> 3; + nT1 = ( nT2 << 2 ) + 2; + nLastInterCount = 1; + + if( nT1 >= nImageHeight ) + { + nT2 -= ( nImageHeight + 1 ) >> 2; + nT1 = ( nT2 << 1 ) + 1; + nLastInterCount = 0; + } + } + } + + nLastImageY = (sal_uInt16) nT1; + nYAcc = nT1; + } + else + { + nLastImageY = ++nImageY; + nYAcc = nImageY; + } + + // Zeile faengt von vorne an + nImageX = 0; + } + + if( nImageY < nImageHeight ) + { + const sal_uInt8 cTmp = pBytes[ i ]; + + if( bGCTransparent ) + { + if( cTmp == nGCTransparentIndex ) + pAcc1->SetPixel( nYAcc, nImageX++, cTransIndex1 ); + else + { + pAcc8->SetPixel( nYAcc, nImageX, cTmp ); + pAcc1->SetPixel( nYAcc, nImageX++, cNonTransIndex1 ); + } + } + else + pAcc8->SetPixel( nYAcc, nImageX++, cTmp ); + } + else + { + bOverreadBlock = sal_True; + break; + } + } +} + +// ------------------------------------------------------------------------ + +void GIFReader::CreateNewBitmaps() +{ + AnimationBitmap aAnimBmp; + + aBmp8.ReleaseAccess( pAcc8 ); + pAcc8 = NULL; + + if( bGCTransparent ) + { + aBmp1.ReleaseAccess( pAcc1 ); + pAcc1 = NULL; + aAnimBmp.aBmpEx = BitmapEx( aBmp8, aBmp1 ); + } + else + aAnimBmp.aBmpEx = BitmapEx( aBmp8 ); + + aAnimBmp.aPosPix = Point( nImagePosX, nImagePosY ); + aAnimBmp.aSizePix = Size( nImageWidth, nImageHeight ); + aAnimBmp.nWait = ( nTimer != 65535 ) ? nTimer : ANIMATION_TIMEOUT_ON_CLICK; + aAnimBmp.bUserInput = sal_False; + + if( nGCDisposalMethod == 2 ) + aAnimBmp.eDisposal = DISPOSE_BACK; + else if( nGCDisposalMethod == 3 ) + aAnimBmp.eDisposal = DISPOSE_PREVIOUS; + else + aAnimBmp.eDisposal = DISPOSE_NOT; + + aAnimation.Insert( aAnimBmp ); + + if( aAnimation.Count() == 1 ) + { + aAnimation.SetDisplaySizePixel( Size( nGlobalWidth, nGlobalHeight ) ); + aAnimation.SetLoopCount( nLoops ); + } +} + +// ------------------------------------------------------------------------ + +const Graphic& GIFReader::GetIntermediateGraphic() +{ + // Intermediate-Graphic nur erzeugen, wenn schon + // Daten vorliegen, aber die Graphic noch nicht + // vollstaendig eingelesen wurde + if ( bImGraphicReady && !aAnimation.Count() ) + { + Bitmap aBmp; + + aBmp8.ReleaseAccess( pAcc8 ); + + if ( bGCTransparent ) + { + aBmp1.ReleaseAccess( pAcc1 ); + aImGraphic = BitmapEx( aBmp8, aBmp1 ); + + pAcc1 = aBmp1.AcquireWriteAccess(); + bStatus = bStatus && ( pAcc1 != NULL ); + } + else + aImGraphic = aBmp8; + + pAcc8 = aBmp8.AcquireWriteAccess(); + bStatus = bStatus && ( pAcc8 != NULL ); + } + + return aImGraphic; +} + +// ------------------------------------------------------------------------ + +sal_Bool GIFReader::ProcessGIF() +{ + sal_Bool bRead = sal_False; + sal_Bool bEnd = sal_False; + + if ( !bStatus ) + eActAction = ABORT_READING; + + // Stream an die richtige Stelle bringen + rIStm.Seek( nLastPos ); + + switch( eActAction ) + { + // naechsten Marker lesen + case( MARKER_READING ): + { + sal_uInt8 cByte; + + rIStm >> cByte; + + if( rIStm.IsEof() ) + eActAction = END_READING; + else if( NO_PENDING( rIStm ) ) + { + bRead = sal_True; + + if( cByte == '!' ) + eActAction = EXTENSION_READING; + else if( cByte == ',' ) + eActAction = LOCAL_HEADER_READING; + else if( cByte == ';' ) + eActAction = END_READING; + else + eActAction = ABORT_READING; + } + } + break; + + // ScreenDescriptor lesen + case( GLOBAL_HEADER_READING ): + { + if( ( bRead = ReadGlobalHeader() ) == sal_True ) + { + ClearImageExtensions(); + eActAction = MARKER_READING; + } + } + break; + + + // Extension lesen + case( EXTENSION_READING ): + { + if( ( bRead = ReadExtension() ) == sal_True ) + eActAction = MARKER_READING; + } + break; + + + // Image-Descriptor lesen + case( LOCAL_HEADER_READING ): + { + if( ( bRead = ReadLocalHeader() ) == sal_True ) + { + nYAcc = nImageX = nImageY = 0; + eActAction = FIRST_BLOCK_READING; + } + } + break; + + + // ersten Datenblock lesen + case( FIRST_BLOCK_READING ): + { + sal_uInt8 cDataSize; + + rIStm >> cDataSize; + + if( rIStm.IsEof() ) + eActAction = ABORT_READING; + else if( cDataSize > 12 ) + bStatus = sal_False; + else if( NO_PENDING( rIStm ) ) + { + bRead = sal_True; + pDecomp = new GIFLZWDecompressor( cDataSize ); + eActAction = NEXT_BLOCK_READING; + bOverreadBlock = sal_False; + } + else + eActAction = FIRST_BLOCK_READING; + } + break; + + // naechsten Datenblock lesen + case( NEXT_BLOCK_READING ): + { + sal_uInt16 nLastX = nImageX; + sal_uInt16 nLastY = nImageY; + sal_uLong nRet = ReadNextBlock(); + + // Return: 0:Pending / 1:OK; / 2:OK und letzter Block: / 3:EOI / 4:HardAbort + if( nRet ) + { + bRead = sal_True; + + if ( nRet == 1UL ) + { + bImGraphicReady = sal_True; + eActAction = NEXT_BLOCK_READING; + bOverreadBlock = sal_False; + } + else + { + if( nRet == 2UL ) + { + delete pDecomp; + CreateNewBitmaps(); + eActAction = MARKER_READING; + ClearImageExtensions(); + } + else if( nRet == 3UL ) + { + eActAction = NEXT_BLOCK_READING; + bOverreadBlock = sal_True; + } + else + { + delete pDecomp; + CreateNewBitmaps(); + eActAction = ABORT_READING; + ClearImageExtensions(); + } + } + } + else + { + nImageX = nLastX; + nImageY = nLastY; + } + } + break; + + // ein Fehler trat auf + case( ABORT_READING ): + { + bEnd = sal_True; + eActAction = END_READING; + } + break; + + default: + break; + } + + // Stream an die richtige Stelle bringen, + // falls Daten gelesen werden konnten + // entweder alte Position oder aktuelle Position + if( bRead || bEnd ) + nLastPos = rIStm.Tell(); + + return bRead; +} + +// ------------------------------------------------------------------------ + +ReadState GIFReader::ReadGIF( Graphic& rGraphic ) +{ + ReadState eReadState; + + bStatus = sal_True; + + while( ProcessGIF() && ( eActAction != END_READING ) ) {} + + if( !bStatus ) + eReadState = GIFREAD_ERROR; + else if( eActAction == END_READING ) + eReadState = GIFREAD_OK; + else + { + if ( rIStm.GetError() == ERRCODE_IO_PENDING ) + rIStm.ResetError(); + + eReadState = GIFREAD_NEED_MORE; + } + + if( aAnimation.Count() == 1 ) + { + rGraphic = aAnimation.Get( 0 ).aBmpEx; + + if( nLogWidth100 && nLogHeight100 ) + { + rGraphic.SetPrefSize( Size( nLogWidth100, nLogHeight100 ) ); + rGraphic.SetPrefMapMode( MAP_100TH_MM ); + } + } + else + rGraphic = aAnimation; + + return eReadState; +} + + +// ------------- +// - ImportGIF - +// ------------- + +sal_Bool ImportGIF( SvStream & rStm, Graphic& rGraphic ) +{ + GIFReader* pGIFReader = (GIFReader*) rGraphic.GetContext(); + sal_uInt16 nOldFormat = rStm.GetNumberFormatInt(); + ReadState eReadState; + sal_Bool bRet = sal_True; + + rStm.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + + if( !pGIFReader ) + pGIFReader = new GIFReader( rStm ); + + rGraphic.SetContext( NULL ); + eReadState = pGIFReader->ReadGIF( rGraphic ); + + if( eReadState == GIFREAD_ERROR ) + { + bRet = sal_False; + delete pGIFReader; + } + else if( eReadState == GIFREAD_OK ) + delete pGIFReader; + else + { + rGraphic = pGIFReader->GetIntermediateGraphic(); + rGraphic.SetContext( pGIFReader ); + } + + rStm.SetNumberFormatInt( nOldFormat ); + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/igif/gifread.hxx b/vcl/source/filter/igif/gifread.hxx new file mode 100644 index 000000000000..35d9b3aa250d --- /dev/null +++ b/vcl/source/filter/igif/gifread.hxx @@ -0,0 +1,133 @@ +/* -*- 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 _GIFREAD_HXX +#define _GIFREAD_HXX + +#include <vcl/graph.hxx> +#include <vcl/bmpacc.hxx> + +#ifdef _GIFPRIVATE + +// --------- +// - Enums - +// --------- + +enum GIFAction +{ + GLOBAL_HEADER_READING, + MARKER_READING, + EXTENSION_READING, + LOCAL_HEADER_READING, + FIRST_BLOCK_READING, + NEXT_BLOCK_READING, + ABORT_READING, + END_READING +}; + +// ------------------------------------------------------------------------ + +enum ReadState +{ + GIFREAD_OK, + GIFREAD_ERROR, + GIFREAD_NEED_MORE +}; + +// ------------- +// - GIFReader - +// ------------- + +class GIFLZWDecompressor; + +class SvStream; + +class GIFReader : public GraphicReader +{ + Graphic aImGraphic; + Animation aAnimation; + Bitmap aBmp8; + Bitmap aBmp1; + BitmapPalette aGPalette; + BitmapPalette aLPalette; + SvStream& rIStm; + HPBYTE pSrcBuf; + GIFLZWDecompressor* pDecomp; + BitmapWriteAccess* pAcc8; + BitmapWriteAccess* pAcc1; + long nYAcc; + long nLastPos; + sal_uInt32 nLogWidth100; + sal_uInt32 nLogHeight100; + sal_uInt16 nTimer; + sal_uInt16 nGlobalWidth; // maximale Bildbreite aus Header + sal_uInt16 nGlobalHeight; // maximale Bildhoehe aus Header + sal_uInt16 nImageWidth; // maximale Bildbreite aus Header + sal_uInt16 nImageHeight; // maximale Bildhoehe aus Header + sal_uInt16 nImagePosX; + sal_uInt16 nImagePosY; + sal_uInt16 nImageX; // maximale Bildbreite aus Header + sal_uInt16 nImageY; // maximale Bildhoehe aus Header + sal_uInt16 nLastImageY; + sal_uInt16 nLastInterCount; + sal_uInt16 nLoops; + GIFAction eActAction; + sal_Bool bStatus; + sal_Bool bGCTransparent; // Ob das Bild Transparent ist, wenn ja: + sal_Bool bInterlaced; + sal_Bool bOverreadBlock; + sal_Bool bImGraphicReady; + sal_Bool bGlobalPalette; + sal_uInt8 nBackgroundColor; // Hintergrundfarbe + sal_uInt8 nGCTransparentIndex; // Pixel von diesem Index sind durchsichtig + sal_uInt8 nGCDisposalMethod; // 'Disposal Method' (siehe GIF-Doku) + sal_uInt8 cTransIndex1; + sal_uInt8 cNonTransIndex1; + + void ReadPaletteEntries( BitmapPalette* pPal, sal_uLong nCount ); + void ClearImageExtensions(); + sal_Bool CreateBitmaps( long nWidth, long nHeight, BitmapPalette* pPal, sal_Bool bWatchForBackgroundColor ); + sal_Bool ReadGlobalHeader(); + sal_Bool ReadExtension(); + sal_Bool ReadLocalHeader(); + sal_uLong ReadNextBlock(); + void FillImages( HPBYTE pBytes, sal_uLong nCount ); + void CreateNewBitmaps(); + sal_Bool ProcessGIF(); + +public: + + ReadState ReadGIF( Graphic& rGraphic ); + const Graphic& GetIntermediateGraphic(); + + GIFReader( SvStream& rStm ); + virtual ~GIFReader(); +}; + +#endif // _GIFPRIVATE + +// ------------- +// - ImportGIF - +// ------------- + + sal_Bool ImportGIF( SvStream& rStream, Graphic& rGraphic ); + +#endif // _GIFREAD_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/ixbm/xbmread.cxx b/vcl/source/filter/ixbm/xbmread.cxx new file mode 100644 index 000000000000..762c6adee913 --- /dev/null +++ b/vcl/source/filter/ixbm/xbmread.cxx @@ -0,0 +1,385 @@ +/* -*- 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 . + */ + + +#define _XBMPRIVATE +#include <ctype.h> +#include <comphelper/string.hxx> +#include "xbmread.hxx" + +// ------------- +// - XBMReader - +// ------------- + +XBMReader::XBMReader( SvStream& rStm ) : + rIStm ( rStm ), + pAcc1 ( NULL ), + nLastPos ( rStm.Tell() ), + nWidth ( 0 ), + nHeight ( 0 ), + bStatus ( sal_True ) +{ + pHexTable = new short[ 256 ]; + maUpperName = rtl::OUString("SVIXBM"); + InitTable(); +} + +// ------------------------------------------------------------------------ + +XBMReader::~XBMReader() +{ + delete[] pHexTable; + + if( pAcc1 ) + aBmp1.ReleaseAccess( pAcc1 ); +} + +// ------------------------------------------------------------------------ + +void XBMReader::InitTable() +{ + memset( pHexTable, 0, sizeof( short ) * 256 ); + + pHexTable[(int)'0'] = 0; + pHexTable[(int)'1'] = 1; + pHexTable[(int)'2'] = 2; + pHexTable[(int)'3'] = 3; + pHexTable[(int)'4'] = 4; + pHexTable[(int)'5'] = 5; + pHexTable[(int)'6'] = 6; + pHexTable[(int)'7'] = 7; + pHexTable[(int)'8'] = 8; + pHexTable[(int)'9'] = 9; + pHexTable[(int)'A'] = 10; + pHexTable[(int)'B'] = 11; + pHexTable[(int)'C'] = 12; + pHexTable[(int)'D'] = 13; + pHexTable[(int)'E'] = 14; + pHexTable[(int)'F'] = 15; + pHexTable[(int)'X'] = 0; + pHexTable[(int)'a'] = 10; + pHexTable[(int)'b'] = 11; + pHexTable[(int)'c'] = 12; + pHexTable[(int)'d'] = 13; + pHexTable[(int)'e'] = 14; + pHexTable[(int)'f'] = 15; + pHexTable[(int)'x'] = 0; + pHexTable[(int)' '] = -1; + pHexTable[(int)','] = -1; + pHexTable[(int)'}'] = -1; + pHexTable[(int)'\n'] = -1; + pHexTable[(int)'\t'] = -1; + pHexTable[(int)'\0'] = -1; +} + +// ------------------------------------------------------------------------ + +rtl::OString XBMReader::FindTokenLine( SvStream* pInStm, const char* pTok1, + const char* pTok2, const char* pTok3 ) +{ + rtl::OString aRet; + sal_Int32 nPos1, nPos2, nPos3; + + bStatus = sal_False; + + do + { + if( !pInStm->ReadLine( aRet ) ) + break; + + if( pTok1 ) + { + if( ( nPos1 = aRet.indexOf( pTok1 ) ) != -1 ) + { + bStatus = sal_True; + + if( pTok2 ) + { + bStatus = sal_False; + + if( ( ( nPos2 = aRet.indexOf( pTok2 ) ) != -1 ) && + ( nPos2 > nPos1 ) ) + { + bStatus = sal_True; + + if( pTok3 ) + { + bStatus = sal_False; + + if( ( ( nPos3 = aRet.indexOf( pTok3 ) ) != -1 ) && ( nPos3 > nPos2 ) ) + bStatus = sal_True; + } + } + } + } + } + } + while( !bStatus ); + + return aRet; +} + +// ------------------------------------------------------------------------ + +long XBMReader::ParseDefine( const sal_Char* pDefine ) +{ + long nRet = 0; + char* pTmp = (char*) pDefine; + unsigned char cTmp; + + // bis zum Ende gehen + pTmp += ( strlen( pDefine ) - 1 ); + cTmp = *pTmp--; + + // letzte Ziffer suchen + while( pHexTable[ cTmp ] == -1 ) + cTmp = *pTmp--; + + // bis vor die Zahl laufen + while( pHexTable[ cTmp ] != -1 ) + cTmp = *pTmp--; + + // auf Anfang der Zahl gehen + pTmp += 2; + + // Hex lesen + if( ( pTmp[0] == '0' ) && ( ( pTmp[1] == 'X' ) || ( pTmp[1] == 'x' ) ) ) + { + pTmp += 2; + cTmp = *pTmp++; + + while ( pHexTable[ cTmp ] != -1 ) + { + nRet = ( nRet << 4 ) + pHexTable[ cTmp ]; + cTmp = *pTmp++; + } + } + // Dezimal lesen + else + { + cTmp = *pTmp++; + while( ( cTmp >= '0' ) && ( cTmp <= '9' ) ) + { + nRet = nRet * 10 + ( cTmp - '0' ); + cTmp = *pTmp++; + } + } + + return nRet; +} + +// ------------------------------------------------------------------------ + +sal_Bool XBMReader::ParseData( SvStream* pInStm, const rtl::OString& aLastLine, XBMFormat eFormat ) +{ + rtl::OString aLine; + long nRow = 0; + long nCol = 0; + long nBits = ( eFormat == XBM10 ) ? 16 : 8; + long nBit; + sal_uInt16 nValue; + sal_uInt16 nDigits; + sal_Bool bFirstLine = sal_True; + + while( nRow < nHeight ) + { + if( bFirstLine ) + { + sal_Int32 nPos; + + // einfuehrende geschweifte Klammer loeschen + if( (nPos = ( aLine = aLastLine ).indexOf('{') ) != -1 ) + aLine = aLine.copy(nPos + 1); + + bFirstLine = sal_False; + } + else if( !pInStm->ReadLine( aLine ) ) + break; + + if (!aLine.isEmpty()) + { + const sal_Int32 nCount = comphelper::string::getTokenCount(aLine, ','); + + for( sal_Int32 i = 0; ( i < nCount ) && ( nRow < nHeight ); ++i ) + { + const rtl::OString aToken(comphelper::string::getToken(aLine,i, ',')); + const sal_Int32 nLen = aToken.getLength(); + sal_Bool bProcessed = sal_False; + + nBit = nDigits = nValue = 0; + + for (sal_Int32 n = 0; n < nLen; ++n) + { + const unsigned char cChar = aToken[n]; + const short nTable = pHexTable[ cChar ]; + + if( isxdigit( cChar ) || !nTable ) + { + nValue = ( nValue << 4 ) + nTable; + nDigits++; + bProcessed = sal_True; + } + else if( ( nTable < 0 ) && nDigits ) + { + bProcessed = sal_True; + break; + } + } + + if( bProcessed ) + { + while( ( nCol < nWidth ) && ( nBit < nBits ) ) + pAcc1->SetPixel( nRow, nCol++, ( nValue & ( 1 << nBit++ ) ) ? aBlack : aWhite ); + + if( nCol == nWidth ) + nCol = 0, nRow++; + } + } + } + } + + return sal_True; +} + +// ------------------------------------------------------------------------ + +ReadState XBMReader::ReadXBM( Graphic& rGraphic ) +{ + ReadState eReadState; + sal_uInt8 cDummy; + + // sehen, ob wir _alles_ lesen koennen + rIStm.Seek( STREAM_SEEK_TO_END ); + rIStm >> cDummy; + + // falls wir nicht alles lesen koennen + // kehren wir zurueck und warten auf neue Daten + if ( rIStm.GetError() != ERRCODE_IO_PENDING ) + { + rIStm.Seek( nLastPos ); + bStatus = sal_False; + rtl::OString aLine = FindTokenLine( &rIStm, "#define", "_width" ); + + if ( bStatus ) + { + int nValue; + if ( ( nValue = (int) ParseDefine( aLine.getStr() ) ) > 0 ) + { + nWidth = nValue; + aLine = FindTokenLine( &rIStm, "#define", "_height" ); + + // Falls die Hoehe nicht folgt, suchen wir noch + // einmal vom Anfang der Datei an + if ( !bStatus ) + { + rIStm.Seek( nLastPos ); + aLine = FindTokenLine( &rIStm, "#define", "_height" ); + } + } + else + bStatus = sal_False; + + if ( bStatus ) + { + if ( ( nValue = (int) ParseDefine( aLine.getStr() ) ) > 0 ) + { + nHeight = nValue; + aLine = FindTokenLine( &rIStm, "static", "_bits" ); + + if ( bStatus ) + { + XBMFormat eFormat = XBM10; + + if (aLine.indexOfL(RTL_CONSTASCII_STRINGPARAM("short")) != -1) + eFormat = XBM10; + else if (aLine.indexOfL(RTL_CONSTASCII_STRINGPARAM("char")) != -1) + eFormat = XBM11; + else + bStatus = sal_False; + + if ( bStatus && nWidth && nHeight ) + { + aBmp1 = Bitmap( Size( nWidth, nHeight ), 1 ); + pAcc1 = aBmp1.AcquireWriteAccess(); + + if( pAcc1 ) + { + aWhite = pAcc1->GetBestMatchingColor( Color( COL_WHITE ) ); + aBlack = pAcc1->GetBestMatchingColor( Color( COL_BLACK ) ); + bStatus = ParseData( &rIStm, aLine, eFormat ); + } + else + bStatus = sal_False; + } + } + } + } + } + + if( bStatus ) + { + Bitmap aBlackBmp( Size( pAcc1->Width(), pAcc1->Height() ), 1 ); + + aBmp1.ReleaseAccess( pAcc1 ), pAcc1 = NULL; + aBlackBmp.Erase( Color( COL_BLACK ) ); + rGraphic = BitmapEx( aBlackBmp, aBmp1 ); + eReadState = XBMREAD_OK; + } + else + eReadState = XBMREAD_ERROR; + } + else + { + rIStm.ResetError(); + eReadState = XBMREAD_NEED_MORE; + } + + return eReadState; +} + +// ------------- +// - ImportXBM - +// ------------- + +sal_Bool ImportXBM( SvStream& rStm, Graphic& rGraphic ) +{ + XBMReader* pXBMReader = (XBMReader*) rGraphic.GetContext(); + ReadState eReadState; + sal_Bool bRet = sal_True; + + if( !pXBMReader ) + pXBMReader = new XBMReader( rStm ); + + rGraphic.SetContext( NULL ); + eReadState = pXBMReader->ReadXBM( rGraphic ); + + if( eReadState == XBMREAD_ERROR ) + { + bRet = sal_False; + delete pXBMReader; + } + else if( eReadState == XBMREAD_OK ) + delete pXBMReader; + else + rGraphic.SetContext( pXBMReader ); + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/ixbm/xbmread.hxx b/vcl/source/filter/ixbm/xbmread.hxx new file mode 100644 index 000000000000..1b66f0956a76 --- /dev/null +++ b/vcl/source/filter/ixbm/xbmread.hxx @@ -0,0 +1,87 @@ +/* -*- 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 _XBMREAD_HXX +#define _XBMREAD_HXX + +#include <vcl/graph.hxx> +#include <vcl/bmpacc.hxx> + +#ifdef _XBMPRIVATE + +// --------- +// - Enums - +// --------- + +enum XBMFormat +{ + XBM10, + XBM11 +}; + +enum ReadState +{ + XBMREAD_OK, + XBMREAD_ERROR, + XBMREAD_NEED_MORE +}; + +// ------------- +// - XBMReader - +// ------------- + +class XBMReader : public GraphicReader +{ + SvStream& rIStm; + Bitmap aBmp1; + BitmapWriteAccess* pAcc1; + short* pHexTable; + BitmapColor aWhite; + BitmapColor aBlack; + long nLastPos; + long nWidth; + long nHeight; + sal_Bool bStatus; + + void InitTable(); + rtl::OString FindTokenLine( SvStream* pInStm, const char* pTok1, + const char* pTok2 = NULL, const char* pTok3 = NULL ); + long ParseDefine( const sal_Char* pDefine ); + sal_Bool ParseData( SvStream* pInStm, const rtl::OString& aLastLine, XBMFormat eFormat ); + + +public: + + XBMReader( SvStream& rStm ); + virtual ~XBMReader(); + + ReadState ReadXBM( Graphic& rGraphic ); +}; + +#endif // _XBMPRIVATE + +// ------------- +// - ImportXBM - +// ------------- + +sal_Bool ImportXBM( SvStream& rStream, Graphic& rGraphic ); + +#endif // _XBMREAD_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/ixpm/rgbtable.hxx b/vcl/source/filter/ixpm/rgbtable.hxx new file mode 100644 index 000000000000..8f86fe8c371c --- /dev/null +++ b/vcl/source/filter/ixpm/rgbtable.hxx @@ -0,0 +1,689 @@ +/* -*- 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 . + */ + +struct XPMRGBTab +{ + const char* name; + sal_uInt8 red; + sal_uInt8 green; + sal_uInt8 blue; +}; + +static XPMRGBTab pRGBTable[] = { +{ "white", 255, 255, 255 }, +{ "black", 0, 0, 0 }, +{ "snow", 255, 250, 250 }, +{ "GhostWhite", 248, 248, 255 }, +{ "WhiteSmoke", 245, 245, 245 }, +{ "gainsboro", 220, 220, 220 }, +{ "FloralWhite", 255, 250, 240 }, +{ "OldLace", 253, 245, 230 }, +{ "linen", 250, 240, 230 }, +{ "AntiqueWhite", 250, 235, 215 }, +{ "PapayaWhip", 255, 239, 213 }, +{ "BlanchedAlmond", 255, 235, 205 }, +{ "bisque", 255, 228, 196 }, +{ "PeachPuff", 255, 218, 185 }, +{ "NavajoWhite", 255, 222, 173 }, +{ "moccasin", 255, 228, 181 }, +{ "cornsilk", 255, 248, 220 }, +{ "ivory", 255, 255, 240 }, +{ "LemonChiffon", 255, 250, 205 }, +{ "seashell", 255, 245, 238 }, +{ "honeydew", 240, 255, 240 }, +{ "MintCream", 245, 255, 250 }, +{ "azure", 240, 255, 255 }, +{ "AliceBlue", 240, 248, 255 }, +{ "lavender", 230, 230, 250 }, +{ "LavenderBlush", 255, 240, 245 }, +{ "MistyRose", 255, 228, 225 }, +{ "DarkSlateGray", 47, 79, 79 }, +{ "DarkSlateGrey", 47, 79, 79 }, +{ "DimGray", 105, 105, 105 }, +{ "DimGrey", 105, 105, 105 }, +{ "SlateGray", 112, 128, 144 }, +{ "SlateGrey", 112, 128, 144 }, +{ "LightSlateGray", 119, 136, 153 }, +{ "LightSlateGrey", 119, 136, 153 }, +{ "gray", 190, 190, 190 }, +{ "grey", 190, 190, 190 }, +{ "LightGrey", 211, 211, 211 }, +{ "LightGray", 211, 211, 211 }, +{ "MidnightBlue", 25, 25, 112 }, +{ "navy", 0, 0, 128 }, +{ "NavyBlue", 0, 0, 128 }, +{ "CornflowerBlue", 100, 149, 237 }, +{ "DarkSlateBlue", 72, 61, 139 }, +{ "SlateBlue", 106, 90, 205 }, +{ "MediumSlateBlue", 123, 104, 238 }, +{ "LightSlateBlue", 132, 112, 255 }, +{ "MediumBlue", 0, 0, 205 }, +{ "RoyalBlue", 65, 105, 225 }, +{ "blue", 0, 0, 255 }, +{ "DodgerBlue", 30, 144, 255 }, +{ "DeepSkyBlue", 0, 191, 255 }, +{ "SkyBlue", 135, 206, 235 }, +{ "LightSkyBlue", 135, 206, 250 }, +{ "SteelBlue", 70, 130, 180 }, +{ "LightSteelBlue", 176, 196, 222 }, +{ "LightBlue", 173, 216, 230 }, +{ "PowderBlue", 176, 224, 230 }, +{ "PaleTurquoise", 175, 238, 238 }, +{ "DarkTurquoise", 0, 206, 209 }, +{ "MediumTurquoise", 72, 209, 204 }, +{ "turquoise", 64, 224, 208 }, +{ "cyan", 0, 255, 255 }, +{ "LightCyan", 224, 255, 255 }, +{ "CadetBlue", 95, 158, 160 }, +{ "MediumAquamarine", 102, 205, 170 }, +{ "aquamarine", 127, 255, 212 }, +{ "DarkGreen", 0, 100, 0 }, +{ "DarkOliveGreen", 85, 107, 47 }, +{ "DarkSeaGreen", 143, 188, 143 }, +{ "SeaGreen", 46, 139, 87 }, +{ "MediumSeaGreen", 60, 179, 113 }, +{ "LightSeaGreen", 32, 178, 170 }, +{ "PaleGreen", 152, 251, 152 }, +{ "SpringGreen", 0, 255, 127 }, +{ "LawnGreen", 124, 252, 0 }, +{ "green", 0, 255, 0 }, +{ "chartreuse", 127, 255, 0 }, +{ "MediumSpringGreen", 0, 250, 154 }, +{ "GreenYellow", 173, 255 , 47 }, +{ "LimeGreen", 50, 205, 50 }, +{ "YellowGreen", 154, 205, 50 }, +{ "ForestGreen", 34, 139, 34 }, +{ "OliveDrab", 107, 142, 35 }, +{ "DarkKhaki", 189, 183, 107 }, +{ "khaki", 240, 230, 140 }, +{ "PaleGoldenrod", 238, 232, 170 }, +{ "LightGoldenrodYellow", 250, 250, 210 }, +{ "LightYellow", 255, 255, 224 }, +{ "yellow", 255, 255, 0 }, +{ "gold", 255, 215, 0 }, +{ "LightGoldenrod", 238, 221, 130 }, +{ "goldenrod", 218, 165, 32 }, +{ "DarkGoldenrod", 184, 134, 11 }, +{ "RosyBrown", 188, 143, 143 }, +{ "IndianRed", 205, 92, 92 }, +{ "SaddleBrown", 139, 69, 19 }, +{ "sienna", 160, 82, 45 }, +{ "peru", 205, 133, 63 }, +{ "burlywood", 222, 184, 135 }, +{ "beige", 245, 245, 220 }, +{ "wheat", 245, 222, 179 }, +{ "SandyBrown", 244, 164, 96 }, +{ "tan", 210, 180, 140 }, +{ "chocolate", 210, 105, 30 }, +{ "firebrick", 178, 34, 34 }, +{ "brown", 165, 42, 42 }, +{ "DarkSalmon", 233, 150, 122 }, +{ "salmon", 250, 128, 114 }, +{ "LightSalmon", 255, 160, 122 }, +{ "orange", 255, 165, 0 }, +{ "DarkOrange", 255, 140, 0 }, +{ "coral", 255, 127, 80 }, +{ "LightCoral", 240, 128, 128 }, +{ "tomato", 255, 99, 71 }, +{ "OrangeRed", 255, 69, 0 }, +{ "red", 255, 0, 0 }, +{ "HotPink", 255, 105, 180 }, +{ "DeepPink", 255, 20, 147 }, +{ "pink", 255, 192, 203 }, +{ "LightPink", 255, 182, 193 }, +{ "PaleVioletRed", 219, 112, 147 }, +{ "maroon", 176, 48, 96 }, +{ "MediumVioletRed", 199, 21, 133 }, +{ "VioletRed", 208, 32, 144 }, +{ "magenta", 255, 0, 255 }, +{ "violet", 238, 130, 238 }, +{ "plum", 221, 160, 221 }, +{ "orchid", 218, 112, 214 }, +{ "MediumOrchid", 186, 85, 211 }, +{ "DarkOrchid", 153, 50, 204 }, +{ "DarkViolet", 148, 0, 211 }, +{ "BlueViolet", 138, 43, 226 }, +{ "purple", 160, 32, 240 }, +{ "MediumPurple", 147, 112, 219 }, +{ "thistle", 216, 191, 216 }, +{ "snow1", 255, 250, 250 }, +{ "snow2", 238, 233, 233 }, +{ "snow3", 205, 201, 201 }, +{ "snow4", 139, 137, 137 }, +{ "seashell1", 255, 245, 238 }, +{ "seashell2", 238, 229, 222 }, +{ "seashell3", 205, 197, 191 }, +{ "seashell4", 139, 134, 130 }, +{ "AntiqueWhite1", 255, 239, 219 }, +{ "AntiqueWhite2", 238, 223, 204 }, +{ "AntiqueWhite3", 205, 192, 176 }, +{ "AntiqueWhite4", 139, 131, 120 }, +{ "bisque1", 255, 228, 196 }, +{ "bisque2", 238, 213, 183 }, +{ "bisque3", 205, 183, 158 }, +{ "bisque4", 139, 125, 107 }, +{ "PeachPuff1", 255, 218, 185 }, +{ "PeachPuff2", 238, 203, 173 }, +{ "PeachPuff3", 205, 175, 149 }, +{ "PeachPuff4", 139, 119, 101 }, +{ "NavajoWhite1", 255, 222, 173 }, +{ "NavajoWhite2", 238, 207, 161 }, +{ "NavajoWhite3", 205, 179, 139 }, +{ "NavajoWhite4", 139, 121, 94 }, +{ "LemonChiffon1", 255, 250, 205 }, +{ "LemonChiffon2", 238, 233, 191 }, +{ "LemonChiffon3", 205, 201, 165 }, +{ "LemonChiffon4", 139, 137, 112 }, +{ "cornsilk1", 255, 248, 220 }, +{ "cornsilk2", 238, 232, 205 }, +{ "cornsilk3", 205, 200, 177 }, +{ "cornsilk4", 139, 136, 120 }, +{ "ivory1", 255, 255, 240 }, +{ "ivory2", 238, 238, 224 }, +{ "ivory3", 205, 205, 193 }, +{ "ivory4", 139, 139, 131 }, +{ "honeydew1", 240, 255, 240 }, +{ "honeydew2", 224, 238, 224 }, +{ "honeydew3", 193, 205, 193 }, +{ "honeydew4", 131, 139, 131 }, +{ "LavenderBlush1", 255, 240, 245 }, +{ "LavenderBlush2", 238, 224, 229 }, +{ "LavenderBlush3", 205, 193, 197 }, +{ "LavenderBlush4", 139, 131, 134 }, +{ "MistyRose1", 255, 228, 225 }, +{ "MistyRose2", 238, 213, 210 }, +{ "MistyRose3", 205, 183, 181 }, +{ "MistyRose4", 139, 125, 123 }, +{ "azure1", 240, 255, 255 }, +{ "azure2", 224, 238, 238 }, +{ "azure3", 193, 205, 205 }, +{ "azure4", 131, 139, 139 }, +{ "SlateBlue1", 131, 111, 255 }, +{ "SlateBlue2", 122, 103, 238 }, +{ "SlateBlue3", 105, 89, 205 }, +{ "SlateBlue4", 71, 60, 139 }, +{ "RoyalBlue1", 72, 118, 255 }, +{ "RoyalBlue2", 67, 110, 238 }, +{ "RoyalBlue3", 58, 95, 205 }, +{ "RoyalBlue4", 39, 64, 139 }, +{ "blue1", 0, 0, 255 }, +{ "blue2", 0, 0, 238 }, +{ "blue3", 0, 0, 205 }, +{ "blue4", 0, 0, 139 }, +{ "DodgerBlue1", 30, 144, 255 }, +{ "DodgerBlue2", 28, 134, 238 }, +{ "DodgerBlue3", 24, 116, 205 }, +{ "DodgerBlue4", 16, 78, 139 }, +{ "SteelBlue1", 99, 184, 255 }, +{ "SteelBlue2", 92, 172, 238 }, +{ "SteelBlue3", 79, 148, 205 }, +{ "SteelBlue4", 54, 100, 139 }, +{ "DeepSkyBlue1", 0, 191, 255 }, +{ "DeepSkyBlue2", 0, 178, 238 }, +{ "DeepSkyBlue3", 0, 154, 205 }, +{ "DeepSkyBlue4", 0, 104, 139 }, +{ "SkyBlue1", 135, 206, 255 }, +{ "SkyBlue2", 126, 192, 238 }, +{ "SkyBlue3", 108, 166, 205 }, +{ "SkyBlue4", 74, 112, 139 }, +{ "LightSkyBlue1", 176, 226, 255 }, +{ "LightSkyBlue2", 164, 211, 238 }, +{ "LightSkyBlue3", 141, 182, 205 }, +{ "LightSkyBlue4", 96, 123, 139 }, +{ "SlateGray1", 198, 226, 255 }, +{ "SlateGray2", 185, 211, 238 }, +{ "SlateGray3", 159, 182, 205 }, +{ "SlateGray4", 108, 123, 139 }, +{ "LightSteelBlue1", 202, 225, 255 }, +{ "LightSteelBlue2", 188, 210, 238 }, +{ "LightSteelBlue3", 162, 181, 205 }, +{ "LightSteelBlue4", 110, 123, 139 }, +{ "LightBlue1", 191, 239, 255 }, +{ "LightBlue2", 178, 223, 238 }, +{ "LightBlue3", 154, 192, 205 }, +{ "LightBlue4", 104, 131, 139 }, +{ "LightCyan1", 224, 255, 255 }, +{ "LightCyan2", 209, 238, 238 }, +{ "LightCyan3", 180, 205, 205 }, +{ "LightCyan4", 122, 139, 139 }, +{ "PaleTurquoise1", 187, 255, 255 }, +{ "PaleTurquoise2", 174, 238, 238 }, +{ "PaleTurquoise3", 150, 205, 205 }, +{ "PaleTurquoise4", 102, 139, 139 }, +{ "CadetBlue1", 152, 245, 255 }, +{ "CadetBlue2", 142, 229, 238 }, +{ "CadetBlue3", 122, 197, 205 }, +{ "CadetBlue4", 83, 134, 139 }, +{ "turquoise1", 0, 245, 255 }, +{ "turquoise2", 0, 229, 238 }, +{ "turquoise3", 0, 197, 205 }, +{ "turquoise4", 0, 134, 139 }, +{ "cyan1", 0, 255, 255 }, +{ "cyan2", 0, 238, 238 }, +{ "cyan3", 0, 205, 205 }, +{ "cyan4", 0, 139, 139 }, +{ "DarkSlateGray1", 151, 255, 255 }, +{ "DarkSlateGray2", 141, 238, 238 }, +{ "DarkSlateGray3", 121, 205, 205 }, +{ "DarkSlateGray4", 82, 139, 139 }, +{ "aquamarine1", 127, 255, 212 }, +{ "aquamarine2", 118, 238, 198 }, +{ "aquamarine3", 102, 205, 170 }, +{ "aquamarine4", 69, 139, 116 }, +{ "DarkSeaGreen1", 193, 255, 193 }, +{ "DarkSeaGreen2", 180, 238, 180 }, +{ "DarkSeaGreen3", 155, 205, 155 }, +{ "DarkSeaGreen4", 105, 139, 105 }, +{ "SeaGreen1", 84, 255, 159 }, +{ "SeaGreen2", 78, 238, 148 }, +{ "SeaGreen3", 67, 205, 128 }, +{ "SeaGreen4", 46, 139, 87 }, +{ "PaleGreen1", 154, 255, 154 }, +{ "PaleGreen2", 144, 238, 144 }, +{ "PaleGreen3", 124, 205, 124 }, +{ "PaleGreen4", 84, 139, 84 }, +{ "SpringGreen1", 0, 255, 127 }, +{ "SpringGreen2", 0, 238, 118 }, +{ "SpringGreen3", 0, 205, 102 }, +{ "SpringGreen4", 0, 139, 69 }, +{ "green1", 0, 255, 0 }, +{ "green2", 0, 238, 0 }, +{ "green3", 0, 205, 0 }, +{ "green4", 0, 139, 0 }, +{ "chartreuse1", 127, 255, 0 }, +{ "chartreuse2", 118, 238, 0 }, +{ "chartreuse3", 102, 205, 0 }, +{ "chartreuse4", 69, 139, 0 }, +{ "OliveDrab1", 192, 255, 62 }, +{ "OliveDrab2", 179, 238, 58 }, +{ "OliveDrab3", 154, 205, 50 }, +{ "OliveDrab4", 105, 139, 34 }, +{ "DarkOliveGreen1", 202, 255, 112 }, +{ "DarkOliveGreen2", 188, 238, 104 }, +{ "DarkOliveGreen3", 162, 205, 90 }, +{ "DarkOliveGreen4", 110, 139, 61 }, +{ "khaki1", 255, 246, 143 }, +{ "khaki2", 238, 230, 133 }, +{ "khaki3", 205, 198, 115 }, +{ "khaki4", 139, 134, 78 }, +{ "LightGoldenrod1", 255, 236, 139 }, +{ "LightGoldenrod2", 238, 220, 130 }, +{ "LightGoldenrod3", 205, 190, 112 }, +{ "LightGoldenrod4", 139, 129, 76 }, +{ "LightYellow1", 255, 255, 224 }, +{ "LightYellow2", 238, 238, 209 }, +{ "LightYellow3", 205, 205, 180 }, +{ "LightYellow4", 139, 139, 122 }, +{ "yellow1", 255, 255, 0 }, +{ "yellow2", 238, 238, 0 }, +{ "yellow3", 205, 205, 0 }, +{ "yellow4", 139, 139, 0 }, +{ "gold1", 255, 215, 0 }, +{ "gold2", 238, 201, 0 }, +{ "gold3", 205, 173, 0 }, +{ "gold4", 139, 117, 0 }, +{ "goldenrod1", 255, 193, 37 }, +{ "goldenrod2", 238, 180, 34 }, +{ "goldenrod3", 205, 155, 29 }, +{ "goldenrod4", 139, 105, 20 }, +{ "DarkGoldenrod1", 255, 185, 15 }, +{ "DarkGoldenrod2", 238, 173, 14 }, +{ "DarkGoldenrod3", 205, 149, 12 }, +{ "DarkGoldenrod4", 139, 101, 8 }, +{ "RosyBrown1", 255, 193, 193 }, +{ "RosyBrown2", 238, 180, 180 }, +{ "RosyBrown3", 205, 155, 155 }, +{ "RosyBrown4", 139, 105, 105 }, +{ "IndianRed1", 255, 106, 106 }, +{ "IndianRed2", 238, 99, 99 }, +{ "IndianRed3", 205, 85, 85 }, +{ "IndianRed4", 139, 58, 58 }, +{ "sienna1", 255, 130, 71 }, +{ "sienna2", 238, 121, 66 }, +{ "sienna3", 205, 104, 57 }, +{ "sienna4", 139, 71, 38 }, +{ "burlywood1", 255, 211, 155 }, +{ "burlywood2", 238, 197, 145 }, +{ "burlywood3", 205, 170, 125 }, +{ "burlywood4", 139, 115, 85 }, +{ "wheat1", 255, 231, 186 }, +{ "wheat2", 238, 216, 174 }, +{ "wheat3", 205, 186, 150 }, +{ "wheat4", 139, 126, 102 }, +{ "tan1", 255, 165, 79 }, +{ "tan2", 238, 154, 73 }, +{ "tan3", 205, 133, 63 }, +{ "tan4", 139 , 90, 43 }, +{ "chocolate1", 255, 127, 36 }, +{ "chocolate2", 238, 118, 33 }, +{ "chocolate3", 205, 102, 29 }, +{ "chocolate4", 139, 69, 19 }, +{ "firebrick1", 255, 48, 48 }, +{ "firebrick2", 238, 44, 44 }, +{ "firebrick3", 205, 38, 38 }, +{ "firebrick4", 139, 26, 26 }, +{ "brown1", 255, 64, 64 }, +{ "brown2", 238, 59, 59 }, +{ "brown3", 205, 51, 51 }, +{ "brown4", 139, 35, 35 }, +{ "salmon1", 255, 140, 105 }, +{ "salmon2", 238, 130, 98 }, +{ "salmon3", 205, 112, 84 }, +{ "salmon4", 139, 76, 57 }, +{ "LightSalmon1", 255, 160, 122 }, +{ "LightSalmon2", 238, 149, 114 }, +{ "LightSalmon3", 205, 129, 98 }, +{ "LightSalmon4", 139, 87, 66 }, +{ "orange1", 255, 165, 0 }, +{ "orange2", 238, 154, 0 }, +{ "orange3", 205, 133, 0 }, +{ "orange4", 139 , 90, 0 }, +{ "DarkOrange1", 255, 127, 0 }, +{ "DarkOrange2", 238, 118, 0 }, +{ "DarkOrange3", 205, 102, 0 }, +{ "DarkOrange4", 139 , 69, 0 }, +{ "coral1", 255, 114, 86 }, +{ "coral2", 238, 106, 80 }, +{ "coral3", 205, 91, 69 }, +{ "coral4", 139, 62, 47 }, +{ "tomato1", 255, 99, 71 }, +{ "tomato2", 238, 92, 66 }, +{ "tomato3", 205, 79, 57 }, +{ "tomato4", 139, 54, 38 }, +{ "OrangeRed1", 255, 69, 0 }, +{ "OrangeRed2", 238, 64, 0 }, +{ "OrangeRed3", 205, 55, 0 }, +{ "OrangeRed4", 139, 37, 0 }, +{ "red1", 255, 0, 0 }, +{ "red2", 238, 0, 0 }, +{ "red3", 205, 0, 0 }, +{ "red4", 139, 0, 0 }, +{ "DeepPink1", 255, 20, 147 }, +{ "DeepPink2", 238, 18, 137 }, +{ "DeepPink3", 205, 16, 118 }, +{ "DeepPink4", 139, 10, 80 }, +{ "HotPink1", 255, 110, 180 }, +{ "HotPink2", 238, 106, 167 }, +{ "HotPink3", 205, 96, 144 }, +{ "HotPink4", 139, 58, 98 }, +{ "pink1", 255, 181, 197 }, +{ "pink2", 238, 169, 184 }, +{ "pink3", 205, 145, 158 }, +{ "pink4", 139, 99, 108 }, +{ "LightPink1", 255, 174, 185 }, +{ "LightPink2", 238, 162, 173 }, +{ "LightPink3", 205, 140, 149 }, +{ "LightPink4", 139, 95, 101 }, +{ "PaleVioletRed1", 255, 130, 171 }, +{ "PaleVioletRed2", 238, 121, 159 }, +{ "PaleVioletRed3", 205, 104, 137 }, +{ "PaleVioletRed4", 139, 71, 93 }, +{ "maroon1", 255, 52, 179 }, +{ "maroon2", 238, 48, 167 }, +{ "maroon3", 205, 41, 144 }, +{ "maroon4", 139, 28, 98 }, +{ "VioletRed1", 255, 62, 150 }, +{ "VioletRed2", 238, 58, 140 }, +{ "VioletRed3", 205, 50, 120 }, +{ "VioletRed4", 139, 34, 82 }, +{ "magenta1", 255, 0, 255 }, +{ "magenta2", 238, 0, 238 }, +{ "magenta3", 205, 0, 205 }, +{ "magenta4", 139, 0, 139 }, +{ "orchid1", 255, 131, 250 }, +{ "orchid2", 238, 122, 233 }, +{ "orchid3", 205, 105, 201 }, +{ "orchid4", 139, 71, 137 }, +{ "plum1", 255, 187, 255 }, +{ "plum2", 238, 174, 238 }, +{ "plum3", 205, 150, 205 }, +{ "plum4", 139, 102, 139 }, +{ "MediumOrchid1", 224, 102, 255 }, +{ "MediumOrchid2", 209, 95, 238 }, +{ "MediumOrchid3", 180, 82, 205 }, +{ "MediumOrchid4", 122, 55, 139 }, +{ "DarkOrchid1", 191, 62, 255 }, +{ "DarkOrchid2", 178, 58, 238 }, +{ "DarkOrchid3", 154, 50, 205 }, +{ "DarkOrchid4", 104, 34, 139 }, +{ "purple1", 155, 48, 255 }, +{ "purple2", 145, 44, 238 }, +{ "purple3", 125, 38, 205 }, +{ "purple4", 85, 26, 139 }, +{ "MediumPurple1", 171, 130, 255 }, +{ "MediumPurple2", 159, 121, 238 }, +{ "MediumPurple3", 137, 104, 205 }, +{ "MediumPurple4", 93, 71, 139 }, +{ "thistle1", 255, 225, 255 }, +{ "thistle2", 238, 210, 238 }, +{ "thistle3", 205, 181, 205 }, +{ "thistle4", 139, 123, 139 }, +{ "gray0", 0, 0, 0 }, +{ "grey0", 0, 0, 0 }, +{ "gray1", 3, 3, 3 }, +{ "grey1", 3, 3, 3 }, +{ "gray2", 5, 5, 5 }, +{ "grey2", 5, 5, 5 }, +{ "gray3", 8, 8, 8 }, +{ "grey3", 8, 8, 8 }, +{ "gray4", 10, 10, 10 }, +{ "grey4", 10, 10, 10 }, +{ "gray5", 13, 13, 13 }, +{ "grey5", 13, 13, 13 }, +{ "gray6", 15, 15, 15 }, +{ "grey6", 15, 15, 15 }, +{ "gray7", 18, 18, 18 }, +{ "grey7", 18, 18, 18 }, +{ "gray8", 20, 20, 20 }, +{ "grey8", 20, 20, 20 }, +{ "gray9", 23, 23, 23 }, +{ "grey9", 23, 23, 23 }, +{ "gray10", 26, 26, 26 }, +{ "grey10", 26, 26, 26 }, +{ "gray11", 28, 28, 28 }, +{ "grey11", 28, 28, 28 }, +{ "gray12", 31, 31, 31 }, +{ "grey12", 31, 31, 31 }, +{ "gray13", 33, 33, 33 }, +{ "grey13", 33, 33, 33 }, +{ "gray14", 36, 36, 36 }, +{ "grey14", 36, 36, 36 }, +{ "gray15", 38, 38, 38 }, +{ "grey15", 38, 38, 38 }, +{ "gray16", 41, 41, 41 }, +{ "grey16", 41, 41, 41 }, +{ "gray17", 43, 43, 43 }, +{ "grey17", 43, 43, 43 }, +{ "gray18", 46, 46, 46 }, +{ "grey18", 46, 46, 46 }, +{ "gray19", 48, 48, 48 }, +{ "grey19", 48, 48, 48 }, +{ "gray20", 51, 51, 51 }, +{ "grey20", 51, 51, 51 }, +{ "gray21", 54, 54, 54 }, +{ "grey21", 54, 54, 54 }, +{ "gray22", 56, 56, 56 }, +{ "grey22", 56, 56, 56 }, +{ "gray23", 59, 59, 59 }, +{ "grey23", 59, 59, 59 }, +{ "gray24", 61, 61, 61 }, +{ "grey24", 61, 61, 61 }, +{ "gray25", 64, 64, 64 }, +{ "grey25", 64, 64, 64 }, +{ "gray26", 66, 66, 66 }, +{ "grey26", 66, 66, 66 }, +{ "gray27", 69, 69, 69 }, +{ "grey27", 69, 69, 69 }, +{ "gray28", 71, 71, 71 }, +{ "grey28", 71, 71, 71 }, +{ "gray29", 74, 74, 74 }, +{ "grey29", 74, 74, 74 }, +{ "gray30", 77, 77, 77 }, +{ "grey30", 77, 77, 77 }, +{ "gray31", 79, 79, 79 }, +{ "grey31", 79, 79, 79 }, +{ "gray32", 82, 82, 82 }, +{ "grey32", 82, 82, 82 }, +{ "gray33", 84, 84, 84 }, +{ "grey33", 84, 84, 84 }, +{ "gray34", 87, 87, 87 }, +{ "grey34", 87, 87, 87 }, +{ "gray35", 89, 89, 89 }, +{ "grey35", 89, 89, 89 }, +{ "gray36", 92, 92, 92 }, +{ "grey36", 92, 92, 92 }, +{ "gray37", 94, 94, 94 }, +{ "grey37", 94, 94, 94 }, +{ "gray38", 97, 97, 97 }, +{ "grey38", 97, 97, 97 }, +{ "gray39", 99, 99, 99 }, +{ "grey39", 99, 99, 99 }, +{ "gray40", 102, 102, 102 }, +{ "grey40", 102, 102, 102 }, +{ "gray41", 105, 105, 105 }, +{ "grey41", 105, 105, 105 }, +{ "gray42", 107, 107, 107 }, +{ "grey42", 107, 107, 107 }, +{ "gray43", 110, 110, 110 }, +{ "grey43", 110, 110, 110 }, +{ "gray44", 112, 112, 112 }, +{ "grey44", 112, 112, 112 }, +{ "gray45", 115, 115, 115 }, +{ "grey45", 115, 115, 115 }, +{ "gray46", 117, 117, 117 }, +{ "grey46", 117, 117, 117 }, +{ "gray47", 120, 120, 120 }, +{ "grey47", 120, 120, 120 }, +{ "gray48", 122, 122, 122 }, +{ "grey48", 122, 122, 122 }, +{ "gray49", 125, 125, 125 }, +{ "grey49", 125, 125, 125 }, +{ "gray50", 127, 127, 127 }, +{ "grey50", 127, 127, 127 }, +{ "gray51", 130, 130, 130 }, +{ "grey51", 130, 130, 130 }, +{ "gray52", 133, 133, 133 }, +{ "grey52", 133, 133, 133 }, +{ "gray53", 135, 135, 135 }, +{ "grey53", 135, 135, 135 }, +{ "gray54", 138, 138, 138 }, +{ "grey54", 138, 138, 138 }, +{ "gray55", 140, 140, 140 }, +{ "grey55", 140, 140, 140 }, +{ "gray56", 143, 143, 143 }, +{ "grey56", 143, 143, 143 }, +{ "gray57", 145, 145, 145 }, +{ "grey57", 145, 145, 145 }, +{ "gray58", 148, 148, 148 }, +{ "grey58", 148, 148, 148 }, +{ "gray59", 150, 150, 150 }, +{ "grey59", 150, 150, 150 }, +{ "gray60", 153, 153, 153 }, +{ "grey60", 153, 153, 153 }, +{ "gray61", 156, 156, 156 }, +{ "grey61", 156, 156, 156 }, +{ "gray62", 158, 158, 158 }, +{ "grey62", 158, 158, 158 }, +{ "gray63", 161, 161, 161 }, +{ "grey63", 161, 161, 161 }, +{ "gray64", 163, 163, 163 }, +{ "grey64", 163, 163, 163 }, +{ "gray65", 166, 166, 166 }, +{ "grey65", 166, 166, 166 }, +{ "gray66", 168, 168, 168 }, +{ "grey66", 168, 168, 168 }, +{ "gray67", 171, 171, 171 }, +{ "grey67", 171, 171, 171 }, +{ "gray68", 173, 173, 173 }, +{ "grey68", 173, 173, 173 }, +{ "gray69", 176, 176, 176 }, +{ "grey69", 176, 176, 176 }, +{ "gray70", 179, 179, 179 }, +{ "grey70", 179, 179, 179 }, +{ "gray71", 181, 181, 181 }, +{ "grey71", 181, 181, 181 }, +{ "gray72", 184, 184, 184 }, +{ "grey72", 184, 184, 184 }, +{ "gray73", 186, 186, 186 }, +{ "grey73", 186, 186, 186 }, +{ "gray74", 189, 189, 189 }, +{ "grey74", 189, 189, 189 }, +{ "gray75", 191, 191, 191 }, +{ "grey75", 191, 191, 191 }, +{ "gray76", 194, 194, 194 }, +{ "grey76", 194, 194, 194 }, +{ "gray77", 196, 196, 196 }, +{ "grey77", 196, 196, 196 }, +{ "gray78", 199, 199, 199 }, +{ "grey78", 199, 199, 199 }, +{ "gray79", 201, 201, 201 }, +{ "grey79", 201, 201, 201 }, +{ "gray80", 204, 204, 204 }, +{ "grey80", 204, 204, 204 }, +{ "gray81", 207, 207, 207 }, +{ "grey81", 207, 207, 207 }, +{ "gray82", 209, 209, 209 }, +{ "grey82", 209, 209, 209 }, +{ "gray83", 212, 212, 212 }, +{ "grey83", 212, 212, 212 }, +{ "gray84", 214, 214, 214 }, +{ "grey84", 214, 214, 214 }, +{ "gray85", 217, 217, 217 }, +{ "grey85", 217, 217, 217 }, +{ "gray86", 219, 219, 219 }, +{ "grey86", 219, 219, 219 }, +{ "gray87", 222, 222, 222 }, +{ "grey87", 222, 222, 222 }, +{ "gray88", 224, 224, 224 }, +{ "grey88", 224, 224, 224 }, +{ "gray89", 227, 227, 227 }, +{ "grey89", 227, 227, 227 }, +{ "gray90", 229, 229, 229 }, +{ "grey90", 229, 229, 229 }, +{ "gray91", 232, 232, 232 }, +{ "grey91", 232, 232, 232 }, +{ "gray92", 235, 235, 235 }, +{ "grey92", 235, 235, 235 }, +{ "gray93", 237, 237, 237 }, +{ "grey93", 237, 237, 237 }, +{ "gray94", 240, 240, 240 }, +{ "grey94", 240, 240, 240 }, +{ "gray95", 242, 242, 242 }, +{ "grey95", 242, 242, 242 }, +{ "gray96", 245, 245, 245 }, +{ "grey96", 245, 245, 245 }, +{ "gray97", 247, 247, 247 }, +{ "grey97", 247, 247, 247 }, +{ "gray98", 250, 250, 250 }, +{ "grey98", 250, 250, 250 }, +{ "gray99", 252, 252, 252 }, +{ "grey99", 252, 252, 252 }, +{ "gray100", 255, 255, 255 }, +{ "grey100", 255, 255, 255 }, +{ "DarkGrey", 169, 169, 169 }, +{ "DarkGray", 169, 169, 169 }, +{ "DarkBlue", 0, 0, 139 }, +{ "DarkCyan", 0, 139, 139 }, +{ "DarkMagenta", 139, 0, 139 }, +{ "DarkRed", 139, 0, 0 }, +{ "LightGreen", 144, 238, 144 }, +{ NULL, 0 , 0, 0} +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/ixpm/xpmread.cxx b/vcl/source/filter/ixpm/xpmread.cxx new file mode 100644 index 000000000000..0317736c208d --- /dev/null +++ b/vcl/source/filter/ixpm/xpmread.cxx @@ -0,0 +1,682 @@ +/* -*- 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 <vcl/bmpacc.hxx> +#include <vcl/graph.hxx> +#include "rgbtable.hxx" +#define _XPMPRIVATE +#include "xpmread.hxx" + +// ------------- +// - XPMReader - +// ------------- + +XPMReader::XPMReader( SvStream& rStm ) : + mrIStm ( rStm ), + mpAcc ( NULL ), + mpMaskAcc ( NULL ), + mnLastPos ( rStm.Tell() ), + mnWidth ( 0 ), + mnHeight ( 0 ), + mnColors ( 0 ), + mnCpp ( 0 ), + mbTransparent ( sal_False ), + mbStatus ( sal_True ), + mnStatus ( 0 ), + mnIdentifier ( XPMIDENTIFIER ), + mcThisByte ( 0 ), + mnTempAvail ( 0 ), + mpFastColorTable( NULL ), + mpColMap ( NULL ) +{ + +} + +// ------------------------------------------------------------------------ + +XPMReader::~XPMReader() +{ + if( mpAcc ) + maBmp.ReleaseAccess( mpAcc ); +} + +// ------------------------------------------------------------------------ + +ReadState XPMReader::ReadXPM( Graphic& rGraphic ) +{ + ReadState eReadState; + sal_uInt8 cDummy; + + // sehen, ob wir _alles_ lesen koennen + mrIStm.Seek( STREAM_SEEK_TO_END ); + mrIStm >> cDummy; + + // falls wir nicht alles lesen koennen + // kehren wir zurueck und warten auf neue Daten + if ( mrIStm.GetError() != ERRCODE_IO_PENDING ) + { + mrIStm.Seek( mnLastPos ); + mbStatus = sal_True; + + if ( mbStatus ) + { + mpStringBuf = new sal_uInt8 [ XPMSTRINGBUF ]; + mpTempBuf = new sal_uInt8 [ XPMTEMPBUFSIZE ]; + + if ( ( mbStatus = ImplGetString() ) == sal_True ) + { + mnIdentifier = XPMVALUES; // Bitmap informationen einholen + mnWidth = ImplGetULONG( 0 ); + mnHeight = ImplGetULONG( 1 ); + mnColors = ImplGetULONG( 2 ); + mnCpp = ImplGetULONG( 3 ); + } + if ( mnColors > ( SAL_MAX_UINT32 / ( 4 + mnCpp ) ) ) + mbStatus = sal_False; + if ( ( mnWidth * mnCpp ) >= XPMSTRINGBUF ) + mbStatus = sal_False; + if ( mbStatus && mnWidth && mnHeight && mnColors && mnCpp ) + { + mnIdentifier = XPMCOLORS; + + // mpColMap beinhaltet fuer jede vorhandene + // Farbe: ( mnCpp )Byte(s)-> ASCII Eintrag der der Farbe zugeordnet ist + // 1 Byte -> 0xff wenn Farbe transparent ist + // 3 Bytes -> RGB Wert der Farbe + mpColMap = new sal_uInt8[ mnColors * ( 4 + mnCpp ) ]; + if ( mpColMap ) + { + for ( sal_uLong i = 0; i < mnColors; i++ ) + { + if ( ImplGetColor( i ) == sal_False ) + { + mbStatus = sal_False; + break; + } + } + } + else + mbStatus = sal_False; + + if ( mbStatus ) + { + // bei mehr als 256 Farben wird eine 24 Bit Grafik erstellt + sal_uInt16 nBits = 1; + if ( mnColors > 256 ) + nBits = 24; + else if ( mnColors > 16 ) + nBits = 8; + else if ( mnColors > 2 ) + nBits = 4; + else + nBits = 1; + + maBmp = Bitmap( Size( mnWidth, mnHeight ), nBits ); + mpAcc = maBmp.AcquireWriteAccess(); + + // mbTransparent ist sal_True wenn mindestens eine Farbe Transparent ist + if ( mbTransparent ) + { + maMaskBmp = Bitmap( Size( mnWidth, mnHeight ), 1 ); + if ( ( mpMaskAcc = maMaskBmp.AcquireWriteAccess() ) == NULL ) + mbStatus = sal_False; + } + if( mpAcc && mbStatus ) + { + sal_uLong i; + if ( mnColors <=256 ) // palette is only needed by using less than 257 + { // colors + + sal_uInt8* pPtr = &mpColMap[mnCpp]; + + for ( i = 0; i < mnColors; i++ ) + { + mpAcc->SetPaletteColor( (sal_uInt8)i, Color( pPtr[1], pPtr[2], pPtr[3] ) ); + pPtr += ( mnCpp + 4 ); + } + // using 2 charakters per pixel and less than 257 Colors we speed up + if ( mnCpp == 2 ) // by using a 64kb indexing table + { + mpFastColorTable = new sal_uInt8[ 256 * 256 ]; + for ( pPtr = mpColMap, i = 0; i < mnColors; i++, pPtr += mnCpp + 4 ) + { + sal_uLong j = pPtr[ 0 ] << 8; + j += pPtr[ 1 ]; + mpFastColorTable[ j ] = (sal_uInt8)i; + } + } + } + // now we get the bitmap data + mnIdentifier = XPMPIXELS; + for ( i = 0; i < mnHeight; i++ ) + { + if ( ImplGetScanLine( i ) == sal_False ) + { + mbStatus = sal_False; + break; + } + } + mnIdentifier = XPMEXTENSIONS; + } + } + } + + delete[] mpFastColorTable; + delete[] mpColMap; + delete[] mpStringBuf; + delete[] mpTempBuf; + + } + if( mbStatus ) + { + if ( mpMaskAcc ) + { + maMaskBmp.ReleaseAccess ( mpMaskAcc), mpMaskAcc = NULL; + maBmp.ReleaseAccess( mpAcc ), mpAcc = NULL; + rGraphic = Graphic( BitmapEx( maBmp, maMaskBmp ) ); + } + else + { + maBmp.ReleaseAccess( mpAcc ), mpAcc = NULL; + rGraphic = maBmp; + } + eReadState = XPMREAD_OK; + } + else + { + if ( mpMaskAcc ) maMaskBmp.ReleaseAccess ( mpMaskAcc), mpMaskAcc = NULL; + if ( mpAcc ) maBmp.ReleaseAccess( mpAcc ), mpAcc = NULL; + eReadState = XPMREAD_ERROR; + } + } + else + { + mrIStm.ResetError(); + eReadState = XPMREAD_NEED_MORE; + } + return eReadState; +} + +// ------------------------------------------------------------------------ +// ImplGetColor ermittelt saemtliche Farbwerte, +// die Rueckgabe ist sal_True wenn saemtliche Farben zugeordnet werden konnten + +sal_Bool XPMReader::ImplGetColor( sal_uLong nNumb ) +{ + sal_uInt8* pString = mpStringBuf; + sal_uInt8* pPtr = ( mpColMap + nNumb * ( 4 + mnCpp ) ); + sal_Bool bStatus = ImplGetString(); + + if ( bStatus ) + { + for ( sal_uLong i = 0; i < mnCpp; i++ ) + *pPtr++ = *pString++; + bStatus = ImplGetColSub ( pPtr ); + } + return bStatus; +} + +// ------------------------------------------------------------------------ +// ImpGetScanLine liest den String mpBufSize aus und schreibt die Pixel in die +// Bitmap. Der Parameter nY gibt die horizontale Position an. + +sal_Bool XPMReader::ImplGetScanLine( sal_uLong nY ) +{ + sal_Bool bStatus = ImplGetString(); + sal_uInt8* pString = mpStringBuf; + sal_uInt8* pColor; + BitmapColor aWhite; + BitmapColor aBlack; + + if ( bStatus ) + { + if ( mpMaskAcc ) + { + aWhite = mpMaskAcc->GetBestMatchingColor( Color( COL_WHITE ) ); + aBlack = mpMaskAcc->GetBestMatchingColor( Color( COL_BLACK ) ); + } + if ( mnStringSize != ( mnWidth * mnCpp )) + bStatus = sal_False; + else + { + sal_uLong i, j; + if ( mpFastColorTable ) + { + for ( i = 0; i < mnWidth; i++ ) + { + j = (*pString++) << 8; + j += *pString++; + sal_uInt8 k = (sal_uInt8)mpFastColorTable[ j ]; + mpAcc->SetPixel( nY, i, BitmapColor( (sal_uInt8)k ) ); + + if ( mpMaskAcc ) + mpMaskAcc->SetPixel( nY, i, + ( mpColMap[ k * (mnCpp + 4) + mnCpp] ) ? aWhite : aBlack ); + } + } + else for ( i = 0; i < mnWidth; i++ ) + { + pColor = mpColMap; + for ( j = 0; j < mnColors; j++ ) + { + if ( ImplCompare( pString, pColor, mnCpp, XPMCASESENSITIVE ) == sal_True ) + { + if ( mnColors > 256 ) + mpAcc->SetPixel( nY, i, Color ( pColor[3], pColor[4], pColor[5] ) ); + else + mpAcc->SetPixel( nY, i, BitmapColor( (sal_uInt8) j ) ); + + if ( mpMaskAcc ) + mpMaskAcc->SetPixel( nY, i, ( + pColor[ mnCpp ] ) ? aWhite : aBlack ); + + break; + } + pColor += ( mnCpp + 4 ); + } + pString += mnCpp; + } + + } + } + return bStatus; +} + +// ------------------------------------------------------------------------ +// versucht aus mpStringBuf einen Farbwert zu uebermitteln +// wurde eine Farbe gefunden wird an pDest[1]..pDest[2] der RGB wert geschrieben +// pDest[0] enthaelt 0xff wenn die Farbe transparent ist sonst 0 + +sal_Bool XPMReader::ImplGetColSub( sal_uInt8* pDest ) +{ + unsigned char cTransparent[] = "None"; + + sal_Bool bColStatus = sal_False; + + if ( ImplGetColKey( 'c' ) || ImplGetColKey( 'm' ) || ImplGetColKey( 'g' ) ) + { + // hexentry for RGB or HSV color ? + if ( *mpPara == '#' ) + { + *pDest++ = 0; + bColStatus = sal_True; + switch ( mnParaSize ) + { + case 25 : + ImplGetRGBHex ( pDest, 6 ); + break; + case 13 : + ImplGetRGBHex ( pDest, 2 ); + break; + case 7 : + ImplGetRGBHex ( pDest, 0 ); + break; + default: + bColStatus = sal_False; + break; + } + } + // maybe pixel is transparent + else if ( ImplCompare( &cTransparent[0], mpPara, 4 )) + { + *pDest++ = 0xff; + bColStatus = sal_True; + mbTransparent = sal_True; + } + // last we will try to get the colorname + else if ( mnParaSize > 2 ) // name must enlarge the minimum size + { + sal_uLong i = 0; + while ( sal_True ) + { + if ( pRGBTable[ i ].name == NULL ) + break; + if ( pRGBTable[ i ].name[ mnParaSize ] == 0 ) + { + if ( ImplCompare ( (unsigned char*)pRGBTable[ i ].name, + mpPara, mnParaSize, XPMCASENONSENSITIVE ) ) + { + bColStatus = sal_True; + *pDest++ = 0; + *pDest++ = pRGBTable[ i ].red; + *pDest++ = pRGBTable[ i ].green; + *pDest++ = pRGBTable[ i ].blue; + } + } + i++; + } + } + } + return bColStatus; +} + +// ------------------------------------------------------------------------ +// ImplGetColKey durchsuch den String mpStringBuf nach einem Parameter 'nKey' +// und gibt einen sal_Bool zurueck. ( wenn sal_True werden mpPara und mnParaSize gesetzt ) + +sal_Bool XPMReader::ImplGetColKey( sal_uInt8 nKey ) +{ + sal_uInt8 nTemp, nPrev = ' '; + + mpPara = mpStringBuf + mnCpp + 1; + mnParaSize = 0; + + while ( *mpPara != 0 ) + { + if ( *mpPara == nKey ) + { + nTemp = *( mpPara + 1 ); + if ( nTemp == ' ' || nTemp == 0x09 ) + { + if ( nPrev == ' ' || nPrev == 0x09 ) + break; + } + } + nPrev = *mpPara; + mpPara++; + } + if ( *mpPara ) + { + mpPara++; + while ( (*mpPara == ' ') || (*mpPara == 0x09) ) + { + mpPara++; + } + if ( *mpPara != 0 ) + { + while ( *(mpPara+mnParaSize) != ' ' && *(mpPara+mnParaSize) != 0x09 && + *(mpPara+mnParaSize) != 0 ) + { + mnParaSize++; + } + } + } + return ( mnParaSize ) ? sal_True : sal_False; +} + +// ------------------------------------------------------------------------ +// ImplGetRGBHex uebersetzt den ASCII-Hexadezimalwert der sich bei mpPara befindet +// in einen RGB wert und schreibt diesen nach pDest +// folgende Formate muessen sich bei mpPara befinden: +// wenn nAdd = 0 : '#12ab12' -> RGB = 0x12, 0xab, 0x12 +// 2 : '#1234abcd1234' " " " " +// 6 : '#12345678abcdefab12345678' " " " " + + +void XPMReader::ImplGetRGBHex( sal_uInt8* pDest,sal_uLong nAdd ) +{ + sal_uInt8* pPtr = mpPara+1; + sal_uInt8 nHex, nTemp; + + for ( sal_uLong i = 0; i < 3; i++ ) + { + nHex = (*pPtr++) - '0'; + if ( nHex > 9 ) + nHex = ((nHex - 'A' + '0') & 7) + 10; + + nTemp = (*pPtr++) - '0'; + if ( nTemp > 9 ) + nTemp = ((nTemp - 'A' + '0') & 7) + 10; + nHex = ( nHex << 4 ) + nTemp; + + pPtr += nAdd; + *pDest++ = (sal_uInt8)nHex; + } +} + +// ------------------------------------------------------------------------ +// ImplGetUlong gibt den wert einer bis zu 6stelligen ASCII-Dezimalzahl zurueck. + +sal_uLong XPMReader::ImplGetULONG( sal_uLong nPara ) +{ + if ( ImplGetPara ( nPara ) ) + { + sal_uLong nRetValue = 0; + sal_uInt8* pPtr = mpPara; + + if ( ( mnParaSize > 6 ) || ( mnParaSize == 0 ) ) return 0; + for ( sal_uLong i = 0; i < mnParaSize; i++ ) + { + sal_uInt8 j = (*pPtr++) - 48; + if ( j > 9 ) return 0; // ascii is invalid + nRetValue*=10; + nRetValue+=j; + } + return nRetValue; + } + else return 0; +} + +// ------------------------------------------------------------------------ + +sal_Bool XPMReader::ImplCompare( sal_uInt8* pSource, sal_uInt8* pDest, sal_uLong nSize, sal_uLong nMode ) +{ + sal_Bool bRet = sal_True; + + if ( nMode == XPMCASENONSENSITIVE ) + { + for ( sal_uLong i = 0; i < nSize; i++ ) + { + if ( ( pSource[i]&~0x20 ) != ( pDest[i]&~0x20 ) ) + { + bRet = sal_False; + break; + } + } + } + else + { + for ( sal_uLong i = 0; i < nSize; i++ ) + { + if ( pSource[i] != pDest[i] ) + { + bRet = sal_False; + break; + } + } + } + return bRet; +} + +// ------------------------------------------------------------------------ +// ImplGetPara versucht den nNumb ( 0...x ) Parameter aus mpStringBuf zu ermitteln. +// Ein Parameter ist durch Spaces oder Tabs von den anderen getrennt. +// Konnte der Parameter gefunden werden ist der Rueckgabewert sal_True und mpPara + mnParaSize +// werden gesetzt. + +sal_Bool XPMReader::ImplGetPara ( sal_uLong nNumb ) +{ + sal_uInt8 nByte; + sal_uLong pSize = 0; + sal_uInt8* pPtr = mpStringBuf; + sal_uLong nCount = 0; + + if ( ( *pPtr != ' ' ) && ( *pPtr != 0x09 ) ) + { + mpPara = pPtr; + mnParaSize = 0; + nCount = 0; + } + else + { + mpPara = NULL; + nCount = 0xffffffff; + } + + while ( pSize < mnStringSize ) + { + nByte = *pPtr; + + if ( mpPara ) + { + if ( ( nByte == ' ' ) || ( nByte == 0x09 ) ) + { + if ( nCount == nNumb ) + break; + else + mpPara = NULL; + } + else + mnParaSize++; + } + else + { + if ( ( nByte != ' ' ) && ( nByte != 0x09 ) ) + { + mpPara = pPtr; + mnParaSize = 1; + nCount++; + } + } + pSize++; + pPtr++; + } + return ( ( nCount == nNumb ) && ( mpPara ) ) ? sal_True : sal_False; +} + +// ------------------------------------------------------------------------ +// Der naechste String wird ausgelesen und in mpStringBuf (mit 0 abgeschlossen) abgelegt; +// mnStringSize enthaelt die Groesse des gelesenen Strings. +// Bemerkungen wie '//' und '/*.....*/' werden uebersprungen. + +sal_Bool XPMReader::ImplGetString( void ) +{ + sal_uInt8 sID[] = "/* XPM */"; + sal_uInt8* pString = mpStringBuf; + + mnStringSize = 0; + mpStringBuf[0] = 0; + + while( mbStatus && ( mnStatus != XPMFINISHED ) ) + { + if ( mnTempAvail == 0 ) + { + mnTempAvail = mrIStm.Read( mpTempBuf, XPMTEMPBUFSIZE ); + if ( mnTempAvail == 0 ) + break; + + mpTempPtr = mpTempBuf; + + if ( mnIdentifier == XPMIDENTIFIER ) + { + if ( mnTempAvail <= 50 ) + { + mbStatus = sal_False; // file is too short to be a correct XPM format + break; + } + for ( int i = 0; i < 9; i++ ) // searching for "/* XPM */" + if ( *mpTempPtr++ != sID[i] ) + { + mbStatus = sal_False; + break; + } + mnTempAvail-=9; + mnIdentifier++; + } + } + mcLastByte = mcThisByte; + mcThisByte = *mpTempPtr++; + mnTempAvail--; + + if ( mnStatus & XPMDOUBLE ) + { + if ( mcThisByte == 0x0a ) + mnStatus &=~XPMDOUBLE; + continue; + } + if ( mnStatus & XPMREMARK ) + { + if ( ( mcThisByte == '/' ) && ( mcLastByte == '*' ) ) + mnStatus &=~XPMREMARK; + continue; + } + if ( mnStatus & XPMSTRING ) // characters in string + { + if ( mcThisByte == '"' ) + { + mnStatus &=~XPMSTRING; // end of parameter by eol + break; + } + if ( mnStringSize >= ( XPMSTRINGBUF - 1 ) ) + { + mbStatus = sal_False; + break; + } + *pString++ = mcThisByte; + pString[0] = 0; + mnStringSize++; + continue; + } + else + { // characters beside string + switch ( mcThisByte ) + { + case '*' : + if ( mcLastByte == '/' ) mnStatus |= XPMREMARK; + break; + case '/' : + if ( mcLastByte == '/' ) mnStatus |= XPMDOUBLE; + break; + case '"' : mnStatus |= XPMSTRING; + break; + case '{' : + if ( mnIdentifier == XPMDEFINITION ) + mnIdentifier++; + break; + case '}' : + if ( mnIdentifier == XPMENDEXT ) + mnStatus = XPMFINISHED; + break; + } + } + } + return mbStatus; +} + +// ------------- +// - ImportXPM - +// ------------- + +sal_Bool ImportXPM( SvStream& rStm, Graphic& rGraphic ) +{ + XPMReader* pXPMReader = (XPMReader*) rGraphic.GetContext(); + ReadState eReadState; + sal_Bool bRet = sal_True; + + if( !pXPMReader ) + pXPMReader = new XPMReader( rStm ); + + rGraphic.SetContext( NULL ); + eReadState = pXPMReader->ReadXPM( rGraphic ); + + if( eReadState == XPMREAD_ERROR ) + { + bRet = sal_False; + delete pXPMReader; + } + else if( eReadState == XPMREAD_OK ) + delete pXPMReader; + else + rGraphic.SetContext( pXPMReader ); + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/ixpm/xpmread.hxx b/vcl/source/filter/ixpm/xpmread.hxx new file mode 100644 index 000000000000..79abfe88e74c --- /dev/null +++ b/vcl/source/filter/ixpm/xpmread.hxx @@ -0,0 +1,123 @@ +/* -*- 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 _XPMREAD_HXX +#define _XPMREAD_HXX + +#include <vcl/bitmap.hxx> + +#ifdef _XPMPRIVATE + +#define XPMTEMPBUFSIZE 0x00008000 +#define XPMSTRINGBUF 0x00008000 + +#define XPMIDENTIFIER 0x00000001 // mnIdentifier includes on of the six phases +#define XPMDEFINITION 0x00000002 // the XPM format consists of +#define XPMVALUES 0x00000003 +#define XPMCOLORS 0x00000004 +#define XPMPIXELS 0x00000005 +#define XPMEXTENSIONS 0x00000006 +#define XPMENDEXT 0x00000007 + + +#define XPMREMARK 0x00000001 // defines used by mnStatus +#define XPMDOUBLE 0x00000002 +#define XPMSTRING 0x00000004 +#define XPMFINISHED 0x00000008 + +#define XPMCASESENSITIVE 0x00000001 +#define XPMCASENONSENSITIVE 0x00000002 + +// --------- +// - Enums - +// --------- + +enum ReadState +{ + XPMREAD_OK, + XPMREAD_ERROR, + XPMREAD_NEED_MORE +}; + +// ------------- +// - XPMReader - +// ------------- + +class BitmapWriteAccess; +class Graphic; + +class XPMReader : public GraphicReader +{ +private: + + SvStream& mrIStm; + Bitmap maBmp; + BitmapWriteAccess* mpAcc; + Bitmap maMaskBmp; + BitmapWriteAccess* mpMaskAcc; + long mnLastPos; + + sal_uLong mnWidth; + sal_uLong mnHeight; + sal_uLong mnColors; + sal_uLong mnCpp; // characters per pix + sal_Bool mbTransparent; + sal_Bool mbStatus; + sal_uLong mnStatus; + sal_uLong mnIdentifier; + sal_uInt8 mcThisByte; + sal_uInt8 mcLastByte; + sal_uLong mnTempAvail; + sal_uInt8* mpTempBuf; + sal_uInt8* mpTempPtr; + sal_uInt8* mpFastColorTable; + sal_uInt8* mpColMap; + sal_uLong mnStringSize; + sal_uInt8* mpStringBuf; + sal_uLong mnParaSize; + sal_uInt8* mpPara; + + sal_Bool ImplGetString( void ); + sal_Bool ImplGetColor( sal_uLong ); + sal_Bool ImplGetScanLine( sal_uLong ); + sal_Bool ImplGetColSub( sal_uInt8* ); + sal_Bool ImplGetColKey( sal_uInt8 ); + void ImplGetRGBHex( sal_uInt8*, sal_uLong ); + sal_Bool ImplGetPara( sal_uLong numb ); + sal_Bool ImplCompare( sal_uInt8*, sal_uInt8*, sal_uLong, sal_uLong nmode = XPMCASENONSENSITIVE ); + sal_uLong ImplGetULONG( sal_uLong nPara ); + +public: + XPMReader( SvStream& rStm ); + virtual ~XPMReader(); + + ReadState ReadXPM( Graphic& rGraphic ); +}; + +#endif // _XPMPRIVATE + +// ------------- +// - ImportXPM - +// ------------- + +sal_Bool ImportXPM( SvStream& rStream, Graphic& rGraphic ); + +#endif // _XPMREAD_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/jpeg/jpeg.cxx b/vcl/source/filter/jpeg/jpeg.cxx new file mode 100644 index 000000000000..6bd130d9a727 --- /dev/null +++ b/vcl/source/filter/jpeg/jpeg.cxx @@ -0,0 +1,777 @@ +/* -*- 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 <tools/solar.h> + +extern "C" +{ + #include "stdio.h" + #include "jpeg.h" + #include "jpeglib.h" + #include "jerror.h" +} + +#define _JPEGPRIVATE +#include <vcl/bmpacc.hxx> +#include "jpeg.hxx" +#include <svtools/FilterConfigItem.hxx> +#include <svtools/filter.hxx> + +// ----------- +// - Defines - +// ----------- + +using namespace ::com::sun::star; + +#define JPEGMINREAD 512 + +// ------------- +// - (C-Calls) - +// ------------- + +// ------------------------------------------------------------------------ + +extern "C" void* CreateBitmap( void* pJPEGReader, void* pJPEGCreateBitmapParam ) +{ + return ( (JPEGReader*) pJPEGReader )->CreateBitmap( pJPEGCreateBitmapParam ); +} + +// ------------------------------------------------------------------------ + +extern "C" void* GetScanline( void* pJPEGWriter, long nY ) +{ + return ( (JPEGWriter*) pJPEGWriter )->GetScanline( nY ); +} + +// ------------------------------------------------------------------------ + +struct JPEGCallbackStruct +{ + uno::Reference< task::XStatusIndicator > xStatusIndicator; +}; + +extern "C" long JPEGCallback( void* pCallbackData, long nPercent ) +{ + JPEGCallbackStruct* pS = (JPEGCallbackStruct*)pCallbackData; + if ( pS && pS->xStatusIndicator.is() ) + { + pS->xStatusIndicator->setValue( nPercent ); + } + return 0L; +} + +#define BUF_SIZE 4096 + +typedef struct +{ + struct jpeg_destination_mgr pub; /* public fields */ + + SvStream* outfile; /* target stream */ + JOCTET * buffer; /* start of buffer */ +} my_destination_mgr; + +typedef my_destination_mgr * my_dest_ptr; + +extern "C" void init_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + /* Allocate the output buffer --- it will be released when done with image */ + dest->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + BUF_SIZE * sizeof(JOCTET)); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = BUF_SIZE; +} + +extern "C" boolean empty_output_buffer (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + + if (dest->outfile->Write(dest->buffer, BUF_SIZE) != + (size_t) BUF_SIZE) + ERREXIT(cinfo, JERR_FILE_WRITE); + + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = BUF_SIZE; + + return sal_True; +} + +extern "C" void term_destination (j_compress_ptr cinfo) +{ + my_dest_ptr dest = (my_dest_ptr) cinfo->dest; + size_t datacount = BUF_SIZE - dest->pub.free_in_buffer; + + /* Write any data remaining in the buffer */ + if (datacount > 0) { + if (dest->outfile->Write(dest->buffer, datacount) != datacount) + ERREXIT(cinfo, JERR_FILE_WRITE); + } +} + +extern "C" void jpeg_svstream_dest (j_compress_ptr cinfo, void* out) +{ + SvStream * outfile = (SvStream*)out; + my_dest_ptr dest; + + /* The destination object is made permanent so that multiple JPEG images + * can be written to the same file without re-executing jpeg_svstream_dest. + * This makes it dangerous to use this manager and a different destination + * manager serially with the same JPEG object, because their private object + * sizes may be different. Caveat programmer. + */ + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(my_destination_mgr)); + } + + dest = (my_dest_ptr) cinfo->dest; + dest->pub.init_destination = init_destination; + dest->pub.empty_output_buffer = empty_output_buffer; + dest->pub.term_destination = term_destination; + dest->outfile = outfile; +} + +/* Expanded data source object for stdio input */ + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + SvStream * infile; /* source stream */ + JOCTET * buffer; /* start of buffer */ + boolean start_of_file; /* have we gotten any data yet? */ +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ + +extern "C" void init_source (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = sal_True; +} + +long StreamRead( SvStream* pSvStm, void* pBuffer, long nBufferSize ) +{ + long nRead = 0; + + if( pSvStm->GetError() != ERRCODE_IO_PENDING ) + { + long nActPos = pSvStm->Tell(); + + nRead = (long) pSvStm->Read( pBuffer, nBufferSize ); + + if( pSvStm->GetError() == ERRCODE_IO_PENDING ) + { + // Damit wir wieder an die alte Position + // seeken koennen, setzen wir den Error temp.zurueck + pSvStm->ResetError(); + pSvStm->Seek( nActPos ); + pSvStm->SetError( ERRCODE_IO_PENDING ); + } + } + + return nRead; +} + +extern "C" boolean fill_input_buffer (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + size_t nbytes; + + nbytes = StreamRead(src->infile, src->buffer, BUF_SIZE); + + if (!nbytes) { + if (src->start_of_file) /* Treat empty input file as fatal error */ + ERREXIT(cinfo, JERR_INPUT_EMPTY); + WARNMS(cinfo, JWRN_JPEG_EOF); + /* Insert a fake EOI marker */ + src->buffer[0] = (JOCTET) 0xFF; + src->buffer[1] = (JOCTET) JPEG_EOI; + nbytes = 2; + } + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = sal_False; + + return sal_True; +} + +extern "C" void skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) fill_input_buffer(cinfo); + /* note we assume that fill_input_buffer will never return sal_False, + * so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + +extern "C" void term_source (j_decompress_ptr) +{ + /* no work necessary here */ +} + +extern "C" void jpeg_svstream_src (j_decompress_ptr cinfo, void * in) +{ + my_src_ptr src; + SvStream * infile = (SvStream*)in; + + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_stdio_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(my_source_mgr)); + src = (my_src_ptr) cinfo->src; + src->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + BUF_SIZE * sizeof(JOCTET)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = term_source; + src->infile = infile; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ +} + +// -------------- +// - JPEGReader - +// -------------- + +JPEGReader::JPEGReader( SvStream& rStm, void* /*pCallData*/, sal_Bool bSetLS ) : + rIStm ( rStm ), + pAcc ( NULL ), + pAcc1 ( NULL ), + pBuffer ( NULL ), + nLastPos ( rStm.Tell() ), + nLastLines ( 0 ), + bSetLogSize ( bSetLS ) +{ + maUpperName = rtl::OUString("SVIJPEG"); + nFormerPos = nLastPos; +} + +// ------------------------------------------------------------------------ + +JPEGReader::~JPEGReader() +{ + if( pBuffer ) + rtl_freeMemory( pBuffer ); + + if( pAcc ) + aBmp.ReleaseAccess( pAcc ); + + if( pAcc1 ) + aBmp1.ReleaseAccess( pAcc1 ); +} + +// ------------------------------------------------------------------------ + +void* JPEGReader::CreateBitmap( void* _pParam ) +{ + JPEGCreateBitmapParam *pParam = (JPEGCreateBitmapParam *) _pParam; + + if (pParam->nWidth > SAL_MAX_INT32/8 || pParam->nHeight > SAL_MAX_INT32/8) + return NULL; // avoid overflows later + + Size aSize( pParam->nWidth, pParam->nHeight ); + sal_Bool bGray = pParam->bGray != 0; + + void* pBmpBuf = NULL; + + if( pAcc ) + aBmp.ReleaseAccess( pAcc ); + + sal_uInt64 nSize = aSize.Width(); + nSize *= aSize.Height(); + if (nSize > SAL_MAX_INT32 / 24) + return NULL; + + if( bGray ) + { + BitmapPalette aGrayPal( 256 ); + + for( sal_uInt16 n = 0; n < 256; n++ ) + { + const sal_uInt8 cGray = (sal_uInt8) n; + aGrayPal[ n ] = BitmapColor( cGray, cGray, cGray ); + } + + aBmp = Bitmap( aSize, 8, &aGrayPal ); + } + else + aBmp = Bitmap( aSize, 24 ); + + if ( bSetLogSize ) + { + unsigned long nUnit = ((JPEGCreateBitmapParam*)pParam)->density_unit; + + if( ( ( 1 == nUnit ) || ( 2 == nUnit ) ) && + pParam->X_density && pParam->Y_density ) + { + Point aEmptyPoint; + Fraction aFractX( 1, pParam->X_density ); + Fraction aFractY( 1, pParam->Y_density ); + MapMode aMapMode( nUnit == 1 ? MAP_INCH : MAP_CM, aEmptyPoint, aFractX, aFractY ); + Size aPrefSize = OutputDevice::LogicToLogic( aSize, aMapMode, MAP_100TH_MM ); + + aBmp.SetPrefSize( aPrefSize ); + aBmp.SetPrefMapMode( MapMode( MAP_100TH_MM ) ); + } + } + + pAcc = aBmp.AcquireWriteAccess(); + + if( pAcc ) + { + const sal_uLong nFormat = pAcc->GetScanlineFormat(); + + if( + ( bGray && ( BMP_FORMAT_8BIT_PAL == nFormat ) ) || + ( !bGray && ( BMP_FORMAT_24BIT_TC_RGB == nFormat ) ) + ) + { + pBmpBuf = pAcc->GetBuffer(); + pParam->nAlignedWidth = pAcc->GetScanlineSize(); + pParam->bTopDown = pAcc->IsTopDown(); + } + else + { + pParam->nAlignedWidth = AlignedWidth4Bytes( aSize.Width() * ( bGray ? 8 : 24 ) ); + pParam->bTopDown = sal_True; + pBmpBuf = pBuffer = rtl_allocateMemory( pParam->nAlignedWidth * aSize.Height() ); + } + } + + // clean up, if no Bitmap buffer can be provided. + if ( !pBmpBuf ) + { + aBmp.ReleaseAccess( pAcc ); + pAcc = NULL; + } + + return pBmpBuf; +} + +// ------------------------------------------------------------------------ + +void JPEGReader::FillBitmap() +{ + if( pBuffer && pAcc ) + { + HPBYTE pTmp; + BitmapColor aColor; + long nAlignedWidth; + long nWidth = pAcc->Width(); + long nHeight = pAcc->Height(); + + if( pAcc->GetBitCount() == 8 ) + { + BitmapColor* pCols = new BitmapColor[ 256 ]; + + for( sal_uInt16 n = 0; n < 256; n++ ) + { + const sal_uInt8 cGray = (sal_uInt8) n; + pCols[ n ] = pAcc->GetBestMatchingColor( BitmapColor( cGray, cGray, cGray ) ); + } + + nAlignedWidth = AlignedWidth4Bytes( pAcc->Width() * 8L ); + + for( long nY = 0L; nY < nHeight; nY++ ) + { + pTmp = (sal_uInt8*) pBuffer + nY * nAlignedWidth; + + for( long nX = 0L; nX < nWidth; nX++ ) + pAcc->SetPixel( nY, nX, pCols[ *pTmp++ ] ); + } + + delete[] pCols; + } + else + { + nAlignedWidth = AlignedWidth4Bytes( pAcc->Width() * 24L ); + + for( long nY = 0L; nY < nHeight; nY++ ) + { + pTmp = (sal_uInt8*) pBuffer + nY * nAlignedWidth; + + for( long nX = 0L; nX < nWidth; nX++ ) + { + aColor.SetRed( *pTmp++ ); + aColor.SetGreen( *pTmp++ ); + aColor.SetBlue( *pTmp++ ); + pAcc->SetPixel( nY, nX, aColor ); + } + } + } + } +} + +// ------------------------------------------------------------------------ + +Graphic JPEGReader::CreateIntermediateGraphic( const Bitmap& rBitmap, long nLines ) +{ + Graphic aGraphic; + const Size aSizePix( rBitmap.GetSizePixel() ); + + if( !nLastLines ) + { + if( pAcc1 ) + aBmp1.ReleaseAccess( pAcc1 ); + + aBmp1 = Bitmap( rBitmap.GetSizePixel(), 1 ); + aBmp1.Erase( Color( COL_WHITE ) ); + pAcc1 = aBmp1.AcquireWriteAccess(); + } + + if( nLines && ( nLines < aSizePix.Height() ) ) + { + if( pAcc1 ) + { + const long nNewLines = nLines - nLastLines; + + if( nNewLines ) + { + pAcc1->SetFillColor( Color( COL_BLACK ) ); + pAcc1->FillRect( Rectangle( Point( 0, nLastLines ), + Size( pAcc1->Width(), nNewLines ) ) ); + } + + aBmp1.ReleaseAccess( pAcc1 ); + aGraphic = BitmapEx( rBitmap, aBmp1 ); + pAcc1 = aBmp1.AcquireWriteAccess(); + } + else + aGraphic = rBitmap; + } + else + aGraphic = rBitmap; + + nLastLines = nLines; + + return aGraphic; +} + +// ------------------------------------------------------------------------ + +ReadState JPEGReader::Read( Graphic& rGraphic ) +{ + long nEndPos; + long nLines; + ReadState eReadState; + sal_Bool bRet = sal_False; + sal_uInt8 cDummy; + +#if 1 // TODO: is it possible to get rid of this seek to the end? + // check if the stream's end is already available + rIStm.Seek( STREAM_SEEK_TO_END ); + rIStm >> cDummy; + nEndPos = rIStm.Tell(); + + // else check if at least JPEGMINREAD bytes can be read + if( rIStm.GetError() == ERRCODE_IO_PENDING ) + { + rIStm.ResetError(); + if( ( nEndPos - nFormerPos ) < JPEGMINREAD ) + { + rIStm.Seek( nLastPos ); + return JPEGREAD_NEED_MORE; + } + } + + // seek back to the original position + rIStm.Seek( nLastPos ); +#endif + + Size aPreviewSize = GetPreviewSize(); + SetJpegPreviewSizeHint( aPreviewSize.Width(), aPreviewSize.Height() ); + + // read the (partial) image + ReadJPEG( this, &rIStm, &nLines ); + + if( pAcc ) + { + if( pBuffer ) + { + FillBitmap(); + rtl_freeMemory( pBuffer ); + pBuffer = NULL; + } + + aBmp.ReleaseAccess( pAcc ); + pAcc = NULL; + + if( rIStm.GetError() == ERRCODE_IO_PENDING ) + rGraphic = CreateIntermediateGraphic( aBmp, nLines ); + else + rGraphic = aBmp; + + bRet = sal_True; + } + else if( rIStm.GetError() == ERRCODE_IO_PENDING ) + bRet = sal_True; + + // Status setzen ( Pending hat immer Vorrang ) + if( rIStm.GetError() == ERRCODE_IO_PENDING ) + { + eReadState = JPEGREAD_NEED_MORE; + rIStm.ResetError(); + nFormerPos = rIStm.Tell(); + } + else + { + if( bRet ) + eReadState = JPEGREAD_OK; + else + eReadState = JPEGREAD_ERROR; + } + + return eReadState; +} + + +// -------------- +// - JPEGWriter - +// -------------- + +JPEGWriter::JPEGWriter( SvStream& rStm, const uno::Sequence< beans::PropertyValue >* pFilterData, bool* pExportWasGrey ) : + rOStm ( rStm ), + pAcc ( NULL ), + pBuffer ( NULL ), + pExpWasGrey ( pExportWasGrey ) +{ + FilterConfigItem aConfigItem( (uno::Sequence< beans::PropertyValue >*)pFilterData ); + bGreys = aConfigItem.ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( "ColorMode" ) ), 0 ) != 0; + nQuality = aConfigItem.ReadInt32( String( RTL_CONSTASCII_USTRINGPARAM( "Quality" ) ), 75 ); + + if ( pFilterData ) + { + int nArgs = pFilterData->getLength(); + const beans::PropertyValue* pValues = pFilterData->getConstArray(); + while( nArgs-- ) + { + if ( pValues->Name == "StatusIndicator" ) + { + pValues->Value >>= xStatusIndicator; + } + pValues++; + } + } +} + +// ------------------------------------------------------------------------ + +void* JPEGWriter::GetScanline( long nY ) +{ + void* pScanline = NULL; + + if( pAcc ) + { + if( bNative ) + pScanline = pAcc->GetScanline( nY ); + else if( pBuffer ) + { + BitmapColor aColor; + long nWidth = pAcc->Width(); + sal_uInt8* pTmp = pBuffer; + + if( pAcc->HasPalette() ) + { + for( long nX = 0L; nX < nWidth; nX++ ) + { + aColor = pAcc->GetPaletteColor( (sal_uInt8) pAcc->GetPixel( nY, nX ) ); + *pTmp++ = aColor.GetRed(); + if ( bGreys ) + continue; + *pTmp++ = aColor.GetGreen(); + *pTmp++ = aColor.GetBlue(); + } + } + else + { + for( long nX = 0L; nX < nWidth; nX++ ) + { + aColor = pAcc->GetPixel( nY, nX ); + *pTmp++ = aColor.GetRed(); + if ( bGreys ) + continue; + *pTmp++ = aColor.GetGreen(); + *pTmp++ = aColor.GetBlue(); + } + } + + pScanline = pBuffer; + } + } + + return pScanline; +} + +// ------------------------------------------------------------------------ + +sal_Bool JPEGWriter::Write( const Graphic& rGraphic ) +{ + sal_Bool bRet = sal_False; + + if ( xStatusIndicator.is() ) + { + rtl::OUString aMsg; + xStatusIndicator->start( aMsg, 100 ); + } + + Bitmap aGraphicBmp( rGraphic.GetBitmap() ); + + if ( bGreys ) + { + if ( !aGraphicBmp.Convert( BMP_CONVERSION_8BIT_GREYS ) ) + aGraphicBmp = rGraphic.GetBitmap(); + } + + pAcc = aGraphicBmp.AcquireReadAccess(); + + if ( !bGreys ) // bitmap was not explicitly converted into greyscale, + { // check if source is greyscale only + + sal_Bool bIsGrey = sal_True; + + long nWidth = pAcc->Width(); + for ( long nY = 0; bIsGrey && ( nY < pAcc->Height() ); nY++ ) + { + BitmapColor aColor; + for( long nX = 0L; bIsGrey && ( nX < nWidth ); nX++ ) + { + aColor = pAcc->HasPalette() ? pAcc->GetPaletteColor( (sal_uInt8) pAcc->GetPixel( nY, nX ) ) + : pAcc->GetPixel( nY, nX ); + bIsGrey = ( aColor.GetRed() == aColor.GetGreen() ) && ( aColor.GetRed() == aColor.GetBlue() ); + } + } + if ( bIsGrey ) + bGreys = sal_True; + } + + if( pExpWasGrey ) + *pExpWasGrey = bGreys; + + if( pAcc ) + { + bNative = ( pAcc->GetScanlineFormat() == BMP_FORMAT_24BIT_TC_RGB ); + + if( !bNative ) + pBuffer = new sal_uInt8[ AlignedWidth4Bytes( bGreys ? pAcc->Width() * 8L : pAcc->Width() * 24L ) ]; + + JPEGCallbackStruct aCallbackData; + aCallbackData.xStatusIndicator = xStatusIndicator; + bRet = (sal_Bool) WriteJPEG( this, &rOStm, pAcc->Width(), pAcc->Height(), bGreys, nQuality, &aCallbackData ); + + delete[] pBuffer; + pBuffer = NULL; + + aGraphicBmp.ReleaseAccess( pAcc ); + pAcc = NULL; + } + if ( xStatusIndicator.is() ) + xStatusIndicator->end(); + + return bRet; +} + +// -------------- +// - ImportJPEG - +// -------------- + +sal_Bool ImportJPEG( SvStream& rStm, Graphic& rGraphic, void* pCallerData, sal_Int32 nImportFlags ) +{ + JPEGReader* pJPEGReader = (JPEGReader*) rGraphic.GetContext(); + ReadState eReadState; + sal_Bool bRet = sal_True; + + if( !pJPEGReader ) + pJPEGReader = new JPEGReader( rStm, pCallerData, ( nImportFlags & GRFILTER_I_FLAGS_SET_LOGSIZE_FOR_JPEG ) != 0 ); + + if( nImportFlags & GRFILTER_I_FLAGS_FOR_PREVIEW ) + pJPEGReader->SetPreviewSize( Size(128,128) ); + else + pJPEGReader->DisablePreviewMode(); + + rGraphic.SetContext( NULL ); + eReadState = pJPEGReader->Read( rGraphic ); + + if( eReadState == JPEGREAD_ERROR ) + { + bRet = sal_False; + delete pJPEGReader; + } + else if( eReadState == JPEGREAD_OK ) + delete pJPEGReader; + else + rGraphic.SetContext( pJPEGReader ); + + return bRet; +} + +// -------------- +// - ExportJPEG - +// -------------- + +sal_Bool ExportJPEG( SvStream& rOStm, const Graphic& rGraphic, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData, + bool* pExportWasGrey + ) +{ + JPEGWriter aJPEGWriter( rOStm, pFilterData, pExportWasGrey ); + return aJPEGWriter.Write( rGraphic ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/jpeg/jpeg.h b/vcl/source/filter/jpeg/jpeg.h new file mode 100644 index 000000000000..9c7e4b71d6a0 --- /dev/null +++ b/vcl/source/filter/jpeg/jpeg.h @@ -0,0 +1,64 @@ +/* -*- 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 _JPEG_H +#define _JPEG_H + +#if defined( ICC ) +#include <stdio.h> +#endif + +#if defined (UNX) || defined(__MINGW32__) +#include <sys/types.h> +#endif + +struct JPEGCreateBitmapParam +{ + unsigned long nWidth; + unsigned long nHeight; + unsigned long density_unit; + unsigned long X_density; + unsigned long Y_density; + long bGray; + + long nAlignedWidth; // these members will be filled by the + long bTopDown; // CreateBitmap method in svtools +}; + +typedef struct my_error_mgr* my_error_ptr; +typedef unsigned char* HPBYTE; + +void* JPEGMalloc( size_t size ); +void JPEGFree( void *ptr ); +long JPEGCallback( void* pCallbackData, long nPercent ); + +long WriteJPEG( void* pJPEGWriter, void* pOStm, long nWidth, long nHeight, long bGreyScale, + long nQualityPercent, void* pCallbackData ); +void* GetScanline( void* pJPEGWriter, long nY ); + +void ReadJPEG( void* pJPEGReader, void* pIStm, long* pLines ); +void* CreateBitmap( void* pJPEGReader, void* pJPEGCreateBitmapParam ); + +/* TODO: when incompatible changes are possible again + the preview size hint should be redone */ +void SetJpegPreviewSizeHint( int nWidth, int nHeight ); + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/jpeg/jpeg.hxx b/vcl/source/filter/jpeg/jpeg.hxx new file mode 100644 index 000000000000..df033bd7b98b --- /dev/null +++ b/vcl/source/filter/jpeg/jpeg.hxx @@ -0,0 +1,123 @@ +/* -*- 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 _JPEG_HXX +#define _JPEG_HXX + +#include <vcl/graph.hxx> +#include <svtools/fltcall.hxx> +#include <com/sun/star/uno/Sequence.h> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/task/XStatusIndicator.hpp> + +#ifdef _JPEGPRIVATE + +// -------- +// - Enum - +// -------- + +enum ReadState +{ + JPEGREAD_OK, + JPEGREAD_ERROR, + JPEGREAD_NEED_MORE +}; + +// -------------- +// - JPEGReader - +// -------------- + +class JPEGReader : public GraphicReader +{ + SvStream& rIStm; + Bitmap aBmp; + Bitmap aBmp1; + BitmapWriteAccess* pAcc; + BitmapWriteAccess* pAcc1; + void* pBuffer; + long nLastPos; + long nFormerPos; + long nLastLines; + sal_Bool bSetLogSize; + + Graphic CreateIntermediateGraphic( const Bitmap& rBitmap, long nLines ); + void FillBitmap(); + +public: + + void* CreateBitmap( void* JPEGCreateBitmapParam ); + +public: + + + + JPEGReader( SvStream& rStm, void* pCallData, sal_Bool bSetLogSize ); + virtual ~JPEGReader(); + + + ReadState Read( Graphic& rGraphic ); +}; + +// -------------- +// - JPEGWriter - +// -------------- + +class JPEGWriter +{ + SvStream& rOStm; + Bitmap aBmp; + BitmapReadAccess* pAcc; + sal_uInt8* pBuffer; + sal_Bool bNative; + + sal_Bool bGreys; + sal_Int32 nQuality; + + bool* pExpWasGrey; + + com::sun::star::uno::Reference< com::sun::star::task::XStatusIndicator > xStatusIndicator; + +public: + + void* GetScanline( long nY ); + + JPEGWriter( SvStream& rOStm, const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData, + bool* pExportWasGrey = NULL ); + ~JPEGWriter() {}; + + sal_Bool Write( const Graphic& rGraphic ); +}; + +#endif // _JPEGPRIVATE + +// --------------------- +// - Import/ExportJPEG - +// --------------------- + +sal_Bool ImportJPEG( SvStream& rStream, Graphic& rGraphic, void* pCallerData, sal_Int32 nImportFlags ); + +sal_Bool ExportJPEG( SvStream& rStream, + const Graphic& rGraphic, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::PropertyValue >* pFilterData, + bool* pExportWasGrey = NULL + ); + +#endif // _JPEG_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/jpeg/jpegc.c b/vcl/source/filter/jpeg/jpegc.c new file mode 100644 index 000000000000..528e19e51216 --- /dev/null +++ b/vcl/source/filter/jpeg/jpegc.c @@ -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 . + */ + +#include <stdio.h> +#include <stdlib.h> +#include "setjmp.h" +#include "jpeglib.h" +#include "jerror.h" +#include "jpeg.h" +#include "rtl/alloc.h" +#include "osl/diagnose.h" + +struct my_error_mgr +{ + struct jpeg_error_mgr pub; + jmp_buf setjmp_buffer; +}; + +void jpeg_svstream_src (j_decompress_ptr cinfo, void* infile); +void jpeg_svstream_dest (j_compress_ptr cinfo, void* outfile); + +METHODDEF( void ) +my_error_exit (j_common_ptr cinfo) +{ + my_error_ptr myerr = (my_error_ptr) cinfo->err; + (*cinfo->err->output_message) (cinfo); + longjmp(myerr->setjmp_buffer, 1); +} + + +METHODDEF( void ) +my_output_message (j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + (*cinfo->err->format_message) (cinfo, buffer); +} + +/* TODO: when incompatible changes are possible again + the preview size hint should be redone */ +static int nPreviewWidth = 0; +static int nPreviewHeight = 0; +void SetJpegPreviewSizeHint( int nWidth, int nHeight ) +{ + nPreviewWidth = nWidth; + nPreviewHeight = nHeight; +} + +void ReadJPEG( void* pJPEGReader, void* pIStm, long* pLines ) +{ + struct jpeg_decompress_struct cinfo; + struct my_error_mgr jerr; + struct JPEGCreateBitmapParam aCreateBitmapParam; + HPBYTE pDIB; + HPBYTE pTmp; + long nWidth; + long nHeight; + long nAlignedWidth; + JSAMPLE * range_limit; + HPBYTE pScanLineBuffer = NULL; + long nScanLineBufferComponents = 0; + // declare bDecompCreated volatile because of gcc + // warning: variable 'bDecompCreated' might be clobbered by `longjmp' or `vfork' + volatile long bDecompCreated = 0; + + /* Falls der Stream nicht ausreicht (IO_PENDING) + wird ueber ein longjmp in der Schleife nach Exit + gesprungen, wir geben dann die Anzahl + der bisher bearbeiteten Scanlines zurueck*/ + if ( setjmp( jerr.setjmp_buffer ) ) + goto Exit; + + cinfo.err = jpeg_std_error( &jerr.pub ); + jerr.pub.error_exit = my_error_exit; + jerr.pub.output_message = my_output_message; + + jpeg_create_decompress( &cinfo ); + bDecompCreated = 1; + jpeg_svstream_src( &cinfo, pIStm ); + jpeg_read_header( &cinfo, sal_True ); + + cinfo.scale_num = 1; + cinfo.scale_denom = 1; + cinfo.output_gamma = 1.0; + cinfo.raw_data_out = sal_False; + cinfo.quantize_colors = sal_False; + if ( cinfo.jpeg_color_space == JCS_YCbCr ) + cinfo.out_color_space = JCS_RGB; + else if ( cinfo.jpeg_color_space == JCS_YCCK ) + cinfo.out_color_space = JCS_CMYK; + + OSL_ASSERT(cinfo.out_color_space == JCS_CMYK || cinfo.out_color_space == JCS_GRAYSCALE || cinfo.out_color_space == JCS_RGB); + + /* change scale for preview import */ + if( nPreviewWidth || nPreviewHeight ) + { + if( nPreviewWidth == 0 ) { + nPreviewWidth = ( cinfo.image_width*nPreviewHeight )/cinfo.image_height; + if( nPreviewWidth <= 0 ) + nPreviewWidth = 1; + } else if( nPreviewHeight == 0 ) { + nPreviewHeight = ( cinfo.image_height*nPreviewWidth )/cinfo.image_width; + if( nPreviewHeight <= 0 ) + nPreviewHeight = 1; + } + + for( cinfo.scale_denom = 1; cinfo.scale_denom < 8; cinfo.scale_denom *= 2 ) + { + if( cinfo.image_width < nPreviewWidth * cinfo.scale_denom ) + break; + if( cinfo.image_height < nPreviewHeight * cinfo.scale_denom ) + break; + } + + if( cinfo.scale_denom > 1 ) + { + cinfo.dct_method = JDCT_FASTEST; + cinfo.do_fancy_upsampling = sal_False; + cinfo.do_block_smoothing = sal_False; + } + } + + jpeg_start_decompress( &cinfo ); + + nWidth = cinfo.output_width; + nHeight = cinfo.output_height; + aCreateBitmapParam.nWidth = nWidth; + aCreateBitmapParam.nHeight = nHeight; + + aCreateBitmapParam.density_unit = cinfo.density_unit; + aCreateBitmapParam.X_density = cinfo.X_density; + aCreateBitmapParam.Y_density = cinfo.Y_density; + aCreateBitmapParam.bGray = cinfo.output_components == 1; + pDIB = CreateBitmap( pJPEGReader, &aCreateBitmapParam ); + nAlignedWidth = aCreateBitmapParam.nAlignedWidth; + range_limit=cinfo.sample_range_limit; + + if ( cinfo.out_color_space == JCS_CMYK ) + { + nScanLineBufferComponents = cinfo.output_width * 4; + pScanLineBuffer = rtl_allocateMemory( nScanLineBufferComponents ); + } + + if( pDIB ) + { + if( aCreateBitmapParam.bTopDown ) + pTmp = pDIB; + else + { + pTmp = pDIB + ( nHeight - 1 ) * nAlignedWidth; + nAlignedWidth = -nAlignedWidth; + } + + for ( *pLines = 0; *pLines < nHeight; (*pLines)++ ) + { + if (pScanLineBuffer!=NULL) { // in other words cinfo.out_color_space == JCS_CMYK + int i; + int j; + jpeg_read_scanlines( &cinfo, (JSAMPARRAY) &pScanLineBuffer, 1 ); + // convert CMYK to RGB + for( i=0, j=0; i < nScanLineBufferComponents; i+=4, j+=3 ) + { + int c_=255-pScanLineBuffer[i+0]; + int m_=255-pScanLineBuffer[i+1]; + int y_=255-pScanLineBuffer[i+2]; + int k_=255-pScanLineBuffer[i+3]; + pTmp[j+0]=range_limit[ 255L - ( c_ + k_ ) ]; + pTmp[j+1]=range_limit[ 255L - ( m_ + k_ ) ]; + pTmp[j+2]=range_limit[ 255L - ( y_ + k_ ) ]; + } + } else { + jpeg_read_scanlines( &cinfo, (JSAMPARRAY) &pTmp, 1 ); + } + /* PENDING ??? */ + if ( cinfo.err->msg_code == 113 ) + break; + + pTmp += nAlignedWidth; + } + } + + jpeg_finish_decompress( &cinfo ); + if (pScanLineBuffer!=NULL) { + rtl_freeMemory( pScanLineBuffer ); + pScanLineBuffer=NULL; + } + +Exit: + + if( bDecompCreated ) + jpeg_destroy_decompress( &cinfo ); +} + +long WriteJPEG( void* pJPEGWriter, void* pOStm, + long nWidth, long nHeight, long bGreys, + long nQualityPercent, void* pCallbackData ) +{ + struct jpeg_compress_struct cinfo; + struct my_error_mgr jerr; + void* pScanline; + long nY; + // declare bCompCreated, bRet volatile because of gcc + // warning: variable 'bCompCreated' might be clobbered by `longjmp' or `vfork' + volatile long bCompCreated = 0; + volatile long bRet = 0; + + if ( setjmp( jerr.setjmp_buffer ) ) + goto Exit; + + cinfo.err = jpeg_std_error( &jerr.pub ); + jerr.pub.error_exit = my_error_exit; + jerr.pub.output_message = my_output_message; + + jpeg_create_compress( &cinfo ); + bCompCreated = 1; + + jpeg_svstream_dest( &cinfo, pOStm ); + + cinfo.image_width = (JDIMENSION) nWidth; + cinfo.image_height = (JDIMENSION) nHeight; + if ( bGreys ) + { + cinfo.input_components = 1; + cinfo.in_color_space = JCS_GRAYSCALE; + } + else + { + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + } + + jpeg_set_defaults( &cinfo ); + jpeg_set_quality( &cinfo, (int) nQualityPercent, sal_False ); + + if ( ( nWidth > 128 ) || ( nHeight > 128 ) ) + jpeg_simple_progression( &cinfo ); + + jpeg_start_compress( &cinfo, sal_True ); + + for( nY = 0; nY < nHeight; nY++ ) + { + pScanline = GetScanline( pJPEGWriter, nY ); + + if( pScanline ) + jpeg_write_scanlines( &cinfo, (JSAMPARRAY) &pScanline, 1 ); + + if( JPEGCallback( pCallbackData, nY * 100L / nHeight ) ) + goto Exit; + } + + bRet = 1; + + jpeg_finish_compress(&cinfo); + +Exit: + + if ( bCompCreated ) + jpeg_destroy_compress( &cinfo ); + + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/sgf.ini b/vcl/source/filter/sgf.ini new file mode 100644 index 000000000000..17c01255b6f1 --- /dev/null +++ b/vcl/source/filter/sgf.ini @@ -0,0 +1,136 @@ +# +# 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 . +# + +#Family : (Roman,Swiss,Modern,Script,Decora); +#CharSet : (Ansi,IBMPC,Mac,Symbol,System); Default is System +#Attribute: (Bold,Ital,Sans,Serf,Fixd); + +[SGV Fonts fuer StarView] +#IF-ID Fontname Attribute SV-Fam ChSet Width FontName + 3848=(ITC Zapf Dingbats) Decora () + 5720=(Symbol) Serf Decora Symbol () + 5721=(Symbol) Bold Serf Decora Symbol () + 5723=(Symbol Sans) Sans Decora Symbol () + 5724=(Symbol Sans) Bold Sans Decora Symbol () + 90133=(Dom Casual) Sans Script () + 90326=(Brush) Bold Ital Serf Script () + 90349=(Park Avenue) Ital Serf Script () + 90508=(Uncial) Sans Roman () + 91118=(Antique Olive) Bold Sans Swiss () + 91119=(Antique Olive) Sans Swiss () + 91120=(Antique Olive Compact) Bold Sans Swiss () + 91335=(ITC Benguiat) Bold Serf Roman () + 91336=(ITC Benguiat) Bold Ital Serf Roman () + 91846=(Antique Olive) Ital Sans Roman () +#92500=(CG Times) Serf Roman () +#92501=(CG Times) Ital Serf Roman () +#92504=(CG Times) Bold Serf Roman () +#92505=(CG Times) Bold Ital Serf Roman () +#93950=(Courier) Serf Fixd Modern () +#93951=(Courier) Ital Serf Fixd Modern () +#93952=(Courier) Bold Serf Fixd Modern () +#93953=(Courier) Bold Ital Serf Fixd Modern () +#94021=(Univers) Sans Swiss () +#94022=(Univers) Ital Sans Swiss () +#94023=(Univers) Bold Sans Swiss () +#94024=(Univers) Bold Ital Sans Swiss () +102004=(Avanti) Bold Ital Sans Swiss () +102005=(Avanti) Ital Sans Swiss () +102007=(Booklet) Bold Sans Roman () +102008=(Booklet) Bold Ital Sans Roman () +102009=(Booklet) Ital Sans Roman () +102010=(Centuri) Sans Roman () +102011=(Centuri) Bold Sans Roman () +102012=(Centuri) Bold Ital Sans Roman () +102013=(Centuri) Ital Sans Roman () +102014=(Paltus) Bold Sans Roman () +102015=(Paltus) Sans Roman () +102016=(Paltus) Bold Ital Sans Roman () +102017=(Paltus) Ital Sans Roman () +102018=(Sans) Sans Swiss () +102019=(Sans) Bold Sans Swiss () +102020=(Sans) Bold Ital Sans Swiss () +102021=(Sans) Ital Sans Swiss () +102022=(SansCondensed) Sans Swiss () +102023=(SansCondensed) Bold Sans Swiss () +102024=(SansCondensed) Bold Ital Sans Swiss () +102025=(SansCondensed) Ital Sans Swiss () +102026=(PS-Roman) Sans Roman () +102027=(PS-Roman) Bold Sans Roman () +102028=(PS-Roman) Bold Ital Sans Roman () +102029=(PS-Roman) Ital Sans Roman () +200111=(Chalenge) Sans () +200112=(Chalenge) Bold Sans () +200113=(Chalenge) Ital Sans () +200114=(Chalenge) Bold Ital Sans () +200121=(Office) Sans () +200122=(Office) Bold Sans () +200123=(Office) Ital Sans () +200124=(Office) Bold Ital Sans () +200131=(Milano) Sans () +200132=(Milano) Bold Sans () +200133=(Milano) Ital Sans () +200134=(Milano) Bold Ital Sans () +200141=(Atlantic) Sans Roman () +200142=(Atlantic) Bold Sans Roman () +200143=(Atlantic) Ital Sans Roman () +200144=(Atlantic) Bold Ital Sans Roman () +200151=(Pentagon) Sans () +200152=(Pentagon) Bold Sans () +200153=(Pentagon) Ital Sans () +200154=(Pentagon) Bold Ital Sans () +200161=(Classico) Sans () +200162=(Classico) Bold Sans () +200163=(Classico) Ital Sans () +200164=(Classico) Bold Ital Sans () +200211=(Westcost) Sans () +200212=(Westcost) Bold Sans () +200213=(Westcost) Ital Sans () +200214=(Westcost) Bold Ital Sans () +200221=(Finish) Sans () +200222=(Finish) Bold Sans () +200223=(Finish) Ital Sans () +200224=(Finish) Bold Ital Sans () +200231=(Classic) Sans () +200232=(Classic) Bold Sans () +200233=(Classic) Ital Sans () +200234=(Classic) Bold Ital Sans () +200241=(Hilton) Sans () +200242=(Hilton) Bold Sans () +200243=(Hilton) Ital Sans () +200244=(Hilton) Bold Ital Sans () +200251=(Progress) Sans () +200252=(Progress) Bold Sans () +200253=(Progress) Ital Sans () +200254=(Progress) Bold Ital Sans () +200261=(PrestigeElite) Sans () +200262=(PrestigeElite) Bold Sans () +200263=(PrestigeElite) Ital Sans () +200271=(Ovetti) Bold Sans () +200272=(Ovetti) Sans () +200301=(Cescendo) Sans () +200302=(Funky) Sans Decora () +200303=(Speed) Sans Decora () +200304=(Skyline) Sans Decora () +200305=(Calculator) Sans Decora () +200306=(Xpress) Sans Decora () +200307=(Console) Sans Decora () +200308=(Paisley) Sans () +200309=(Nova) Sans () +200310=(New York) Sans Decora () +200311=(Shanghai) Sans Decora () diff --git a/vcl/source/filter/sgfbram.cxx b/vcl/source/filter/sgfbram.cxx new file mode 100644 index 000000000000..f698329a0c6d --- /dev/null +++ b/vcl/source/filter/sgfbram.cxx @@ -0,0 +1,532 @@ +/* -*- 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 <string.h> +#include <osl/endian.h> +#include <tools/stream.hxx> +#include <vcl/gdimtf.hxx> +#include <tools/color.hxx> +#include <vcl/virdev.hxx> +#include "sgffilt.hxx" +#include "sgfbram.hxx" + +SvStream& operator>>(SvStream& rIStream, SgfHeader& rHead) +{ + rIStream.Read((char*)&rHead.Magic,SgfHeaderSize); +#if defined OSL_BIGENDIAN + rHead.Magic =OSL_SWAPWORD(rHead.Magic ); + rHead.Version=OSL_SWAPWORD(rHead.Version); + rHead.Typ =OSL_SWAPWORD(rHead.Typ ); + rHead.Xsize =OSL_SWAPWORD(rHead.Xsize ); + rHead.Ysize =OSL_SWAPWORD(rHead.Ysize ); + rHead.Xoffs =OSL_SWAPWORD(rHead.Xoffs ); + rHead.Yoffs =OSL_SWAPWORD(rHead.Yoffs ); + rHead.Planes =OSL_SWAPWORD(rHead.Planes ); + rHead.SwGrCol=OSL_SWAPWORD(rHead.SwGrCol); + rHead.OfsLo =OSL_SWAPWORD(rHead.OfsLo ); + rHead.OfsHi =OSL_SWAPWORD(rHead.OfsHi ); +#endif + return rIStream; +} + +sal_Bool SgfHeader::ChkMagic() +{ return Magic=='J'*256+'J'; } + +sal_uInt32 SgfHeader::GetOffset() +{ return sal_uInt32(OfsLo)+0x00010000*sal_uInt32(OfsHi); } + +SvStream& operator>>(SvStream& rIStream, SgfEntry& rEntr) +{ + rIStream.Read((char*)&rEntr.Typ,SgfEntrySize); +#if defined OSL_BIGENDIAN + rEntr.Typ =OSL_SWAPWORD(rEntr.Typ ); + rEntr.iFrei=OSL_SWAPWORD(rEntr.iFrei); + rEntr.lFreiLo=OSL_SWAPWORD (rEntr.lFreiLo); + rEntr.lFreiHi=OSL_SWAPWORD (rEntr.lFreiHi); + rEntr.OfsLo=OSL_SWAPWORD(rEntr.OfsLo); + rEntr.OfsHi=OSL_SWAPWORD(rEntr.OfsHi); +#endif + return rIStream; +} + +sal_uInt32 SgfEntry::GetOffset() +{ return sal_uInt32(OfsLo)+0x00010000*sal_uInt32(OfsHi); } + +SvStream& operator>>(SvStream& rIStream, SgfVector& rVect) +{ + rIStream.Read((char*)&rVect,sizeof(rVect)); +#if defined OSL_BIGENDIAN + rVect.Flag =OSL_SWAPWORD(rVect.Flag ); + rVect.x =OSL_SWAPWORD(rVect.x ); + rVect.y =OSL_SWAPWORD(rVect.y ); + rVect.OfsLo=OSL_SWAPDWORD (rVect.OfsLo); + rVect.OfsHi=OSL_SWAPDWORD (rVect.OfsHi); +#endif + return rIStream; +} + +SvStream& operator<<(SvStream& rOStream, BmpFileHeader& rHead) +{ +#if defined OSL_BIGENDIAN + rHead.Typ =OSL_SWAPWORD(rHead.Typ ); + rHead.SizeLo =OSL_SWAPWORD(rHead.SizeLo ); + rHead.SizeHi =OSL_SWAPWORD(rHead.SizeHi ); + rHead.Reserve1=OSL_SWAPWORD(rHead.Reserve1); + rHead.Reserve2=OSL_SWAPWORD(rHead.Reserve2); + rHead.OfsLo =OSL_SWAPWORD(rHead.OfsLo ); + rHead.OfsHi =OSL_SWAPWORD(rHead.OfsHi ); +#endif + rOStream.Write((char*)&rHead,sizeof(rHead)); +#if defined OSL_BIGENDIAN + rHead.Typ =OSL_SWAPWORD(rHead.Typ ); + rHead.SizeLo =OSL_SWAPWORD(rHead.SizeLo ); + rHead.SizeHi =OSL_SWAPWORD(rHead.SizeHi ); + rHead.Reserve1=OSL_SWAPWORD(rHead.Reserve1); + rHead.Reserve2=OSL_SWAPWORD(rHead.Reserve2); + rHead.OfsLo =OSL_SWAPWORD(rHead.OfsLo ); + rHead.OfsHi =OSL_SWAPWORD(rHead.OfsHi ); +#endif + return rOStream; +} + +void BmpFileHeader::SetSize(sal_uInt32 Size) +{ + SizeLo=sal_uInt16(Size & 0x0000FFFF); + SizeHi=sal_uInt16((Size & 0xFFFF0000)>>16); +} + +void BmpFileHeader::SetOfs(sal_uInt32 Ofs) +{ + OfsLo=sal_uInt16(Ofs & 0x0000FFFF); + OfsHi=sal_uInt16((Ofs & 0xFFFF0000)>>16); +} + +sal_uInt32 BmpFileHeader::GetOfs() +{ + return sal_uInt32(OfsLo)+0x00010000*sal_uInt32(OfsHi); +} + +SvStream& operator<<(SvStream& rOStream, BmpInfoHeader& rInfo) +{ +#if defined OSL_BIGENDIAN + rInfo.Size =OSL_SWAPDWORD (rInfo.Size ); + rInfo.Width =OSL_SWAPDWORD (rInfo.Width ); + rInfo.Hight =OSL_SWAPDWORD (rInfo.Hight ); + rInfo.Planes =OSL_SWAPWORD(rInfo.Planes ); + rInfo.PixBits =OSL_SWAPWORD(rInfo.PixBits ); + rInfo.Compress=OSL_SWAPDWORD (rInfo.Compress); + rInfo.ImgSize =OSL_SWAPDWORD (rInfo.ImgSize ); + rInfo.xDpmm =OSL_SWAPDWORD (rInfo.xDpmm ); + rInfo.yDpmm =OSL_SWAPDWORD (rInfo.yDpmm ); + rInfo.ColUsed =OSL_SWAPDWORD (rInfo.ColUsed ); + rInfo.ColMust =OSL_SWAPDWORD (rInfo.ColMust ); +#endif + rOStream.Write((char*)&rInfo,sizeof(rInfo)); +#if defined OSL_BIGENDIAN + rInfo.Size =OSL_SWAPDWORD (rInfo.Size ); + rInfo.Width =OSL_SWAPDWORD (rInfo.Width ); + rInfo.Hight =OSL_SWAPDWORD (rInfo.Hight ); + rInfo.Planes =OSL_SWAPWORD(rInfo.Planes ); + rInfo.PixBits =OSL_SWAPWORD(rInfo.PixBits ); + rInfo.Compress=OSL_SWAPDWORD (rInfo.Compress); + rInfo.ImgSize =OSL_SWAPDWORD (rInfo.ImgSize ); + rInfo.xDpmm =OSL_SWAPDWORD (rInfo.xDpmm ); + rInfo.yDpmm =OSL_SWAPDWORD (rInfo.yDpmm ); + rInfo.ColUsed =OSL_SWAPDWORD (rInfo.ColUsed ); + rInfo.ColMust =OSL_SWAPDWORD (rInfo.ColMust ); +#endif + return rOStream; +} + +SvStream& operator<<(SvStream& rOStream, const RGBQuad& rQuad) +{ + rOStream.Write((char*)&rQuad,sizeof(rQuad)); + return rOStream; +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// PcxExpand /////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +class PcxExpand +{ +private: + sal_uInt16 Count; + sal_uInt8 Data; +public: + PcxExpand() { Count=0; } + sal_uInt8 GetByte(SvStream& rInp); +}; + +sal_uInt8 PcxExpand::GetByte(SvStream& rInp) +{ + if (Count>0) { + Count--; + } else { + rInp.Read((char*)&Data,1); + if ((Data & 0xC0) == 0xC0) { + Count=(Data & 0x3F) -1; + rInp.Read((char*)&Data,1); + } + } + return Data; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// SgfBMapFilter /////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +sal_Bool SgfFilterBMap(SvStream& rInp, SvStream& rOut, SgfHeader& rHead, SgfEntry&) +{ + BmpFileHeader aBmpHead; + BmpInfoHeader aBmpInfo; + sal_uInt16 nWdtInp=(rHead.Xsize+7)/8; // Breite der Input-Bitmap in Bytes + sal_uInt16 nWdtOut; // Breite der Output-Bitmap in Bytes + sal_uInt16 nColors; // Anzahl der Farben (1,16,256) + sal_uInt16 nColBits; // Anzahl der Bits/Pixel (2, 4, 8) + sal_uInt16 i,j,k; // Spaltenzaehler, Zeilenzaehler, Planezaehler + sal_uInt16 a,b; // Hilfsvariable + sal_uInt8 pl1 = 0; // Masken fuer die Planes + sal_uInt8* pBuf=NULL; // Buffer fuer eine Pixelzeile + PcxExpand aPcx; + sal_uLong nOfs; + sal_uInt8 cRGB[4]; + + if (rHead.Planes<=1) nColBits=1; else nColBits=4; if (rHead.Typ==4) nColBits=8; + nColors=1<<nColBits; + nWdtOut=((rHead.Xsize*nColBits+31)/32)*4; + aBmpHead.Typ='B'+'M'*256; + aBmpHead.SetOfs(sizeof(aBmpHead)+sizeof(aBmpInfo)+nColors*4); + aBmpHead.SetSize(aBmpHead.GetOfs()+nWdtOut*rHead.Ysize); + aBmpHead.Reserve1=0; + aBmpHead.Reserve2=0; + aBmpInfo.Size=sizeof(aBmpInfo); + aBmpInfo.Width=rHead.Xsize; + aBmpInfo.Hight=rHead.Ysize; + aBmpInfo.Planes=1; + aBmpInfo.PixBits=nColBits; + aBmpInfo.Compress=0; + aBmpInfo.ImgSize=0; + aBmpInfo.xDpmm=0; + aBmpInfo.yDpmm=0; + aBmpInfo.ColUsed=0; + aBmpInfo.ColMust=0; + pBuf=new sal_uInt8[nWdtOut]; + if (!pBuf) return sal_False; // Fehler: kein Speichel da + rOut<<aBmpHead<<aBmpInfo; + memset(pBuf,0,nWdtOut); // Buffer mit Nullen fuellen + + if (nColors==2) + { + + rOut<<RGBQuad(0x00,0x00,0x00); // Schwarz + rOut<<RGBQuad(0xFF,0xFF,0xFF); // Weiss + nOfs=rOut.Tell(); + for (j=0;j<rHead.Ysize;j++) + rOut.Write((char*)pBuf,nWdtOut); // Datei erstmal komplett mit Nullen fuellen + for (j=0;j<rHead.Ysize;j++) { + for(i=0;i<nWdtInp;i++) { + pBuf[i]=aPcx.GetByte(rInp); + } + for(i=nWdtInp;i<nWdtOut;i++) pBuf[i]=0; // noch bis zu 3 Bytes + rOut.Seek(nOfs+((sal_uLong)rHead.Ysize-j-1L)*(sal_uLong)nWdtOut); // rueckwaerts schreiben! + rOut.Write((char*)pBuf,nWdtOut); + } + } else if (nColors==16) { + sal_uInt8 pl2= 0; // Masken fuer die Planes + + rOut<<RGBQuad(0x00,0x00,0x00); // Schwarz + rOut<<RGBQuad(0x24,0x24,0x24); // Grau 80% + rOut<<RGBQuad(0x49,0x49,0x49); // Grau 60% + rOut<<RGBQuad(0x92,0x92,0x92); // Grau 40% + rOut<<RGBQuad(0x6D,0x6D,0x6D); // Grau 30% + rOut<<RGBQuad(0xB6,0xB6,0xB6); // Grau 20% + rOut<<RGBQuad(0xDA,0xDA,0xDA); // Grau 10% + rOut<<RGBQuad(0xFF,0xFF,0xFF); // Weiss + rOut<<RGBQuad(0x00,0x00,0x00); // Schwarz + rOut<<RGBQuad(0xFF,0x00,0x00); // Rot + rOut<<RGBQuad(0x00,0x00,0xFF); // Blau + rOut<<RGBQuad(0xFF,0x00,0xFF); // Magenta + rOut<<RGBQuad(0x00,0xFF,0x00); // Gruen + rOut<<RGBQuad(0xFF,0xFF,0x00); // Gelb + rOut<<RGBQuad(0x00,0xFF,0xFF); // Cyan + rOut<<RGBQuad(0xFF,0xFF,0xFF); // Weiss + + nOfs=rOut.Tell(); + for (j=0;j<rHead.Ysize;j++) + rOut.Write((char*)pBuf,nWdtOut); // Datei erstmal komplett mit Nullen fuellen + for (j=0;j<rHead.Ysize;j++) { + memset(pBuf,0,nWdtOut); + for(k=0;k<4;k++) { + if (k==0) { + pl1=0x10; pl2=0x01; + } else { + pl1<<=1; pl2<<=1; + } + for(i=0;i<nWdtInp;i++) { + a=i*4; + b=aPcx.GetByte(rInp); + if (b & 0x80) pBuf[a ]|=pl1; + if (b & 0x40) pBuf[a ]|=pl2; + if (b & 0x20) pBuf[a+1]|=pl1; + if (b & 0x10) pBuf[a+1]|=pl2; + if (b & 0x08) pBuf[a+2]|=pl1; + if (b & 0x04) pBuf[a+2]|=pl2; + if (b & 0x02) pBuf[a+3]|=pl1; + if (b & 0x01) pBuf[a+3]|=pl2; + } + } + for(i=nWdtInp*4;i<nWdtOut;i++) pBuf[i]=0; // noch bis zu 3 Bytes + rOut.Seek(nOfs+((sal_uLong)rHead.Ysize-j-1L)*(sal_uLong)nWdtOut); // rueckwaerts schreiben! + rOut.Write((char*)pBuf,nWdtOut); + } + } else if (nColors==256) { + cRGB[3]=0; // der 4. Paletteneintrag fuer BMP + for (i=0;i<256;i++) { // Palette kopieren + rInp.Read((char*)cRGB,3); + pl1=cRGB[0]; // Rot mit Blau tauschen + cRGB[0]=cRGB[2]; + cRGB[2]=pl1; + rOut.Write((char*)cRGB,4); + } + + nOfs=rOut.Tell(); + for (j=0;j<rHead.Ysize;j++) + rOut.Write((char*)pBuf,nWdtOut); // Datei erstmal komplett mit Nullen fuellen + for (j=0;j<rHead.Ysize;j++) { + for(i=0;i<rHead.Xsize;i++) + pBuf[i]=aPcx.GetByte(rInp); + for(i=rHead.Xsize;i<nWdtOut;i++) pBuf[i]=0; // noch bis zu 3 Bytes + rOut.Seek(nOfs+((sal_uLong)rHead.Ysize-j-1L)*(sal_uLong)nWdtOut); // rueckwaerts schreiben! + rOut.Write((char*)pBuf,nWdtOut); + } + } + delete[] pBuf; + return sal_True; +} + +sal_Bool SgfBMapFilter(SvStream& rInp, SvStream& rOut) +{ + sal_uLong nFileStart; // Offset des SgfHeaders. Im allgemeinen 0. + SgfHeader aHead; + SgfEntry aEntr; + sal_uLong nNext; + sal_Bool bRdFlag=sal_False; // Grafikentry gelesen ? + sal_Bool bRet=sal_False; // Returncode + + nFileStart=rInp.Tell(); + rInp>>aHead; + if (aHead.ChkMagic() && (aHead.Typ==SgfBitImag0 || aHead.Typ==SgfBitImag1 || + aHead.Typ==SgfBitImag2 || aHead.Typ==SgfBitImgMo)) { + nNext=aHead.GetOffset(); + while (nNext && !bRdFlag && !rInp.GetError() && !rOut.GetError()) { + rInp.Seek(nFileStart+nNext); + rInp>>aEntr; + nNext=aEntr.GetOffset(); + if (aEntr.Typ==aHead.Typ) { + bRdFlag=sal_True; + switch(aEntr.Typ) { + case SgfBitImag0: + case SgfBitImag1: + case SgfBitImag2: + case SgfBitImgMo: bRet=SgfFilterBMap(rInp,rOut,aHead,aEntr); break; + } + } + } // while(nNext) + } + if (rInp.GetError()) bRet=sal_False; + return(bRet); +} + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// SgfVectFilter /////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// Fuer StarDraw Embedded SGF-Vector +long SgfVectXofs=0; +long SgfVectYofs=0; +long SgfVectXmul=0; +long SgfVectYmul=0; +long SgfVectXdiv=0; +long SgfVectYdiv=0; +sal_Bool SgfVectScal=sal_False; + +//////////////////////////////////////////////////////////// +// Hpgl2SvFarbe //////////////////////////////////////////// +//////////////////////////////////////////////////////////// + +Color Hpgl2SvFarbe( sal_uInt8 nFarb ) +{ + sal_uLong nColor = COL_BLACK; + + switch (nFarb & 0x07) { + case 0: nColor=COL_WHITE; break; + case 1: nColor=COL_YELLOW; break; + case 2: nColor=COL_LIGHTMAGENTA; break; + case 3: nColor=COL_LIGHTRED; break; + case 4: nColor=COL_LIGHTCYAN; break; + case 5: nColor=COL_LIGHTGREEN; break; + case 6: nColor=COL_LIGHTBLUE; break; + case 7: nColor=COL_BLACK; break; + } + Color aColor( nColor ); + return aColor; +} + +sal_Bool SgfFilterVect(SvStream& rInp, SgfHeader& rHead, SgfEntry&, GDIMetaFile& rMtf) +{ + VirtualDevice aOutDev; + SgfVector aVect; + sal_uInt8 nFarb; + sal_uInt8 nFrb0=7; + sal_uInt8 nLTyp; + sal_uInt8 nOTyp; + sal_Bool bEoDt=sal_False; + sal_Bool bPDwn=sal_False; + Point aP0(0,0); + Point aP1(0,0); + String Msg; + sal_uInt16 RecNr=0; + + rMtf.Record(&aOutDev); + aOutDev.SetLineColor(Color(COL_BLACK)); + aOutDev.SetFillColor(Color(COL_BLACK)); + + while (!bEoDt && !rInp.GetError()) { + rInp>>aVect; RecNr++; + nFarb=(sal_uInt8) (aVect.Flag & 0x000F); + nLTyp=(sal_uInt8)((aVect.Flag & 0x00F0) >>4); + nOTyp=(sal_uInt8)((aVect.Flag & 0x0F00) >>8); + bEoDt=(aVect.Flag & 0x4000) !=0; + bPDwn=(aVect.Flag & 0x8000) !=0; + + long x=aVect.x-rHead.Xoffs; + long y=rHead.Ysize-(aVect.y-rHead.Yoffs); + if (SgfVectScal) { + if (SgfVectXdiv==0) SgfVectXdiv=rHead.Xsize; + if (SgfVectYdiv==0) SgfVectYdiv=rHead.Ysize; + if (SgfVectXdiv==0) SgfVectXdiv=1; + if (SgfVectYdiv==0) SgfVectYdiv=1; + x=SgfVectXofs+ x *SgfVectXmul /SgfVectXdiv; + y=SgfVectYofs+ y *SgfVectXmul /SgfVectYdiv; + } + aP1=Point(x,y); + if (!bEoDt && !rInp.GetError()) { + if (bPDwn && nLTyp<=6) { + switch(nOTyp) { + case 1: if (nFarb!=nFrb0) { + switch(rHead.SwGrCol) { + case SgfVectFarb: aOutDev.SetLineColor(Hpgl2SvFarbe(nFarb)); break; + case SgfVectGray: break; + case SgfVectWdth: break; + } + } + aOutDev.DrawLine(aP0,aP1); break; // Linie + case 2: break; // Kreis + case 3: break; // Text + case 5: aOutDev.DrawRect(Rectangle(aP0,aP1)); break; // Rechteck (solid) + } + } + aP0=aP1; + nFrb0=nFarb; + } + } + rMtf.Stop(); + rMtf.WindStart(); + MapMode aMap( MAP_10TH_MM, Point(), + Fraction( 1, 4 ), Fraction( 1, 4 ) ); + rMtf.SetPrefMapMode( aMap ); + rMtf.SetPrefSize( Size( (short)rHead.Xsize, (short)rHead.Ysize ) ); + return sal_True; +} + + +sal_Bool SgfVectFilter(SvStream& rInp, GDIMetaFile& rMtf) +{ + sal_uLong nFileStart; // Offset des SgfHeaders. Im allgemeinen 0. + SgfHeader aHead; + SgfEntry aEntr; + sal_uLong nNext; + sal_Bool bRdFlag=sal_False; // Grafikentry gelesen ? + sal_Bool bRet=sal_False; // Returncode + + nFileStart=rInp.Tell(); + rInp>>aHead; + if (aHead.ChkMagic() && aHead.Typ==SGF_SIMPVECT) { + nNext=aHead.GetOffset(); + while (nNext && !bRdFlag && !rInp.GetError()) { + rInp.Seek(nFileStart+nNext); + rInp>>aEntr; + nNext=aEntr.GetOffset(); + if (aEntr.Typ==aHead.Typ) { + bRet=SgfFilterVect(rInp,aHead,aEntr,rMtf); + } + } // while(nNext) + if (bRdFlag) { + if (!rInp.GetError()) bRet=sal_True; // Scheinbar Ok + } + } + return(bRet); +} + +/************************************************************************* +|* +|* CheckSgfTyp() +|* +|* Beschreibung Feststellen, um was fuer ein SGF/SGV es sich handelt. +|* +*************************************************************************/ +sal_uInt8 CheckSgfTyp(SvStream& rInp, sal_uInt16& nVersion) +{ +#if OSL_DEBUG_LEVEL > 1 // Recordgroessen checken. Neuer Compiler hat vielleichte anderes Allignment! + if (sizeof(SgfHeader)!=SgfHeaderSize || + sizeof(SgfEntry) !=SgfEntrySize || + sizeof(SgfVector)!=SgfVectorSize || + sizeof(BmpFileHeader)!=BmpFileHeaderSize || + sizeof(BmpInfoHeader)!=BmpInfoHeaderSize || + sizeof(RGBQuad )!=RGBQuadSize ) return SGF_DONTKNOW; +#endif + + sal_uLong nPos; + SgfHeader aHead; + nVersion=0; + nPos=rInp.Tell(); + rInp>>aHead; + rInp.Seek(nPos); + if (aHead.ChkMagic()) { + nVersion=aHead.Version; + switch(aHead.Typ) { + case SgfBitImag0: + case SgfBitImag1: + case SgfBitImag2: + case SgfBitImgMo: return SGF_BITIMAGE; + case SgfSimpVect: return SGF_SIMPVECT; + case SgfPostScrp: return SGF_POSTSCRP; + case SgfStarDraw: return SGF_STARDRAW; + default : return SGF_DONTKNOW; + } + } else { + return SGF_DONTKNOW; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/sgfbram.hxx b/vcl/source/filter/sgfbram.hxx new file mode 100644 index 000000000000..ad7231c2911b --- /dev/null +++ b/vcl/source/filter/sgfbram.hxx @@ -0,0 +1,151 @@ +/* -*- 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 _SGFBRAM_HXX +#define _SGFBRAM_HXX + +#include <tools/solar.h> + +#define SgfBitImag0 1 /* Bitmap */ +#define SgfBitImag1 4 /* Bitmap */ +#define SgfBitImag2 5 /* Bitmap */ +#define SgfBitImgMo 6 /* Monochrome Bitmap */ +#define SgfSimpVect 2 /* Einfaches Vectorformat */ +#define SgfPostScrp 3 /* Postscript file */ +#define SgfStarDraw 7 /* StarDraw SGV-Datei */ +#define SgfDontKnow 255 /* Unbekannt oder kein SGF/SGV */ + +// Konstanten fr SgfHeader.SwGrCol +#define SgfBlckWhit 1 /* Schwarz/Wei?Bild Ŀ SimpVector, */ +#define SgfGrayscal 2 /* Bild mit Graustufen ?StarDraw und */ +#define Sgf16Colors 3 /* Farbbild (16 Farben) Bit Image */ +#define SgfVectFarb 4 /* Farben fr Linien verwenden Ŀ */ +#define SgfVectGray 5 /* Graustufen fr Linien verwenden ?Nur fr */ +#define SgfVectWdth 6 /* Strichstrken fr Linien verwenden SimpVector */ + + +#define SgfHeaderSize 42 +class SgfHeader +{ +public: + sal_uInt16 Magic; + sal_uInt16 Version; + sal_uInt16 Typ; + sal_uInt16 Xsize; + sal_uInt16 Ysize; + sal_Int16 Xoffs; + sal_Int16 Yoffs; + sal_uInt16 Planes; // Layer + sal_uInt16 SwGrCol; + char Autor[10]; + char Programm[10]; + sal_uInt16 OfsLo,OfsHi; // DWord-Allignment ist notwendig (38 mod 4 =2) ! + + sal_uInt32 GetOffset(); + friend SvStream& operator>>(SvStream& rIStream, SgfHeader& rHead); + sal_Bool ChkMagic(); +}; + +#define SgfEntrySize 22 +class SgfEntry +{ +public: + sal_uInt16 Typ; + sal_uInt16 iFrei; + sal_uInt16 lFreiLo,lFreiHi; + char cFrei[10]; + sal_uInt16 OfsLo,OfsHi; // DWord-Allignment ist notwendig (18 mod 4 =2) ! + + sal_uInt32 GetOffset(); + friend SvStream& operator>>(SvStream& rIStream, SgfEntry& rEntr); +}; + +#define SgfVectorSize 10 +class SgfVector +{ +public: + sal_uInt16 Flag; + sal_Int16 x; + sal_Int16 y; + sal_uInt16 OfsLo,OfsHi; // DWord-Allignment ist notwendig (6 mod 4 =2) ! + + friend SvStream& operator>>(SvStream& rIStream, SgfVector& rEntr); +}; + +extern long SgfVectXofs; +extern long SgfVectYofs; +extern long SgfVectXmul; +extern long SgfVectYmul; +extern long SgfVectXdiv; +extern long SgfVectYdiv; +extern sal_Bool SgfVectScal; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Windows BMP ///////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#define BmpFileHeaderSize 14 +class BmpFileHeader +{ +public: + sal_uInt16 Typ; // = "BM" + sal_uInt16 SizeLo,SizeHi; // Filesize in Bytes + sal_uInt16 Reserve1; // Reserviert + sal_uInt16 Reserve2; // Reserviert + sal_uInt16 OfsLo,OfsHi; // Offset? + + void SetSize(sal_uInt32 Size); + void SetOfs(sal_uInt32 Size); + sal_uInt32 GetOfs(); + friend SvStream& operator<<(SvStream& rOStream, BmpFileHeader& rHead); +}; + +#define BmpInfoHeaderSize 40 +class BmpInfoHeader +{ +public: + sal_uInt32 Size; // Gre des BmpInfoHeaders + sal_Int32 Width; // Breite in Pixel + sal_Int32 Hight; // Hhe in Pixel + sal_uInt16 Planes; // Anzahl der Planes (immer 1) + sal_uInt16 PixBits; // Anzahl der Bit je Pixel (1,4,8,oder 24) + sal_uInt32 Compress; // Datenkompression + sal_uInt32 ImgSize; // Gre der Images in Bytes. Ohne Kompression ist auch 0 erlaubt. + sal_Int32 xDpmm; // Dot per Meter (0 ist erlaubt) + sal_Int32 yDpmm; // Dot per Meter (0 ist erlaubt) + sal_uInt32 ColUsed; // Anzahl der verwendeten Farben (0=alle) + sal_uInt32 ColMust; // Anzahl der wichtigen Farben (0=alle) + + friend SvStream& operator<<(SvStream& rOStream, BmpInfoHeader& rHead); +}; + +#define RGBQuadSize 4 +class RGBQuad { +private: + sal_uInt8 Red; + sal_uInt8 Grn; + sal_uInt8 Blu; + sal_uInt8 Fil; +public: + RGBQuad(sal_uInt8 R, sal_uInt8 G, sal_uInt8 B) { Red=R; Grn=G; Blu=B; Fil=0; } +}; + +#endif //_SGFBRAM_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/sgffilt.hxx b/vcl/source/filter/sgffilt.hxx new file mode 100644 index 000000000000..9d19dbbc42ad --- /dev/null +++ b/vcl/source/filter/sgffilt.hxx @@ -0,0 +1,40 @@ +/* -*- 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 _SGFFILT_HXX +#define _SGFFILT_HXX +#include <tools/urlobj.hxx> + +sal_uInt8 CheckSgfTyp(SvStream& rInp, sal_uInt16& nVersion); +sal_Bool SgfBMapFilter(SvStream& rInp, SvStream& rOut); +sal_Bool SgfVectFilter(SvStream& rInp, GDIMetaFile& rMtf); +sal_Bool SgfSDrwFilter(SvStream& rInp, GDIMetaFile& rMtf, INetURLObject aIniPath ); + +// Konstanten fr CheckSgfTyp() +#define SGF_BITIMAGE 1 /* Bitmap */ +#define SGF_SIMPVECT 2 /* Einfaches Vectorformat */ +#define SGF_POSTSCRP 3 /* Postscript file */ +#define SGF_STARDRAW 7 /* StarDraw SGV-Datei */ +#define SGF_DONTKNOW 255 /* Unbekannt oder kein SGF/SGV */ + +#define SGV_VERSION 3 /* SGV mit anderer Version wird abgewiesen */ + /* 3 entspricht StarDraw 2.00/2.01 Mrz'93 */ +#endif //_SGFFILT_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/sgvmain.cxx b/vcl/source/filter/sgvmain.cxx new file mode 100644 index 000000000000..667856464164 --- /dev/null +++ b/vcl/source/filter/sgvmain.cxx @@ -0,0 +1,966 @@ +/* -*- 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 <rtl/math.hxx> +#include <osl/endian.h> +#include <vcl/graph.hxx> +#include <tools/poly.hxx> +#include <svtools/filter.hxx> +#include "sgffilt.hxx" +#include "sgfbram.hxx" +#include "sgvmain.hxx" +#include "sgvspln.hxx" +#include <unotools/ucbstreamhelper.hxx> + +#define SWAPPOINT(p) { \ + p.x=OSL_SWAPWORD(p.x); \ + p.y=OSL_SWAPWORD(p.y); } + +#define SWAPPAGE(p) { \ + p.Next =OSL_SWAPDWORD (p.Next ); \ + p.nList =OSL_SWAPDWORD (p.nList ); \ + p.ListEnd=OSL_SWAPDWORD (p.ListEnd); \ + p.Paper.Size.x=OSL_SWAPWORD(p.Paper.Size.x); \ + p.Paper.Size.y=OSL_SWAPWORD(p.Paper.Size.y); \ + p.Paper.RandL =OSL_SWAPWORD(p.Paper.RandL ); \ + p.Paper.RandR =OSL_SWAPWORD(p.Paper.RandR ); \ + p.Paper.RandO =OSL_SWAPWORD(p.Paper.RandO ); \ + p.Paper.RandU =OSL_SWAPWORD(p.Paper.RandU ); \ + SWAPPOINT(p.U); \ + sal_uInt16 iTemp; \ + for (iTemp=0;iTemp<20;iTemp++) { \ + rPage.HlpLnH[iTemp]=OSL_SWAPWORD(rPage.HlpLnH[iTemp]); \ + rPage.HlpLnV[iTemp]=OSL_SWAPWORD(rPage.HlpLnV[iTemp]); }} + +#define SWAPOBJK(o) { \ + o.Last =OSL_SWAPDWORD (o.Last ); \ + o.Next =OSL_SWAPDWORD (o.Next ); \ + o.MemSize =OSL_SWAPWORD(o.MemSize ); \ + SWAPPOINT(o.ObjMin); \ + SWAPPOINT(o.ObjMax); } + +#define SWAPLINE(l) { \ + l.LMSize=OSL_SWAPWORD(l.LMSize); \ + l.LDicke=OSL_SWAPWORD(l.LDicke); } + +#define SWAPAREA(a) { \ + a.FDummy2=OSL_SWAPWORD(a.FDummy2); \ + a.FMuster=OSL_SWAPWORD(a.FMuster); } + +#define SWAPTEXT(t) { \ + SWAPLINE(t.L); \ + SWAPAREA(t.F); \ + t.FontLo =OSL_SWAPWORD(t.FontLo ); \ + t.FontHi =OSL_SWAPWORD(t.FontHi ); \ + t.Grad =OSL_SWAPWORD(t.Grad ); \ + t.Breite =OSL_SWAPWORD(t.Breite ); \ + t.Schnitt=OSL_SWAPWORD(t.Schnitt); \ + t.LnFeed =OSL_SWAPWORD(t.LnFeed ); \ + t.Slant =OSL_SWAPWORD(t.Slant ); \ + SWAPLINE(t.ShdL); \ + SWAPAREA(t.ShdF); \ + SWAPPOINT(t.ShdVers); \ + SWAPAREA(t.BackF); } + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Einschraenkungen: +// +// - Flaechenmuster werden den unter StarView verfuegbaren Mustern angenaehert. +// - Linienenden werden unter StarView immer rund dargestellt und gehen ueber +// den Endpunkt der Linie hinaus. +// - Linienmuster werden den unter StarView verfuegbaren Mustern angenaehert. +// Transparent/Opak wird zur Zeit noch nicht beruecksichtigt. +// - Keine gedrehten Ellipsen +// +// +// +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Fuer Fontuebersetzung /////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +SgfFontLst* pSgfFonts = 0; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Fuer Kreisunterarten, Text und gedrehte Rechtecke /////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// +void RotatePoint(PointType& P, sal_Int16 cx, sal_Int16 cy, double sn, double cs) +{ + sal_Int16 dx,dy; + double x1,y1; + dx=P.x-cx; + dy=P.y-cy; + x1=dx*cs-dy*sn; + y1=dy*cs+dx*sn; + P.x=cx+sal_Int16(x1); + P.y=cy+sal_Int16(y1); +} + +void RotatePoint(Point& P, sal_Int16 cx, sal_Int16 cy, double sn, double cs) +{ + sal_Int16 dx,dy; + double x1,y1; + dx=(sal_Int16)(P.X()-cx); + dy=(sal_Int16)(P.Y()-cy); + x1=dx*cs-dy*sn; + y1=dy*cs+dx*sn; + P=Point(cx+sal_Int16(x1),cy+sal_Int16(y1)); +} + +sal_Int16 iMulDiv(sal_Int16 a, sal_Int16 Mul, sal_Int16 Div) +{ + sal_Int32 Temp; + Temp=sal_Int32(a)*sal_Int32(Mul)/sal_Int32(Div); + return sal_Int16(Temp); +} + +sal_uInt16 MulDiv(sal_uInt16 a, sal_uInt16 Mul, sal_uInt16 Div) +{ + sal_uInt32 Temp; + Temp=sal_uInt32(a)*sal_uInt32(Mul)/sal_uInt32(Div); + return sal_uInt16(Temp); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// SgfFilterSDrw /////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +SvStream& operator>>(SvStream& rIStream, DtHdType& rDtHd) +{ + rIStream.Read((char*)&rDtHd.Reserved[0],DtHdSize); + return rIStream; +} + +void DtHdOverSeek(SvStream& rInp) +{ + sal_uLong FPos=rInp.Tell(); + FPos+=(sal_uLong)DtHdSize; + rInp.Seek(FPos); +} + + +SvStream& operator>>(SvStream& rIStream, PageType& rPage) +{ + rIStream.Read((char*)&rPage.Next,PageSize); +#if defined OSL_BIGENDIAN + SWAPPAGE(rPage); +#endif + return rIStream; +} + +void ObjkOverSeek(SvStream& rInp, ObjkType& rObjk) +{ + sal_uLong Siz; + Siz=(sal_uLong)rObjk.MemSize+rObjk.Last; // ObjSize+ObjAnhSize + rInp.Seek(rInp.Tell()+Siz); +} + +SvStream& operator>>(SvStream& rInp, ObjkType& rObjk) +{ // Die Fileposition im Stream bleibt unveraendert! + sal_uLong nPos; + nPos=rInp.Tell(); + rInp.Read((char*)&rObjk.Last,ObjkSize); +#if defined OSL_BIGENDIAN + SWAPOBJK(rObjk); +#endif +#ifdef InArbeit + sal_uLong nPos1=rInp.Tell(); + if(nPos == nPos1) InfoBox( NULL, "tellg funkt nich" ).Execute(); +#endif + rInp.Seek(nPos); +#ifdef InArbeit + if (rInp.Tell() != nPos) InfoBox( NULL, "seekg funkt nich" ).Execute(); +#endif + return rInp; +} +SvStream& operator>>(SvStream& rInp, StrkType& rStrk) +{ + rInp.Read((char*)&rStrk.Last,StrkSize); +#if defined OSL_BIGENDIAN + SWAPOBJK (rStrk); + SWAPLINE (rStrk.L); + SWAPPOINT(rStrk.Pos1); + SWAPPOINT(rStrk.Pos2); +#endif + return rInp; +} +SvStream& operator>>(SvStream& rInp, RectType& rRect) +{ + rInp.Read((char*)&rRect.Last,RectSize); +#if defined OSL_BIGENDIAN + SWAPOBJK (rRect); + SWAPLINE (rRect.L); + SWAPAREA (rRect.F); + SWAPPOINT(rRect.Pos1); + SWAPPOINT(rRect.Pos2); + rRect.Radius =OSL_SWAPWORD(rRect.Radius ); + rRect.DrehWink=OSL_SWAPWORD(rRect.DrehWink); + rRect.Slant =OSL_SWAPWORD(rRect.Slant ); +#endif + return rInp; +} +SvStream& operator>>(SvStream& rInp, PolyType& rPoly) +{ + rInp.Read((char*)&rPoly.Last,PolySize); +#if defined OSL_BIGENDIAN + SWAPOBJK (rPoly); + SWAPLINE (rPoly.L); + SWAPAREA (rPoly.F); +#endif + return rInp; +} +SvStream& operator>>(SvStream& rInp, SplnType& rSpln) +{ + rInp.Read((char*)&rSpln.Last,SplnSize); +#if defined OSL_BIGENDIAN + SWAPOBJK (rSpln); + SWAPLINE (rSpln.L); + SWAPAREA (rSpln.F); +#endif + return rInp; +} +SvStream& operator>>(SvStream& rInp, CircType& rCirc) +{ + rInp.Read((char*)&rCirc.Last,CircSize); +#if defined OSL_BIGENDIAN + SWAPOBJK (rCirc); + SWAPLINE (rCirc.L); + SWAPAREA (rCirc.F); + SWAPPOINT(rCirc.Radius); + SWAPPOINT(rCirc.Center); + rCirc.DrehWink =OSL_SWAPWORD(rCirc.DrehWink ); + rCirc.StartWink=OSL_SWAPWORD(rCirc.StartWink); + rCirc.RelWink =OSL_SWAPWORD(rCirc.RelWink ); +#endif + return rInp; +} +SvStream& operator>>(SvStream& rInp, TextType& rText) +{ + rInp.Read((char*)&rText.Last,TextSize); +#if defined OSL_BIGENDIAN + SWAPOBJK (rText); + SWAPTEXT (rText.T); + SWAPPOINT(rText.Pos1); + SWAPPOINT(rText.Pos2); + rText.TopOfs =OSL_SWAPWORD(rText.TopOfs ); + rText.DrehWink=OSL_SWAPWORD(rText.DrehWink); + rText.BoxSlant=OSL_SWAPWORD(rText.BoxSlant); + rText.BufSize =OSL_SWAPWORD(rText.BufSize ); + SWAPPOINT(rText.FitSize); + rText.FitBreit=OSL_SWAPWORD(rText.FitBreit); +#endif + rText.Buffer=NULL; + return rInp; +} +SvStream& operator>>(SvStream& rInp, BmapType& rBmap) +{ + rInp.Read((char*)&rBmap.Last,BmapSize); +#if defined OSL_BIGENDIAN + SWAPOBJK (rBmap); + SWAPAREA (rBmap.F); + SWAPPOINT(rBmap.Pos1); + SWAPPOINT(rBmap.Pos2); + rBmap.DrehWink=OSL_SWAPWORD(rBmap.DrehWink); + rBmap.Slant =OSL_SWAPWORD(rBmap.Slant ); + SWAPPOINT(rBmap.PixSize); +#endif + return rInp; +} +SvStream& operator>>(SvStream& rInp, GrupType& rGrup) +{ + rInp.Read((char*)&rGrup.Last,GrupSize); +#if defined OSL_BIGENDIAN + SWAPOBJK (rGrup); + rGrup.SbLo =OSL_SWAPWORD(rGrup.SbLo ); + rGrup.SbHi =OSL_SWAPWORD(rGrup.SbHi ); + rGrup.UpLo =OSL_SWAPWORD(rGrup.UpLo ); + rGrup.UpHi =OSL_SWAPWORD(rGrup.UpHi ); + rGrup.ChartSize=OSL_SWAPWORD(rGrup.ChartSize); + rGrup.ChartPtr =OSL_SWAPDWORD (rGrup.ChartPtr ); +#endif + return rInp; +} + + + +/************************************************************************* +|* +|* Sgv2SvFarbe() +|* +*************************************************************************/ +Color Sgv2SvFarbe(sal_uInt8 nFrb1, sal_uInt8 nFrb2, sal_uInt8 nInts) +{ + sal_uInt16 r1=0,g1=0,b1=0,r2=0,g2=0,b2=0; + sal_uInt8 nInt2=100-nInts; + switch(nFrb1 & 0x07) { + case 0: r1=0xFF; g1=0xFF; b1=0xFF; break; + case 1: r1=0xFF; g1=0xFF; break; + case 2: g1=0xFF; b1=0xFF; break; + case 3: g1=0xFF; break; + case 4: r1=0xFF; b1=0xFF; break; + case 5: r1=0xFF; break; + case 6: b1=0xFF; break; + case 7: break; + } + switch(nFrb2 & 0x07) { + case 0: r2=0xFF; g2=0xFF; b2=0xFF; break; + case 1: r2=0xFF; g2=0xFF; break; + case 2: g2=0xFF; b2=0xFF; break; + case 3: g2=0xFF; break; + case 4: r2=0xFF; b2=0xFF; break; + case 5: r2=0xFF; break; + case 6: b2=0xFF; break; + case 7: break; + } + r1=(sal_uInt16)((sal_uInt32)r1*nInts/100+(sal_uInt32)r2*nInt2/100); + g1=(sal_uInt16)((sal_uInt32)g1*nInts/100+(sal_uInt32)g2*nInt2/100); + b1=(sal_uInt16)((sal_uInt32)b1*nInts/100+(sal_uInt32)b2*nInt2/100); + Color aColor( (sal_uInt8)r1, (sal_uInt8)g1, (sal_uInt8)b1 ); + return aColor; +} + +void SetLine(ObjLineType& rLine, OutputDevice& rOut) +{ + if( 0 == ( rLine.LMuster & 0x07 ) ) + rOut.SetLineColor(); + else + rOut.SetLineColor( Sgv2SvFarbe(rLine.LFarbe,rLine.LBFarbe,rLine.LIntens) ); +} + +void SetArea(ObjAreaType& rArea, OutputDevice& rOut) +{ + if( 0 == ( rArea.FMuster & 0x00FF ) ) + rOut.SetFillColor(); + else + rOut.SetFillColor( Sgv2SvFarbe( rArea.FFarbe,rArea.FBFarbe,rArea.FIntens ) ); +} + +/************************************************************************* +|* +|* ObjkType::DrawObjekt() +|* +*************************************************************************/ +void ObjkType::Draw(OutputDevice&) +{ +} + +void Obj0Type::Draw(OutputDevice&) {} + +/************************************************************************* +|* +|* StrkType::DrawObjekt() +|* +*************************************************************************/ +void StrkType::Draw(OutputDevice& rOut) +{ + SetLine(L,rOut); + rOut.DrawLine(Point(Pos1.x,Pos1.y),Point(Pos2.x,Pos2.y)); // !!! +} + +/************************************************************************* +|* +|* RectType::DrawObjekt() +|* +*************************************************************************/ +void SgfAreaColorIntens(sal_uInt16 Muster, sal_uInt8 Col1, sal_uInt8 Col2, sal_uInt8 Int, OutputDevice& rOut) +{ + ObjAreaType F; + F.FMuster=Muster; + F.FFarbe=Col2; + F.FBFarbe=Col1; + F.FIntens=Int; + SetArea(F,rOut); +} + +void DrawSlideRect(sal_Int16 x1, sal_Int16 y1, sal_Int16 x2, sal_Int16 y2, ObjAreaType& F, OutputDevice& rOut) +{ + sal_Int16 i,i0,b,b0; + sal_Int16 Int1,Int2; + sal_Int16 Col1,Col2; + // ClipMerk: HgdClipRec; + sal_Int16 cx,cy; + sal_Int16 MaxR; + sal_Int32 dx,dy; + + rOut.SetLineColor(); + if (x1>x2) { i=x1; x1=x2; x2=i; } + if (y1>y2) { i=y1; y1=y2; y2=i; } + Col1=F.FBFarbe & 0x87; Col2=F.FFarbe & 0x87; + Int1=100-F.FIntens; Int2=F.FIntens; + if (Int1==Int2) { + SgfAreaColorIntens(F.FMuster,(sal_uInt8)Col1,(sal_uInt8)Col2,(sal_uInt8)Int2,rOut); + rOut.DrawRect(Rectangle(x1,y1,x2,y2)); + } else { + b0=Int1; + switch (F.FBFarbe & 0x38) { + case 0x08: { // vertikal + i0=y1; + i=y1; + while (i<=y2) { + b=Int1+sal_Int16((sal_Int32)(Int2-Int1)*(sal_Int32)(i-y1) /(sal_Int32)(y2-y1+1)); + if (b!=b0) { + SgfAreaColorIntens(F.FMuster,(sal_uInt8)Col1,(sal_uInt8)Col2,(sal_uInt8)b0,rOut); + rOut.DrawRect(Rectangle(x1,i0,x2,i-1)); + i0=i; b0=b; + } + i++; + } + SgfAreaColorIntens(F.FMuster,(sal_uInt8)Col1,(sal_uInt8)Col2,(sal_uInt8)Int2,rOut); + rOut.DrawRect(Rectangle(x1,i0,x2,y2)); + } break; + case 0x28: { // horizontal + i0=x1; + i=x1; + while (i<=x2) { + b=Int1+sal_Int16((sal_Int32)(Int2-Int1)*(sal_Int32)(i-x1) /(sal_Int32)(x2-x1+1)); + if (b!=b0) { + SgfAreaColorIntens(F.FMuster,(sal_uInt8)Col1,(sal_uInt8)Col2,(sal_uInt8)b0,rOut); + rOut.DrawRect(Rectangle(i0,y1,i-1,y2)); + i0=i; b0=b; + } + i++; + } + SgfAreaColorIntens(F.FMuster,(sal_uInt8)Col1,(sal_uInt8)Col2,(sal_uInt8)Int2,rOut); + rOut.DrawRect(Rectangle(i0,y1,x2,y2)); + } break; + + case 0x18: case 0x38: { // Kreis + Region ClipMerk=rOut.GetClipRegion(); + double a; + + rOut.SetClipRegion(Region(Rectangle(x1,y1,x2,y2))); + cx=(x1+x2) /2; + cy=(y1+y2) /2; + dx=x2-x1+1; + dy=y2-y1+1; + a=sqrt((double)(dx*dx+dy*dy)); + MaxR=sal_Int16(a) /2 +1; + b0=Int2; + i0=MaxR; if (MaxR<1) MaxR=1; + i=MaxR; + while (i>=0) { + b=Int1+sal_Int16((sal_Int32(Int2-Int1)*sal_Int32(i)) /sal_Int32(MaxR)); + if (b!=b0) { + SgfAreaColorIntens(F.FMuster,(sal_uInt8)Col1,(sal_uInt8)Col2,(sal_uInt8)b0,rOut); + rOut.DrawEllipse(Rectangle(cx-i0,cy-i0,cx+i0,cy+i0)); + i0=i; b0=b; + } + i--; + } + SgfAreaColorIntens(F.FMuster,(sal_uInt8)Col1,(sal_uInt8)Col2,(sal_uInt8)Int1,rOut); + rOut.DrawEllipse(Rectangle(cx-i0,cy-i0,cx+i0,cy+i0)); + rOut.SetClipRegion(ClipMerk); + } break; // Kreis + } + } +} + + +void RectType::Draw(OutputDevice& rOut) +{ + if (L.LMuster!=0) L.LMuster=1; // keine Linienmuster hier, nur an oder aus + SetArea(F,rOut); + if (DrehWink==0) { + if ((F.FBFarbe & 0x38)==0 || Radius!=0) { + SetLine(L,rOut); + rOut.DrawRect(Rectangle(Pos1.x,Pos1.y,Pos2.x,Pos2.y),Radius,Radius); + } else { + DrawSlideRect(Pos1.x,Pos1.y,Pos2.x,Pos2.y,F,rOut); + if (L.LMuster!=0) { + SetLine(L,rOut); + rOut.SetFillColor(); + rOut.DrawRect(Rectangle(Pos1.x,Pos1.y,Pos2.x,Pos2.y)); + } + } + } else { + Point aPts[4]; + sal_uInt16 i; + double sn,cs; + sn=sin(double(DrehWink)*3.14159265359/18000); + cs=cos(double(DrehWink)*3.14159265359/18000); + aPts[0]=Point(Pos1.x,Pos1.y); + aPts[1]=Point(Pos2.x,Pos1.y); + aPts[2]=Point(Pos2.x,Pos2.y); + aPts[3]=Point(Pos1.x,Pos2.y); + for (i=0;i<4;i++) { + RotatePoint(aPts[i],Pos1.x,Pos1.y,sn,cs); + } + SetLine(L,rOut); + Polygon aPoly(4,aPts); + rOut.DrawPolygon(aPoly); + } +} + +/************************************************************************* +|* +|* PolyType::Draw() +|* +*************************************************************************/ +void PolyType::Draw(OutputDevice& rOut) +{ + if ((Flags & PolyClosBit) !=0) SetArea(F,rOut); + SetLine(L,rOut); + Polygon aPoly(nPoints); + sal_uInt16 i; + for(i=0;i<nPoints;i++) aPoly.SetPoint(Point(EckP[i].x,EckP[i].y),i); + if ((Flags & PolyClosBit) !=0) { + rOut.DrawPolygon(aPoly); + } else { + rOut.DrawPolyLine(aPoly); + } +} + +/************************************************************************* +|* +|* SplnType::Draw() +|* +*************************************************************************/ +void SplnType::Draw(OutputDevice& rOut) +{ + if ((Flags & PolyClosBit) !=0) SetArea(F,rOut); + SetLine(L,rOut); + Polygon aPoly(0); + Polygon aSpln(nPoints); + sal_uInt16 i; + for(i=0;i<nPoints;i++) aSpln.SetPoint(Point(EckP[i].x,EckP[i].y),i); + if ((Flags & PolyClosBit) !=0) { + Spline2Poly(aSpln,sal_True,aPoly); + if (aPoly.GetSize()>0) rOut.DrawPolygon(aPoly); + } else { + Spline2Poly(aSpln,sal_False,aPoly); + if (aPoly.GetSize()>0) rOut.DrawPolyLine(aPoly); + } +} + +/************************************************************************* +|* +|* CircType::Draw() +|* +*************************************************************************/ +void DrawSlideCirc(sal_Int16 cx, sal_Int16 cy, sal_Int16 rx, sal_Int16 ry, ObjAreaType& F, OutputDevice& rOut) +{ + sal_Int16 x1=cx-rx; + sal_Int16 y1=cy-ry; + sal_Int16 x2=cx+rx; + sal_Int16 y2=cy+ry; + + sal_Int16 i,i0,b,b0; + sal_Int16 Int1,Int2; + sal_Int16 Col1,Col2; + + rOut.SetLineColor(); + Col1=F.FBFarbe & 0x87; Col2=F.FFarbe & 0x87; + Int1=100-F.FIntens; Int2=F.FIntens; + if (Int1==Int2) { + SgfAreaColorIntens(F.FMuster,(sal_uInt8)Col1,(sal_uInt8)Col2,(sal_uInt8)Int2,rOut); + rOut.DrawEllipse(Rectangle(x1,y1,x2,y2)); + } else { + b0=Int1; + switch (F.FBFarbe & 0x38) { + case 0x08: { // vertikal + Region ClipMerk=rOut.GetClipRegion(); + i0=y1; + i=y1; + while (i<=y2) { + b=Int1+sal_Int16((sal_Int32)(Int2-Int1)*(sal_Int32)(i-y1) /(sal_Int32)(y2-y1+1)); + if (b!=b0) { + SgfAreaColorIntens(F.FMuster,(sal_uInt8)Col1,(sal_uInt8)Col2,(sal_uInt8)b0,rOut); + rOut.SetClipRegion(Rectangle(x1,i0,x2,i-1)); + rOut.DrawEllipse(Rectangle(x1,y1,x2,y2)); + i0=i; b0=b; + } + i++; + } + SgfAreaColorIntens(F.FMuster,(sal_uInt8)Col1,(sal_uInt8)Col2,(sal_uInt8)Int2,rOut); + rOut.SetClipRegion(Rectangle(x1,i0,x2,y2)); + rOut.DrawEllipse(Rectangle(x1,y1,x2,y2)); + rOut.SetClipRegion(ClipMerk); + } break; + case 0x28: { // horizontal + Region ClipMerk=rOut.GetClipRegion(); + i0=x1; + i=x1; + while (i<=x2) { + b=Int1+sal_Int16((sal_Int32)(Int2-Int1)*(sal_Int32)(i-x1) /(sal_Int32)(x2-x1+1)); + if (b!=b0) { + SgfAreaColorIntens(F.FMuster,(sal_uInt8)Col1,(sal_uInt8)Col2,(sal_uInt8)b0,rOut); + rOut.SetClipRegion(Rectangle(i0,y1,i-1,y2)); + rOut.DrawEllipse(Rectangle(x1,y1,x2,y2)); + i0=i; b0=b; + } + i++; + } + SgfAreaColorIntens(F.FMuster,(sal_uInt8)Col1,(sal_uInt8)Col2,(sal_uInt8)Int2,rOut); + rOut.SetClipRegion(Rectangle(i0,y1,x2,y2)); + rOut.DrawEllipse(Rectangle(x1,y1,x2,y2)); + rOut.SetClipRegion(ClipMerk); + } break; + + case 0x18: case 0x38: { // Kreis + sal_Int16 MaxR; + + if (rx<1) rx=1; + if (ry<1) ry=1; + MaxR=rx; + b0=Int2; + i0=MaxR; if (MaxR<1) MaxR=1; + i=MaxR; + while (i>=0) { + b=Int1+sal_Int16((sal_Int32(Int2-Int1)*sal_Int32(i)) /sal_Int32(MaxR)); + if (b!=b0) { + sal_Int32 temp=sal_Int32(i0)*sal_Int32(ry)/sal_Int32(rx); + sal_Int16 j0=sal_Int16(temp); + SgfAreaColorIntens(F.FMuster,(sal_uInt8)Col1,(sal_uInt8)Col2,(sal_uInt8)b0,rOut); + rOut.DrawEllipse(Rectangle(cx-i0,cy-j0,cx+i0,cy+j0)); + i0=i; b0=b; + } + i--; + } + SgfAreaColorIntens(F.FMuster,(sal_uInt8)Col1,(sal_uInt8)Col2,(sal_uInt8)Int1,rOut); + rOut.DrawEllipse(Rectangle(cx-i0,cy-i0,cx+i0,cy+i0)); + } break; // Kreis + } + } +} + + +void CircType::Draw(OutputDevice& rOut) +{ + Rectangle aRect(Center.x-Radius.x,Center.y-Radius.y,Center.x+Radius.x,Center.y+Radius.y); + + if (L.LMuster!=0) L.LMuster=1; // keine Linienmuster hier, nur an oder aus + SetArea(F,rOut); + if ((Flags & 0x03)==CircFull) { + if ((F.FBFarbe & 0x38)==0) { + SetLine(L,rOut); + rOut.DrawEllipse(aRect); + } else { + DrawSlideCirc(Center.x,Center.y,Radius.x,Radius.y,F,rOut); + if (L.LMuster!=0) { + SetLine(L,rOut); + rOut.SetFillColor(); + rOut.DrawEllipse(aRect); + } + } + } else { + PointType a,b; + Point aStrt,aEnde; + double sn,cs; + + a.x=Center.x+Radius.x; a.y=Center.y; b=a; + sn=sin(double(StartWink)*3.14159265359/18000); + cs=cos(double(StartWink)*3.14159265359/18000); + RotatePoint(a,Center.x,Center.y,sn,cs); + sn=sin(double(StartWink+RelWink)*3.14159265359/18000); + cs=cos(double(StartWink+RelWink)*3.14159265359/18000); + RotatePoint(b,Center.x,Center.y,sn,cs); + if (Radius.x!=Radius.y) { + if (Radius.x<1) Radius.x=1; + if (Radius.y<1) Radius.y=1; + a.y = a.y - Center.y; + b.y = b.y - Center.y; + a.y=iMulDiv(a.y,Radius.y,Radius.x); + b.y=iMulDiv(b.y,Radius.y,Radius.x); + a.y = a.y + Center.y; + b.y = b.y + Center.y; + } + aStrt=Point(a.x,a.y); + aEnde=Point(b.x,b.y); + SetLine(L,rOut); + switch (Flags & 0x03) { + case CircArc : rOut.DrawArc(aRect,aEnde,aStrt); break; + case CircSect: + case CircAbsn: rOut.DrawPie(aRect,aEnde,aStrt); break; + } + } +} + +/************************************************************************* +|* +|* BmapType::Draw() +|* +*************************************************************************/ + +void BmapType::Draw(OutputDevice& rOut) +{ + //ifstream aInp; + unsigned char nSgfTyp; + sal_uInt16 nVersion; + String aStr( + reinterpret_cast< char const * >(&Filename[ 1 ]), + (xub_StrLen)Filename[ 0 ], RTL_TEXTENCODING_UTF8 ); + INetURLObject aFNam( aStr ); + + SvStream* pInp = ::utl::UcbStreamHelper::CreateStream( aFNam.GetMainURL( INetURLObject::NO_DECODE ), STREAM_READ ); + if ( pInp ) + { + nSgfTyp=CheckSgfTyp( *pInp,nVersion); + switch(nSgfTyp) { + case SGF_BITIMAGE: { + GraphicFilter aFlt; + Graphic aGrf; + aFlt.ImportGraphic(aGrf,aFNam); + aGrf.Draw(&rOut,Point(Pos1.x,Pos1.y),Size(Pos2.x-Pos1.x,Pos2.y-Pos1.y)); + } break; + case SGF_SIMPVECT: { + GDIMetaFile aMtf; + SgfVectXofs=Pos1.x; + SgfVectYofs=Pos1.y; + SgfVectXmul=Pos2.x-Pos1.x; + SgfVectYmul=Pos2.y-Pos1.y; + SgfVectXdiv=0; + SgfVectYdiv=0; + SgfVectScal=sal_True; + SgfVectFilter(*pInp,aMtf); + SgfVectXofs=0; + SgfVectYofs=0; + SgfVectXmul=0; + SgfVectYmul=0; + SgfVectXdiv=0; + SgfVectYdiv=0; + SgfVectScal=sal_False; + aMtf.Play(&rOut); + } break; + } + delete pInp; + } +} + + +/************************************************************************* +|* +|* GrupType::... +|* +*************************************************************************/ +sal_uInt32 GrupType::GetSubPtr() +{ + return sal_uInt32(SbLo)+0x00010000*sal_uInt32(SbHi); +} + +/************************************************************************* +|* +|* DrawObjkList() +|* +*************************************************************************/ +void DrawObjkList( SvStream& rInp, OutputDevice& rOut ) +{ + ObjkType aObjk; + sal_uInt16 nGrpCnt=0; + sal_Bool bEnde=sal_False; + do { + rInp>>aObjk; + if (!rInp.GetError()) { + switch(aObjk.Art) { + case ObjStrk: { StrkType aStrk; rInp>>aStrk; if (!rInp.GetError()) aStrk.Draw(rOut); } break; + case ObjRect: { RectType aRect; rInp>>aRect; if (!rInp.GetError()) aRect.Draw(rOut); } break; + case ObjCirc: { CircType aCirc; rInp>>aCirc; if (!rInp.GetError()) aCirc.Draw(rOut); } break; + case ObjText: { + TextType aText; + rInp>>aText; + if (!rInp.GetError()) { + aText.Buffer=new UCHAR[aText.BufSize+1]; // Ein mehr fuer LookAhead bei CK-Trennung + rInp.Read((char* )aText.Buffer,aText.BufSize); + if (!rInp.GetError()) aText.Draw(rOut); + delete[] aText.Buffer; + } + } break; + case ObjBmap: { + BmapType aBmap; + rInp>>aBmap; + if (!rInp.GetError()) { + aBmap.Draw(rOut); + } + } break; + case ObjPoly: { + PolyType aPoly; + rInp>>aPoly; + if (!rInp.GetError()) { + aPoly.EckP=new PointType[aPoly.nPoints]; + rInp.Read((char*)aPoly.EckP,4*aPoly.nPoints); +#if defined OSL_BIGENDIAN + for(short i=0;i<aPoly.nPoints;i++) SWAPPOINT(aPoly.EckP[i]); +#endif + if (!rInp.GetError()) aPoly.Draw(rOut); + delete[] aPoly.EckP; + } + } break; + case ObjSpln: { + SplnType aSpln; + rInp>>aSpln; + if (!rInp.GetError()) { + aSpln.EckP=new PointType[aSpln.nPoints]; + rInp.Read((char*)aSpln.EckP,4*aSpln.nPoints); +#if defined OSL_BIGENDIAN + for(short i=0;i<aSpln.nPoints;i++) SWAPPOINT(aSpln.EckP[i]); +#endif + if (!rInp.GetError()) aSpln.Draw(rOut); + delete[] aSpln.EckP; + } + } break; + case ObjGrup: { + GrupType aGrup; + rInp>>aGrup; + if (!rInp.GetError()) { + rInp.Seek(rInp.Tell()+aGrup.Last); // Obj-Anhaengsel + if(aGrup.GetSubPtr()!=0L) nGrpCnt++;// DrawObjkList(rInp,rOut ); + } + } break; + default: { + aObjk.Draw(rOut); // Objektbezeichnung auf 2. Screen + ObjkOverSeek(rInp,aObjk); // zum naechsten Objekt + } + } + } // if rInp + if (!rInp.GetError()) { + if (aObjk.Next==0L) { + if (nGrpCnt==0) bEnde=sal_True; + else nGrpCnt--; + } + } else { + bEnde=sal_True; // Lesefehler + } + } while (!bEnde); +} + +/************************************************************************* +|* +|* SkipObjkList() +|* +*************************************************************************/ +void SkipObjkList(SvStream& rInp) +{ + ObjkType aObjk; + do + { + rInp>>aObjk; + if(aObjk.Art==ObjGrup) { + GrupType aGrup; + rInp>>aGrup; + rInp.Seek(rInp.Tell()+aGrup.Last); // Obj-Anhaengsel + if(aGrup.GetSubPtr()!=0L) SkipObjkList(rInp); + } else { + ObjkOverSeek(rInp,aObjk); // zum naechsten Objekt + } + } while (aObjk.Next!=0L && !rInp.GetError()); +} + +/************************************************************************* +|* +|* SgfFilterSDrw() +|* +*************************************************************************/ +sal_Bool SgfFilterSDrw( SvStream& rInp, SgfHeader&, SgfEntry&, GDIMetaFile& rMtf ) +{ + sal_Bool bRet = sal_False; + PageType aPage; + VirtualDevice aOutDev; + OutputDevice* pOutDev; + sal_uLong nStdPos; + sal_uLong nZchPos; + sal_uInt16 Num; + + pOutDev=&aOutDev; + DtHdOverSeek(rInp); // DataHeader weglesen + + nStdPos=rInp.Tell(); + do { // Standardseiten weglesen + rInp>>aPage; + if (aPage.nList!=0) SkipObjkList(rInp); + } while (aPage.Next!=0L && !rInp.GetError()); + +// ShowMsg("Zeichnungseite(n)\n"); + nZchPos=rInp.Tell(); + rInp>>aPage; + + rMtf.Record(pOutDev); + Num=aPage.StdPg; + if (Num!=0) { + rInp.Seek(nStdPos); + while(Num>1 && aPage.Next!=0L && !rInp.GetError()) { // Standardseite suchen + rInp>>aPage; + if (aPage.nList!=0) SkipObjkList(rInp); + Num--; + } + rInp>>aPage; + if(Num==1 && aPage.nList!=0L) DrawObjkList( rInp,*pOutDev ); + rInp.Seek(nZchPos); + nZchPos=rInp.Tell(); + rInp>>aPage; + } + if (aPage.nList!=0L) DrawObjkList(rInp,*pOutDev ); + + rMtf.Stop(); + rMtf.WindStart(); + MapMode aMap(MAP_10TH_MM,Point(),Fraction(1,4),Fraction(1,4)); + rMtf.SetPrefMapMode(aMap); + rMtf.SetPrefSize(Size((sal_Int16)aPage.Paper.Size.x,(sal_Int16)aPage.Paper.Size.y)); + bRet=sal_True; + return bRet; +} + + + +/************************************************************************* +|* +|* SgfSDrwFilter() +|* +*************************************************************************/ +sal_Bool SgfSDrwFilter(SvStream& rInp, GDIMetaFile& rMtf, INetURLObject aIniPath ) +{ +#if OSL_DEBUG_LEVEL > 1 // Recordgroessen checken. Neuer Compiler hat vielleichte anderes Alignment! + if (sizeof(ObjTextType)!=ObjTextTypeSize) return sal_False; +#endif + + sal_uLong nFileStart; // Offset des SgfHeaders. Im allgemeinen 0. + SgfHeader aHead; + SgfEntry aEntr; + sal_uLong nNext; + sal_Bool bRdFlag=sal_False; // Grafikentry gelesen ? + sal_Bool bRet=sal_False; // Returncode + + aIniPath.Append(rtl::OUString("sgf.ini")); + + pSgfFonts = new SgfFontLst; + + pSgfFonts->AssignFN( aIniPath.GetMainURL( INetURLObject::NO_DECODE ) ); + nFileStart=rInp.Tell(); + rInp>>aHead; + if (aHead.ChkMagic() && aHead.Typ==SgfStarDraw && aHead.Version==SGV_VERSION) { + nNext=aHead.GetOffset(); + while (nNext && !bRdFlag && !rInp.GetError()) { + rInp.Seek(nFileStart+nNext); + rInp>>aEntr; + nNext=aEntr.GetOffset(); + if (aEntr.Typ==aHead.Typ) { + bRet=SgfFilterSDrw( rInp,aHead,aEntr,rMtf ); + } + } // while(nNext) + if (bRdFlag) { + if (!rInp.GetError()) bRet=sal_True; // Scheinbar Ok + } + } + delete pSgfFonts; + return(bRet); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/sgvmain.hxx b/vcl/source/filter/sgvmain.hxx new file mode 100644 index 000000000000..0d08ba310ef4 --- /dev/null +++ b/vcl/source/filter/sgvmain.hxx @@ -0,0 +1,352 @@ +/* -*- 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 _SGVMAIN_HXX +#define _SGVMAIN_HXX + +#include <vcl/font.hxx> +#include <vcl/outdev.hxx> +#include <vcl/virdev.hxx> + + +#define UCHAR unsigned char + +struct PointType { + sal_Int16 x; + sal_Int16 y; +}; + +#define SgfDpmm 40 + +#define DtHdSize 256 +class DtHdType { +public: + sal_uInt8 Reserved[256]; + friend SvStream& operator>>(SvStream& rIStream, DtHdType& rDtHd); + friend void DtHdOverSeek(SvStream& rInp); +}; + + +struct Seitenformat { + PointType Size; // 0.00mm...819.175mm (Papiergr��e) + sal_Int16 RandL; // links Rand auf + sal_Int16 RandR; // rechts dem Papier + sal_Int16 RandO; // oben Rand auf + sal_Int16 RandU; // unten dem Papier + sal_uInt8 PColor; // Future Use + sal_uInt8 PIntens; // erst recht Future use +// sal_Bool BorderClip; // Objekte am Rand abschneiden (Schummel wg. Allignment unter NT) +}; + + +#define PageSize 146 +class PageType { +public: + sal_uInt32 Next; // N�chste Seite + sal_uInt32 nList; // Objektdaten, erster Record + sal_uInt32 ListEnd; // Objektdaten, letzter Record + Seitenformat Paper; // Papierdaten + sal_Bool BorderClip; // Objekte am Rand abschneiden (Schummel wg. Allignment unter NT) + sal_uInt8 StdPg; // welche Standardseite einblenden ? + PointType U; // Nullpunkt + sal_Int16 HlpLnH[20]; // Hilfslinien + sal_Int16 HlpLnV[20]; + sal_uInt8 LnAnzH; + sal_uInt8 LnAnzV; + UCHAR PgName[32]; // Seitenname + friend SvStream& operator>>(SvStream& rIStream, PageType& rPage); +}; + + +enum ObjArtType {ObjStrk,ObjRect,ObjPoly,ObjCirc,ObjSpln, + ObjText,ObjGrup,ObjBmap,ObjVirt,ObjTxtX,ObjMaxi}; + +struct ObjLineType { + sal_uInt8 LFarbe; // [Index] + sal_uInt8 LBFarbe; // [Index] + sal_uInt8 LIntens; // [%] + sal_uInt8 LMuster; // [Index] inkl. Transparenz + sal_Int16 LMSize; // [Koeffizient/100] + sal_Int16 LDicke; // Strichst�rke +}; + +struct ObjAreaType { + sal_uInt8 FFarbe; // [Index] + sal_uInt8 FBFarbe; // [Index] + sal_uInt8 FIntens; // [%] + // Despite the "Dummy" in the name, and not being used anywhere in + // the code, these two fields are *essential*. These structs are + // 1:1 mappings of actual on-disk/wire file format structures... + // So don't clean the "unused dummy" fields away. (Actually it + // might well be that many other fields around here are never used + // in our code either.) + sal_uInt8 FDummy1; // + sal_Int16 FDummy2; // + sal_uInt16 FMuster; // [Index] inkl. Invers, Transparenz +}; + +#define ObjTextTypeSize 64 +class ObjTextType { +public: + ObjLineType L; // Text-Outline (future) + ObjAreaType F; // Text innen + sal_uInt16 FontLo,FontHi;// z.B. 92500 (CG Times), zweigeteilt wegen DWordAllign in TextType. + sal_uInt16 Grad; // 0.5..32767.5 Pt - bei 1000 Pt sollte aber schlu� sein + sal_uInt16 Breite; // 1..65535% bitte nicht mehr als 500% + sal_uInt8 Justify; // 2 Bit Vert (Hi), 3 Bit Hor (Lo) + sal_uInt8 Kapit; // 1..255% + sal_uInt16 Schnitt; // 8 Flags + sal_uInt16 LnFeed; // 1..32767% vom max. Schriftgrad der Zeile + sal_uInt16 Slant; // Kursivwinkel 0.00..89.99� default 15.00� doppelt Breit angesehen) + sal_uInt8 ZAbst; // Zeichenabstand 0..255% (0=auf der Stelle; 100=normal; 200=Zeichen wird als + sal_sChar ChrVPos; // Zeichen V-Position default 0= on Baseline, 10= 5Pt drunter (-64..63�) + ObjLineType ShdL; // Schatten-Outline (neu 2.0) + ObjAreaType ShdF; // Schatten-innen (neu 2.0) + PointType ShdVers; // Schattenversatz Max.300.00% + sal_Bool ShdAbs; // True-> Schattenversatz ist absolut statt relativ zum Schriftgrad + sal_Bool NoSpc; // True-> kein Zwischenraum (f�r BackArea) + ObjAreaType BackF; // Hintergrundfl�che + sal_uInt32 GetFont(); + void SetFont(sal_uInt32 FontID); +}; + +class Obj0Type { // SuperClass f�r Apple-VMT +public: + virtual void Draw(OutputDevice& rOut); + virtual ~Obj0Type() {} +}; + +#define ObjkSize 20 /* eigentlich 21. Wg. Allignment ist Flags jedoch verschoben worden*/ +class ObjkType: public Obj0Type { // Grundkomponenten aller Stardraw-Objekte +public: + sal_uInt32 Last; + sal_uInt32 Next; + sal_uInt16 MemSize; // in Bytes + PointType ObjMin; // XY-Minimum des Objekts + PointType ObjMax; // XY-Maximum des Objekts + sal_uInt8 Art; + sal_uInt8 Layer; +// sal_uInt8 Flags; // (Schummel f�r Allignment unter NT) + friend SvStream& operator>>(SvStream& rIStream, ObjkType& rObjk); + friend sal_Bool ObjOverSeek(SvStream& rInp, ObjkType& rObjk); + virtual void Draw(OutputDevice& rOut); +}; + + +#define StrkSize 38 +class StrkType: public ObjkType { +public: + sal_uInt8 Flags; // (Schummel f�r Allignment unter NT) + sal_uInt8 LEnden; // Linienenden + ObjLineType L; + PointType Pos1; // Anfangspunkt + PointType Pos2; // Endpunkt + friend SvStream& operator>>(SvStream& rIStream, StrkType& rStrk); + virtual void Draw(OutputDevice& rOut); +}; + + +#define RectSize 52 +class RectType: public ObjkType { +public: + sal_uInt8 Flags; // (Schummel f�r Allignment unter NT) + sal_uInt8 Reserve; + ObjLineType L; + ObjAreaType F; + PointType Pos1; // LO-Ecke = Bezugspunkt + PointType Pos2; // R-Ecke + sal_Int16 Radius; // Eckenradius + sal_uInt16 DrehWink; // 315...<45 + sal_uInt16 Slant; // >270...<90 + friend SvStream& operator>>(SvStream& rIStream, RectType& rRect); + virtual void Draw(OutputDevice& rOut); +}; + + +#define PolySize 44 +class PolyType: public ObjkType { // identisch mit Spline ! +public: + sal_uInt8 Flags; // (Schummel f�r Allignment unter NT) + sal_uInt8 LEnden; // nur f�r Polyline + ObjLineType L; + ObjAreaType F; // nicht f�r Polyline + sal_uInt8 nPoints; + sal_uInt8 Reserve; + sal_uInt32 SD_EckP; // Zeiger auf die Eckpunkte (StarDraw) + PointType* EckP; // Zeiger auf die Eckpunkte (StarView (wird nicht von Disk gelesen!)) + friend SvStream& operator>>(SvStream& rIStream, PolyType& rPoly); + virtual void Draw(OutputDevice& rOut); +}; +#define PolyClosBit 0x01 // Unterarten von Poly: 0: PolyLine 1: Polygon + + +#define SplnSize 44 +class SplnType: public ObjkType { // identisch mit Poly ! +public: + sal_uInt8 Flags; // (Schummel f�r Allignment unter NT) + sal_uInt8 LEnden; // nur f�r nSpline + ObjLineType L; + ObjAreaType F; // nicht f�r nSpline + sal_uInt8 nPoints; + sal_uInt8 Reserve; + sal_uInt32 SD_EckP; // Zeiger auf die Eckpunkte (StarDraw) + PointType* EckP; // Zeiger auf die Eckpunkte (StarView (wird nicht von Disk gelesen!)) + friend SvStream& operator>>(SvStream& rIStream, SplnType& rSpln); + virtual void Draw(OutputDevice& rOut); +}; +// Unterarten von Spline: siehe Poly + + +#define CircSize 52 +class CircType: public ObjkType { +public: + sal_uInt8 Flags; // (Schummel f�r Allignment unter NT) + sal_uInt8 LEnden; // nur Bogen (Kr & El) + ObjLineType L; + ObjAreaType F; // nicht f�r Bogen (Kr & El) + PointType Center; // Mittelpunkt + PointType Radius; // Radius + sal_uInt16 DrehWink; // nur Ellipse + sal_uInt16 StartWink; // � nicht f�r Vollkreis + sal_uInt16 RelWink; // � und Vollellipse + friend SvStream& operator>>(SvStream& rIStream, CircType& rCirc); + virtual void Draw(OutputDevice& rOut); +}; +#define CircFull 0x00 /* Unterarten von Kreis: 0: Kreis */ +#define CircSect 0x01 /* 1: Kreissektor */ +#define CircAbsn 0x02 /* 2: Kreisabschnitt */ +#define CircArc 0x03 /* 3: Kreisbogen */ + + +#define TextSize 116 +class TextType: public ObjkType { +public: + sal_uInt8 Flags; // (Schummel f�r Allignment unter NT) + sal_uInt8 Reserve; // f�r Word Allign + ObjTextType T; // 64 Bytes << DWord-Allign bei FontID erforderlich + PointType Pos1; // Bezugspunkt (ObenLinks) + PointType Pos2; // (untenRechts) + sal_Int16 TopOfs; // Von Oberkante bis Textbegin (future f�r vJustify) + sal_uInt16 DrehWink; // 0...<360 + sal_uInt16 BoxSlant; // >270...<90 (nur Box) + sal_uInt16 BufSize; // Gr��e von Buf f�r Load, Save, Copy und so + sal_uInt16 BufLo,BufHi;// (UCHAR*) Zeiger auf den Textbuffer << ShortArr, weil sonst DWord-Allign erforderlich + sal_uInt16 ExtLo,ExtHi;// (Ptr) Text �ber mehrere Rahmen << ShortArr, weil sonst DWord-Allign erforderlich + PointType FitSize; // Ursprungsgr��e f�r Fit2Size + sal_Int16 FitBreit; // Breite zum formatieren bei Fit2Size + UCHAR* Buffer; // Diese Variable wird nicht durch Lesen von Disk gef�llt, sondern explizit! + friend SvStream& operator>>(SvStream& rIStream, TextType& rText); + virtual void Draw(OutputDevice& rOut); +}; +#define TextOutlBit 0x01 /* 1=Sourcecode f�r Outliner (wird von DrawObjekt() ignoriert) */ +#define TextFitSBit 0x02 /* Bit1: 1=Text-FitToSize, auch Outliner (2.0) */ +#define TextFitZBit 0x08 /* Bit3: 1=Fit2Size Zeilenweise (2.0) */ +#define TextDrftBit 0x04 /* Bit2: 1=DraftDraw (2.0) */ +#define TextFitBits (TextFitSBit | TextFitZBit) + + +enum GrafStat {NoGraf,Pic,Pcx,Hpgl,Img,Msp,Tiff,Dxf,Lot,Usr,Sgf}; + +#define BmapSize 132 +class BmapType: public ObjkType { +public: + sal_uInt8 Flags; // (Schummel f�r Allignment unter NT) + sal_uInt8 Reserve; + ObjAreaType F; // Farbe und Muster der 1-Plane Bitmap + PointType Pos1; + PointType Pos2; + sal_uInt16 DrehWink; // 315...<45 (Future) + sal_uInt16 Slant; // >270...<90 (Future) + UCHAR Filename[80]; // Pfad + PointType PixSize; // Gr��e in Pixel (0 bei Vektor) + GrafStat Format; // siehe GpmDef.Pas + sal_uInt8 nPlanes; // Anzahl der Bitplanes (0 bei Vektor) + sal_Bool RawOut; // als Raw ausgeben ? + sal_Bool InvOut; // invertiert ausgeben ? + sal_Bool LightOut; // aufhellen? (SD20) + sal_uInt8 GrfFlg; // (SD20) 0=nSGF 1=Pcx 2=Hpgl 4=Raw $FF=Undef(f�r Fix in DrawBmp) + + INetURLObject aFltPath; // F�r GraphicFilter + friend SvStream& operator>>(SvStream& rIStream, BmapType& rBmap); + virtual void Draw(OutputDevice& rOut); + void SetPaths( const INetURLObject rFltPath ); +}; + + +#define GrupSize 48 +class GrupType: public ObjkType { +public: + sal_uInt8 Flags; // (Schummel f�r Allignment unter NT) + UCHAR Name[13]; // Name der Gruppe + sal_uInt16 SbLo,SbHi; // (Ptr) Gruppenliste << ShortArr, weil sonst DWord Allign erforderlich + sal_uInt16 UpLo,UpHi; // (Ptr) Vaterliste << ShortArr, weil sonst DWord Allign erforderlich + sal_uInt16 ChartSize; // Speicherbedarf der Diagrammstruktur Struktur + sal_uInt32 ChartPtr; // Diagrammstruktur + sal_uInt32 GetSubPtr(); // hier nur zum Checken, ob Sublist evtl. leer ist. + friend SvStream& operator>>(SvStream& rIStream, GrupType& rGrup); +// virtual void Draw(OutputDevice& rOut); +}; + + +void SetLine(ObjLineType& rLine, OutputDevice& rOut); +void SetArea(ObjAreaType& rArea, OutputDevice& rOut); +Color Sgv2SvFarbe(sal_uInt8 nFrb1, sal_uInt8 nFrb2, sal_uInt8 nInts); +void RotatePoint(PointType& P, sal_Int16 cx, sal_Int16 cy, double sn, double cs); +void RotatePoint(Point& P, sal_Int16 cx, sal_Int16 cy, double sn, double cs); +sal_Int16 iMulDiv(sal_Int16 a, sal_Int16 Mul, sal_Int16 Div); +sal_uInt16 MulDiv(sal_uInt16 a, sal_uInt16 Mul, sal_uInt16 Div); + + +class SgfFontOne { +public: + SgfFontOne* Next; // Zeiger f�r Listenverkettung + sal_uInt32 IFID; + sal_Bool Bold; + sal_Bool Ital; + sal_Bool Sans; + sal_Bool Serf; + sal_Bool Fixd; + FontFamily SVFamil; + CharSet SVChSet; + String SVFName; // z.B. "Times New Roman" = 15 Chars + sal_uInt16 SVWidth; // Durchschnittliche Zeichenbreite in % + SgfFontOne(); + void ReadOne(const rtl::OString& rID, rtl::OString& rDsc); +}; + +class SgfFontLst { +public: + String FNam; // vollst�ndiger Filename des Inifiles + SgfFontOne* pList; // Listenanfang + SgfFontOne* Last; // Listenende + sal_uInt32 LastID; // f�r schnelleren Zugriff bei Wiederholungen + SgfFontOne* LastLn; // f�r schnelleren Zugriff bei Wiederholungen + sal_Bool Tried; + SgfFontLst(); + ~SgfFontLst(); + void AssignFN(const String& rFName); + void ReadList(); + void RausList(); + SgfFontOne* GetFontDesc(sal_uInt32 ID); +}; + +#endif //_SGVMAIN_HXX + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/sgvspln.cxx b/vcl/source/filter/sgvspln.cxx new file mode 100644 index 000000000000..2449b743ce11 --- /dev/null +++ b/vcl/source/filter/sgvspln.cxx @@ -0,0 +1,861 @@ +/* -*- 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 <math.h> + + +#include <tools/poly.hxx> + +extern "C" { + +/*.pn 277 */ +/*.hlAnhang: C - Programme*/ +/*.hrKonstanten- und Macro-Definitionen*/ +/*.fe Die Include-Datei u_const.h ist in das Verzeichnis zu stellen, */ +/*.fe wo der Compiler nach Include-Dateien sucht. */ + + +/*----------------------- FILE u_const.h ---------------------------*/ + +#define IEEE + +/* IEEE - Norm fuer die Darstellung von Gleitkommazahlen: + + 8 Byte lange Gleitkommazahlen, mit + + 53 Bit Mantisse ==> Mantissenbereich: 2 hoch 52 versch. Zahlen + mit 0.1 <= Zahl < 1.0, + 1 Vorzeichen-Bit + 11 Bit Exponent ==> Exponentenbereich: -1024...+1023 + + Die 1. Zeile ( #define IEEE ) ist zu loeschen, falls die Maschine + bzw. der Compiler keine Gleitpunktzahlen gemaess der IEEE-Norm + benutzt. Zusaetzlich muessen die Zahlen MAXEXPON, MINEXPON + (s.u.) angepasst werden. + */ + +#ifdef IEEE /*----------- Falls IEEE Norm --------------------*/ + +#define MACH_EPS 2.220446049250313e-016 /* Maschinengenauigkeit */ + /* IBM-AT: = 2 hoch -52 */ +/* MACH_EPS ist die kleinste positive, auf der Maschine darstellbare + Zahl x, die der Bedingung genuegt: 1.0 + x > 1.0 */ + +#define EPSQUAD 4.930380657631324e-032 +#define EPSROOT 1.490116119384766e-008 + +#define POSMAX 8.98846567431158e+307 /* groesste positive Zahl */ +#define POSMIN 5.56268464626800e-309 /* kleinste positive Zahl */ +#define MAXROOT 9.48075190810918e+153 + +#define BASIS 2 /* Basis der Zahlendarst. */ +#ifndef PI +#define PI 3.141592653589793e+000 +#endif +#define EXP_1 2.718281828459045e+000 + +#else /*------------------ sonst -----------------------*/ + +double exp (double); +double atan (double); +double pow (double,double); +double sqrt (double); + +double masch() /* MACH_EPS maschinenunabhaengig bestimmen */ +{ + double eps = 1.0, x = 2.0, y = 1.0; + while ( y < x ) + { eps *= 0.5; + x = 1.0 + eps; + } + eps *= 2.0; return (eps); +} + +short basis() /* BASIS maschinenunabhaengig bestimmen */ +{ + double x = 1.0, one = 1.0, b = 1.0; + + while ( (x + one) - x == one ) x *= 2.0; + while ( (x + b) == x ) b *= 2.0; + + return ( (short) ((x + b) - x) ); +} + +#define BASIS basis() /* Basis der Zahlendarst. */ + +/* Falls die Maschine (der Compiler) keine IEEE-Darstellung fuer + Gleitkommazahlen nutzt, muessen die folgenden 2 Konstanten an- + gepasst werden. + */ + +#define MAXEXPON 1023.0 /* groesster Exponent */ +#define MINEXPON -1024.0 /* kleinster Exponent */ + + +#define MACH_EPS masch() +#define EPSQUAD MACH_EPS * MACH_EPS +#define EPSROOT sqrt(MACH_EPS) + +#define POSMAX pow ((double) BASIS, MAXEXPON) +#define POSMIN pow ((double) BASIS, MINEXPON) +#define MAXROOT sqrt(POSMAX) + +#define PI 4.0 * atan (1.0) +#define EXP_1 exp(1.0) + +#endif /*-------------- ENDE ifdef ----------------------*/ + + +#define NEGMAX -POSMIN /* groesste negative Zahl */ +#define NEGMIN -POSMAX /* kleinste negative Zahl */ + +/* Definition von Funktionsmakros: + */ + +#define abs(X) ((X) >= 0 ? (X) : -(X)) /* Absolutbetrag von X */ +#define sign(X, Y) (Y < 0 ? -abs(X) : abs(X)) /* Vorzeichen von */ + /* Y mal abs(X) */ +#define sqr(X) ((X) * (X)) /* Quadrat von X */ + +/*------------------- ENDE FILE u_const.h --------------------------*/ + + + + + + + + + +/*.HL Anhang: C - Programme*/ +/*.HRGleichungssysteme fuer Tridiagonalmatrizen*/ + +/*.FE P 3.7 TRIDIAGONALE GLEICHUNGSSYSTEME*/ + + +/*---------------------- MODUL TRIDIAGONAL ------------------------*/ + +sal_uInt16 TriDiagGS(sal_Bool rep, sal_uInt16 n, double* lower, + double* diag, double* upper, double* b) + /************************/ + /* GAUSS-Verfahren fuer */ + /* Tridiagonalmatrizen */ + /************************/ + +/*====================================================================*/ +/* */ +/* trdiag bestimmt die Loesung x des linearen Gleichungssystems */ +/* A * x = b mit tridiagonaler n x n Koeffizientenmatrix A, die in */ +/* den 3 Vektoren lower, upper und diag wie folgt abgespeichert ist: */ +/* */ +/* ( diag[0] upper[0] 0 0 . . . 0 ) */ +/* ( lower[1] diag[1] upper[1] 0 . . . ) */ +/* ( 0 lower[2] diag[2] upper[2] 0 . ) */ +/* A = ( . 0 lower[3] . . . ) */ +/* ( . . . . . 0 ) */ +/* ( . . . . . ) */ +/* ( . . . upper[n-2] ) */ +/* ( 0 . . . 0 lower[n-1] diag[n-1] ) */ +/* */ +/*====================================================================*/ +/* */ +/* Anwendung: */ +/* ========= */ +/* Vorwiegend fuer diagonaldominante Tridiagonalmatrizen, wie */ +/* sie bei der Spline-Interpolation auftreten. */ +/* Fuer diagonaldominante Matrizen existiert immer eine LU- */ +/* Zerlegung; fuer nicht diagonaldominante Tridiagonalmatrizen */ +/* sollte die Funktion band vorgezogen werden, da diese mit */ +/* Spaltenpivotsuche arbeitet und daher numerisch stabiler ist. */ +/* */ +/*====================================================================*/ +/* */ +/* Eingabeparameter: */ +/* ================ */ +/* n Dimension der Matrix ( > 1 ) sal_uInt16 n */ +/* */ +/* lower untere Nebendiagonale double lower[n] */ +/* diag Hauptdiagonale double diag[n] */ +/* upper obere Nebendiagonale double upper[n] */ +/* */ +/* bei rep != 0 enthalten lower, diag und upper die */ +/* Dreieckzerlegung der Ausgangsmatrix. */ +/* */ +/* b rechte Seite des Systems double b[n] */ +/* rep = 0 erstmaliger Aufruf sal_Bool rep */ +/* !=0 wiederholter Aufruf */ +/* fuer gleiche Matrix, */ +/* aber verschiedenes b. */ +/* */ +/* Ausgabeparameter: */ +/* ================ */ +/* b Loesungsvektor des Systems; double b[n] */ +/* die urspruengliche rechte Seite wird ueberspeichert */ +/* */ +/* lower ) enthalten bei rep = 0 die Zerlegung der Matrix; */ +/* diag ) die urspruenglichen Werte von lower u. diag werden */ +/* upper ) ueberschrieben */ +/* */ +/* Die Determinante der Matrix ist bei rep = 0 durch */ +/* det A = diag[0] * ... * diag[n-1] bestimmt. */ +/* */ +/* Rueckgabewert: */ +/* ============= */ +/* = 0 alles ok */ +/* = 1 n < 2 gewaehlt */ +/* = 2 Die Dreieckzerlegung der Matrix existiert nicht */ +/* */ +/*====================================================================*/ +/* */ +/* Benutzte Funktionen: */ +/* =================== */ +/* */ +/* Aus der C Bibliothek: fabs() */ +/* */ +/*====================================================================*/ + +/*.cp 5 */ +{ + sal_uInt16 i; + short j; + +// double fabs(double); + + if ( n < 2 ) return(1); /* n mindestens 2 */ + + /* Wenn rep = 0 ist, */ + /* Dreieckzerlegung der */ + if (rep == 0) /* Matrix u. det be- */ + { /* stimmen */ + for (i = 1; i < n; i++) + { if ( fabs(diag[i-1]) < MACH_EPS ) /* Wenn ein diag[i] = 0 */ + return(2); /* ist, ex. keine Zerle- */ + lower[i] /= diag[i-1]; /* gung. */ + diag[i] -= lower[i] * upper[i-1]; + } + } + + if ( fabs(diag[n-1]) < MACH_EPS ) return(2); + + for (i = 1; i < n; i++) /* Vorwaertselimination */ + b[i] -= lower[i] * b[i-1]; + + b[n-1] /= diag[n-1]; /* Rueckwaertselimination */ + for (j = n-2; j >= 0; j--) { + i=j; + b[i] = ( b[i] - upper[i] * b[i+1] ) / diag[i]; + } + return(0); +} + +/*----------------------- ENDE TRIDIAGONAL -------------------------*/ + + + + + + + + + +/*.HL Anhang: C - Programme*/ +/*.HRGleichungssysteme mit zyklisch tridiagonalen Matrizen*/ + +/*.FE P 3.8 SYSTEME MIT ZYKLISCHEN TRIDIAGONALMATRIZEN */ + + +/*---------------- MODUL ZYKLISCH TRIDIAGONAL ----------------------*/ + + +sal_uInt16 ZyklTriDiagGS(sal_Bool rep, sal_uInt16 n, double* lower, double* diag, + double* upper, double* lowrow, double* ricol, double* b) + /******************************/ + /* Systeme mit zyklisch tri- */ + /* diagonalen Matrizen */ + /******************************/ + +/*====================================================================*/ +/* */ +/* tzdiag bestimmt die Loesung x des linearen Gleichungssystems */ +/* A * x = b mit zyklisch tridiagonaler n x n Koeffizienten- */ +/* matrix A, die in den 5 Vektoren lower, upper, diag, lowrow und */ +/* ricol wie folgt abgespeichert ist: */ +/* */ +/* ( diag[0] upper[0] 0 0 . . 0 ricol[0] ) */ +/* ( lower[1] diag[1] upper[1] 0 . . 0 ) */ +/* ( 0 lower[2] diag[2] upper[2] 0 . ) */ +/* A = ( . 0 lower[3] . . . . ) */ +/* ( . . . . . 0 ) */ +/* ( . . . . . ) */ +/* ( 0 . . . upper[n-2] ) */ +/* ( lowrow[0] 0 . . 0 lower[n-1] diag[n-1] ) */ +/* */ +/* Speicherplatz fuer lowrow[1],..,lowrow[n-3] und ricol[1],..., */ +/* ricol[n-3] muss zusaetzlich bereitgestellt werden, da dieser */ +/* fuer die Aufnahme der Zerlegungsmatrix verfuegbar sein muss, die */ +/* auf die 5 genannten Vektoren ueberspeichert wird. */ +/* */ +/*====================================================================*/ +/* */ +/* Anwendung: */ +/* ========= */ +/* Vorwiegend fuer diagonaldominante zyklische Tridiagonalmatri- */ +/* zen wie sie bei der Spline-Interpolation auftreten. */ +/* Fuer diagonaldominante Matrizen existiert immer eine LU- */ +/* Zerlegung. */ +/* */ +/*====================================================================*/ +/* */ +/* Eingabeparameter: */ +/* ================ */ +/* n Dimension der Matrix ( > 2 ) sal_uInt16 n */ +/* lower untere Nebendiagonale double lower[n] */ +/* diag Hauptdiagonale double diag[n] */ +/* upper obere Nebendiagonale double upper[n] */ +/* b rechte Seite des Systems double b[n] */ +/* rep = 0 erstmaliger Aufruf sal_Bool rep */ +/* !=0 wiederholter Aufruf */ +/* fuer gleiche Matrix, */ +/* aber verschiedenes b. */ +/* */ +/* Ausgabeparameter: */ +/* ================ */ +/* b Loesungsvektor des Systems, double b[n] */ +/* die urspruengliche rechte Seite wird ueberspeichert */ +/* */ +/* lower ) enthalten bei rep = 0 die Zerlegung der Matrix; */ +/* diag ) die urspruenglichen Werte von lower u. diag werden */ +/* upper ) ueberschrieben */ +/* lowrow ) double lowrow[n-2] */ +/* ricol ) double ricol[n-2] */ +/* */ +/* Die Determinante der Matrix ist bei rep = 0 durch */ +/* det A = diag[0] * ... * diag[n-1] bestimmt. */ +/* */ +/* Rueckgabewert: */ +/* ============= */ +/* = 0 alles ok */ +/* = 1 n < 3 gewaehlt */ +/* = 2 Die Zerlegungsmatrix existiert nicht */ +/* */ +/*====================================================================*/ +/* */ +/* Benutzte Funktionen: */ +/* =================== */ +/* */ +/* Aus der C Bibliothek: fabs() */ +/* */ +/*====================================================================*/ + +/*.cp 5 */ +{ + double temp; // fabs(double); + sal_uInt16 i; + short j; + + if ( n < 3 ) return(1); + + if (rep == 0) /* Wenn rep = 0 ist, */ + { /* Zerlegung der */ + lower[0] = upper[n-1] = 0.0; /* Matrix berechnen. */ + + if ( fabs (diag[0]) < MACH_EPS ) return(2); + /* Ist ein Diagonalelement */ + temp = 1.0 / diag[0]; /* betragsmaessig kleiner */ + upper[0] *= temp; /* MACH_EPS, so ex. keine */ + ricol[0] *= temp; /* Zerlegung. */ + + for (i = 1; i < n-2; i++) + { diag[i] -= lower[i] * upper[i-1]; + if ( fabs(diag[i]) < MACH_EPS ) return(2); + temp = 1.0 / diag[i]; + upper[i] *= temp; + ricol[i] = -lower[i] * ricol[i-1] * temp; + } + + diag[n-2] -= lower[n-2] * upper[n-3]; + if ( fabs(diag[n-2]) < MACH_EPS ) return(2); + + for (i = 1; i < n-2; i++) + lowrow[i] = -lowrow[i-1] * upper[i-1]; + + lower[n-1] -= lowrow[n-3] * upper[n-3]; + upper[n-2] = ( upper[n-2] - lower[n-2] * ricol[n-3] ) / diag[n-2]; + + for (temp = 0.0, i = 0; i < n-2; i++) + temp -= lowrow[i] * ricol[i]; + diag[n-1] += temp - lower[n-1] * upper[n-2]; + + if ( fabs(diag[n-1]) < MACH_EPS ) return(2); + } /* end if ( rep == 0 ) */ + + b[0] /= diag[0]; /* Vorwaertselemination */ + for (i = 1; i < n-1; i++) + b[i] = ( b[i] - b[i-1] * lower[i] ) / diag[i]; + + for (temp = 0.0, i = 0; i < n-2; i++) + temp -= lowrow[i] * b[i]; + + b[n-1] = ( b[n-1] + temp - lower[n-1] * b[n-2] ) / diag[n-1]; + + b[n-2] -= b[n-1] * upper[n-2]; /* Rueckwaertselimination */ + for (j = n-3; j >= 0; j--) { + i=j; + b[i] -= upper[i] * b[i+1] + ricol[i] * b[n-1]; + } + return(0); +} + +/*------------------ ENDE ZYKLISCH TRIDIAGONAL ---------------------*/ + + +} // extern "C" + + +/************************************************************************* +|* +|* NaturalSpline() +|* +|* Beschreibung Berechnet die Koeffizienten eines natuerlichen +|* kubischen Polynomsplines mit n Stuetzstellen. +|* +*************************************************************************/ + +sal_uInt16 NaturalSpline(sal_uInt16 n, double* x, double* y, + double Marg0, double MargN, + sal_uInt8 MargCond, + double* b, double* c, double* d) +{ + sal_uInt16 i; + double* a; + double* h; + sal_uInt16 error; + + if (n<2) return 1; + if ( (MargCond & ~3) ) return 2; + a=new double[n+1]; + h=new double[n+1]; + for (i=0;i<n;i++) { + h[i]=x[i+1]-x[i]; + if (h[i]<=0.0) { delete[] a; delete[] h; return 1; } + } + for (i=0;i<n-1;i++) { + a[i]=3.0*((y[i+2]-y[i+1])/h[i+1]-(y[i+1]-y[i])/h[i]); + b[i]=h[i]; + c[i]=h[i+1]; + d[i]=2.0*(h[i]+h[i+1]); + } + switch (MargCond) { + case 0: { + if (n==2) { + a[0]=a[0]/3.0; + d[0]=d[0]*0.5; + } else { + a[0] =a[0]*h[1]/(h[0]+h[1]); + a[n-2]=a[n-2]*h[n-2]/(h[n-1]+h[n-2]); + d[0] =d[0]-h[0]; + d[n-2]=d[n-2]-h[n-1]; + c[0] =c[0]-h[0]; + b[n-2]=b[n-2]-h[n-1]; + } + } + case 1: { + a[0] =a[0]-1.5*((y[1]-y[0])/h[0]-Marg0); + a[n-2]=a[n-2]-1.5*(MargN-(y[n]-y[n-1])/h[n-1]); + d[0] =d[0]-h[0]*0.5; + d[n-2]=d[n-2]-h[n-1]*0.5; + } + case 2: { + a[0] =a[0]-h[0]*Marg0*0.5; + a[n-2]=a[n-2]-h[n-1]*MargN*0.5; + } + case 3: { + a[0] =a[0]+Marg0*h[0]*h[0]*0.5; + a[n-2]=a[n-2]-MargN*h[n-1]*h[n-1]*0.5; + d[0] =d[0]+h[0]; + d[n-2]=d[n-2]+h[n-1]; + } + } // switch MargCond + if (n==2) { + c[1]=a[0]/d[0]; + } else { + error=TriDiagGS(sal_False,n-1,b,d,c,a); + if (error!=0) { delete[] a; delete[] h; return error+2; } + for (i=0;i<n-1;i++) c[i+1]=a[i]; + } + switch (MargCond) { + case 0: { + if (n==2) { + c[2]=c[1]; + c[0]=c[1]; + } else { + c[0]=c[1]+h[0]*(c[1]-c[2])/h[1]; + c[n]=c[n-1]+h[n-1]*(c[n-1]-c[n-2])/h[n-2]; + } + } + case 1: { + c[0]=1.5*((y[1]-y[0])/h[0]-Marg0); + c[0]=(c[0]-c[1]*h[0]*0.5)/h[0]; + c[n]=1.5*((y[n]-y[n-1])/h[n-1]-MargN); + c[n]=(c[n]-c[n-1]*h[n-1]*0.5)/h[n-1]; + } + case 2: { + c[0]=Marg0*0.5; + c[n]=MargN*0.5; + } + case 3: { + c[0]=c[1]-Marg0*h[0]*0.5; + c[n]=c[n-1]+MargN*h[n-1]*0.5; + } + } // switch MargCond + for (i=0;i<n;i++) { + b[i]=(y[i+1]-y[i])/h[i]-h[i]*(c[i+1]+2.0*c[i])/3.0; + d[i]=(c[i+1]-c[i])/(3.0*h[i]); + } + delete[] a; + delete[] h; + return 0; +} + + +/************************************************************************* +|* +|* PeriodicSpline() +|* +|* Beschreibung Berechnet die Koeffizienten eines periodischen +|* kubischen Polynomsplines mit n Stuetzstellen. +|* +*************************************************************************/ + + +sal_uInt16 PeriodicSpline(sal_uInt16 n, double* x, double* y, + double* b, double* c, double* d) +{ // Arrays muessen von [0..n] dimensioniert sein! + sal_uInt16 Error; + sal_uInt16 i,im1,nm1; //integer + double hr,hl; + double* a; + double* lowrow; + double* ricol; + + if (n<2) return 4; + nm1=n-1; + for (i=0;i<=nm1;i++) if (x[i+1]<=x[i]) return 2; // muss streng nonoton fallend sein! + if (y[n]!=y[0]) return 3; // Anfang muss gleich Ende sein! + + a =new double[n+1]; + lowrow=new double[n+1]; + ricol =new double[n+1]; + + if (n==2) { + c[1]=3.0*((y[2]-y[1])/(x[2]-x[1])); + c[1]=c[1]-3.0*((y[i]-y[0])/(x[1]-x[0])); + c[1]=c[1]/(x[2]-x[0]); + c[2]=-c[1]; + } else { + for (i=1;i<=nm1;i++) { + im1=i-1; + hl=x[i]-x[im1]; + hr=x[i+1]-x[i]; + b[im1]=hl; + d[im1]=2.0*(hl+hr); + c[im1]=hr; + a[im1]=3.0*((y[i+1]-y[i])/hr-(y[i]-y[im1])/hl); + } + hl=x[n]-x[nm1]; + hr=x[1]-x[0]; + b[nm1]=hl; + d[nm1]=2.0*(hl+hr); + lowrow[0]=hr; + ricol[0]=hr; + a[nm1]=3.0*((y[1]-y[0])/hr-(y[n]-y[nm1])/hl); + Error=ZyklTriDiagGS(sal_False,n,b,d,c,lowrow,ricol,a); + if ( Error != 0 ) + { + delete[] a; + delete[] lowrow; + delete[] ricol; + return(Error+4); + } + for (i=0;i<=nm1;i++) c[i+1]=a[i]; + } + c[0]=c[n]; + for (i=0;i<=nm1;i++) { + hl=x[i+1]-x[i]; + b[i]=(y[i+1]-y[i])/hl; + b[i]=b[i]-hl*(c[i+1]+2.0*c[i])/3.0; + d[i]=(c[i+1]-c[i])/hl/3.0; + } + delete[] a; + delete[] lowrow; + delete[] ricol; + return 0; +} + + + +/************************************************************************* +|* +|* ParaSpline() +|* +|* Beschreibung Berechnet die Koeffizienten eines parametrischen +|* natuerlichen oder periodischen kubischen +|* Polynomsplines mit n Stuetzstellen. +|* +*************************************************************************/ + +sal_uInt16 ParaSpline(sal_uInt16 n, double* x, double* y, sal_uInt8 MargCond, + double Marg01, double Marg02, + double MargN1, double MargN2, + sal_Bool CondT, double* T, + double* bx, double* cx, double* dx, + double* by, double* cy, double* dy) +{ + sal_uInt16 Error; + sal_uInt16 i; + double deltX,deltY,delt, + alphX = 0,alphY = 0, + betX = 0,betY = 0; + + if (n<2) return 1; + if ((MargCond & ~3) && (MargCond != 4)) return 2; // ungueltige Randbedingung + if (CondT==sal_False) { + T[0]=0.0; + for (i=0;i<n;i++) { + deltX=x[i+1]-x[i]; deltY=y[i+1]-y[i]; + delt =deltX*deltX+deltY*deltY; + if (delt<=0.0) return 3; // zwei identische Punkte nacheinander! + T[i+1]=T[i]+sqrt(delt); + } + } + switch (MargCond) { + case 0: break; + case 1: case 2: { + alphX=Marg01; betX=MargN1; + alphY=Marg02; betY=MargN2; + } break; + case 3: { + if (x[n]!=x[0]) return 3; + if (y[n]!=y[0]) return 4; + } break; + case 4: { + if (abs(Marg01)>=MAXROOT) { + alphX=0.0; + alphY=sign(1.0,y[1]-y[0]); + } else { + alphX=sign(sqrt(1.0/(1.0+Marg01*Marg01)),x[1]-x[0]); + alphY=alphX*Marg01; + } + if (abs(MargN1)>=MAXROOT) { + betX=0.0; + betY=sign(1.0,y[n]-y[n-1]); + } else { + betX=sign(sqrt(1.0/(1.0+MargN1*MargN1)),x[n]-x[n-1]); + betY=betX*MargN1; + } + } + } // switch MargCond + if (MargCond==3) { + Error=PeriodicSpline(n,T,x,bx,cx,dx); + if (Error!=0) return(Error+4); + Error=PeriodicSpline(n,T,y,by,cy,dy); + if (Error!=0) return(Error+10); + } else { + Error=NaturalSpline(n,T,x,alphX,betX,MargCond,bx,cx,dx); + if (Error!=0) return(Error+4); + Error=NaturalSpline(n,T,y,alphY,betY,MargCond,by,cy,dy); + if (Error!=0) return(Error+9); + } + return 0; +} + + + +/************************************************************************* +|* +|* CalcSpline() +|* +|* Beschreibung Berechnet die Koeffizienten eines parametrischen +|* natuerlichen oder periodischen kubischen +|* Polynomsplines. Die Eckpunkte des uebergebenen +|* Polygons werden als Stuetzstellen angenommen. +|* n liefert die Anzahl der Teilpolynome. +|* Ist die Berechnung fehlerfrei verlaufen, so +|* liefert die Funktion sal_True. Nur in diesem Fall +|* ist Speicher fuer die Koeffizientenarrays +|* allokiert, der dann spaeter vom Aufrufer mittels +|* delete freizugeben ist. +|* +*************************************************************************/ + +sal_Bool CalcSpline(Polygon& rPoly, sal_Bool Periodic, sal_uInt16& n, + double*& ax, double*& ay, double*& bx, double*& by, + double*& cx, double*& cy, double*& dx, double*& dy, double*& T) +{ + sal_uInt8 Marg; + double Marg01; + double MargN1,MargN2; + sal_uInt16 i; + Point P0(-32768,-32768); + Point Pt; + + n=rPoly.GetSize(); + ax=new double[rPoly.GetSize()+2]; + ay=new double[rPoly.GetSize()+2]; + + n=0; + for (i=0;i<rPoly.GetSize();i++) { + Pt=rPoly.GetPoint(i); + if (i==0 || Pt!=P0) { + ax[n]=Pt.X(); + ay[n]=Pt.Y(); + n++; + P0=Pt; + } + } + + if (Periodic) { + Marg=3; + ax[n]=ax[0]; + ay[n]=ay[0]; + n++; + } else { + Marg=2; + } + + bx=new double[n+1]; + by=new double[n+1]; + cx=new double[n+1]; + cy=new double[n+1]; + dx=new double[n+1]; + dy=new double[n+1]; + T =new double[n+1]; + + Marg01=0.0; + MargN1=0.0; + MargN2=0.0; + if (n>0) n--; // n Korregieren (Anzahl der Teilpolynome) + + sal_Bool bRet = sal_False; + if ( ( Marg == 3 && n >= 3 ) || ( Marg == 2 && n >= 2 ) ) + { + bRet = ParaSpline(n,ax,ay,Marg,Marg01,Marg01,MargN1,MargN2,sal_False,T,bx,cx,dx,by,cy,dy) == 0; + } + if ( bRet == sal_False ) + { + delete[] ax; + delete[] ay; + delete[] bx; + delete[] by; + delete[] cx; + delete[] cy; + delete[] dx; + delete[] dy; + delete[] T; + n=0; + } + return bRet; +} + + +/************************************************************************* +|* +|* Spline2Poly() +|* +|* Beschreibung Konvertiert einen parametrichen kubischen +|* Polynomspline Spline (natuerlich oder periodisch) +|* in ein angenaehertes Polygon. +|* Die Funktion liefert sal_False, wenn ein Fehler bei +|* der Koeffizientenberechnung aufgetreten ist oder +|* das Polygon zu gross wird (>PolyMax=16380). Im 1. +|* Fall hat das Polygon 0, im 2. Fall PolyMax Punkte. +|* Um Koordinatenueberlaeufe zu vermeiden werden diese +|* auf +/-32000 begrenzt. +|* +*************************************************************************/ +sal_Bool Spline2Poly(Polygon& rSpln, sal_Bool Periodic, Polygon& rPoly) +{ + short MinKoord=-32000; // zur Vermeidung + short MaxKoord=32000; // von Ueberlaeufen + + double* ax; // Koeffizienten der Polynome + double* ay; + double* bx; + double* by; + double* cx; + double* cy; + double* dx; + double* dy; + double* tv; + + double Step; // Schrittweite fuer t + double dt1,dt2,dt3; // Delta t, y, ^3 + double t; + sal_Bool bEnde; // Teilpolynom zu Ende? + sal_uInt16 n; // Anzahl der zu zeichnenden Teilpolynome + sal_uInt16 i; // aktuelles Teilpolynom + sal_Bool bOk; // noch alles ok? + sal_uInt16 PolyMax=16380;// Maximale Anzahl von Polygonpunkten + long x,y; + + bOk=CalcSpline(rSpln,Periodic,n,ax,ay,bx,by,cx,cy,dx,dy,tv); + if (bOk) { + Step =10; + + rPoly.SetSize(1); + rPoly.SetPoint(Point(short(ax[0]),short(ay[0])),0); // erster Punkt + i=0; + while (i<n) { // n Teilpolynome malen + t=tv[i]+Step; + bEnde=sal_False; + while (!bEnde) { // ein Teilpolynom interpolieren + bEnde=t>=tv[i+1]; + if (bEnde) t=tv[i+1]; + dt1=t-tv[i]; dt2=dt1*dt1; dt3=dt2*dt1; + x=long(ax[i]+bx[i]*dt1+cx[i]*dt2+dx[i]*dt3); + y=long(ay[i]+by[i]*dt1+cy[i]*dt2+dy[i]*dt3); + if (x<MinKoord) x=MinKoord; if (x>MaxKoord) x=MaxKoord; + if (y<MinKoord) y=MinKoord; if (y>MaxKoord) y=MaxKoord; + if (rPoly.GetSize()<PolyMax) { + rPoly.SetSize(rPoly.GetSize()+1); + rPoly.SetPoint(Point(short(x),short(y)),rPoly.GetSize()-1); + } else { + bOk=sal_False; // Fehler: Polygon wird zu gross + } + t=t+Step; + } // Ende von Teilpolynom + i++; // naechstes Teilpolynom + } + delete[] ax; + delete[] ay; + delete[] bx; + delete[] by; + delete[] cx; + delete[] cy; + delete[] dx; + delete[] dy; + delete[] tv; + return bOk; + } // Ende von if (bOk) + rPoly.SetSize(0); + return sal_False; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/sgvspln.hxx b/vcl/source/filter/sgvspln.hxx new file mode 100644 index 000000000000..93c08ab62883 --- /dev/null +++ b/vcl/source/filter/sgvspln.hxx @@ -0,0 +1,63 @@ +/* -*- 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 _SGVSPLN_HXX +#define _SGVSPLN_HXX + +/************************************************************************* +|* +|* CalcSpline() +|* +|* Beschreibung Berechnet die Koeffizienten eines parametrischen +|* natrlichen oder periodischen kubischen +|* Polynomsplines. Die Eckpunkte des bergebenen +|* Polygons werden als Sttzstellen angenommen. +|* n liefert die Anzahl der Teilpolynome. +|* Ist die Berechnung fehlerfrei verlaufen, so +|* liefert die Funktion sal_True. Nur in diesem Fall +|* ist Speicher fr die Koeffizientenarrays +|* allokiert, der dann spter vom Aufrufer mittels +|* delete freizugeben ist. +|* +*************************************************************************/ + +sal_Bool CalcSpline(Polygon& rPoly, sal_Bool Periodic, sal_uInt16& n, + double*& ax, double*& ay, double*& bx, double*& by, + double*& cx, double*& cy, double*& dx, double*& dy, double*& T); + +/************************************************************************* +|* +|* Poly2Spline() +|* +|* Beschreibung Konvertiert einen parametrichen kubischen +|* Polynomspline Spline (natrlich oder periodisch) +|* in ein angenhertes Polygon. +|* Die Funktion liefert sal_False, wenn ein Fehler bei +|* der Koeffizientenberechnung aufgetreten ist oder +|* das Polygon zu gro?wird (>PolyMax=16380). Im 1. +|* Fall hat das Polygon 0, im 2. Fall PolyMax Punkte. +|* Um Koordinatenberlufe zu vermeiden werden diese +|* auf +/-32000 begrenzt. +|* +*************************************************************************/ +sal_Bool Spline2Poly(Polygon& rSpln, sal_Bool Periodic, Polygon& rPoly); + +#endif //_SGVSPLN_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/sgvtext.cxx b/vcl/source/filter/sgvtext.cxx new file mode 100644 index 000000000000..235f36808298 --- /dev/null +++ b/vcl/source/filter/sgvtext.cxx @@ -0,0 +1,1277 @@ +/* -*- 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 <rtl/math.h> +#include <comphelper/string.hxx> +#include <tools/config.hxx> +#include <svtools/filter.hxx> +#include "sgffilt.hxx" +#include "sgfbram.hxx" +#include "sgvmain.hxx" + +extern SgfFontLst* pSgfFonts; + +#ifndef abs +#define abs(x) ((x)<0 ? -(x) : (x)) +#endif + + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Einschraenkungen: Schatten nur grau, 2D und mit fixem Abstand. +// +// +// +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +// AbsBase.Pas + +// die folgenden Werte sind in % vom maximalen Schriftgrad der Zeile */ +#define UndlSpace 5 /* Untersteichungsabstand von der Baseline */ +#define UndlWidth 6 /* Untersteichungsdicke */ +#define UndlSpac2 7 /* Zwischenraum bei doppelter Unterstreichung */ +#define StrkSpace 25 /* Abstand der Durchstreichlinie von der Baseline*/ +#define StrkWidth 5 /* Durchstreichungsliniendicke */ +#define StrkSpac2 7 /* Zwischenraum bei doppelter Durchstreichung */ +#define OutlWidth 2 /* Strichstaerke ist 2% vom Schriftgrad */ + +// vvv Sonderzeichen im TextBuffer vvv +#define TextEnd 0 /* ^@ Ende der Zeichenkette */ +#define HardSpace 6 /* ^F Hartspace (wird nicht umbrochen) ,' ' */ +#define GrafText 7 /* ^G Im Text eingebundene Grafik (future) */ +#define Tabulator 9 /* ^I Tabulatorzeichen, Pfeil */ +#define LineFeed 10 /* ^J Neue Zeile */ +#define SoftTrennK 11 /* ^K Zeichen fuer k-c-Austausch bei Trennung, 'k' */ +#define AbsatzEnd 13 /* ^M Neuer Absatz =CR */ +#define HardTrenn 16 /* ^P Hartes Trennzeichen (wird nicht umbrochen), '-' */ +#define SoftTrennAdd 19 /* ^S Zusatz-Zeichen Trennung von z.b."Schiff-fahrt" */ +#define Paragraf 21 /* ^U Zeichen welches fuer Paragraf-Zeichen */ +#define Escape 27 /* ^[ Escapesequenz einleiten */ +#define SoftTrenn 31 /* ^_ Weiches Trennzeichen, '-' nur Zeilenende */ +#define MaxEscValLen 8 +#define MaxEscLen (MaxEscValLen+3) + +//============================================================================== +// Escapesequenzen: [Esc]<Ident><Value>[Esc] also mind. 4 Char +// Max. Laenge von Value soll sein: 8 Char (7+Vorzeichen). Demnach max. Laenge +// einer Escapesequenz: 11 Char. +// Identifer: + +#define EscFont 'F' /* FontID, z.B. 92500 fuer CG Times */ +#define EscGrad 'G' /* Schriftgrad 1..255 fuer <<Pt-127<<Pt */ +#define EscBreit 'B' /* Breite 1..255% des Schriftgrades */ +#define EscKaptS 'K' /* Kapitaelchengroesse 1..255% des Schriftgrades */ +#define EscLFeed 'L' /* Zeilenabstand 1..32767% vom max. Schriftgrad der Zeile */ + // oder 1..32767 fuer 1..16383<<Pt absolut (Wenn Bit 15=1) +#define EscSlant 'S' /* Kursiv(Winkel) 1..8999 fuer 0.01deg..89.99deg */ +#define EscVPos 'V' /* Zeichen Vertikal-Position 1..255 fuer <<Pt..127<<Pt */ +#define EscZAbst 'Z' /* Zeichenabstand -128..127% */ +#define EscHJust 'A' /* H-Justify Absatz: Links, Zentr, Rechts, Block, Austreibend, Gesperrt (0..5)*/ + +#define EscFarbe 'C' /* Farbe 0..7 */ +#define EscBFarb 'U' /* BackFarbe 0..7 */ +#define EscInts 'I' /* Farbintensitaet 0..100% */ +#define EscMustr 'M' /* Muster 0..? inkl. Transp... */ +#define EscMFarb 'O' /* Musterfarbe 0..7 */ +#define EscMBFrb 'P' /* 2. Musterfarbe 0..7 */ +#define EscMInts 'W' /* Musterintensitaet 0..7 */ + +#define EscSMstr 'E' /* Schattenmuster 0..? inkl. Transp... */ +#define EscSFarb 'R' /* Schattenfarbe 0..7 */ +#define EscSBFrb 'T' /* 2. Schattenfarbe 0..7 */ +#define EscSInts 'Q' /* Schattenintensitaet 0..7 */ + +#define EscSXDst 'X' /* Schattenversatz X 0..100% */ +#define EscSYDst 'Y' /* Schattenversatz Y 0..100% */ +#define EscSDist 'D' /* Schattenversatz X-Y 0..100% */ + +#define EscBold 'f' /* Fett */ +#define EscLSlnt 'l' /* LKursiv */ +#define EscRSlnt 'r' /* RKursiv */ +#define EscUndln 'u' /* Unterstrichen */ +#define EscDbUnd 'p' /* doppelt Unterstrichen */ +#define EscKaptF 'k' /* Kapitaelchenflag */ +#define EscStrik 'd' /* Durchgestrichen */ +#define EscDbStk 'e' /* doppelt Durchgestrichen */ +#define EscSupSc 'h' /* Hochgestellt */ +#define EscSubSc 't' /* Tiefgestellt */ +#define Esc2DShd 's' /* 2D-Schatten */ +#define Esc3DShd 'j' /* 3D-Schatten */ +#define Esc4DShd 'i' /* 4D-Schatten */ +#define EscEbShd 'b' /* Embossed */ + +// AllEscIdent =[EscFont, EscGrad, EscBreit,EscKaptS,EscLFeed,EscSlant,EscVPos, EscZAbst,EscHJust, +// EscFarbe,EscBFarb,EscInts, EscMustr,EscMFarb,EscMBFrb,EscMInts, +// EscSMstr,EscSFarb,EscSBFrb,EscSInts,EscSXDst,EscSYDst,EscSDist, +// EscBold, EscLSlnt,EscRSlnt,EscUndln,EscDbUnd,EscKaptF,EscStrik,EscDbStk, +// EscSupSc,EscSubSc,Esc2DShd,Esc3DShd,Esc4DShd]; +// Justify muss spaetestens am Anfang des Absatzes stehen +#define EscSet '\x1e' /* Flag setzen */ +#define EscReset '\x1f' /* Flag loeschen */ +#define EscDeflt '\x11' /* Flag auf default setzen */ +#define EscToggl '\x1d' /* Flag Toggeln */ +#define EscNoFlg 0 +#define EscNoVal -2147483647 /* -MaxLongInt */ +//============================================================================== +#define NoTrenn 0xFFFF /* Wert fuer Parameter 'Rest' von GetTextChar(), wenn auf keinen Fall getrennt werden soll */ +#define DoTrenn 0xFFFE /* Wert fuer Parameter 'Rest' von GetTextChar(), wenn getrennt werden soll */ + +#define MaxLineChars 1024 + +#define ChrXPosArrSize (MaxLineChars+1+1) /* 2k - Beginnt mit 0 im gegensatz zu StarDraw */ +#define CharLineSize (MaxLineChars+1+1) + +#define MinChar 32 +#define MaxChar 255 + + +//============================================================================== + +#define GradDiv 2 +#define CharTopToBase 100 /* wegen Apostrophe und Umlaute mehr als 75% */ +#define CharTopToBtm 120 /* Zeilenhoehe ist groesser als Schriftgrad */ + // bei Avanti-Bold 'ue' eigentlich sogar 130% + +// end of AbsBase.Pas +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// + + + +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +// DefBase.Pas + +#define TextBoldBit 0x0001 /* Fett */ +#define TextRSlnBit 0x0002 /* Kursiv */ +#define TextUndlBit 0x0004 /* Unterstrichen */ +#define TextStrkBit 0x0008 /* Durchgesteichen */ +#define TextSupSBit 0x0010 /* Hocgestellt */ +#define TextSubSBit 0x0020 /* Tiefgestellt */ +#define TextKaptBit 0x0040 /* Kapitaelchen */ +#define TextLSlnBit 0x0080 /* Linkskursiv */ +#define TextDbUnBit 0x0100 /* Doppelt unterstrichen */ +#define TextDbStBit 0x0200 /* Doppelt durchgestrichen */ +#define TextSh2DBit 0x0400 /* 2D-Schatten 2.0 */ +#define TextSh3DBit 0x0800 /* 3D-Schatten 2.0 */ +#define TextSh4DBit 0x1000 /* 4D-Schatten 2.0 */ +#define TextShEbBit 0x2000 /* Embossed-Schatten 2.0 */ +#define FontAtrBits (TextBoldBit | TextRSlnBit) + +#define THJustLeft 0x00 +#define THJustCenter 0x01 +#define THJustRight 0x02 +#define THJustBlock 0x03 +#define THJustDrvOut 0x04 /* Austreibend Formatiert */ +#define THJustLocked 0x05 /* A l s S p e r r s c h r i f t */ +#define TVJustTop 0x00 /* Future */ +#define TVJustCenter 0x10 /* Future */ +#define TVJustBottom 0x20 /* Future */ +#define TVJustBlock 0x30 /* Future */ + +#define MaxCharSlant 4200 /* Maximal 42deg kursiv ! */ + +// end of DefBase.Pas +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// + + +sal_Bool CheckTextOutl(ObjAreaType& F, ObjLineType& L); + +sal_Bool CheckTextOutl(ObjAreaType& F, ObjLineType& L) +{ + return (F.FIntens!=L.LIntens) || + ((F.FFarbe!=L.LFarbe) && (F.FIntens>0)) || + ((F.FBFarbe!=L.LBFarbe) && (F.FIntens<100)); +} + + +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +// Misc.Pas + +short hPoint2Sgf(short a) +{ + long b; + b=long(a)*127*SgfDpmm/(144*5); + return short(b); +} + +// End of Misc.Pas +// AbsRead.Pas + +// ====================================================================== +// Function GetTopToBaseLine() Function GetBaseLineToBtm() +// +// Abstand von Zeilenoberkante bis BaseLine bzw. von BaseLine bis +// Unterkante berechnen. Alles in SGF-Units. +// ====================================================================== + +sal_uInt16 GetTopToBaseLine(sal_uInt16 MaxGrad) +{ + long ret; + ret=long(MaxGrad)*long(CharTopToBase) /long(100); + return sal_uInt16(ret); +} + +// ====================================================================== +// Function GetTextChar() Function GetTextCharConv() +// +// Liest ein Zeichen aus dem Textbuffer, wertet dabei eventuell +// auftretende Escapesequenzen aus und setzt dementsprechend den +// Ein-/Ausgabeparameter AktAtr. Index wird entsprechend erhoeht. +// Der Parameter Rest muss immer die Anzahl der Zeichen beinhalten, +// den angeforderten Zeichen in der aktuellen Zeile noch folgen. +// Ansonsten funktioniert die Silbentrennung nicht richtig. Gibt man +// stattdessen die Konstante NoTrenn an, wird in keinem Fall +// getrennt, die Konstante DoTrenn bewirkt dagegen, dass ueberall dort +// getrennt wird, wo ein SoftTrenner vorkommt. +// +// SoftTrenner werden immer in ein Minuszeichen konvertiert. +// GetTextCharConv() konvertiert zusaetzlich HardSpace und AbsatzEnde +// in Spaces sowie HardTrenner in Minuszeichen. TextEnde wird immer +// als Char(0) geliefert. +// ====================================================================== + + + +UCHAR ConvertTextChar(UCHAR c) +{ + if (c<32) { + switch (c) { + case HardSpace : c=' '; break; + case AbsatzEnd : c=' '; break; + case SoftTrenn : c='-'; break; + case HardTrenn : c='-'; break; + case SoftTrennK : c='-'; break; + case SoftTrennAdd: c='-'; + } + } + return c; +} + +long ChgValue(long Def, long Min, long Max, UCHAR FlgVal, long NumVal) +{ + long r=0; + + if (FlgVal==EscDeflt) { + r=Def; // zurueck auf Default + } else { + if (NumVal!=EscNoVal) r=NumVal; // Hart setzen + } + + if (Min!=0 || Max!=0) { + if (r>Max) r=Max; + if (r<Min) r=Min; + } + return r; +} + + + +void ChgSchnittBit(sal_uInt16 Bit, sal_uInt16 Radio1, sal_uInt16 Radio2, sal_uInt16 Radio3, + UCHAR FlgVal, sal_uInt16 Schnitt0, sal_uInt16& Schnitt) +{ + sal_uInt16 All,Rad; + + Rad=Radio1 | Radio2 | Radio3; + All=Bit | Rad; + + switch (FlgVal) { + case EscSet : Schnitt=(Schnitt & ~All) | Bit; break; + case EscReset: Schnitt=(Schnitt & ~All); break; + case EscDeflt: Schnitt=(Schnitt & ~All) | (Schnitt0 & All); break; + case EscToggl: Schnitt=(Schnitt & ~Rad) ^ Bit; + } +} + + + +UCHAR GetNextChar(UCHAR* TBuf, sal_uInt16 Index) +{ + sal_uInt16 Cnt; + while (TBuf[Index]==Escape) { + Index++; + Cnt=0; + while (TBuf[Index]!=Escape && Cnt<=MaxEscLen) { + Index++; Cnt++; } + Index++; + } + return TBuf[Index]; +} + + + +UCHAR ProcessOne(UCHAR* TBuf, sal_uInt16& Index, + ObjTextType& Atr0, ObjTextType& AktAtr, + sal_Bool ScanEsc) +{ + UCHAR c; + UCHAR Ident; + sal_Bool Ende; + sal_Bool q; + UCHAR FlgVal; + long NumVal; + long Sgn; + short i; + sal_Bool EoVal; + + do { + c=TBuf[Index]; Index++; + Ende=(c!=Escape); + if (Ende==sal_False) { + c=TBuf[Index]; Index++; + Ident=c; // Identifer merken + FlgVal=EscNoFlg; + NumVal=EscNoVal; + c=TBuf[Index]; Index++; // Hier faengt der Wert an + if (c==EscSet || c==EscReset || c==EscDeflt || c==EscToggl) FlgVal=c; else { + if (c=='-') Sgn=-1; else Sgn=1; + if (c=='+' || c=='-') { c=TBuf[Index]; Index++; } + i=MaxEscValLen; + NumVal=0; + do { + NumVal=10*NumVal+c-'0'; + EoVal=(TBuf[Index]<'0' || TBuf[Index]>'9'); + if (EoVal==sal_False) { c=TBuf[Index]; Index++; } + i--; + } while (i>0 && EoVal==sal_False); + NumVal=Sgn*NumVal; + } + q=!CheckTextOutl(AktAtr.F,AktAtr.L); + + switch (Ident) { + case EscFont : AktAtr.SetFont(sal_uLong (ChgValue(Atr0.GetFont(),0,0 ,FlgVal,NumVal)));break; + case EscGrad : AktAtr.Grad =sal_uInt16(ChgValue(Atr0.Grad, 2,2000 ,FlgVal,NumVal)); break; + case EscBreit: AktAtr.Breite =sal_uInt16(ChgValue(Atr0.Breite, 1,1000 ,FlgVal,NumVal)); break; + case EscKaptS: AktAtr.Kapit =(sal_uInt8)(ChgValue(Atr0.Kapit, 1,255 ,FlgVal,NumVal)); break; + case EscLFeed: AktAtr.LnFeed =sal_uInt16(ChgValue(Atr0.LnFeed, 1,65535 ,FlgVal,NumVal)); break; + case EscSlant: AktAtr.Slant =sal_uInt16(ChgValue(Atr0.Slant, 1,MaxCharSlant ,FlgVal,NumVal)); break; + case EscVPos : AktAtr.ChrVPos=char (ChgValue(Atr0.ChrVPos,-128,127 ,FlgVal,NumVal)); break; + case EscZAbst: AktAtr.ZAbst =(sal_uInt8)(ChgValue(Atr0.ZAbst, 1,255 ,FlgVal,NumVal)); break; + case EscHJust: AktAtr.Justify=(sal_uInt8)(ChgValue(Atr0.Justify & 0x0F,0,5 ,FlgVal,NumVal)); break; + case EscFarbe: { AktAtr.L.LFarbe =(sal_uInt8)(ChgValue(Atr0.L.LFarbe,0,7 ,FlgVal,NumVal)); if (q) AktAtr.F.FFarbe =AktAtr.L.LFarbe; } break; + case EscBFarb: { AktAtr.L.LBFarbe=(sal_uInt8)(ChgValue(Atr0.L.LBFarbe,0,255,FlgVal,NumVal)); if (q) AktAtr.F.FBFarbe=AktAtr.L.LBFarbe; } break; + case EscInts : { AktAtr.L.LIntens=(sal_uInt8)(ChgValue(Atr0.L.LIntens,0,100,FlgVal,NumVal)); if (q) AktAtr.F.FIntens=AktAtr.L.LIntens; } break; + + case EscMustr: { AktAtr.F.FMuster=sal_uInt16(ChgValue(Atr0.F.FMuster,0,65535,FlgVal,NumVal)); } break; + case EscMFarb: { AktAtr.F.FFarbe =(sal_uInt8)(ChgValue(Atr0.F.FFarbe,0,7 ,FlgVal,NumVal)); } break; + case EscMBFrb: { AktAtr.F.FBFarbe=(sal_uInt8)(ChgValue(Atr0.F.FBFarbe,0,255,FlgVal,NumVal)); } break; + case EscMInts: { AktAtr.F.FIntens=(sal_uInt8)(ChgValue(Atr0.F.FIntens,0,100,FlgVal,NumVal)); } break; + + case EscSMstr: { AktAtr.ShdF.FMuster=sal_uInt16(ChgValue(Atr0.ShdF.FMuster,0,65535,FlgVal,NumVal)); } break; + case EscSFarb: { AktAtr.ShdL.LFarbe =(sal_uInt8)(ChgValue(Atr0.ShdL.LFarbe,0,7 ,FlgVal,NumVal)); AktAtr.ShdF.FFarbe =AktAtr.ShdL.LFarbe; } break; + case EscSBFrb: { AktAtr.ShdL.LBFarbe=(sal_uInt8)(ChgValue(Atr0.ShdL.LBFarbe,0,255,FlgVal,NumVal)); AktAtr.ShdF.FBFarbe=AktAtr.ShdL.LBFarbe; } break; + case EscSInts: { AktAtr.ShdL.LIntens=(sal_uInt8)(ChgValue(Atr0.ShdL.LIntens,0,100,FlgVal,NumVal)); AktAtr.ShdF.FIntens=AktAtr.ShdL.LIntens; } break; + case EscSDist: { AktAtr.ShdVers.x=(short)ChgValue(Atr0.ShdVers.x,0,30000,FlgVal,NumVal); AktAtr.ShdVers.y=AktAtr.ShdVers.x; } break; + case EscSXDst: { AktAtr.ShdVers.x=(short)ChgValue(Atr0.ShdVers.x,0,30000,FlgVal,NumVal); } break; + case EscSYDst: { AktAtr.ShdVers.y=(short)ChgValue(Atr0.ShdVers.y,0,30000,FlgVal,NumVal); } break; + + case EscBold : ChgSchnittBit(TextBoldBit,0,0,0 ,FlgVal,Atr0.Schnitt,AktAtr.Schnitt); break; + case EscRSlnt: ChgSchnittBit(TextRSlnBit,TextLSlnBit,0,0 ,FlgVal,Atr0.Schnitt,AktAtr.Schnitt); break; + case EscUndln: ChgSchnittBit(TextUndlBit,TextDbUnBit,0,0 ,FlgVal,Atr0.Schnitt,AktAtr.Schnitt); break; + case EscStrik: ChgSchnittBit(TextStrkBit,TextDbStBit,0,0 ,FlgVal,Atr0.Schnitt,AktAtr.Schnitt); break; + case EscDbUnd: ChgSchnittBit(TextDbUnBit,TextUndlBit,0,0 ,FlgVal,Atr0.Schnitt,AktAtr.Schnitt); break; + case EscDbStk: ChgSchnittBit(TextDbStBit,TextStrkBit,0,0 ,FlgVal,Atr0.Schnitt,AktAtr.Schnitt); break; + case EscSupSc: ChgSchnittBit(TextSupSBit,TextSubSBit,0,0 ,FlgVal,Atr0.Schnitt,AktAtr.Schnitt); break; + case EscSubSc: ChgSchnittBit(TextSubSBit,TextSupSBit,0,0 ,FlgVal,Atr0.Schnitt,AktAtr.Schnitt); break; + case EscKaptF: ChgSchnittBit(TextKaptBit,0,0,0 ,FlgVal,Atr0.Schnitt,AktAtr.Schnitt); break; + case EscLSlnt: ChgSchnittBit(TextLSlnBit,TextRSlnBit,0,0 ,FlgVal,Atr0.Schnitt,AktAtr.Schnitt); break; + case Esc2DShd: ChgSchnittBit(TextSh2DBit,TextSh3DBit,TextSh4DBit,TextShEbBit,FlgVal,Atr0.Schnitt,AktAtr.Schnitt); break; + case Esc3DShd: ChgSchnittBit(TextSh3DBit,TextSh2DBit,TextSh4DBit,TextShEbBit,FlgVal,Atr0.Schnitt,AktAtr.Schnitt); break; + case Esc4DShd: ChgSchnittBit(TextSh4DBit,TextSh2DBit,TextSh3DBit,TextShEbBit,FlgVal,Atr0.Schnitt,AktAtr.Schnitt); break; + case EscEbShd: ChgSchnittBit(TextShEbBit,TextSh2DBit,TextSh3DBit,TextSh4DBit,FlgVal,Atr0.Schnitt,AktAtr.Schnitt); break; + } //endcase + if (TBuf[Index]==Escape) Index++; // zweites Esc weglesen } + } // if Ende==sal_False + } while (Ende==sal_False && ScanEsc==sal_False); + if (Ende==sal_False) c=Escape; + return c; +} // end of ProcessOne + + +UCHAR GetTextChar(UCHAR* TBuf, sal_uInt16& Index, + ObjTextType& Atr0, ObjTextType& AktAtr, + sal_uInt16 Rest, sal_Bool ScanEsc) +{ + UCHAR c,c0,nc; + + c=ProcessOne(TBuf,Index,Atr0,AktAtr,ScanEsc); + if (ScanEsc==sal_False) { + if (c==SoftTrennAdd || c==SoftTrennK || c==SoftTrenn) { + nc=GetNextChar(TBuf,Index); + c0=c; + if (Rest==0 || Rest==DoTrenn || + nc==' ' || nc==AbsatzEnd || nc==TextEnd) c='-'; + else { + c=ProcessOne(TBuf,Index,Atr0,AktAtr,ScanEsc); // den Trenner ueberspringen + if (c0==SoftTrennAdd) { + if (c>=32) c=ProcessOne(TBuf,Index,Atr0,AktAtr,ScanEsc); // und hier noch 'nen Buchstaben ueberspringen + } + } + } + if ((Rest==1 || Rest==DoTrenn) && GetNextChar(TBuf,Index)==SoftTrennK) { + if (c=='c') c='k'; + else if (c=='C') c='K'; + } + } + return c; +} + + // HardSpace und HardTrenn muessen explizit konvertiert werden ! } + // if AktAtr.Schnitt and TextKaptBit =TextKaptBit then c:=UpCase(c);(explizit) } + + // Bei der Trennmethode SoftTrennAdd wird davon ausgegangen, dass der zu } + // trennende Konsonant bereits 3x mal im TextBuf vorhanden ist, z.b.: } + // "Schiff-fahrt". Wenn nicht getrennt, dann wird "-f" entfernt. } + + + +UCHAR GetTextCharConv(UCHAR* TBuf, sal_uInt16& Index, + ObjTextType& Atr0, ObjTextType& AktAtr, + sal_uInt16 Rest, sal_Bool ScanEsc) +{ + UCHAR c; + + c=GetTextChar(TBuf,Index,Atr0,AktAtr,Rest,ScanEsc); + if (c<32) { + switch (c) { + case HardSpace : c=' '; break; + case AbsatzEnd : c=' '; break; + case HardTrenn : c='-'; + } + } + return c; +} + + +// ====================================================================== +// Function GetLineFeed() +// +// Benoetigter Zeilenabstand in SGF-Units. ChrVPos wird beruecksichtigt. +// ====================================================================== +sal_uInt16 GetLineFeed(UCHAR* TBuf, sal_uInt16 Index, ObjTextType Atr0, ObjTextType AktAtr, + sal_uInt16 nChar, sal_uInt16& LF, sal_uInt16& MaxGrad) +{ + UCHAR c=0; + sal_Bool AbsEnd=sal_False; + sal_uLong LF100=0; + sal_uLong MaxLF100=0; + sal_Bool LFauto=0; + sal_Bool First=sal_True; + sal_uInt16 Grad; + sal_uInt16 i=0; + sal_uInt16 r=1; + + MaxGrad=0; + while (!AbsEnd && nChar>0) { + nChar--; + c=GetTextChar(TBuf,Index,Atr0,AktAtr,nChar,sal_False); + i++; + AbsEnd=(c==TextEnd || c==AbsatzEnd); + if (First || (!AbsEnd && c!=' ' && c!=HardTrenn)) { + LFauto=(AktAtr.LnFeed & 0x8000)==0; + LF100=AktAtr.LnFeed & 0x7FFF; + if (LFauto) LF100=LF100*AktAtr.Grad; else LF100*=LF100; + if (AktAtr.ChrVPos>0) LF100-=AktAtr.ChrVPos*100; + if (LF100>MaxLF100) MaxLF100=LF100; + Grad=AktAtr.Grad; + if (AktAtr.ChrVPos>0) Grad=Grad-AktAtr.ChrVPos; + if (Grad>MaxGrad) MaxGrad=Grad; + First=sal_False; + } + if (!AbsEnd && c!=' ') r=i; + } + MaxGrad=hPoint2Sgf(MaxGrad); + if (MaxLF100<=4000) { // sonst Overflowgefahr + LF=sal_uInt16(hPoint2Sgf(short(MaxLF100)) /100); + } else { + LF=sal_uInt16(hPoint2Sgf(short(MaxLF100) /100)); + } + + return r; +} + +// End of AbsRead.Pas +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// + + + +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +// iFont.Pas + +#define DefaultSlant 1500 /* Default: Italic ist 15deg */ +#define SuperSubFact 60 /* SuperScript/SubScript: 60% vom Schriftgrad */ +#define DefaultSpace 40 /* Default: Space ist 40% vom SchriftGrad */ + +sal_uInt16 SetTextContext(OutputDevice& rOut, ObjTextType& Atr, sal_Bool Kapt, sal_uInt16 Dreh, + sal_uInt16 FitXMul, sal_uInt16 FitXDiv, sal_uInt16 FitYMul, sal_uInt16 FitYDiv) +{ + SgfFontOne* pSgfFont; // Font aus dem IniFile + Font aFont; + Color aColor; + sal_uLong Grad; + sal_uLong Brei; + String FNam; + sal_uInt16 StdBrei=50; // Durchschnittliche Zeichenbreite in % von Schriftgrad + sal_Bool bFit=(FitXMul!=1 || FitXDiv!=1 || FitYMul!=1 || FitYDiv!=1); + + pSgfFont = pSgfFonts->GetFontDesc(Atr.GetFont()); + + if ( pSgfFont!=NULL ) + { + FNam =pSgfFont->SVFName; + StdBrei=pSgfFont->SVWidth; + if (pSgfFont->Fixd) aFont.SetPitch(PITCH_FIXED); else aFont.SetPitch(PITCH_VARIABLE); + aFont.SetFamily(pSgfFont->SVFamil); + aFont.SetCharSet(pSgfFont->SVChSet); + aFont.SetName(FNam); + } + else + { // Falls nich im Inifile, sind hier einige Fonts hart kodiert + aFont.SetPitch(PITCH_VARIABLE); + switch (Atr.GetFont()) { + case 92500: case 92501: case 92504: case 92505: + { +#if defined(WNT) + FNam=rtl::OUString("Times New Roman"); // CG Times ist unter Windows Times New Roman +#else + FNam=rtl::OUString("Times"); // ansonsten ist das einfach Times +#endif + StdBrei=40; + aFont.SetFamily(FAMILY_ROMAN); + } break; + case 94021: case 94022: case 94023: case 94024: { +#if defined(WNT) + FNam=rtl::OUString("Arial"); // Univers ist unter Windows Arial +#else + FNam=rtl::OUString("Helvetica"); // und ansonsten Helvetica +#endif + aFont.SetFamily(FAMILY_SWISS); + StdBrei=47; + } break; + case 93950: case 93951: case 93952: case 93953: { +#if defined(WNT) + FNam=rtl::OUString("Courier New"); // Der Vector-Courierfont unter Windows heisst Courier New +#else + FNam=rtl::OUString("Courier"); // ansonsten ist und bleibt Courier immer Courier +#endif + aFont.SetFamily(FAMILY_ROMAN); + aFont.SetPitch(PITCH_FIXED); + } break; + default: FNam = rtl::OUString("Helvetica"); + } + aFont.SetName(FNam); + //aFont.SetCharSet(CHARSET_SYSTEM); + } + + Grad=sal_uLong(Atr.Grad); + if ((Atr.Schnitt & TextKaptBit) !=0 && Kapt) Grad=Grad*sal_uLong(Atr.Kapit)/100; + if ((Atr.Schnitt & TextSupSBit) !=0 || (Atr.Schnitt & TextSubSBit) !=0) Grad=Grad*SuperSubFact/100; + Brei=Grad; + if (Atr.Breite!=100 || bFit) { + if (bFit) { + Grad=Grad*sal_uLong(FitYMul)/sal_uLong(FitYDiv); + Brei=Brei*sal_uLong(FitXMul)/sal_uLong(FitXDiv); + } + Brei=Brei*sal_uLong(Atr.Breite)/100; + Brei=Brei*sal_uLong(StdBrei)/100; + aFont.SetSize(Size(hPoint2Sgf(sal_uInt16(Brei)),hPoint2Sgf(sal_uInt16(Grad)))); + } else { + aFont.SetSize(Size(0,hPoint2Sgf(sal_uInt16(Grad)))); + } + + aColor=Sgv2SvFarbe(Atr.L.LFarbe,Atr.L.LBFarbe,Atr.L.LIntens); aFont.SetColor(aColor); + aColor=Sgv2SvFarbe(Atr.F.FFarbe,Atr.F.FBFarbe,Atr.F.FIntens); aFont.SetFillColor(aColor); + aFont.SetTransparent(sal_True); + aFont.SetAlign(ALIGN_BASELINE); + + Dreh/=10; Dreh=3600-Dreh; if (Dreh==3600) Dreh=0; + aFont.SetOrientation(Dreh); + + if ((Atr.Schnitt & TextBoldBit) !=0) aFont.SetWeight(WEIGHT_BOLD); + if ((Atr.Schnitt & TextRSlnBit) !=0) aFont.SetItalic(ITALIC_NORMAL); + if ((Atr.Schnitt & TextUndlBit) !=0) aFont.SetUnderline(UNDERLINE_SINGLE); + if ((Atr.Schnitt & TextDbUnBit) !=0) aFont.SetUnderline(UNDERLINE_DOUBLE); + if ((Atr.Schnitt & TextStrkBit) !=0) aFont.SetStrikeout(STRIKEOUT_SINGLE); + if ((Atr.Schnitt & TextDbStBit) !=0) aFont.SetStrikeout(STRIKEOUT_DOUBLE); + if ((Atr.Schnitt & TextSh2DBit) !=0) aFont.SetShadow(sal_True); + if ((Atr.Schnitt & TextSh3DBit) !=0) aFont.SetShadow(sal_True); + if ((Atr.Schnitt & TextSh4DBit) !=0) aFont.SetShadow(sal_True); + if ((Atr.Schnitt & TextShEbBit) !=0) aFont.SetShadow(sal_True); + if (CheckTextOutl(Atr.F,Atr.L)) aFont.SetOutline(sal_True); + + if (aFont!=rOut.GetFont()) rOut.SetFont(aFont); + + return 0; +} + +// iFont.Pas +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +// Absatz.Pas + +struct ProcChrSta { + sal_uInt16 Index; + sal_uInt16 ChrXP; + UCHAR OutCh; + sal_Bool Kapt; + ObjTextType Attrib; +}; + +void InitProcessCharState(ProcChrSta& State, ObjTextType& AktAtr, sal_uInt16 IndexA) +{ + State.Attrib=AktAtr; + State.OutCh=0; + State.Index=IndexA; + State.ChrXP=0; + State.Kapt=sal_False; +} + +sal_Bool UpcasePossible(UCHAR c) +{ + if ((c>='a' && c<='z') || c == 0xe4 || c == 0xf6 || c == 0xfc ) return sal_True; + else return sal_False; +} + +UCHAR Upcase(UCHAR c) +{ + if ((c>=(UCHAR)'a' && c<=(UCHAR)'z')) c=(c-(UCHAR)'a')+(UCHAR)'A'; + else if ( c == 0xe4 ) c = 0xc4; + else if ( c == 0xf6 ) c = 0xd6; + else if ( c == 0xfc ) c = 0xdc; + return c; +} + +sal_uInt16 GetCharWidth(OutputDevice& rOut, UCHAR c) +{ + sal_uInt16 ChrWidth; + + if (c==' ') + { + ChrWidth=(sal_uInt16)rOut.GetTextWidth( rtl::OUString('A') ); + if (rOut.GetFont().GetPitch()!=PITCH_FIXED) { + ChrWidth=MulDiv(ChrWidth,DefaultSpace,100); + } + } + else + { + // with MaxChar == 255 c cannot be greater than MaxChar + // assert if MaxChar is ever changed + OSL_ENSURE( MaxChar == 255, "MaxChar not 255" ); + OSL_ENSURE(sizeof(UCHAR) == 1, "should be 1"); + if (c>=MinChar /*&& c<=MaxChar*/) + { + ChrWidth=(sal_uInt16)rOut.GetTextWidth(rtl::OUString(reinterpret_cast<sal_Char*>(&c), 1, RTL_TEXTENCODING_IBM_437)); + } + else + { + ChrWidth=(sal_uInt16)rOut.GetTextWidth(rtl::OUString(static_cast<sal_Unicode>('A'))); + } + } + return ChrWidth; +} + +UCHAR ProcessChar(OutputDevice& rOut, UCHAR* TBuf, ProcChrSta& R, ObjTextType& Atr0, + sal_uInt16& nChars, sal_uInt16 Rest, + short* Line, UCHAR* cLine) +{ + sal_uInt16 KernDist=0; // Wert fuer Kerning + sal_uInt16 ChrWidth; + UCHAR c; + UCHAR c1; + sal_Bool AbsEnd; + + c=GetTextChar(TBuf,R.Index,Atr0,R.Attrib,Rest,sal_False); // versucht evtl. zu trennen, wenn Rest entsprechenden Wert besitzt + + AbsEnd=(c==AbsatzEnd || c==TextEnd); + if (AbsEnd==sal_False) { + R.OutCh=ConvertTextChar(c); // von HardTrenn nach '-', ... + R.Kapt=(R.Attrib.Schnitt & TextKaptBit) !=0 && UpcasePossible(R.OutCh); + if (R.Kapt) R.OutCh=Upcase(R.OutCh); + SetTextContext(rOut,R.Attrib,R.Kapt,0,1,1,1,1); + + if (R.Kapt) c1=Upcase(c); else c1=c; + ChrWidth=GetCharWidth(rOut,c1); + + if (R.Attrib.ZAbst!=100) { // Spezial-Zeichenabstand ? + sal_uLong Temp; + Temp=sal_uLong(ChrWidth)*sal_uLong(R.Attrib.ZAbst)/100; + ChrWidth=sal_uInt16(Temp); + } + nChars++; + if (R.ChrXP>32000) R.ChrXP=32000; + Line[nChars]=R.ChrXP-KernDist; + cLine[nChars]=c; + R.ChrXP+=ChrWidth-KernDist; // Position fuer den naechsten Character + } + return c; +} + +void FormatLine(UCHAR* TBuf, sal_uInt16& Index, ObjTextType& Atr0, ObjTextType& AktAtr, + sal_uInt16 UmbWdt, sal_uInt16 AdjWdt, + short* Line, sal_uInt16& nChars, + double, double, + UCHAR* cLine, sal_Bool TextFit) +{ + VirtualDevice vOut; + UCHAR c,c0; + UCHAR ct; + sal_Bool First; // erster Char ? + sal_uInt8 Just = 0; // Absatzformatierung + sal_Bool Border; // Rand der Box erreicht ? + sal_Bool Border0; + sal_Bool AbsEnd; // Ende des Absatzes erreicht ? + ProcChrSta* R=new ProcChrSta; + ProcChrSta* R0=new ProcChrSta; + ProcChrSta* WErec=new ProcChrSta; + sal_uInt16 WEnChar; + ProcChrSta* WErec0=new ProcChrSta; + sal_uInt16 WEnChar0; + ProcChrSta* TRrec=new ProcChrSta; + sal_uInt16 TRnChar; + + sal_uInt16 WordEndCnt; // Justieren und Trennen + sal_Bool WordEnd; + sal_Bool Trenn; + + short BoxRest; // zum Quetschen und formatieren + sal_uInt16 i,j,k,h; + sal_uInt16 re,li; + + vOut.SetMapMode(MapMode(MAP_10TH_MM,Point(),Fraction(1,4),Fraction(1,4))); + + nChars=0; + SetTextContext(vOut,AktAtr,sal_False,0,1,1,1,1); + InitProcessCharState(*R,AktAtr,Index); + (*R0)=(*R); (*WErec)=(*R); WEnChar=0; c0=0; Border0=sal_False; + Border=sal_False; First=sal_True; + WordEndCnt=0; + + do { // mal schauen, wieviele Worte so in die Zeile passen + if (Border) c=ProcessChar(vOut,TBuf,*R,Atr0,nChars,DoTrenn,Line,cLine); + else c=ProcessChar(vOut,TBuf,*R,Atr0,nChars,NoTrenn,Line,cLine); + AbsEnd=(c==AbsatzEnd || c==TextEnd); + //if not AbsEnd then + { + if (First) { + Just=R->Attrib.Justify & 0x0F; // Absatzformat steht wenn, dann am Anfang + } + Border=R->ChrXP>UmbWdt; + WordEnd=(AbsEnd || (c==' ')) && (c0!=' ') && (c0!=0); + Trenn=c=='-'; + if (WordEnd && !Border0) { + WordEndCnt++; + (*WErec)=(*R0); + WEnChar=nChars-1; + } + if (Trenn && !Border) { + WordEndCnt++; + (*WErec)=(*R); + WEnChar=nChars; + } + } + (*R0)=(*R); c0=c; + Border0=Border; + First=sal_False; + AbsEnd=AbsEnd || (nChars>=MaxLineChars); + } while (!(AbsEnd || (Border && ((WordEndCnt>0) || WordEnd || Trenn)))); + + if (Border) { // Trennen und Quetschen + (*WErec0)=(*WErec); WEnChar0=WEnChar; + AbsEnd=sal_False; c0=0; + (*R)=(*WErec); nChars=WEnChar; + (*TRrec)=(*R); TRnChar=nChars; + Border0=sal_False; Border=sal_False; + do { // erst mal gucken wieviele Silben noch reinpassen + ct=ProcessChar(vOut,TBuf,*TRrec,Atr0,TRnChar,DoTrenn,Line,cLine); + c=ProcessChar(vOut,TBuf,*R,Atr0,nChars,NoTrenn,Line,cLine); + AbsEnd=(ct==AbsatzEnd) || (ct==TextEnd) || (nChars>=MaxLineChars); + + Border=TRrec->ChrXP>UmbWdt; + WordEnd=AbsEnd || ((AbsEnd || (c==' ')) && (c0!=' ') && (c0!=0)); + Trenn=ct=='-'; + if (WordEnd && (!Border0 || (WordEndCnt==0))) { + WordEndCnt++; + (*WErec)=(*R0); + if (AbsEnd) WEnChar=nChars; else WEnChar=nChars-1; + (*TRrec)=(*R); TRnChar=nChars; // zum weitersuchen + } + if (Trenn && (!Border || (WordEndCnt==0))) { + WordEndCnt++; // merken, dass man hier trennen kann + (*WErec)=(*TRrec); + WEnChar=TRnChar; + (*TRrec)=(*R); TRnChar=nChars; // zum weitersuchen + } + (*R0)=(*R); c0=c; + Border0=Border; + Border=R->ChrXP>UmbWdt; + } while (!(AbsEnd || (Border && ((WordEndCnt>0) || WordEnd || Trenn)))); + + while (WErec0->Index<WErec->Index) { // damit Line[] auch garantiert stimmt } + c=ProcessChar(vOut,TBuf,*WErec0,Atr0,WEnChar0,WEnChar-WEnChar0-1,Line,cLine); + } + + (*R)=(*WErec); nChars=WEnChar; + + if (UmbWdt>=R->ChrXP) { + BoxRest=UmbWdt-R->ChrXP; + } else { // Zusammenquetschen + BoxRest=R->ChrXP-UmbWdt; // um soviel muss gequetscht werden + for (i=2;i<=nChars;i++) { // 1. CharPosition bleibt ! + Line[i]-=(i-1)*(BoxRest) /(nChars-1); + } + R->ChrXP=UmbWdt; + Line[nChars+1]=UmbWdt; + } + } + + if (!AbsEnd) { + do { // Leerzeichen weglesen + (*WErec)=(*R); + c=GetTextChar(TBuf,R->Index,Atr0,R->Attrib,NoTrenn,sal_False); + nChars++; + Line[nChars]=R->ChrXP; + cLine[nChars]=c; + } while (c==' '); + if (c!=' ' && c!=AbsatzEnd && c!=TextEnd) { + nChars--; + (*R)=(*WErec); + } + } + + if (AbsEnd && nChars<MaxLineChars) { // Ausrichten, statt Blocksatz aber linksbuendig + if (Just==3) Just=0; + nChars++; Line[nChars]=R->ChrXP; // Damit AbsatzEnde auch weggelesen wird + Line[nChars+1]=R->ChrXP; // denn die Breite von CR oder #0 ist nun mal sehr klein + if (TBuf[R->Index-1]!=AbsatzEnd && TBuf[R->Index-1]!=TextEnd) { + c=GetTextChar(TBuf,R->Index,Atr0,R->Attrib,NoTrenn,sal_False); // Kleine Korrektur. Notig, wenn nur 1 Wort in + } + } + + BoxRest=AdjWdt-R->ChrXP; + if (TextFit) Just=THJustLeft; + + switch (Just) { + case THJustLeft: break; // Links + case THJustCenter: { + BoxRest=BoxRest /2; // Mitte + for (i=1;i<=nChars;i++) Line[i]=Line[i]+BoxRest; + } break; + case THJustRight: { // Rechts + for (i=1;i<=nChars;i++) Line[i]=Line[i]+BoxRest; + } break; + case THJustDrvOut: + case THJustBlock: { // Block und Austreibend + re=nChars; + if (Just==THJustDrvOut) re--; + while (re>=1 && (cLine[re]==' ' || cLine[re]==TextEnd || cLine[re]==AbsatzEnd)) re--; + li=1; + while (li<=re && (cLine[li]==' ' || cLine[li]==TextEnd || cLine[li]==AbsatzEnd)) li++; + if (Just==THJustDrvOut) BoxRest=AdjWdt-Line[re+1]; + + j=0; // Anzahl der Spaces ermitteln + for (i=li;i<=re;i++) { + if (cLine[i]==' ') { + j++; + } + } + + if (j==0) { // nur 1 Wort ? -> Strecken ! + for (i=li+1;i<=re;i++) { // von links nach rechts + Line[i]=Line[i]+MulDiv(i-li,BoxRest,re-li+1-1); + } + } else { + k=0; h=0; + for (i=li;i<=re;i++) { // j Spaces aufbohren ! + if (cLine[i]==' ') { // Space gefunden ! + k++; + h=MulDiv(k,BoxRest,j); + } + Line[i]=Line[i]+h; + } + } + for (i=re+1;i<=nChars;i++) Line[i]=Line[i]+BoxRest; // und den Rest anpassen + Line[nChars+1]=AdjWdt; + } break; + case THJustLocked: { //Gesperrt + re=nChars-1; + while (re>=1 && (cLine[re]==' ' || cLine[re]==TextEnd || cLine[re]==AbsatzEnd)) re--; + li=1; + while (li<=re && (cLine[li]==' ' || cLine[li]==TextEnd || cLine[li]==AbsatzEnd)) li++; + BoxRest=AdjWdt-Line[re+1]; + for (i=li+1;i<=re;i++) { // Strecken von links nach rechts + Line[i]=Line[i]+MulDiv(i-li,BoxRest,re-li+1-1); + } + for (i=re+1;i<=nChars;i++) Line[i]=Line[i]+BoxRest; // und den Rest anpassen + Line[nChars+1]=AdjWdt; + } break; + } + Index=R->Index; + AktAtr=R->Attrib; + delete R; + delete R0; + delete WErec; + delete WErec0; + delete TRrec; +} + + + +// End of Absatz.Pas +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +// DrawText.Pas + +void DrawChar(OutputDevice& rOut, UCHAR c, ObjTextType T, PointType Pos, sal_uInt16 DrehWink, + sal_uInt16 FitXMul, sal_uInt16 FitXDiv, sal_uInt16 FitYMul, sal_uInt16 FitYDiv) +{ + SetTextContext(rOut,T,UpcasePossible(c),DrehWink,FitXMul,FitXDiv,FitYMul,FitYDiv); + if ((T.Schnitt & TextKaptBit)!=0 && UpcasePossible(c)) c=Upcase(c); + rtl::OUString s(reinterpret_cast<const sal_Char*>(&c), 1, + RTL_TEXTENCODING_IBM_437); + rOut.DrawText( Point( Pos.x, Pos.y ), s ); +} + +/************************************************************************* +|* +|* TextType::Draw() +|* +*************************************************************************/ +void TextType::Draw(OutputDevice& rOut) +{ + if ((Flags & TextOutlBit)!=0) return; // Sourcetext fuer Outliner !! + + ObjTextType T1,T2; + sal_uInt16 Index1; + sal_uInt16 Index2; + UCHAR c = TextEnd; + sal_uInt16 l; // Anzahl der Zeichen in der Zeile + sal_uInt16 i; + short yPos0; + short xPos; + short yPos; + sal_uInt16 LF; + sal_uInt16 MaxGrad; + short xSize; + short xSAdj; + short ySize; + double sn,cs; + sal_uInt16 TopToBase; + sal_Bool Ende = 0; + sal_uInt16 lc; + sal_Bool LineFit; // FitSize.x=0? oder Flags -> jede Zeile stretchen + sal_Bool TextFit; + short* xLine; + UCHAR* cLine; // Buffer fuer FormatLine + sal_uInt16 FitXMul; + sal_uInt16 FitXDiv; + sal_uInt16 FitYMul; + sal_uInt16 FitYDiv; + sal_Bool Fehler; + UCHAR* Buf=Buffer; // Zeiger auf die Buchstaben + + pSgfFonts->ReadList(); + xLine=new short[ChrXPosArrSize]; + cLine=new UCHAR[CharLineSize]; + + TextFit=(Flags & TextFitBits)!=0; + LineFit=sal_False; + LineFit=((Flags & TextFitZBit)!=0); + if (TextFit && FitSize.x==0) LineFit=sal_True; + + if (DrehWink==0) { + sn=0.0; + cs=1.0; + } else { + sn=sin(double(DrehWink)*3.14159265359/18000); + cs=cos(double(DrehWink)*3.14159265359/18000); + } + + T1=T; Index1=0; yPos=0; xPos=0; + if (TextFit) { + ySize=Pos2.y-Pos1.y; + xSize=32000 /2; // Umbruch + xSAdj=Pos2.x-Pos1.x; // zum Ausrichten bei Zentriert/Blocksatz + //if (xSize<=0) { xSize=32000 /2; LineFit=sal_True; } + FitXMul=sal::static_int_cast< sal_uInt16 >(abs(Pos2.x-Pos1.x)); FitXDiv=FitSize.x; if (FitXDiv==0) FitXDiv=1; + FitYMul=sal::static_int_cast< sal_uInt16 >(abs(Pos2.y-Pos1.y)); FitYDiv=FitSize.y; if (FitYDiv==0) FitYDiv=1; + } else { + xSize=Pos2.x-Pos1.x; + xSAdj=xSize; + ySize=Pos2.y-Pos1.y; + FitXMul=1; FitXDiv=1; + FitYMul=1; FitYDiv=1; + } + if (xSize<0) xSize=0; + if (xSAdj<0) xSAdj=0; + + do { + T2=T1; Index2=Index1; + FormatLine(Buf,Index2,T,T2,xSize,xSAdj,xLine,l,sn,cs,cLine,LineFit); + Fehler=(Index2==Index1); + if (!Fehler) { + lc=GetLineFeed(Buf,Index1,T,T1,l,LF,MaxGrad); + if (TextFit) { + if (LineFit) FitXDiv=xLine[lc+1]; + if (FitXDiv>0) { + long Temp; + for (i=1;i<=l+1;i++) { + Temp=long(xLine[i])*long(FitXMul) /long(FitXDiv); + xLine[i]=short(Temp); + } + LF=MulDiv(LF,FitYMul,FitYDiv); + MaxGrad=MulDiv(MaxGrad,FitYMul,FitYDiv); + } else { + FitXDiv=1; // 0 gibts nicht + } + } + yPos0=yPos; + TopToBase=GetTopToBaseLine(MaxGrad); + yPos=yPos+TopToBase; + Ende=(yPos0+short(MulDiv(MaxGrad,CharTopToBtm,100))>ySize) && !TextFit; + if (!Ende) { + T2=T1; Index2=Index1; + i=1; + while (i<=l) { + c=GetTextCharConv(Buf,Index2,T,T2,l-i,sal_False); + long xp1,yp1; // wegen Overflowgefahr + PointType Pos; + xp1=long(Pos1.x)+xPos+long(xLine[i]); + yp1=long(Pos1.y)+yPos; + if (xp1>32000) xp1=32000; if (xp1<-12000) xp1=-12000; + if (yp1>32000) yp1=32000; if (yp1<-12000) yp1=-12000; + Pos.x=short(xp1); + Pos.y=short(yp1); + + if (DrehWink!=0) RotatePoint(Pos,Pos1.x,Pos1.y,sn,cs); + DrawChar(rOut,c,T2,Pos,DrehWink,FitXMul,FitXDiv,FitYMul,FitYDiv); + i++; + } // while i<=l + yPos=yPos0+LF; + T1=T2; Index1=Index2; // Fuer die naechste Zeile + } // if ObjMin.y+yPos<=Obj_Max.y + } // if !Fehler + } while (c!=TextEnd && !Ende && !Fehler); + delete[] cLine; + delete[] xLine; +} + +// End of DrawText.Pas +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// + +// nicht mehr benoetigt, da der Pointer nun extra gefuehrt wird +// (DEC Alpha hat naemlich 64Bit-Pointer!) +//UCHAR* TextType::GetBufPtr() +//{ +// sal_uLong Temp; +// Temp=sal_uLong(BufLo)+0x00010000*sal_uLong(BufHi); +// return (UCHAR*)Temp; +//} +// +//void TextType::SetBufPtr(UCHAR* Ptr) +//{ +// sal_uLong Temp=(sal_uLong)Ptr; +// BufLo=sal_uInt16(Temp & 0x0000FFFF); +// BufHi=sal_uInt16((Temp & 0xFFFF0000)>>16); +//} + +sal_uInt32 ObjTextType::GetFont() +{ + return sal_uLong(FontLo)+0x00010000*sal_uLong(FontHi); +} + +void ObjTextType::SetFont(sal_uInt32 FontID) +{ + FontLo=sal_uInt16(FontID & 0x0000FFFF); + FontHi=sal_uInt16((FontID & 0xFFFF0000)>>16); +} + + +///////////////////////////////////////////////////////////////////////////////// +// SGF.Ini lesen //////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////// +SgfFontOne::SgfFontOne() +{ + Next=NULL; + IFID=0; + Bold=sal_False; + Ital=sal_False; + Sans=sal_False; + Serf=sal_False; + Fixd=sal_False; + SVFamil=FAMILY_DONTKNOW; + SVChSet=RTL_TEXTENCODING_DONTKNOW; + SVWidth=40; +} + +void SgfFontOne::ReadOne( const rtl::OString& rID, rtl::OString& Dsc ) +{ + if ( Dsc.getLength() < 4 || ( Dsc[0] != '(' ) ) + return; + sal_Int32 i=1; // Erster Buchstabe des IF-Fontnamen. Davor ist eine '(' + while ( i < Dsc.getLength() && ( Dsc[i] !=')' ) ) + i++; + Dsc = Dsc.copy(i+1); // IF-Fontname loeschen inkl. () + + if ( Dsc.getLength() < 2 || ( Dsc[Dsc.getLength() - 1] !=')' ) ) + return; + i=Dsc.getLength()-2; // hier ist die ')' des SV-Fontnames + sal_Int32 j=0; + while ( i > 0 && ( Dsc[i] != '(' ) ) + { + i--; + j++; + } + SVFName = rtl::OStringToOUString(Dsc.copy(i+1,j), RTL_TEXTENCODING_IBM_437); // SV-Fontname rausholen + Dsc = rtl::OStringBuffer(Dsc).remove(i,j).makeStringAndClear(); + + IFID = (sal_uInt32)rID.toInt32(); + sal_Int32 nTokenCount = comphelper::string::getTokenCount(Dsc, ' '); + for (sal_Int32 nIdx = 0; nIdx < nTokenCount; ++nIdx) + { + rtl::OString s(Dsc.getToken(nIdx, ' ')); + if (!s.isEmpty()) + { + s = s.toAsciiUpperCase(); + if (s.matchL(RTL_CONSTASCII_STRINGPARAM("BOLD"))) Bold=sal_True; + else if (s.matchL(RTL_CONSTASCII_STRINGPARAM("ITAL"))) Ital=sal_True; + else if (s.matchL(RTL_CONSTASCII_STRINGPARAM("SERF"))) Serf=sal_True; + else if (s.matchL(RTL_CONSTASCII_STRINGPARAM("SANS"))) Sans=sal_True; + else if (s.matchL(RTL_CONSTASCII_STRINGPARAM("FIXD"))) Fixd=sal_True; + else if (s.matchL(RTL_CONSTASCII_STRINGPARAM("ROMAN"))) SVFamil=FAMILY_ROMAN; + else if (s.matchL(RTL_CONSTASCII_STRINGPARAM("SWISS"))) SVFamil=FAMILY_SWISS; + else if (s.matchL(RTL_CONSTASCII_STRINGPARAM("MODERN"))) SVFamil=FAMILY_MODERN; + else if (s.matchL(RTL_CONSTASCII_STRINGPARAM("SCRIPT"))) SVFamil=FAMILY_SCRIPT; + else if (s.matchL(RTL_CONSTASCII_STRINGPARAM("DECORA"))) SVFamil=FAMILY_DECORATIVE; + else if (s.matchL(RTL_CONSTASCII_STRINGPARAM("ANSI"))) SVChSet=RTL_TEXTENCODING_MS_1252; + else if (s.matchL(RTL_CONSTASCII_STRINGPARAM("IBMPC"))) SVChSet=RTL_TEXTENCODING_IBM_850; + else if (s.matchL(RTL_CONSTASCII_STRINGPARAM("MAC"))) SVChSet=RTL_TEXTENCODING_APPLE_ROMAN; + else if (s.matchL(RTL_CONSTASCII_STRINGPARAM("SYMBOL"))) SVChSet=RTL_TEXTENCODING_SYMBOL; + else if (s.matchL(RTL_CONSTASCII_STRINGPARAM("SYSTEM"))) SVChSet = osl_getThreadTextEncoding(); + else if (comphelper::string::isdigitAsciiString(s) ) SVWidth=sal::static_int_cast< sal_uInt16 >(s.toInt32()); + } + } +} + +///////////////////////////////////////////////////////////////////////////////// + +SgfFontLst::SgfFontLst() +{ + pList=NULL; + Last=NULL; + LastID=0; + LastLn=NULL; + Tried=sal_False; +} + +SgfFontLst::~SgfFontLst() +{ + RausList(); +} + +void SgfFontLst::RausList() +{ + SgfFontOne* P; + SgfFontOne* P1; + P=pList; + while (P!=NULL) { + P1=P->Next; + delete P; + P=P1; + } + pList=NULL; + Last=NULL; + Tried=sal_False; + LastID=0; + LastLn=NULL; +} + +void SgfFontLst::AssignFN(const String& rFName) +{ FNam=rFName; } + +void SgfFontLst::ReadList() +{ + if (!Tried) + { + Tried=sal_True; + LastID=0; + LastLn=NULL; + SgfFontOne* P,P1; + Config aCfg(FNam); + aCfg.SetGroup("SGV Fonts fuer StarView"); + sal_uInt16 Anz=aCfg.GetKeyCount(); + sal_uInt16 i; + rtl::OString FID; + rtl::OString Dsc; + + for (i=0;i<Anz;i++) + { + FID = comphelper::string::remove(aCfg.GetKeyName(i), ' '); + Dsc = aCfg.ReadKey( i ); + if (comphelper::string::isdigitAsciiString(FID)) + { + P=new SgfFontOne; // neuer Eintrag + if (Last!=NULL) Last->Next=P; else pList=P; Last=P; // einklinken + P->ReadOne(FID,Dsc); // und Zeile interpretieren + } + } + } +} + +SgfFontOne* SgfFontLst::GetFontDesc(sal_uInt32 ID) +{ + if (ID!=LastID) { + SgfFontOne* P; + P=pList; + while (P!=NULL && P->IFID!=ID) P=P->Next; + LastID=ID; + LastLn=P; + } + return LastLn; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/emfwr.cxx b/vcl/source/filter/wmf/emfwr.cxx new file mode 100644 index 000000000000..bb2f2404c27d --- /dev/null +++ b/vcl/source/filter/wmf/emfwr.cxx @@ -0,0 +1,1625 @@ +/* -*- 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 "emfwr.hxx" +#include <rtl/strbuf.hxx> +#include <tools/helpers.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <vcl/lineinfo.hxx> + +// ----------- +// - Defines - +// ----------- + +#define WIN_EMR_HEADER 1 +#define WIN_EMR_POLYBEZIER 2 +#define WIN_EMR_POLYGON 3 +#define WIN_EMR_POLYLINE 4 +#define WIN_EMR_POLYBEZIERTO 5 +#define WIN_EMR_POLYLINETO 6 +#define WIN_EMR_POLYPOLYLINE 7 +#define WIN_EMR_POLYPOLYGON 8 +#define WIN_EMR_SETWINDOWEXTEX 9 +#define WIN_EMR_SETWINDOWORGEX 10 +#define WIN_EMR_SETVIEWPORTEXTEX 11 +#define WIN_EMR_SETVIEWPORTORGEX 12 +#define WIN_EMR_SETBRUSHORGEX 13 +#define WIN_EMR_EOF 14 +#define WIN_EMR_SETPIXELV 15 +#define WIN_EMR_SETMAPPERFLAGS 16 +#define WIN_EMR_SETMAPMODE 17 +#define WIN_EMR_SETBKMODE 18 +#define WIN_EMR_SETPOLYFILLMODE 19 +#define WIN_EMR_SETROP2 20 +#define WIN_EMR_SETSTRETCHBLTMODE 21 +#define WIN_EMR_SETTEXTALIGN 22 +#define WIN_EMR_SETCOLORADJUSTMENT 23 +#define WIN_EMR_SETTEXTCOLOR 24 +#define WIN_EMR_SETBKCOLOR 25 +#define WIN_EMR_OFFSETCLIPRGN 26 +#define WIN_EMR_MOVETOEX 27 +#define WIN_EMR_SETMETARGN 28 +#define WIN_EMR_EXCLUDECLIPRECT 29 +#define WIN_EMR_INTERSECTCLIPRECT 30 +#define WIN_EMR_SCALEVIEWPORTEXTEX 31 +#define WIN_EMR_SCALEWINDOWEXTEX 32 +#define WIN_EMR_SAVEDC 33 +#define WIN_EMR_RESTOREDC 34 +#define WIN_EMR_SETWORLDTRANSFORM 35 +#define WIN_EMR_MODIFYWORLDTRANSFORM 36 +#define WIN_EMR_SELECTOBJECT 37 +#define WIN_EMR_CREATEPEN 38 +#define WIN_EMR_CREATEBRUSHINDIRECT 39 +#define WIN_EMR_DELETEOBJECT 40 +#define WIN_EMR_ANGLEARC 41 +#define WIN_EMR_ELLIPSE 42 +#define WIN_EMR_RECTANGLE 43 +#define WIN_EMR_ROUNDRECT 44 +#define WIN_EMR_ARC 45 +#define WIN_EMR_CHORD 46 +#define WIN_EMR_PIE 47 +#define WIN_EMR_SELECTPALETTE 48 +#define WIN_EMR_CREATEPALETTE 49 +#define WIN_EMR_SETPALETTEENTRIES 50 +#define WIN_EMR_RESIZEPALETTE 51 +#define WIN_EMR_REALIZEPALETTE 52 +#define WIN_EMR_EXTFLOODFILL 53 +#define WIN_EMR_LINETO 54 +#define WIN_EMR_ARCTO 55 +#define WIN_EMR_POLYDRAW 56 +#define WIN_EMR_SETARCDIRECTION 57 +#define WIN_EMR_SETMITERLIMIT 58 +#define WIN_EMR_BEGINPATH 59 +#define WIN_EMR_ENDPATH 60 +#define WIN_EMR_CLOSEFIGURE 61 +#define WIN_EMR_FILLPATH 62 +#define WIN_EMR_STROKEANDFILLPATH 63 +#define WIN_EMR_STROKEPATH 64 +#define WIN_EMR_FLATTENPATH 65 +#define WIN_EMR_WIDENPATH 66 +#define WIN_EMR_SELECTCLIPPATH 67 +#define WIN_EMR_ABORTPATH 68 + +#define WIN_EMR_GDICOMMENT 70 +#define WIN_EMR_FILLRGN 71 +#define WIN_EMR_FRAMERGN 72 +#define WIN_EMR_INVERTRGN 73 +#define WIN_EMR_PAINTRGN 74 +#define WIN_EMR_EXTSELECTCLIPRGN 75 +#define WIN_EMR_BITBLT 76 +#define WIN_EMR_STRETCHBLT 77 +#define WIN_EMR_MASKBLT 78 +#define WIN_EMR_PLGBLT 79 +#define WIN_EMR_SETDIBITSTODEVICE 80 +#define WIN_EMR_STRETCHDIBITS 81 +#define WIN_EMR_EXTCREATEFONTINDIRECTW 82 +#define WIN_EMR_EXTTEXTOUTA 83 +#define WIN_EMR_EXTTEXTOUTW 84 +#define WIN_EMR_POLYBEZIER16 85 +#define WIN_EMR_POLYGON16 86 +#define WIN_EMR_POLYLINE16 87 +#define WIN_EMR_POLYBEZIERTO16 88 +#define WIN_EMR_POLYLINETO16 89 +#define WIN_EMR_POLYPOLYLINE16 90 +#define WIN_EMR_POLYPOLYGON16 91 +#define WIN_EMR_POLYDRAW16 92 +#define WIN_EMR_CREATEMONOBRUSH 93 +#define WIN_EMR_CREATEDIBPATTERNBRUSHPT 94 +#define WIN_EMR_EXTCREATEPEN 95 +#define WIN_EMR_POLYTEXTOUTA 96 +#define WIN_EMR_POLYTEXTOUTW 97 + +#define WIN_SRCCOPY 0x00CC0020L +#define WIN_SRCPAINT 0x00EE0086L +#define WIN_SRCAND 0x008800C6L +#define WIN_SRCINVERT 0x00660046L +#define WIN_EMR_COMMENT_EMFSPOOL 0x00000000L +#define WIN_EMR_COMMENT_EMFPLUS 0x2B464D45L +#define WIN_EMR_COMMENT_PUBLIC 0x43494447L + +#define HANDLE_INVALID 0xffffffff +#define MAXHANDLES 65000 + +#define LINE_SELECT 0x00000001 +#define FILL_SELECT 0x00000002 +#define TEXT_SELECT 0x00000004 + +/* Text Alignment Options */ +#define TA_NOUPDATECP 0 +#define TA_UPDATECP 1 + +#define TA_LEFT 0 +#define TA_RIGHT 2 +#define TA_CENTER 6 + +#define TA_TOP 0 +#define TA_BOTTOM 8 +#define TA_BASELINE 24 +#define TA_RTLREADING 256 +#define TA_MASK (TA_BASELINE+TA_CENTER+TA_UPDATECP+TA_RTLREADING) + +#define MM_ANISOTROPIC 8 + +typedef enum +{ + EmfPlusHeader = 0x4001, + EmfPlusEndOfFile = 0x4002, + EmfPlusComment = 0x4003, + EmfPlusGetDC = 0x4004, + EmfPlusMultiFormatStart = 0x4005, + EmfPlusMultiFormatSection = 0x4006, + EmfPlusMultiFormatEnd = 0x4007, + EmfPlusObject = 0x4008, + EmfPlusClear = 0x4009, + EmfPlusFillRects = 0x400A, + EmfPlusDrawRects = 0x400B, + EmfPlusFillPolygon = 0x400C, + EmfPlusDrawLines = 0x400D, + EmfPlusFillEllipse = 0x400E, + EmfPlusDrawEllipse = 0x400F, + EmfPlusFillPie = 0x4010, + EmfPlusDrawPie = 0x4011, + EmfPlusDrawArc = 0x4012, + EmfPlusFillRegion = 0x4013, + EmfPlusFillPath = 0x4014, + EmfPlusDrawPath = 0x4015, + EmfPlusFillClosedCurve = 0x4016, + EmfPlusDrawClosedCurve = 0x4017, + EmfPlusDrawCurve = 0x4018, + EmfPlusDrawBeziers = 0x4019, + EmfPlusDrawImage = 0x401A, + EmfPlusDrawImagePoints = 0x401B, + EmfPlusDrawstring = 0x401C, + EmfPlusSetRenderingOrigin = 0x401D, + EmfPlusSetAntiAliasMode = 0x401E, + EmfPlusSetTextRenderingHint = 0x401F, + EmfPlusSetTextContrast = 0x4020, + EmfPlusSetInterpolationMode = 0x4021, + EmfPlusSetPixelOffsetMode = 0x4022, + EmfPlusSetCompositingMode = 0x4023, + EmfPlusSetCompositingQuality = 0x4024, + EmfPlusSave = 0x4025, + EmfPlusRestore = 0x4026, + EmfPlusBeginContainer = 0x4027, + EmfPlusBeginContainerNoParams = 0x4028, + EmfPlusEndContainer = 0x4029, + EmfPlusSetWorldTransform = 0x402A, + EmfPlusResetWorldTransform = 0x402B, + EmfPlusMultiplyWorldTransform = 0x402C, + EmfPlusTranslateWorldTransform = 0x402D, + EmfPlusScaleWorldTransform = 0x402E, + EmfPlusRotateWorldTransform = 0x402F, + EmfPlusSetPageTransform = 0x4030, + EmfPlusResetClip = 0x4031, + EmfPlusSetClipRect = 0x4032, + EmfPlusSetClipPath = 0x4033, + EmfPlusSetClipRegion = 0x4034, + EmfPlusOffsetClip = 0x4035, + EmfPlusDrawDriverstring = 0x4036, + EmfPlusStrokeFillPath = 0x4037, + EmfPlusSerializableObject = 0x4038, + EmfPlusSetTSGraphics = 0x4039, + EmfPlusSetTSClip = 0x403A +} EmfPlusRecordType; + + +// ------------- +// - EMFWriter - +// ------------- + +void EMFWriter::ImplBeginCommentRecord( sal_Int32 nCommentType ) +{ + ImplBeginRecord( WIN_EMR_GDICOMMENT ); + m_rStm.SeekRel( 4 ); + m_rStm<< (sal_Int32) nCommentType; +} + +void EMFWriter::ImplEndCommentRecord() +{ + if( mbRecordOpen ) + { + sal_Int32 nActPos = m_rStm.Tell(); + m_rStm.Seek( mnRecordPos + 8 ); + m_rStm << (sal_uInt32)( nActPos - mnRecordPos - 0xc ); + m_rStm.Seek( nActPos ); + } + ImplEndRecord(); +} + +void EMFWriter::ImplBeginPlusRecord( sal_uInt16 nType, sal_uInt16 nFlags ) +{ + DBG_ASSERT( !mbRecordPlusOpen, "Another EMF+ record is already opened!" ); + + if( !mbRecordPlusOpen ) + { + mbRecordPlusOpen = sal_True; + mnRecordPlusPos = m_rStm.Tell(); + + m_rStm << (sal_uInt16) nType << (sal_uInt16) nFlags; + m_rStm.SeekRel( 8 ); + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplEndPlusRecord() +{ + DBG_ASSERT( mbRecordPlusOpen, "EMF+ Record was not opened!" ); + + if( mbRecordPlusOpen ) + { + sal_Int32 nActPos = m_rStm.Tell(); + sal_Int32 nSize = nActPos - mnRecordPlusPos; + m_rStm.Seek( mnRecordPlusPos + 4 ); + m_rStm << (sal_uInt32)( nSize ) // Size + << (sal_uInt32) ( nSize - 0xc ); // Data Size + m_rStm.Seek( nActPos ); + mbRecordPlusOpen = sal_False; + } +} + +void EMFWriter::ImplPlusRecord( sal_uInt16 nType, sal_uInt16 nFlags ) +{ + ImplBeginPlusRecord( nType, nFlags ); + ImplEndPlusRecord(); +} + +void EMFWriter::WriteEMFPlusHeader( const Size &rMtfSizePix, const Size &rMtfSizeLog ) +{ + ImplBeginCommentRecord( WIN_EMR_COMMENT_EMFPLUS ); + + sal_Int32 nDPIX = rMtfSizePix.Width()*25; + sal_Int32 nDivX = rMtfSizeLog.Width()/100; + if (nDivX) + nDPIX /= nDivX; // DPI X + + sal_Int32 nDPIY = rMtfSizePix.Height()*25; + sal_Int32 nDivY = rMtfSizeLog.Height()/100; + if (nDivY) + nDPIY /= nDivY; // DPI Y + + m_rStm<< (sal_Int16) EmfPlusHeader; + m_rStm<< (sal_Int16) 0x01 // Flags - Dual Mode // TODO: Check this + << (sal_Int32) 0x1C // Size + << (sal_Int32) 0x10 // Data Size + << (sal_Int32) 0xdbc01002 // (lower 12bits) 1-> v1 2-> v1.1 // TODO: Check this + << (sal_Int32) 0x01 // Video display + << nDPIX + << nDPIY; + ImplEndCommentRecord(); + + // Write more properties + ImplBeginCommentRecord( WIN_EMR_COMMENT_EMFPLUS ); + ImplPlusRecord( EmfPlusSetPixelOffsetMode, 0x0 ); + ImplPlusRecord( EmfPlusSetAntiAliasMode, 0x09 ); // TODO: Check actual values for AntiAlias + ImplPlusRecord( EmfPlusSetCompositingQuality, 0x0100 ); // Default Quality + ImplPlusRecord( EmfPlusSetPageTransform, 1 ); + ImplPlusRecord( EmfPlusSetInterpolationMode, 0x00 ); // Default + ImplPlusRecord( EmfPlusGetDC, 0x00 ); + ImplEndCommentRecord(); +} + +void EMFWriter::ImplWritePlusEOF() +{ + ImplBeginCommentRecord( WIN_EMR_COMMENT_EMFPLUS ); + ImplPlusRecord( EmfPlusEndOfFile, 0x0 ); + ImplEndCommentRecord(); +} + +void EMFWriter::ImplWritePlusColor( const Color& rColor, const sal_uInt32& nTrans ) +{ + sal_uInt32 nAlpha = ((100-nTrans)*0xFF)/100; + sal_uInt32 nCol = rColor.GetBlue(); + + nCol |= ( (sal_uInt32) rColor.GetGreen() ) << 8; + nCol |= ( (sal_uInt32) rColor.GetRed() ) << 16; + nCol |= ( nAlpha << 24 ); + m_rStm << nCol; +} + +void EMFWriter::ImplWritePlusPoint( const Point& rPoint ) +{ + // Convert to pixels + const Point aPoint(maVDev.LogicToPixel( rPoint, maDestMapMode )); + m_rStm << (sal_uInt16) aPoint.X() << (sal_uInt16) aPoint.Y(); +} + +void EMFWriter::ImplWritePlusFillPolygonRecord( const Polygon& rPoly, const sal_uInt32& nTrans ) +{ + ImplBeginCommentRecord( WIN_EMR_COMMENT_EMFPLUS ); + if( rPoly.GetSize() ) + { + ImplBeginPlusRecord( EmfPlusFillPolygon, 0xC000 ); // Sets the color as well + ImplWritePlusColor( maVDev.GetFillColor(), nTrans ); + m_rStm << (sal_uInt32) rPoly.GetSize(); + for( sal_uInt16 i = 0; i < rPoly.GetSize(); i++ ) + ImplWritePlusPoint( rPoly[ i ] ); + ImplEndPlusRecord(); + } + ImplEndCommentRecord(); +} + +sal_Bool EMFWriter::WriteEMF( const GDIMetaFile& rMtf, FilterConfigItem* pFilterConfigItem ) +{ + const sal_uLong nHeaderPos = m_rStm.Tell(); + + mpHandlesUsed = new sal_Bool[ MAXHANDLES ]; + memset( mpHandlesUsed, 0, MAXHANDLES * sizeof( sal_Bool ) ); + mnHorTextAlign = mnHandleCount = mnLastPercent = mnRecordPos = mnRecordCount = 0; + mnRecordPlusPos = 0; + mnLineHandle = mnFillHandle = mnTextHandle = HANDLE_INVALID; + mbRecordOpen = sal_False; + mbRecordPlusOpen = false; + + + maVDev.EnableOutput( sal_False ); + maVDev.SetMapMode( rMtf.GetPrefMapMode() ); + mpFilterConfigItem = pFilterConfigItem; + + // don't work with pixel as destination map mode -> higher resolution preferrable + maDestMapMode.SetMapUnit( MAP_100TH_MM ); + + const Size aMtfSizePix( maVDev.LogicToPixel( rMtf.GetPrefSize(), rMtf.GetPrefMapMode() ) ); + const Size aMtfSizeLog( maVDev.LogicToLogic( rMtf.GetPrefSize(), rMtf.GetPrefMapMode(), MAP_100TH_MM ) ); + + // seek over header + // use [MS-EMF 2.2.11] HeaderExtension2 Object, otherwise resulting EMF cannot be converted with GetWinMetaFileBits() + m_rStm.SeekRel( 108 ); + + // Write EMF+ Header + WriteEMFPlusHeader( aMtfSizePix, aMtfSizeLog ); + + // write initial values + + // set 100th mm map mode in EMF + ImplBeginRecord( WIN_EMR_SETMAPMODE ); + m_rStm << (sal_Int32) MM_ANISOTROPIC; + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SETVIEWPORTEXTEX ); + m_rStm << (sal_Int32) maVDev.ImplGetDPIX() << (sal_Int32) maVDev.ImplGetDPIY(); + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SETWINDOWEXTEX ); + m_rStm << (sal_Int32) 2540 << (sal_Int32) 2540; + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SETVIEWPORTORGEX ); + m_rStm << (sal_Int32) 0 << (sal_Int32) 0; + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SETWINDOWORGEX ); + m_rStm << (sal_Int32) 0 << (sal_Int32) 0; + ImplEndRecord(); + + ImplWriteRasterOp( ROP_OVERPAINT ); + + ImplBeginRecord( WIN_EMR_SETBKMODE ); + m_rStm << (sal_uInt32) 1; // TRANSPARENT + ImplEndRecord(); + + // write emf data + ImplWrite( rMtf ); + + ImplWritePlusEOF(); + + ImplBeginRecord( WIN_EMR_EOF ); + m_rStm<< (sal_uInt32)0 // nPalEntries + << (sal_uInt32)0x10 // offPalEntries + << (sal_uInt32)0x14; // nSizeLast + ImplEndRecord(); + + + // write header + const sal_uLong nEndPos = m_rStm.Tell(); m_rStm.Seek( nHeaderPos ); + + m_rStm << (sal_uInt32) 0x00000001 << (sal_uInt32) 108 //use [MS-EMF 2.2.11] HeaderExtension2 Object + << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) ( aMtfSizePix.Width() - 1 ) << (sal_Int32) ( aMtfSizePix.Height() - 1 ) + << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) ( aMtfSizeLog.Width() - 1 ) << (sal_Int32) ( aMtfSizeLog.Height() - 1 ) + << (sal_uInt32) 0x464d4520 << (sal_uInt32) 0x10000 << (sal_uInt32) ( nEndPos - nHeaderPos ) + << (sal_uInt32) mnRecordCount << (sal_uInt16) ( mnHandleCount + 1 ) << (sal_uInt16) 0 << (sal_uInt32) 0 << (sal_uInt32) 0 << (sal_uInt32) 0 + << (sal_Int32) aMtfSizePix.Width() << (sal_Int32) aMtfSizePix.Height() + << (sal_Int32) ( aMtfSizeLog.Width() / 100 ) << (sal_Int32) ( aMtfSizeLog.Height() / 100 ) + << (sal_uInt32) 0 << (sal_uInt32) 0 << (sal_uInt32) 0 + << (sal_Int32) ( aMtfSizeLog.Width() * 10 ) << (sal_Int32) ( aMtfSizeLog.Height() * 10 ); //use [MS-EMF 2.2.11] HeaderExtension2 Object + + m_rStm.Seek( nEndPos ); + delete[] mpHandlesUsed; + + return( m_rStm.GetError() == ERRCODE_NONE ); +} + +// ----------------------------------------------------------------------------- + +sal_uLong EMFWriter::ImplAcquireHandle() +{ + sal_uLong nHandle = HANDLE_INVALID; + + for( sal_uLong i = 0; i < MAXHANDLES && ( HANDLE_INVALID == nHandle ); i++ ) + { + if( !mpHandlesUsed[ i ] ) + { + mpHandlesUsed[ i ] = sal_True; + + if( ( nHandle = i ) == mnHandleCount ) + mnHandleCount++; + } + } + + DBG_ASSERT( nHandle != HANDLE_INVALID, "No more handles available" ); + return( nHandle != HANDLE_INVALID ? nHandle + 1 : HANDLE_INVALID ); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplReleaseHandle( sal_uLong nHandle ) +{ + DBG_ASSERT( nHandle && ( nHandle < MAXHANDLES ), "Handle out of range" ); + mpHandlesUsed[ nHandle - 1 ] = sal_False; +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplBeginRecord( sal_uInt32 nType ) +{ + DBG_ASSERT( !mbRecordOpen, "Another record is already opened!" ); + + if( !mbRecordOpen ) + { + mbRecordOpen = sal_True; + mnRecordPos = m_rStm.Tell(); + + m_rStm << nType; + m_rStm.SeekRel( 4 ); + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplEndRecord() +{ + DBG_ASSERT( mbRecordOpen, "Record was not opened!" ); + + if( mbRecordOpen ) + { + sal_Int32 nFillBytes, nActPos = m_rStm.Tell(); + m_rStm.Seek( mnRecordPos + 4 ); + nFillBytes = nActPos - mnRecordPos; + nFillBytes += 3; // each record has to be dword aligned + nFillBytes ^= 3; + nFillBytes &= 3; + m_rStm << (sal_uInt32)( ( nActPos - mnRecordPos ) + nFillBytes ); + m_rStm.Seek( nActPos ); + while( nFillBytes-- ) + m_rStm << (sal_uInt8)0; + mnRecordCount++; + mbRecordOpen = sal_False; + } +} + +// ----------------------------------------------------------------------------- + +sal_Bool EMFWriter::ImplPrepareHandleSelect( sal_uInt32& rHandle, sal_uLong nSelectType ) +{ + if( rHandle != HANDLE_INVALID ) + { + sal_uInt32 nStockObject = 0x80000000; + + if( LINE_SELECT == nSelectType ) + nStockObject |= 0x00000007; + else if( FILL_SELECT == nSelectType ) + nStockObject |= 0x00000001; + else if( TEXT_SELECT == nSelectType ) + nStockObject |= 0x0000000a; + + // select stock object first + ImplBeginRecord( WIN_EMR_SELECTOBJECT ); + m_rStm << nStockObject; + ImplEndRecord(); + + // destroy handle of created object + ImplBeginRecord( WIN_EMR_DELETEOBJECT ); + m_rStm << rHandle; + ImplEndRecord(); + + // mark handle as free + ImplReleaseHandle( rHandle ); + } + + rHandle = ImplAcquireHandle(); + + return( HANDLE_INVALID != rHandle ); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplCheckLineAttr() +{ + if( mbLineChanged && ImplPrepareHandleSelect( mnLineHandle, LINE_SELECT ) ) + { + sal_uInt32 nStyle = maVDev.IsLineColor() ? 0 : 5; + sal_uInt32 nWidth = 0, nHeight = 0; + + ImplBeginRecord( WIN_EMR_CREATEPEN ); + m_rStm << mnLineHandle << nStyle << nWidth << nHeight; + ImplWriteColor( maVDev.GetLineColor() ); + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SELECTOBJECT ); + m_rStm << mnLineHandle; + ImplEndRecord(); + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplCheckFillAttr() +{ + if( mbFillChanged && ImplPrepareHandleSelect( mnFillHandle, FILL_SELECT ) ) + { + sal_uInt32 nStyle = maVDev.IsFillColor() ? 0 : 1; + sal_uInt32 nPatternStyle = 0; + + ImplBeginRecord( WIN_EMR_CREATEBRUSHINDIRECT ); + m_rStm << mnFillHandle << nStyle; + ImplWriteColor( maVDev.GetFillColor() ); + m_rStm << nPatternStyle; + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SELECTOBJECT ); + m_rStm << mnFillHandle; + ImplEndRecord(); + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplCheckTextAttr() +{ + if( mbTextChanged && ImplPrepareHandleSelect( mnTextHandle, TEXT_SELECT ) ) + { + const Font& rFont = maVDev.GetFont(); + String aFontName( rFont.GetName() ); + sal_Int32 nWeight; + sal_uInt16 i; + sal_uInt8 nPitchAndFamily; + + ImplBeginRecord( WIN_EMR_EXTCREATEFONTINDIRECTW ); + m_rStm << mnTextHandle; + ImplWriteExtent( -rFont.GetSize().Height() ); + ImplWriteExtent( rFont.GetSize().Width() ); + m_rStm << (sal_Int32) rFont.GetOrientation() << (sal_Int32) rFont.GetOrientation(); + + switch( rFont.GetWeight() ) + { + case WEIGHT_THIN: nWeight = 100; break; + case WEIGHT_ULTRALIGHT: nWeight = 200; break; + case WEIGHT_LIGHT: nWeight = 300; break; + case WEIGHT_SEMILIGHT: nWeight = 300; break; + case WEIGHT_NORMAL: nWeight = 400; break; + case WEIGHT_MEDIUM: nWeight = 500; break; + case WEIGHT_SEMIBOLD: nWeight = 600; break; + case WEIGHT_BOLD: nWeight = 700; break; + case WEIGHT_ULTRABOLD: nWeight = 800; break; + case WEIGHT_BLACK: nWeight = 900; break; + default: nWeight = 0; break; + } + + m_rStm << nWeight; + m_rStm << (sal_uInt8) ( ( ITALIC_NONE == rFont.GetItalic() ) ? 0 : 1 ); + m_rStm << (sal_uInt8) ( ( UNDERLINE_NONE == rFont.GetUnderline() ) ? 0 : 1 ); + m_rStm << (sal_uInt8) ( ( STRIKEOUT_NONE == rFont.GetStrikeout() ) ? 0 : 1 ); + m_rStm << (sal_uInt8) ( ( RTL_TEXTENCODING_SYMBOL == rFont.GetCharSet() ) ? 2 : 0 ); + m_rStm << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0; + + switch( rFont.GetPitch() ) + { + case PITCH_FIXED: nPitchAndFamily = 0x01; break; + case PITCH_VARIABLE: nPitchAndFamily = 0x02; break; + default: nPitchAndFamily = 0x00; break; + } + + switch( rFont.GetFamily() ) + { + case FAMILY_DECORATIVE: nPitchAndFamily |= 0x50; break; + case FAMILY_MODERN: nPitchAndFamily |= 0x30; break; + case FAMILY_ROMAN: nPitchAndFamily |= 0x10; break; + case FAMILY_SCRIPT: nPitchAndFamily |= 0x40; break; + case FAMILY_SWISS: nPitchAndFamily |= 0x20; break; + default: break; + } + + m_rStm << nPitchAndFamily; + + for( i = 0; i < 32; i++ ) + m_rStm << (sal_Unicode) ( ( i < aFontName.Len() ) ? aFontName.GetChar( i ) : 0 ); + + // dummy elfFullName + for( i = 0; i < 64; i++ ) + m_rStm << (sal_Unicode) 0; + + // dummy elfStyle + for( i = 0; i < 32; i++ ) + m_rStm << (sal_Unicode) 0; + + // dummy elfVersion, elfStyleSize, elfMatch, elfReserved + m_rStm << (sal_uInt32) 0 << (sal_uInt32) 0 << (sal_uInt32) 0 << (sal_uInt32) 0 ; + + // dummy elfVendorId + m_rStm << (sal_uInt32) 0; + + // dummy elfCulture + m_rStm << (sal_uInt32) 0; + + // dummy elfPanose + m_rStm << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0 << (sal_uInt8) 0; + + // fill record to get a record size divideable by 4 + m_rStm << (sal_uInt16) 0; + + ImplEndRecord(); + + // TextAlign + sal_uInt32 nTextAlign; + + switch( rFont.GetAlign() ) + { + case ALIGN_TOP: nTextAlign = TA_TOP; break; + case ALIGN_BOTTOM: nTextAlign = TA_BOTTOM; break; + default: nTextAlign = TA_BASELINE; break; + } + nTextAlign |= mnHorTextAlign; + + ImplBeginRecord( WIN_EMR_SETTEXTALIGN ); + m_rStm << nTextAlign; + ImplEndRecord(); + + // Text color + ImplBeginRecord( WIN_EMR_SETTEXTCOLOR ); + ImplWriteColor( maVDev.GetTextColor() ); + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SELECTOBJECT ); + m_rStm << mnTextHandle; + ImplEndRecord(); + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteColor( const Color& rColor ) +{ + sal_uInt32 nCol = rColor.GetRed(); + + nCol |= ( (sal_uInt32) rColor.GetGreen() ) << 8; + nCol |= ( (sal_uInt32) rColor.GetBlue() ) << 16; + + m_rStm << nCol; +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteRasterOp( RasterOp eRop ) +{ + sal_uInt32 nROP2; + + switch( eRop ) + { + case ROP_INVERT: nROP2 = 6; break; + case ROP_XOR: nROP2 = 7; break; + default: nROP2 = 13;break; + } + + ImplBeginRecord( WIN_EMR_SETROP2 ); + m_rStm << nROP2; + ImplEndRecord(); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteExtent( long nExtent ) +{ + nExtent = maVDev.LogicToLogic( Size( nExtent, 0 ), maVDev.GetMapMode(), maDestMapMode ).Width(); + m_rStm << (sal_Int32) nExtent; +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWritePoint( const Point& rPoint ) +{ + const Point aPoint( maVDev.LogicToLogic( rPoint, maVDev.GetMapMode(), maDestMapMode )); + m_rStm << (sal_Int32) aPoint.X() << (sal_Int32) aPoint.Y(); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteSize( const Size& rSize) +{ + const Size aSize( maVDev.LogicToLogic( rSize, maVDev.GetMapMode(), maDestMapMode )); + m_rStm << (sal_Int32) aSize.Width() << (sal_Int32) aSize.Height(); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteRect( const Rectangle& rRect ) +{ + const Rectangle aRect( maVDev.LogicToLogic ( rRect, maVDev.GetMapMode(), maDestMapMode )); + m_rStm + << static_cast<sal_Int32>(aRect.Left()) + << static_cast<sal_Int32>(aRect.Top()) + << static_cast<sal_Int32>(aRect.Right()) + << static_cast<sal_Int32>(aRect.Bottom()); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWritePolygonRecord( const Polygon& rPoly, sal_Bool bClose ) +{ + if( rPoly.GetSize() ) + { + if( rPoly.HasFlags() ) + ImplWritePath( rPoly, bClose ); + else + { + if( bClose ) + ImplCheckFillAttr(); + + ImplCheckLineAttr(); + + ImplBeginRecord( bClose ? WIN_EMR_POLYGON : WIN_EMR_POLYLINE ); + ImplWriteRect( rPoly.GetBoundRect() ); + m_rStm << (sal_uInt32) rPoly.GetSize(); + + for( sal_uInt16 i = 0; i < rPoly.GetSize(); i++ ) + ImplWritePoint( rPoly[ i ] ); + + ImplEndRecord(); + } + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWritePolyPolygonRecord( const PolyPolygon& rPolyPoly ) +{ + sal_uInt16 n, i, nPolyCount = rPolyPoly.Count(); + + if( nPolyCount ) + { + if( 1 == nPolyCount ) + ImplWritePolygonRecord( rPolyPoly[ 0 ], sal_True ); + else + { + sal_Bool bHasFlags = sal_False; + sal_uInt32 nTotalPoints = 0; + + for( i = 0; i < nPolyCount; i++ ) + { + nTotalPoints += rPolyPoly[ i ].GetSize(); + if ( rPolyPoly[ i ].HasFlags() ) + bHasFlags = sal_True; + } + if( nTotalPoints ) + { + if ( bHasFlags ) + ImplWritePath( rPolyPoly, sal_True ); + else + { + ImplCheckFillAttr(); + ImplCheckLineAttr(); + + ImplBeginRecord( WIN_EMR_POLYPOLYGON ); + ImplWriteRect( rPolyPoly.GetBoundRect() ); + m_rStm << (sal_uInt32)nPolyCount << nTotalPoints; + + for( i = 0; i < nPolyCount; i++ ) + m_rStm << (sal_uInt32)rPolyPoly[ i ].GetSize(); + + for( i = 0; i < nPolyCount; i++ ) + { + const Polygon& rPoly = rPolyPoly[ i ]; + + for( n = 0; n < rPoly.GetSize(); n++ ) + ImplWritePoint( rPoly[ n ] ); + } + ImplEndRecord(); + } + } + } + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWritePath( const PolyPolygon& rPolyPoly, sal_Bool bClosed ) +{ + if ( bClosed ) + ImplCheckFillAttr(); + ImplCheckLineAttr(); + + ImplBeginRecord( WIN_EMR_BEGINPATH ); + ImplEndRecord(); + + sal_uInt16 i, n, o, nPolyCount = rPolyPoly.Count(); + for ( i = 0; i < nPolyCount; i++ ) + { + n = 0; + const Polygon& rPoly = rPolyPoly[ i ]; + while ( n < rPoly.GetSize() ) + { + if( n == 0 ) + { + ImplBeginRecord( WIN_EMR_MOVETOEX ); + ImplWritePoint( rPoly[ 0 ] ); + ImplEndRecord(); + n++; + continue; + } + + sal_uInt16 nBezPoints = 0; + + while ( ( ( nBezPoints + n + 2 ) < rPoly.GetSize() ) && ( rPoly.GetFlags( nBezPoints + n ) == POLY_CONTROL ) ) + nBezPoints += 3; + + if ( nBezPoints ) + { + ImplBeginRecord( WIN_EMR_POLYBEZIERTO ); + Polygon aNewPoly( nBezPoints + 1 ); + aNewPoly[ 0 ] = rPoly[ n - 1 ]; + for ( o = 0; o < nBezPoints; o++ ) + aNewPoly[ o + 1 ] = rPoly[ n + o ]; + ImplWriteRect( aNewPoly.GetBoundRect() ); + m_rStm << (sal_uInt32)nBezPoints; + for( o = 1; o < aNewPoly.GetSize(); o++ ) + ImplWritePoint( aNewPoly[ o ] ); + ImplEndRecord(); + n = n + nBezPoints; + } + else + { + sal_uInt16 nPoints = 1; + while( ( nPoints + n ) < rPoly.GetSize() && ( rPoly.GetFlags( nPoints + n ) != POLY_CONTROL ) ) + nPoints++; + + if ( nPoints > 1 ) + { + ImplBeginRecord( WIN_EMR_POLYLINETO ); + Polygon aNewPoly( nPoints + 1 ); + aNewPoly[ 0 ] = rPoly[ n - 1]; + for ( o = 1; o <= nPoints; o++ ) + aNewPoly[ o ] = rPoly[ n - 1 + o ]; + ImplWriteRect( aNewPoly.GetBoundRect() ); + m_rStm << (sal_uInt32)( nPoints ); + for( o = 1; o < aNewPoly.GetSize(); o++ ) + ImplWritePoint( aNewPoly[ o ] ); + ImplEndRecord(); + } + else + { + ImplBeginRecord( WIN_EMR_LINETO ); + ImplWritePoint( rPoly[ n ] ); + ImplEndRecord(); + } + n = n + nPoints; + } + if ( bClosed && ( n == rPoly.GetSize() ) ) + { + ImplBeginRecord( WIN_EMR_CLOSEFIGURE ); + ImplEndRecord(); + } + } + } + ImplBeginRecord( WIN_EMR_ENDPATH ); + ImplEndRecord(); + ImplBeginRecord( bClosed ? WIN_EMR_FILLPATH : WIN_EMR_STROKEPATH ); + ImplWriteRect( rPolyPoly.GetBoundRect() ); + ImplEndRecord(); +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteBmpRecord( const Bitmap& rBmp, const Point& rPt, + const Size& rSz, sal_uInt32 nROP ) +{ + if( !!rBmp ) + { + SvMemoryStream aMemStm( 65535, 65535 ); + const Size aBmpSizePixel( rBmp.GetSizePixel() ); + + ImplBeginRecord( WIN_EMR_STRETCHDIBITS ); + ImplWriteRect( Rectangle( rPt, rSz ) ); + ImplWritePoint( rPt ); + m_rStm << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) aBmpSizePixel.Width() << (sal_Int32) aBmpSizePixel.Height(); + + // write offset positions and sizes later + const sal_uLong nOffPos = m_rStm.Tell(); + m_rStm.SeekRel( 16 ); + + m_rStm << (sal_uInt32) 0 << sal_Int32( ( ROP_XOR == maVDev.GetRasterOp() && WIN_SRCCOPY == nROP ) ? WIN_SRCINVERT : nROP ); + ImplWriteSize( rSz ); + + rBmp.Write( aMemStm, sal_True, sal_False ); + + sal_uInt32 nDIBSize = aMemStm.Tell(), nHeaderSize, nCompression, nColsUsed, nPalCount, nImageSize; + sal_uInt16 nBitCount; + + // get DIB parameters + aMemStm.Seek( 0 ); + aMemStm >> nHeaderSize; + aMemStm.SeekRel( 10 ); + aMemStm >> nBitCount >> nCompression >> nImageSize; + aMemStm.SeekRel( 8 ); + aMemStm >> nColsUsed; + + nPalCount = ( nBitCount <= 8 ) ? ( nColsUsed ? nColsUsed : ( 1 << (sal_uInt32) nBitCount ) ) : + ( ( 3 == nCompression ) ? 12 : 0 ); + + m_rStm.Write( aMemStm.GetData(), nDIBSize ); + + const sal_uLong nEndPos = m_rStm.Tell(); + m_rStm.Seek( nOffPos ); + m_rStm << (sal_uInt32) 80 << (sal_uInt32)( nHeaderSize + ( nPalCount << 2 ) ); + m_rStm << (sal_uInt32)( 80 + ( nHeaderSize + ( nPalCount << 2 ) ) ) << nImageSize; + m_rStm.Seek( nEndPos ); + + ImplEndRecord(); + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWriteTextRecord( const Point& rPos, const String rText, const sal_Int32* pDXArray, sal_uInt32 nWidth ) +{ + xub_StrLen nLen = rText.Len(), i; + + if( nLen ) + { + sal_uInt32 nNormWidth; + sal_Int32* pOwnArray; + sal_Int32* pDX; + + // get text sizes + if( pDXArray ) + { + pOwnArray = NULL; + nNormWidth = maVDev.GetTextWidth( rText ); + pDX = (sal_Int32*) pDXArray; + } + else + { + pOwnArray = new sal_Int32[ nLen ]; + nNormWidth = maVDev.GetTextArray( rText, pOwnArray ); + pDX = pOwnArray; + } + + if( nLen > 1 ) + { + nNormWidth = pDX[ nLen - 2 ] + maVDev.GetTextWidth( rtl::OUString(rText.GetChar( nLen - 1 )) ); + + if( nWidth && nNormWidth && ( nWidth != nNormWidth ) ) + { + const double fFactor = (double) nWidth / nNormWidth; + + for( i = 0; i < ( nLen - 1 ); i++ ) + pDX[ i ] = FRound( pDX[ i ] * fFactor ); + } + } + + // write text record + ImplBeginRecord( WIN_EMR_EXTTEXTOUTW ); + + ImplWriteRect( Rectangle( rPos, Size( nNormWidth, maVDev.GetTextHeight() ) ) ); + m_rStm << (sal_uInt32)1; + m_rStm << (sal_Int32) 0 << (sal_Int32) 0; + ImplWritePoint( rPos ); + m_rStm << (sal_uInt32) nLen << (sal_uInt32) 76 << (sal_uInt32) 2; + m_rStm << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) 0 << (sal_Int32) 0; + m_rStm << (sal_uInt32) ( 76 + ( nLen << 1 ) + ( (nLen & 1 ) ? 2 : 0 ) ); + + // write text + for( i = 0; i < nLen; i++ ) + m_rStm << (sal_Unicode)rText.GetChar( i ); + + // padding word + if( nLen & 1 ) + m_rStm << (sal_uInt16) 0; + + // write DX array + ImplWriteExtent( pDX[ 0 ] ); + + if( nLen > 1 ) + { + for( i = 1; i < ( nLen - 1 ); i++ ) + ImplWriteExtent( pDX[ i ] - pDX[ i - 1 ] ); + + ImplWriteExtent( pDX[ nLen - 2 ] / ( nLen - 1 ) ); + } + + ImplEndRecord(); + delete[] pOwnArray; + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::Impl_handleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon) +{ + if(rLinePolygon.count()) + { + basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon); + basegfx::B2DPolyPolygon aFillPolyPolygon; + + rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon); + + if(aLinePolyPolygon.count()) + { + for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++) + { + const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a)); + ImplWritePolygonRecord( Polygon(aCandidate), sal_False ); + } + } + + if(aFillPolyPolygon.count()) + { + const Color aOldLineColor(maVDev.GetLineColor()); + const Color aOldFillColor(maVDev.GetFillColor()); + + maVDev.SetLineColor(); + maVDev.SetFillColor(aOldLineColor); + + for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++) + { + const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a)); + ImplWritePolyPolygonRecord(PolyPolygon(Polygon(aPolygon))); + } + + maVDev.SetLineColor(aOldLineColor); + maVDev.SetFillColor(aOldFillColor); + } + } +} + +// ----------------------------------------------------------------------------- + +void EMFWriter::ImplWrite( const GDIMetaFile& rMtf ) +{ + for( size_t j = 0, nActionCount = rMtf.GetActionSize(); j < nActionCount; j++ ) + { + const MetaAction* pAction = rMtf.GetAction( j ); + const sal_uInt16 nType = pAction->GetType(); + + switch( nType ) + { + case( META_PIXEL_ACTION ): + { + const MetaPixelAction* pA = (const MetaPixelAction*) pAction; + + ImplCheckLineAttr(); + ImplBeginRecord( WIN_EMR_SETPIXELV ); + ImplWritePoint( pA->GetPoint() ); + ImplWriteColor( pA->GetColor() ); + ImplEndRecord(); + } + break; + + case( META_POINT_ACTION ): + { + if( maVDev.IsLineColor() ) + { + const MetaPointAction* pA = (const MetaPointAction*) pAction; + + ImplCheckLineAttr(); + ImplBeginRecord( WIN_EMR_SETPIXELV ); + ImplWritePoint( pA->GetPoint() ); + ImplWriteColor( maVDev.GetLineColor() ); + ImplEndRecord(); + } + } + break; + + case( META_LINE_ACTION ): + { + if( maVDev.IsLineColor() ) + { + const MetaLineAction* pA = (const MetaLineAction*) pAction; + + if(pA->GetLineInfo().IsDefault()) + { + ImplCheckLineAttr(); + + ImplBeginRecord( WIN_EMR_MOVETOEX ); + ImplWritePoint( pA->GetStartPoint() ); + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_LINETO ); + ImplWritePoint( pA->GetEndPoint() ); + ImplEndRecord(); + + ImplBeginRecord( WIN_EMR_SETPIXELV ); + ImplWritePoint( pA->GetEndPoint() ); + ImplWriteColor( maVDev.GetLineColor() ); + ImplEndRecord(); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + basegfx::B2DPolygon aPolygon; + aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y())); + aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y())); + Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon); + } + } + } + break; + + case( META_RECT_ACTION ): + { + if( maVDev.IsLineColor() || maVDev.IsFillColor() ) + { + const MetaRectAction* pA = (const MetaRectAction*) pAction; + + ImplCheckFillAttr(); + ImplCheckLineAttr(); + + ImplBeginRecord( WIN_EMR_RECTANGLE ); + ImplWriteRect( pA->GetRect() ); + ImplEndRecord(); + } + } + break; + + case( META_ROUNDRECT_ACTION ): + { + if( maVDev.IsLineColor() || maVDev.IsFillColor() ) + { + const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pAction; + + ImplCheckFillAttr(); + ImplCheckLineAttr(); + + ImplBeginRecord( WIN_EMR_ROUNDRECT ); + ImplWriteRect( pA->GetRect() ); + ImplWriteSize( Size( pA->GetHorzRound(), pA->GetVertRound() ) ); + ImplEndRecord(); + } + } + break; + + case( META_ELLIPSE_ACTION ): + { + if( maVDev.IsLineColor() || maVDev.IsFillColor() ) + { + const MetaEllipseAction* pA = (const MetaEllipseAction*) pAction; + + ImplCheckFillAttr(); + ImplCheckLineAttr(); + + ImplBeginRecord( WIN_EMR_ELLIPSE ); + ImplWriteRect( pA->GetRect() ); + ImplEndRecord(); + } + } + break; + + case( META_ARC_ACTION ): + case( META_PIE_ACTION ): + case( META_CHORD_ACTION ): + case( META_POLYGON_ACTION ): + { + if( maVDev.IsLineColor() || maVDev.IsFillColor() ) + { + Polygon aPoly; + + switch( nType ) + { + case( META_ARC_ACTION ): + { + const MetaArcAction* pA = (const MetaArcAction*) pAction; + aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_ARC ); + } + break; + + case( META_PIE_ACTION ): + { + const MetaPieAction* pA = (const MetaPieAction*) pAction; + aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_PIE ); + } + break; + + case( META_CHORD_ACTION ): + { + const MetaChordAction* pA = (const MetaChordAction*) pAction; + aPoly = Polygon( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint(), POLY_CHORD ); + } + break; + + case( META_POLYGON_ACTION ): + aPoly = ( (const MetaPolygonAction*) pAction )->GetPolygon(); + break; + } + + ImplWritePolygonRecord( aPoly, nType != META_ARC_ACTION ); + } + } + break; + + case( META_POLYLINE_ACTION ): + { + if( maVDev.IsLineColor() ) + { + const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pAction; + const Polygon& rPoly = pA->GetPolygon(); + + if( rPoly.GetSize() ) + { + if(pA->GetLineInfo().IsDefault()) + { + ImplWritePolygonRecord( rPoly, sal_False ); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + Impl_handleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon()); + } + } + } + } + break; + + case( META_POLYPOLYGON_ACTION ): + { + if( maVDev.IsLineColor() || maVDev.IsFillColor() ) + ImplWritePolyPolygonRecord( ( (const MetaPolyPolygonAction*) pAction )->GetPolyPolygon() ); + } + break; + + case( META_GRADIENT_ACTION ): + { + const MetaGradientAction* pA = (const MetaGradientAction*) pAction; + GDIMetaFile aTmpMtf; + + maVDev.AddGradientActions( pA->GetRect(), pA->GetGradient(), aTmpMtf ); + ImplWrite( aTmpMtf ); + } + break; + + case META_HATCH_ACTION: + { + const MetaHatchAction* pA = (const MetaHatchAction*) pAction; + GDIMetaFile aTmpMtf; + + maVDev.AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf ); + ImplWrite( aTmpMtf ); + } + break; + + case META_TRANSPARENT_ACTION: + { + const PolyPolygon& rPolyPoly = ( (MetaTransparentAction*) pAction )->GetPolyPolygon(); + if( rPolyPoly.Count() ) + ImplWritePlusFillPolygonRecord( rPolyPoly[0], ( (MetaTransparentAction*)pAction)->GetTransparence() ); + ImplCheckFillAttr(); + ImplCheckLineAttr(); + ImplWritePolyPolygonRecord( rPolyPoly ); + + ImplBeginCommentRecord( WIN_EMR_COMMENT_EMFPLUS ); + ImplPlusRecord( EmfPlusGetDC, 0x00 ); + ImplEndCommentRecord(); + } + break; + + case META_FLOATTRANSPARENT_ACTION: + { + const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*) pAction; + + GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() ); + Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() ); + const Size aSrcSize( aTmpMtf.GetPrefSize() ); + const Point aDestPt( pA->GetPoint() ); + const Size aDestSize( pA->GetSize() ); + const double fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0; + const double fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0; + long nMoveX, nMoveY; + + if( fScaleX != 1.0 || fScaleY != 1.0 ) + { + aTmpMtf.Scale( fScaleX, fScaleY ); + aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY ); + } + + nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y(); + + if( nMoveX || nMoveY ) + aTmpMtf.Move( nMoveX, nMoveY ); + + ImplCheckFillAttr(); + ImplCheckLineAttr(); + ImplCheckTextAttr(); + ImplWrite( aTmpMtf ); + } + break; + + case( META_EPS_ACTION ): + { + const MetaEPSAction* pA = (const MetaEPSAction*) pAction; + const GDIMetaFile aSubstitute( pA->GetSubstitute() ); + + for( size_t i = 0, nCount = aSubstitute.GetActionSize(); i < nCount; i++ ) + { + const MetaAction* pSubstAct = aSubstitute.GetAction( i ); + if( pSubstAct->GetType() == META_BMPSCALE_ACTION ) + { + maVDev.Push( PUSH_ALL ); + ImplBeginRecord( WIN_EMR_SAVEDC ); + ImplEndRecord(); + + MapMode aMapMode( aSubstitute.GetPrefMapMode() ); + Size aOutSize( maVDev.LogicToLogic( pA->GetSize(), maVDev.GetMapMode(), aMapMode ) ); + aMapMode.SetScaleX( Fraction( aOutSize.Width(), aSubstitute.GetPrefSize().Width() ) ); + aMapMode.SetScaleY( Fraction( aOutSize.Height(), aSubstitute.GetPrefSize().Height() ) ); + aMapMode.SetOrigin( maVDev.LogicToLogic( pA->GetPoint(), maVDev.GetMapMode(), aMapMode ) ); + maVDev.SetMapMode( aMapMode ); + ImplWrite( aSubstitute ); + + maVDev.Pop(); + ImplBeginRecord( WIN_EMR_RESTOREDC ); + m_rStm << (sal_Int32) -1; + ImplEndRecord(); + break; + } + } + } + break; + + case META_BMP_ACTION: + { + const MetaBmpAction* pA = (const MetaBmpAction *) pAction; + ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), maVDev.PixelToLogic( pA->GetBitmap().GetSizePixel() ), WIN_SRCCOPY ); + } + break; + + case META_BMPSCALE_ACTION: + { + const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pAction; + ImplWriteBmpRecord( pA->GetBitmap(), pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY ); + } + break; + + case META_BMPSCALEPART_ACTION: + { + const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*) pAction; + Bitmap aTmp( pA->GetBitmap() ); + + if( aTmp.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ) ) + ImplWriteBmpRecord( aTmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCCOPY ); + } + break; + + case META_BMPEX_ACTION: + { + const MetaBmpExAction* pA = (const MetaBmpExAction *) pAction; + Bitmap aBmp( pA->GetBitmapEx().GetBitmap() ); + Bitmap aMsk( pA->GetBitmapEx().GetMask() ); + + if( !!aMsk ) + { + aBmp.Replace( aMsk, COL_WHITE ); + aMsk.Invert(); + ImplWriteBmpRecord( aMsk, pA->GetPoint(), maVDev.PixelToLogic( aMsk.GetSizePixel() ), WIN_SRCPAINT ); + ImplWriteBmpRecord( aBmp, pA->GetPoint(), maVDev.PixelToLogic( aBmp.GetSizePixel() ), WIN_SRCAND ); + } + else + ImplWriteBmpRecord( aBmp, pA->GetPoint(), aBmp.GetSizePixel(), WIN_SRCCOPY ); + } + break; + + case META_BMPEXSCALE_ACTION: + { + const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pAction; + Bitmap aBmp( pA->GetBitmapEx().GetBitmap() ); + Bitmap aMsk( pA->GetBitmapEx().GetMask() ); + + if( !!aMsk ) + { + aBmp.Replace( aMsk, COL_WHITE ); + aMsk.Invert(); + ImplWriteBmpRecord( aMsk, pA->GetPoint(), pA->GetSize(), WIN_SRCPAINT ); + ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCAND ); + } + else + ImplWriteBmpRecord( aBmp, pA->GetPoint(), pA->GetSize(), WIN_SRCCOPY ); + } + break; + + case META_BMPEXSCALEPART_ACTION: + { + const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*) pAction; + BitmapEx aBmpEx( pA->GetBitmapEx() ); + aBmpEx.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ); + Bitmap aBmp( aBmpEx.GetBitmap() ); + Bitmap aMsk( aBmpEx.GetMask() ); + + if( !!aMsk ) + { + aBmp.Replace( aMsk, COL_WHITE ); + aMsk.Invert(); + ImplWriteBmpRecord( aMsk, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCPAINT ); + ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCAND ); + } + else + ImplWriteBmpRecord( aBmp, pA->GetDestPoint(), pA->GetDestSize(), WIN_SRCCOPY ); + } + break; + + case META_TEXT_ACTION: + { + const MetaTextAction* pA = (const MetaTextAction*) pAction; + const String aText( pA->GetText(), pA->GetIndex(), pA->GetLen() ); + + ImplCheckTextAttr(); + ImplWriteTextRecord( pA->GetPoint(), aText, NULL, 0 ); + } + break; + + case META_TEXTRECT_ACTION: + { + const MetaTextRectAction* pA = (const MetaTextRectAction*) pAction; + const String aText( pA->GetText() ); + + ImplCheckTextAttr(); + ImplWriteTextRecord( pA->GetRect().TopLeft(), aText, NULL, 0 ); + } + break; + + case META_TEXTARRAY_ACTION: + { + const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pAction; + const String aText( pA->GetText(), pA->GetIndex(), pA->GetLen() ); + + ImplCheckTextAttr(); + ImplWriteTextRecord( pA->GetPoint(), aText, pA->GetDXArray(), 0 ); + } + break; + + case META_STRETCHTEXT_ACTION: + { + const MetaStretchTextAction* pA = (const MetaStretchTextAction*) pAction; + const String aText( pA->GetText(), pA->GetIndex(), pA->GetLen() ); + + ImplCheckTextAttr(); + ImplWriteTextRecord( pA->GetPoint(), aText, NULL, pA->GetWidth() ); + } + break; + + case( META_LINECOLOR_ACTION ): + { + ( (MetaAction*) pAction )->Execute( &maVDev ); + mbLineChanged = sal_True; + } + break; + + case( META_FILLCOLOR_ACTION ): + { + ( (MetaAction*) pAction )->Execute( &maVDev ); + mbFillChanged = sal_True; + } + break; + + case( META_TEXTCOLOR_ACTION ): + case( META_TEXTLINECOLOR_ACTION ): + case( META_TEXTFILLCOLOR_ACTION ): + case( META_TEXTALIGN_ACTION ): + case( META_FONT_ACTION ): + { + ( (MetaAction*) pAction )->Execute( &maVDev ); + mbTextChanged = sal_True; + } + break; + + case( META_ISECTRECTCLIPREGION_ACTION ): + { + ( (MetaAction*) pAction )->Execute( &maVDev ); + + ImplBeginRecord( WIN_EMR_INTERSECTCLIPRECT ); + ImplWriteRect( ( (MetaISectRectClipRegionAction*) pAction )->GetRect() ); + ImplEndRecord(); + } + break; + + case( META_CLIPREGION_ACTION ): + case( META_ISECTREGIONCLIPREGION_ACTION ): + case( META_MOVECLIPREGION_ACTION ): + { + ( (MetaAction*) pAction )->Execute( &maVDev ); + } + break; + + case( META_REFPOINT_ACTION ): + case( META_MAPMODE_ACTION ): + ( (MetaAction*) pAction )->Execute( &maVDev ); + break; + + case( META_PUSH_ACTION ): + { + ( (MetaAction*) pAction )->Execute( &maVDev ); + + ImplBeginRecord( WIN_EMR_SAVEDC ); + ImplEndRecord(); + } + break; + + case( META_POP_ACTION ): + { + ( (MetaAction*) pAction )->Execute( &maVDev ); + + ImplBeginRecord( WIN_EMR_RESTOREDC ); + m_rStm << (sal_Int32) -1; + ImplEndRecord(); + + ImplWriteRasterOp( maVDev.GetRasterOp() ); + mbLineChanged = mbFillChanged = mbTextChanged = sal_True; + } + break; + + case( META_RASTEROP_ACTION ): + { + ( (MetaAction*) pAction )->Execute( &maVDev ); + ImplWriteRasterOp( ( (MetaRasterOpAction*) pAction )->GetRasterOp() ); + } + break; + + case( META_LAYOUTMODE_ACTION ): + { + sal_uInt32 nLayoutMode = ( (MetaLayoutModeAction*) pAction )->GetLayoutMode(); + mnHorTextAlign = 0; + if (nLayoutMode & TEXT_LAYOUT_BIDI_RTL) + { + mnHorTextAlign = TA_RIGHT | TA_RTLREADING; + } + if (nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_RIGHT) + mnHorTextAlign |= TA_RIGHT; + else if (nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT) + mnHorTextAlign &= ~TA_RIGHT; + break; + } + + case( META_MASK_ACTION ): + case( META_MASKSCALE_ACTION ): + case( META_MASKSCALEPART_ACTION ): + case( META_WALLPAPER_ACTION ): + case( META_TEXTLINE_ACTION ): + case( META_COMMENT_ACTION ): + case( META_GRADIENTEX_ACTION ): + { + // !!! >>> we don't want to support these actions + } + break; + + default: + OSL_FAIL(rtl::OStringBuffer(RTL_CONSTASCII_STRINGPARAM( + "EMFWriter::ImplWriteActions: unsupported MetaAction #" )). + append(static_cast<sal_Int32>(nType)).getStr()); + break; + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/emfwr.hxx b/vcl/source/filter/wmf/emfwr.hxx new file mode 100644 index 000000000000..3e22e0385f17 --- /dev/null +++ b/vcl/source/filter/wmf/emfwr.hxx @@ -0,0 +1,105 @@ +/* -*- 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 _EMFWR_HXX +#define _EMFWR_HXX + +#include <vcl/metaact.hxx> +#include <vcl/graph.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/virdev.hxx> +#include <svtools/fltcall.hxx> + +// ------------- +// - EMFWriter - +// ------------- + +class LineInfo; +namespace basegfx { class B2DPolygon; } + +class EMFWriter +{ +private: + + VirtualDevice maVDev; + MapMode maDestMapMode; + FilterConfigItem* mpFilterConfigItem; + SvStream& m_rStm; + sal_Bool* mpHandlesUsed; + sal_uLong mnHandleCount; + sal_uLong mnLastPercent; + sal_uLong mnRecordCount; + sal_uLong mnRecordPos; + sal_uLong mnRecordPlusPos; + sal_Bool mbRecordOpen; + sal_Bool mbRecordPlusOpen; + sal_Bool mbLineChanged; + sal_uInt32 mnLineHandle; + sal_Bool mbFillChanged; + sal_uInt32 mnFillHandle; + sal_Bool mbTextChanged; + sal_uInt32 mnTextHandle; + sal_uInt32 mnHorTextAlign; + + void ImplBeginRecord( sal_uInt32 nType ); + void ImplEndRecord(); + void ImplBeginPlusRecord( sal_uInt16 nType, sal_uInt16 nFlags ); + void ImplEndPlusRecord(); + void ImplPlusRecord( sal_uInt16 nType, sal_uInt16 nFlags ); + void ImplBeginCommentRecord( sal_Int32 nCommentType ); + void ImplEndCommentRecord(); + + sal_uLong ImplAcquireHandle(); + void ImplReleaseHandle( sal_uLong nHandle ); + + sal_Bool ImplPrepareHandleSelect( sal_uInt32& rHandle, sal_uLong nSelectType ); + void ImplCheckLineAttr(); + void ImplCheckFillAttr(); + void ImplCheckTextAttr(); + + void ImplWriteColor( const Color& rColor ); + void ImplWriteRasterOp( RasterOp eRop ); + void ImplWriteExtent( long nExtent ); + void ImplWritePoint( const Point& rPoint ); + void ImplWriteSize( const Size& rSize); + void ImplWriteRect( const Rectangle& rRect ); + void ImplWritePath( const PolyPolygon& rPolyPoly, sal_Bool bClose ); + void ImplWritePolygonRecord( const Polygon& rPoly, sal_Bool bClose ); + void ImplWritePolyPolygonRecord( const PolyPolygon& rPolyPoly ); + void ImplWriteBmpRecord( const Bitmap& rBmp, const Point& rPt, const Size& rSz, sal_uInt32 nROP ); + void ImplWriteTextRecord( const Point& rPos, const String rText, const sal_Int32* pDXArray, sal_uInt32 nWidth ); + + void Impl_handleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon); + void ImplWrite( const GDIMetaFile& rMtf ); + void WriteEMFPlusHeader( const Size &rMtfSizePix, const Size &rMtfSizeLog ); + void ImplWritePlusEOF(); + void ImplWritePlusFillPolygonRecord( const Polygon& rPoly, const sal_uInt32& nTrans ); + void ImplWritePlusColor( const Color& rColor, const sal_uInt32& nTrans ); + void ImplWritePlusPoint( const Point& rPoint ); + +public: + + EMFWriter(SvStream &rStream) : m_rStm(rStream) {} + + sal_Bool WriteEMF( const GDIMetaFile& rMtf, FilterConfigItem* pConfigItem = NULL ); +}; + +#endif // _EMFWR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/enhwmf.cxx b/vcl/source/filter/wmf/enhwmf.cxx new file mode 100644 index 000000000000..f8b98845be4e --- /dev/null +++ b/vcl/source/filter/wmf/enhwmf.cxx @@ -0,0 +1,1418 @@ +/* -*- 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 "winmtf.hxx" +#include <osl/endian.h> +#include <boost/bind.hpp> + +using namespace std; +//=========================== GDI-Array =================================== + +#define EMR_HEADER 1 +#define EMR_POLYBEZIER 2 +#define EMR_POLYGON 3 +#define EMR_POLYLINE 4 +#define EMR_POLYBEZIERTO 5 +#define EMR_POLYLINETO 6 +#define EMR_POLYPOLYLINE 7 +#define EMR_POLYPOLYGON 8 +#define EMR_SETWINDOWEXTEX 9 +#define EMR_SETWINDOWORGEX 10 +#define EMR_SETVIEWPORTEXTEX 11 +#define EMR_SETVIEWPORTORGEX 12 +#define EMR_SETBRUSHORGEX 13 +#define EMR_EOF 14 +#define EMR_SETPIXELV 15 +#define EMR_SETMAPPERFLAGS 16 +#define EMR_SETMAPMODE 17 +#define EMR_SETBKMODE 18 +#define EMR_SETPOLYFILLMODE 19 +#define EMR_SETROP2 20 +#define EMR_SETSTRETCHBLTMODE 21 +#define EMR_SETTEXTALIGN 22 +#define EMR_SETCOLORADJUSTMENT 23 +#define EMR_SETTEXTCOLOR 24 +#define EMR_SETBKCOLOR 25 +#define EMR_OFFSETCLIPRGN 26 +#define EMR_MOVETOEX 27 +#define EMR_SETMETARGN 28 +#define EMR_EXCLUDECLIPRECT 29 +#define EMR_INTERSECTCLIPRECT 30 +#define EMR_SCALEVIEWPORTEXTEX 31 +#define EMR_SCALEWINDOWEXTEX 32 +#define EMR_SAVEDC 33 +#define EMR_RESTOREDC 34 +#define EMR_SETWORLDTRANSFORM 35 +#define EMR_MODIFYWORLDTRANSFORM 36 +#define EMR_SELECTOBJECT 37 +#define EMR_CREATEPEN 38 +#define EMR_CREATEBRUSHINDIRECT 39 +#define EMR_DELETEOBJECT 40 +#define EMR_ANGLEARC 41 +#define EMR_ELLIPSE 42 +#define EMR_RECTANGLE 43 +#define EMR_ROUNDRECT 44 +#define EMR_ARC 45 +#define EMR_CHORD 46 +#define EMR_PIE 47 +#define EMR_SELECTPALETTE 48 +#define EMR_CREATEPALETTE 49 +#define EMR_SETPALETTEENTRIES 50 +#define EMR_RESIZEPALETTE 51 +#define EMR_REALIZEPALETTE 52 +#define EMR_EXTFLOODFILL 53 +#define EMR_LINETO 54 +#define EMR_ARCTO 55 +#define EMR_POLYDRAW 56 +#define EMR_SETARCDIRECTION 57 +#define EMR_SETMITERLIMIT 58 +#define EMR_BEGINPATH 59 +#define EMR_ENDPATH 60 +#define EMR_CLOSEFIGURE 61 +#define EMR_FILLPATH 62 +#define EMR_STROKEANDFILLPATH 63 +#define EMR_STROKEPATH 64 +#define EMR_FLATTENPATH 65 +#define EMR_WIDENPATH 66 +#define EMR_SELECTCLIPPATH 67 +#define EMR_ABORTPATH 68 + +#define EMR_GDICOMMENT 70 +#define EMR_FILLRGN 71 +#define EMR_FRAMERGN 72 +#define EMR_INVERTRGN 73 +#define EMR_PAINTRGN 74 +#define EMR_EXTSELECTCLIPRGN 75 +#define EMR_BITBLT 76 +#define EMR_STRETCHBLT 77 +#define EMR_MASKBLT 78 +#define EMR_PLGBLT 79 +#define EMR_SETDIBITSTODEVICE 80 +#define EMR_STRETCHDIBITS 81 +#define EMR_EXTCREATEFONTINDIRECTW 82 +#define EMR_EXTTEXTOUTA 83 +#define EMR_EXTTEXTOUTW 84 +#define EMR_POLYBEZIER16 85 +#define EMR_POLYGON16 86 +#define EMR_POLYLINE16 87 +#define EMR_POLYBEZIERTO16 88 +#define EMR_POLYLINETO16 89 +#define EMR_POLYPOLYLINE16 90 +#define EMR_POLYPOLYGON16 91 +#define EMR_POLYDRAW16 92 +#define EMR_CREATEMONOBRUSH 93 +#define EMR_CREATEDIBPATTERNBRUSHPT 94 +#define EMR_EXTCREATEPEN 95 +#define EMR_POLYTEXTOUTA 96 +#define EMR_POLYTEXTOUTW 97 + +// WINDOWS VERSION >= 0x400 +#define EMR_SETICMMODE 98 +#define EMR_CREATECOLORSPACE 99 +#define EMR_SETCOLORSPACE 100 +#define EMR_DELETECOLORSPACE 101 +#define EMR_GLSRECORD 102 +#define EMR_GLSBOUNDEDRECORD 103 +#define EMR_PIXELFORMAT 104 + +// WINDOWS VERSION >= 0x500 +#define EMR_DRAWESCAPE 105 +#define EMR_EXTESCAPE 106 +#define EMR_STARTDOC 107 +#define EMR_SMALLTEXTOUT 108 +#define EMR_FORCEUFIMAPPING 109 +#define EMR_NAMEDESCAPE 110 +#define EMR_COLORCORRECTPALETTE 111 +#define EMR_SETICMPROFILEA 112 +#define EMR_SETICMPROFILEW 113 +#define EMR_ALPHABLEND 114 +#define EMR_ALPHADIBBLEND 115 +#define EMR_TRANSPARENTBLT 116 +#define EMR_TRANSPARENTDIB 117 +#define EMR_GRADIENTFILL 118 +#define EMR_SETLINKEDUFIS 119 +#define EMR_SETTEXTJUSTIFICATION 120 + +#if OSL_DEBUG_LEVEL > 1 +#define EMFP_DEBUG(x) x +#else +#define EMFP_DEBUG(x) +#endif + +//----------------------------------------------------------------------------------- + +#ifdef OSL_BIGENDIAN +// currently unused +static float GetSwapFloat( SvStream& rSt ) +{ + float fTmp; + sal_Int8* pPtr = (sal_Int8*)&fTmp; + rSt >> pPtr[3] >> pPtr[2] >> pPtr[1] >> pPtr[0]; // Little Endian <-> Big Endian switch + return fTmp; +} +#endif + +SvStream& operator>>( SvStream& rIn, XForm& rXForm ) +{ + if ( sizeof( float ) != 4 ) + { + OSL_FAIL( "EnhWMFReader::sizeof( float ) != 4" ); + rXForm = XForm(); + } + else + { +#ifdef OSL_BIGENDIAN + rXForm.eM11 = GetSwapFloat( rIn ); + rXForm.eM12 = GetSwapFloat( rIn ); + rXForm.eM21 = GetSwapFloat( rIn ); + rXForm.eM22 = GetSwapFloat( rIn ); + rXForm.eDx = GetSwapFloat( rIn ); + rXForm.eDy = GetSwapFloat( rIn ); +#else + rIn >> rXForm.eM11 >> rXForm.eM12 >> rXForm.eM21 >> rXForm.eM22 + >> rXForm.eDx >> rXForm.eDy; +#endif + } + return rIn; +} + +static sal_Bool ImplReadRegion( PolyPolygon& rPolyPoly, SvStream& rSt, sal_uInt32 nLen ) +{ + sal_Bool bOk = sal_False; + if ( nLen ) + { + sal_uInt32 nHdSize, nType, nCount, nRgnSize, i; + rSt >> nHdSize + >> nType + >> nCount + >> nRgnSize; + + if ( nCount && ( nType == RDH_RECTANGLES ) && + ( nLen >= ( ( nCount << 4 ) + ( nHdSize - 16 ) ) ) ) + { + sal_Int32 nx1, ny1, nx2, ny2; + + for ( i = 0; i < nCount; i++ ) + { + rSt >> nx1 >> ny1 >> nx2 >> ny2; + + Rectangle aRect( Point( nx1, ny1 ), Point( nx2, ny2 ) ); + Polygon aPolygon( aRect ); + PolyPolygon aPolyPolyOr1( aPolygon ); + PolyPolygon aPolyPolyOr2( rPolyPoly ); + rPolyPoly.GetUnion( aPolyPolyOr1, aPolyPolyOr2 ); + rPolyPoly = aPolyPolyOr2; + } + bOk = sal_True; + } + } + return bOk; +} + +EMFP_DEBUG(void dumpWords( SvStream& s, int i ) +{ + sal_uInt32 pos = s.Tell(); + sal_Int16 data; + for( ; i > 0; i -- ) { + s >> data; + EMFP_DEBUG(printf ("\t\t\tdata: %04hx\n", data)); + } + s.Seek (pos); +}); + +void EnhWMFReader::ReadEMFPlusComment(sal_uInt32 length, sal_Bool& bHaveDC) +{ + if (!bEMFPlus) { + pOut->PassEMFPlusHeaderInfo(); + + // debug code - write the stream to debug file /tmp/emf-stream.emf + EMFP_DEBUG(int pos = pWMF->Tell(); + pWMF->Seek(0); + SvFileStream file( rtl::OUString( "/tmp/emf-stream.emf" ), STREAM_WRITE | STREAM_TRUNC ); + + *pWMF >> file; + file.Flush(); + file.Close(); + + pWMF->Seek( pos );) + } + bEMFPlus = true; + + sal_Size pos = pWMF->Tell(); + void *buffer = malloc( length ); + pOut->PassEMFPlus( buffer, pWMF->Read( buffer, length ) ); + free( buffer ); + pWMF->Seek( pos ); + + bHaveDC = false; + + OSL_ASSERT(length >= 4); + //reduce by 32bit length itself, skip in SeekRel if + //impossibly unavailble + sal_uInt32 nRemainder = length >= 4 ? length-4 : length; + + const size_t nRequiredHeaderSize = 12; + while (nRemainder >= nRequiredHeaderSize) + { + sal_uInt16 type(0), flags(0); + sal_uInt32 size(0), dataSize(0); + + *pWMF >> type >> flags >> size >> dataSize; + nRemainder -= nRequiredHeaderSize; + + EMFP_DEBUG(printf ("\t\tEMF+ record type: %d\n", type)); + + // GetDC + if( type == 16388 ) { + bHaveDC = true; + EMFP_DEBUG(printf ("\t\tEMF+ lock DC (device context)\n")); + } + + //Get the length of the remaining data of this record based + //on the alleged size + sal_uInt32 nRemainingRecordData = size >= nRequiredHeaderSize ? + size-nRequiredHeaderSize : 0; + //clip to available size + nRemainingRecordData = std::min(nRemainingRecordData, nRemainder); + pWMF->SeekRel(nRemainingRecordData); + nRemainder -= nRemainingRecordData; + } + pWMF->SeekRel(nRemainder); +} + +/** + * Reads polygons from the stream. + * The <class T> parameter is for the type of the points (sal_uInt32 or sal_uInt16). + * The <class Drawer> parameter is a boost binding for the method that will draw the polygon. + * skipFirst: if the first point read is the 0th point or the 1st point in the array. + * */ +template <class T, class Drawer> +void EnhWMFReader::ReadAndDrawPolygon(Drawer drawer, const sal_Bool skipFirst) +{ + sal_uInt32 nPoints(0), nStartIndex(0); + pWMF->SeekRel( 16 ); + *pWMF >> nPoints; + if (skipFirst) + { + nPoints ++; + nStartIndex ++; + } + + Polygon aPolygon = ReadPolygon<T>(nStartIndex, nPoints); + drawer(pOut, aPolygon, skipFirst, bRecordPath); +} + + +/** + * Reads polygons from the stream. + * The <class T> parameter is for the type of the points + * nStartIndex: which is the starting index in the polygon of the first point read + * nPoints: number of points + * pWMF: the stream containings the polygons + * */ +template <class T> +Polygon EnhWMFReader::ReadPolygon(sal_uInt32 nStartIndex, sal_uInt32 nPoints) +{ + Polygon aPolygon(nPoints); + for (sal_uInt16 i = nStartIndex ; i < nPoints && pWMF->good(); i++ ) + { + T nX, nY; + *pWMF >> nX >> nY; + if (!pWMF->good()) + break; + aPolygon[ i ] = Point( nX, nY ); + } + + return aPolygon; +} + +/** + * Reads a polyline from the WMF file and draws it + * The <class T> parameter refers to the type of the points. (e.g. sal_uInt16 or sal_uInt32) + * */ +template <class T> +void EnhWMFReader::ReadAndDrawPolyLine() +{ + sal_uInt32 nPoints; + sal_Int32 i, nPoly(0), nGesPoints(0); + pWMF->SeekRel( 0x10 ); + // Number of Polygons: + *pWMF >> nPoly >> nGesPoints; + + // taking the amount of points of each polygon, retrieving the total number of points + if ( pWMF->good() && + ( static_cast< sal_uInt32 >(nPoly) < SAL_MAX_UINT32 / sizeof(sal_uInt16) ) && + ( static_cast< sal_uInt32 >( nPoly ) * sizeof(sal_uInt16) ) <= ( nEndPos - pWMF->Tell() ) + ) + { + sal_uInt16* pnPoints = new sal_uInt16[ nPoly ]; + for ( i = 0; i < nPoly && pWMF->good(); i++ ) + { + *pWMF >> nPoints; + pnPoints[ i ] = (sal_uInt16)nPoints; + } + // Get polygon points: + for ( i = 0; ( i < nPoly ) && pWMF->good(); i++ ) + { + Polygon aPolygon = ReadPolygon<T>(0, pnPoints[i]); + pOut->DrawPolyLine( aPolygon, sal_False, bRecordPath ); + } + delete[] pnPoints; + } +} + +/** + * Reads a poly polygon from the WMF file and draws it. + * The <class T> parameter refers to the type of the points. (e.g. sal_uInt16 or sal_uInt32) + * */ +template <class T> +void EnhWMFReader::ReadAndDrawPolyPolygon() +{ + sal_uInt32 i, nPoly, nGesPoints, nPoints; + pWMF->SeekRel( 0x10 ); + // Number of polygons + *pWMF >> nPoly >> nGesPoints; + if ( pWMF->good() && + ( nGesPoints < SAL_MAX_UINT32 / sizeof(Point) ) && //check against numeric overflowing + ( nPoly < SAL_MAX_UINT32 / sizeof(sal_uInt16) ) && + ( ( nPoly * sizeof( sal_uInt16 ) ) <= ( nEndPos - pWMF->Tell() ) )) + { + //Get number of points in each polygon + sal_uInt16 * pnPoints = new sal_uInt16[ nPoly ]; + for ( i = 0; i < nPoly && pWMF->good(); i++ ) + { + *pWMF >> nPoints; + pnPoints[ i ] = (sal_uInt16)nPoints; + } //end for + if ( pWMF->good() && ( nGesPoints * (sizeof(T)+sizeof(T)) ) <= ( nEndPos - pWMF->Tell() ) ) + { + // Get polygon points + Point * pPtAry = new Point[ nGesPoints ]; + for ( i = 0; i < nGesPoints && pWMF->good(); i++ ) + { + T nX, nY; + *pWMF >> nX >> nY; + pPtAry[ i ] = Point( nX, nY ); + } //end for + // Create PolyPolygon Actions + PolyPolygon aPolyPoly( (sal_uInt16)nPoly, pnPoints, pPtAry ); + pOut->DrawPolyPolygon( aPolyPoly, bRecordPath ); + delete[] pPtAry; + } //end if + delete[] pnPoints; + } //end if +} + +sal_Bool EnhWMFReader::ReadEnhWMF() +{ + sal_uInt32 nStretchBltMode = 0; + sal_uInt32 nRecType(0), nRecSize(0), nNextPos(0), + nW(0), nH(0), nColor(0), nIndex(0), + nDat32(0), nNom1(0), nDen1(0), nNom2(0), nDen2(0); + sal_Int32 nX32(0), nY32(0), nx32(0), ny32(0); + + sal_Bool bFlag(sal_False), bStatus = ReadHeader(); + sal_Bool bHaveDC = false; + + static sal_Bool bEnableEMFPlus = ( getenv( "EMF_PLUS_DISABLE" ) == NULL ); + + while( bStatus && nRecordCount-- && pWMF->good()) + { + *pWMF >> nRecType >> nRecSize; + + if ( !pWMF->good() || ( nRecSize < 8 ) || ( nRecSize & 3 ) ) // Parameters are always divisible by 4 + { + bStatus = sal_False; + break; + } + + nNextPos = pWMF->Tell() + ( nRecSize - 8 ); + + if ( !pWMF->good() || nNextPos > nEndPos ) + { + bStatus = sal_False; + break; + } + + if( !aBmpSaveList.empty() + && ( nRecType != EMR_STRETCHBLT ) + && ( nRecType != EMR_STRETCHDIBITS ) + ) + pOut->ResolveBitmapActions( aBmpSaveList ); + + bFlag = sal_False; + + EMFP_DEBUG(printf ("0x%04x-0x%04x record type: %d size: %d\n",(unsigned int) (nNextPos - nRecSize),(unsigned int) nNextPos, (int)nRecType,(int) nRecSize)); + + if( bEnableEMFPlus && nRecType == EMR_GDICOMMENT ) { + sal_uInt32 length; + + *pWMF >> length; + + EMFP_DEBUG(printf ("\tGDI comment\n\t\tlength: %d\n", (int)length)); + + if( pWMF->good() && length >= 4 ) { + sal_uInt32 id; + + *pWMF >> id; + + EMFP_DEBUG(printf ("\t\tbegin %c%c%c%c id: 0x%x\n", (char)(id & 0xff), (char)((id & 0xff00) >> 8), (char)((id & 0xff0000) >> 16), (char)((id & 0xff000000) >> 24), (unsigned int)id)); + + // EMF+ comment (fixme: BE?) + if( id == 0x2B464D45 && nRecSize >= 12 ) + ReadEMFPlusComment( length, bHaveDC ); + // GDIC comment, doesn't do anything useful yet + else if( id == 0x43494447 && nRecSize >= 12 ) { + //ToDo: ReadGDIComment() + } else { + EMFP_DEBUG(printf ("\t\tunknown id: 0x%x\n",(unsigned int) id)); + } + } + } else if( !bEMFPlus || bHaveDC || nRecType == EMR_EOF ) + + switch( nRecType ) + { + case EMR_POLYBEZIERTO : + ReadAndDrawPolygon<sal_Int32>(boost::bind(&WinMtfOutput::DrawPolyBezier, _1, _2, _3, _4), sal_True); + break; + case EMR_POLYBEZIER : + ReadAndDrawPolygon<sal_Int32>(boost::bind(&WinMtfOutput::DrawPolyBezier, _1, _2, _3, _4), sal_False); + break; + + case EMR_POLYGON : + ReadAndDrawPolygon<sal_Int32>(boost::bind(&WinMtfOutput::DrawPolygon, _1, _2, _3, _4), sal_False); + break; + + case EMR_POLYLINETO : + ReadAndDrawPolygon<sal_Int32>(boost::bind(&WinMtfOutput::DrawPolyLine, _1, _2, _3, _4), sal_True); + break; + case EMR_POLYLINE : + ReadAndDrawPolygon<sal_Int32>(boost::bind(&WinMtfOutput::DrawPolyLine, _1, _2, _3, _4), sal_False); + break; + + case EMR_POLYPOLYLINE : + ReadAndDrawPolyLine<sal_Int32>(); + break; + + case EMR_POLYPOLYGON : + ReadAndDrawPolyPolygon<sal_Int32>(); + break; + + case EMR_SETWINDOWEXTEX : + { // #75383# + *pWMF >> nW >> nH; + pOut->SetWinExt( Size( nW, nH ) ); + } + break; + + case EMR_SETWINDOWORGEX : + { + *pWMF >> nX32 >> nY32; + pOut->SetWinOrg( Point( nX32, nY32 ) ); + } + break; + + case EMR_SCALEWINDOWEXTEX : + { + *pWMF >> nNom1 >> nDen1 >> nNom2 >> nDen2; + pOut->ScaleWinExt( (double)nNom1 / nDen1, (double)nNom2 / nDen2 ); + } + break; + + case EMR_SETVIEWPORTORGEX : + { + *pWMF >> nX32 >> nY32; + pOut->SetDevOrg( Point( nX32, nY32 ) ); + } + break; + + case EMR_SCALEVIEWPORTEXTEX : + { + *pWMF >> nNom1 >> nDen1 >> nNom2 >> nDen2; + pOut->ScaleDevExt( (double)nNom1 / nDen1, (double)nNom2 / nDen2 ); + } + break; + + case EMR_SETVIEWPORTEXTEX : + { + *pWMF >> nW >> nH; + pOut->SetDevExt( Size( nW, nH ) ); + } + break; + + case EMR_EOF : + nRecordCount = 0; // #76846# + break; + + case EMR_SETPIXELV : + { + *pWMF >> nX32 >> nY32; + pOut->DrawPixel( Point( nX32, nY32 ), ReadColor() ); + } + break; + + case EMR_SETMAPMODE : + { + sal_uInt32 nMapMode; + *pWMF >> nMapMode; + pOut->SetMapMode( nMapMode ); + } + break; + + case EMR_SETBKMODE : + { + *pWMF >> nDat32; + pOut->SetBkMode( nDat32 ); + } + break; + + case EMR_SETPOLYFILLMODE : + break; + + case EMR_SETROP2 : + { + *pWMF >> nDat32; + pOut->SetRasterOp( nDat32 ); + } + break; + + case EMR_SETSTRETCHBLTMODE : + { + *pWMF >> nStretchBltMode; + } + break; + + case EMR_SETTEXTALIGN : + { + *pWMF >> nDat32; + pOut->SetTextAlign( nDat32 ); + } + break; + + case EMR_SETTEXTCOLOR : + { + pOut->SetTextColor( ReadColor() ); + } + break; + + case EMR_SETBKCOLOR : + { + pOut->SetBkColor( ReadColor() ); + } + break; + + case EMR_OFFSETCLIPRGN : + { + *pWMF >> nX32 >> nY32; + pOut->MoveClipRegion( Size( nX32, nY32 ) ); + } + break; + + case EMR_MOVETOEX : + { + *pWMF >> nX32 >> nY32; + pOut->MoveTo( Point( nX32, nY32 ), bRecordPath ); + } + break; + + case EMR_INTERSECTCLIPRECT : + { + *pWMF >> nX32 >> nY32 >> nx32 >> ny32; + pOut->IntersectClipRect( ReadRectangle( nX32, nY32, nx32, ny32 ) ); + } + break; + + case EMR_SAVEDC : + { + pOut->Push(); + } + break; + + case EMR_RESTOREDC : + { + pOut->Pop(); + } + break; + + case EMR_SETWORLDTRANSFORM : + { + XForm aTempXForm; + *pWMF >> aTempXForm; + pOut->SetWorldTransform( aTempXForm ); + } + break; + + case EMR_MODIFYWORLDTRANSFORM : + { + sal_uInt32 nMode; + XForm aTempXForm; + *pWMF >> aTempXForm >> nMode; + pOut->ModifyWorldTransform( aTempXForm, nMode ); + } + break; + + case EMR_SELECTOBJECT : + { + *pWMF >> nIndex; + pOut->SelectObject( nIndex ); + } + break; + + case EMR_CREATEPEN : + { + *pWMF >> nIndex; + if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) + { + + LineInfo aLineInfo; + sal_uInt32 nStyle; + Size aSize; + //#fdo39428 Remove SvStream operator>>(long&) + sal_Int32 nTmpW(0), nTmpH(0); + + *pWMF >> nStyle >> nTmpW >> nTmpH; + aSize.Width() = nTmpW; + aSize.Height() = nTmpH; + + if ( aSize.Width() ) + aLineInfo.SetWidth( aSize.Width() ); + + sal_Bool bTransparent = sal_False; + sal_uInt16 nDashCount = 0; + sal_uInt16 nDotCount = 0; + switch( nStyle ) + { + case PS_DASHDOTDOT : + nDotCount++; + case PS_DASHDOT : + nDashCount++; + case PS_DOT : + nDotCount++; + break; + case PS_DASH : + nDashCount++; + break; + case PS_NULL : + bTransparent = sal_True; + aLineInfo.SetStyle( LINE_NONE ); + break; + default : + case PS_INSIDEFRAME : + case PS_SOLID : + aLineInfo.SetStyle( LINE_SOLID ); + } + if ( nDashCount | nDotCount ) + { + aLineInfo.SetStyle( LINE_DASH ); + aLineInfo.SetDashCount( nDashCount ); + aLineInfo.SetDotCount( nDotCount ); + } + pOut->CreateObject( nIndex, GDI_PEN, new WinMtfLineStyle( ReadColor(), aLineInfo, bTransparent ) ); + } + } + break; + + case EMR_EXTCREATEPEN : + { + sal_Int32 elpHatch; + sal_uInt32 offBmi, cbBmi, offBits, cbBits, nStyle, nWidth, nBrushStyle, elpNumEntries; + Color aColorRef; + + *pWMF >> nIndex; + if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) + { + *pWMF >> offBmi >> cbBmi >> offBits >> cbBits >> nStyle >> nWidth >> nBrushStyle; + aColorRef = ReadColor(); + *pWMF >> elpHatch >> elpNumEntries; + + LineInfo aLineInfo; + if ( nWidth ) + aLineInfo.SetWidth( nWidth ); + + sal_Bool bTransparent = sal_False; + sal_uInt16 nDashCount = 0; + sal_uInt16 nDotCount = 0; + + switch( nStyle & PS_STYLE_MASK ) + { + case PS_DASHDOTDOT : + nDotCount++; + case PS_DASHDOT : + nDashCount++; + case PS_DOT : + nDotCount++; + break; + case PS_DASH : + nDashCount++; + break; + case PS_NULL : + bTransparent = sal_True; + aLineInfo.SetStyle( LINE_NONE ); + break; + + default : + case PS_INSIDEFRAME : + case PS_SOLID : + aLineInfo.SetStyle( LINE_SOLID ); + } + if ( nDashCount | nDotCount ) + { + aLineInfo.SetStyle( LINE_DASH ); + aLineInfo.SetDashCount( nDashCount ); + aLineInfo.SetDotCount( nDotCount ); + } + pOut->CreateObject( nIndex, GDI_PEN, new WinMtfLineStyle( aColorRef, aLineInfo, bTransparent ) ); + } + } + break; + + case EMR_CREATEBRUSHINDIRECT : + { + sal_uInt32 nStyle; + *pWMF >> nIndex; + if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) + { + *pWMF >> nStyle; + pOut->CreateObject( nIndex, GDI_BRUSH, new WinMtfFillStyle( ReadColor(), ( nStyle == BS_HOLLOW ) ? sal_True : sal_False ) ); + } + } + break; + + case EMR_DELETEOBJECT : + { + *pWMF >> nIndex; + if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) + pOut->DeleteObject( nIndex ); + } + break; + + case EMR_ELLIPSE : + { + *pWMF >> nX32 >> nY32 >> nx32 >> ny32; + pOut->DrawEllipse( ReadRectangle( nX32, nY32, nx32, ny32 ) ); + } + break; + + case EMR_RECTANGLE : + { + *pWMF >> nX32 >> nY32 >> nx32 >> ny32; + pOut->DrawRect( ReadRectangle( nX32, nY32, nx32, ny32 ) ); + } + break; + + case EMR_ROUNDRECT : + { + *pWMF >> nX32 >> nY32 >> nx32 >> ny32 >> nW >> nH; + Size aSize( Size( nW, nH ) ); + pOut->DrawRoundRect( ReadRectangle( nX32, nY32, nx32, ny32 ), aSize ); + } + break; + + case EMR_ARC : + { + sal_uInt32 nStartX, nStartY, nEndX, nEndY; + *pWMF >> nX32 >> nY32 >> nx32 >> ny32 >> nStartX >> nStartY >> nEndX >> nEndY; + pOut->DrawArc( ReadRectangle( nX32, nY32, nx32, ny32 ), Point( nStartX, nStartY ), Point( nEndX, nEndY ) ); + } + break; + + case EMR_CHORD : + { + sal_uInt32 nStartX, nStartY, nEndX, nEndY; + *pWMF >> nX32 >> nY32 >> nx32 >> ny32 >> nStartX >> nStartY >> nEndX >> nEndY; + pOut->DrawChord( ReadRectangle( nX32, nY32, nx32, ny32 ), Point( nStartX, nStartY ), Point( nEndX, nEndY ) ); + } + break; + + case EMR_PIE : + { + sal_uInt32 nStartX, nStartY, nEndX, nEndY; + *pWMF >> nX32 >> nY32 >> nx32 >> ny32 >> nStartX >> nStartY >> nEndX >> nEndY; + const Rectangle aRect( ReadRectangle( nX32, nY32, nx32, ny32 )); + + // #i73608# OutputDevice deviates from WMF + // semantics. start==end means full ellipse here. + if( nStartX == nEndX && nStartY == nEndY ) + pOut->DrawEllipse( aRect ); + else + pOut->DrawPie( aRect, Point( nStartX, nStartY ), Point( nEndX, nEndY ) ); + } + break; + + case EMR_LINETO : + { + *pWMF >> nX32 >> nY32; + pOut->LineTo( Point( nX32, nY32 ), bRecordPath ); + } + break; + + case EMR_ARCTO : + { + sal_uInt32 nStartX, nStartY, nEndX, nEndY; + *pWMF >> nX32 >> nY32 >> nx32 >> ny32 >> nStartX >> nStartY >> nEndX >> nEndY; + pOut->DrawArc( ReadRectangle( nX32, nY32, nx32, ny32 ), Point( nStartX, nStartY ), Point( nEndX, nEndY ), sal_True ); + } + break; + + case EMR_BEGINPATH : + { + pOut->ClearPath(); + bRecordPath = sal_True; + } + break; + + case EMR_ABORTPATH : + pOut->ClearPath(); + case EMR_ENDPATH : + bRecordPath = sal_False; + break; + + case EMR_CLOSEFIGURE : + pOut->ClosePath(); + break; + + case EMR_FILLPATH : + pOut->StrokeAndFillPath( sal_False, sal_True ); + break; + + case EMR_STROKEANDFILLPATH : + pOut->StrokeAndFillPath( sal_True, sal_True ); + break; + + case EMR_STROKEPATH : + pOut->StrokeAndFillPath( sal_True, sal_False ); + break; + + case EMR_SELECTCLIPPATH : + { + sal_Int32 nClippingMode; + *pWMF >> nClippingMode; + pOut->SetClipPath( pOut->GetPathObj(), nClippingMode, sal_True ); + } + break; + + case EMR_EXTSELECTCLIPRGN : + { + sal_Int32 iMode, cbRgnData; + *pWMF >> cbRgnData + >> iMode; + + PolyPolygon aPolyPoly; + if ( cbRgnData ) + ImplReadRegion( aPolyPoly, *pWMF, nRecSize ); + pOut->SetClipPath( aPolyPoly, iMode, sal_False ); + } + break; + + case EMR_BITBLT : // PASSTHROUGH INTENDED + case EMR_STRETCHBLT : + { + sal_Int32 xDest, yDest, cxDest, cyDest, xSrc, ySrc, cxSrc, cySrc; + sal_uInt32 dwRop, iUsageSrc, offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc; + XForm xformSrc; + + sal_uInt32 nStart = pWMF->Tell() - 8; + + pWMF->SeekRel( 0x10 ); + *pWMF >> xDest >> yDest >> cxDest >> cyDest >> dwRop >> xSrc >> ySrc + >> xformSrc >> nColor >> iUsageSrc >> offBmiSrc >> cbBmiSrc + >> offBitsSrc >> cbBitsSrc; + + if ( nRecType == EMR_STRETCHBLT ) + *pWMF >> cxSrc >> cySrc; + else + cxSrc = cySrc = 0; + + Bitmap aBitmap; + Rectangle aRect( Point( xDest, yDest ), Size( cxDest, cyDest ) ); + + cxDest = abs( (int)cxDest ); // sj: i37894, size can be negative + cyDest = abs( (int)cyDest ); // and also 122889 + + if ( (cbBitsSrc > (SAL_MAX_UINT32 - 14)) || ((SAL_MAX_UINT32 - 14) - cbBitsSrc < cbBmiSrc) ) + bStatus = sal_False; + else + { + sal_uInt32 nSize = cbBmiSrc + cbBitsSrc + 14; + if ( nSize <= ( nEndPos - nStartPos ) ) + { + char* pBuf = new char[ nSize ]; + SvMemoryStream aTmp( pBuf, nSize, STREAM_READ | STREAM_WRITE ); + aTmp.ObjectOwnsMemory( sal_True ); + aTmp << (sal_uInt8)'B' + << (sal_uInt8)'M' + << (sal_uInt32)cbBitsSrc + << (sal_uInt16)0 + << (sal_uInt16)0 + << (sal_uInt32)cbBmiSrc + 14; + pWMF->Seek( nStart + offBmiSrc ); + pWMF->Read( pBuf + 14, cbBmiSrc ); + pWMF->Seek( nStart + offBitsSrc ); + pWMF->Read( pBuf + 14 + cbBmiSrc, cbBitsSrc ); + aTmp.Seek( 0 ); + aBitmap.Read( aTmp, sal_True ); + + // test if it is sensible to crop + if ( ( cxSrc > 0 ) && ( cySrc > 0 ) && + ( xSrc >= 0 ) && ( ySrc >= 0 ) && + ( xSrc + cxSrc <= aBitmap.GetSizePixel().Width() ) && + ( ySrc + cySrc <= aBitmap.GetSizePixel().Height() ) ) + { + Rectangle aCropRect( Point( xSrc, ySrc ), Size( cxSrc, cySrc ) ); + aBitmap.Crop( aCropRect ); + } + aBmpSaveList.push_back( new BSaveStruct( aBitmap, aRect, dwRop, pOut->GetFillStyle () ) ); + } + } + } + break; + + case EMR_STRETCHDIBITS : + { + sal_Int32 xDest, yDest, xSrc, ySrc, cxSrc, cySrc, cxDest, cyDest; + sal_uInt32 offBmiSrc, cbBmiSrc, offBitsSrc, cbBitsSrc, iUsageSrc, dwRop; + sal_uInt32 nStart = pWMF->Tell() - 8; + + pWMF->SeekRel( 0x10 ); + *pWMF >> xDest + >> yDest + >> xSrc + >> ySrc + >> cxSrc + >> cySrc + >> offBmiSrc + >> cbBmiSrc + >> offBitsSrc + >> cbBitsSrc + >> iUsageSrc + >> dwRop + >> cxDest + >> cyDest; + + Bitmap aBitmap; + Rectangle aRect( Point( xDest, yDest ), Size( cxDest, cyDest ) ); + + cxDest = abs( (int)cxDest ); // sj: i37894, size can be negative + cyDest = abs( (int)cyDest ); // and also 122889 + + if ( ((SAL_MAX_UINT32 - 14) < cbBitsSrc) + || ((SAL_MAX_UINT32 - 14) - cbBitsSrc < cbBmiSrc ) + ) + { + bStatus = sal_False; + } + else + { + sal_uInt32 nSize = cbBmiSrc + cbBitsSrc + 14; + if ( nSize <= ( nEndPos - nStartPos ) ) + { + char* pBuf = new char[ nSize ]; + SvMemoryStream aTmp( pBuf, nSize, STREAM_READ | STREAM_WRITE ); + aTmp.ObjectOwnsMemory( sal_True ); + aTmp << (sal_uInt8)'B' + << (sal_uInt8)'M' + << (sal_uInt32)cbBitsSrc + << (sal_uInt16)0 + << (sal_uInt16)0 + << (sal_uInt32)cbBmiSrc + 14; + pWMF->Seek( nStart + offBmiSrc ); + pWMF->Read( pBuf + 14, cbBmiSrc ); + pWMF->Seek( nStart + offBitsSrc ); + pWMF->Read( pBuf + 14 + cbBmiSrc, cbBitsSrc ); + aTmp.Seek( 0 ); + aBitmap.Read( aTmp, sal_True ); + + // test if it is sensible to crop + if ( ( cxSrc > 0 ) && ( cySrc > 0 ) && + ( xSrc >= 0 ) && ( ySrc >= 0 ) && + ( xSrc + cxSrc <= aBitmap.GetSizePixel().Width() ) && + ( ySrc + cySrc <= aBitmap.GetSizePixel().Height() ) ) + { + Rectangle aCropRect( Point( xSrc, ySrc ), Size( cxSrc, cySrc ) ); + aBitmap.Crop( aCropRect ); + } + aBmpSaveList.push_back( new BSaveStruct( aBitmap, aRect, dwRop, pOut->GetFillStyle () ) ); + } + } + } + break; + + case EMR_EXTCREATEFONTINDIRECTW : + { + *pWMF >> nIndex; + if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) + { + LOGFONTW aLogFont; + *pWMF >> aLogFont.lfHeight + >> aLogFont.lfWidth + >> aLogFont.lfEscapement + >> aLogFont.lfOrientation + >> aLogFont.lfWeight + >> aLogFont.lfItalic + >> aLogFont.lfUnderline + >> aLogFont.lfStrikeOut + >> aLogFont.lfCharSet + >> aLogFont.lfOutPrecision + >> aLogFont.lfClipPrecision + >> aLogFont.lfQuality + >> aLogFont.lfPitchAndFamily; + + sal_Unicode lfFaceName[ LF_FACESIZE ]; + + for ( int i = 0; i < LF_FACESIZE; i++ ) + { + sal_uInt16 nChar; + *pWMF >> nChar; + lfFaceName[ i ] = nChar; + } + aLogFont.alfFaceName = rtl::OUString( lfFaceName ); + pOut->CreateObject( nIndex, GDI_FONT, new WinMtfFontStyle( aLogFont ) ); + } + } + break; + + case EMR_EXTTEXTOUTA : + bFlag = sal_True; + case EMR_EXTTEXTOUTW : + { + sal_Int32 nLeft, nTop, nRight, nBottom, ptlReferenceX, ptlReferenceY, nGfxMode, nXScale, nYScale; + sal_uInt32 nCurPos, nLen, nOffString, nOptions, offDx; + sal_Int32* pDX = NULL; + + nCurPos = pWMF->Tell() - 8; + + *pWMF >> nLeft >> nTop >> nRight >> nBottom >> nGfxMode >> nXScale >> nYScale + >> ptlReferenceX >> ptlReferenceY >> nLen >> nOffString >> nOptions; + + pWMF->SeekRel( 0x10 ); + *pWMF >> offDx; + + sal_Int32 nTextLayoutMode = TEXT_LAYOUT_DEFAULT; + if ( nOptions & ETO_RTLREADING ) + nTextLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT; + pOut->SetTextLayoutMode( nTextLayoutMode ); + DBG_ASSERT( ( nOptions & ( ETO_PDY | ETO_GLYPH_INDEX ) ) == 0, "SJ: ETO_PDY || ETO_GLYPH_INDEX in EMF" ); + + Point aPos( ptlReferenceX, ptlReferenceY ); + if ( nLen && ( nLen < SAL_MAX_UINT32 / sizeof(sal_Int32) ) ) + { + if ( offDx && (( nCurPos + offDx + nLen * 4 ) <= nNextPos ) ) + { + pWMF->Seek( nCurPos + offDx ); + if ( ( nLen * sizeof(sal_uInt32) ) <= ( nEndPos - pWMF->Tell() ) ) + { + pDX = new sal_Int32[ nLen ]; + sal_uInt32 i; + for ( i = 0; i < nLen; i++ ) + *pWMF >> pDX[ i ]; + } + } + pWMF->Seek( nCurPos + nOffString ); + String aText; + if ( bFlag ) + { + if ( nLen <= ( nEndPos - pWMF->Tell() ) ) + { + sal_Char* pBuf = new sal_Char[ nLen ]; + pWMF->Read( pBuf, nLen ); + aText = String( pBuf, (sal_uInt16)nLen, pOut->GetCharSet() ); + delete[] pBuf; + + if ( aText.Len() != nLen ) + { + sal_uInt16 i, j; + sal_Int32* pOldDx = pDX; + pDX = new sal_Int32[ aText.Len() ]; + for ( i = 0, j = 0; i < aText.Len(); i++ ) + { + sal_Unicode cUniChar = aText.GetChar(i); + rtl::OString aCharacter(&cUniChar, 1, pOut->GetCharSet()); + pDX[ i ] = 0; + for (sal_Int32 k = 0; ( k < aCharacter.getLength() ) && ( j < nLen ) && ( i < aText.Len() ); ++k) + pDX[ i ] += pOldDx[ j++ ]; + } + delete[] pOldDx; + } + } + } + else + { + if ( ( nLen * sizeof(sal_Unicode) ) <= ( nEndPos - pWMF->Tell() ) ) + { + sal_Unicode* pBuf = new sal_Unicode[ nLen ]; + pWMF->Read( pBuf, nLen << 1 ); +#ifdef OSL_BIGENDIAN + sal_Char nTmp, *pTmp = (sal_Char*)( pBuf + nLen ); + while ( pTmp-- != (sal_Char*)pBuf ) + { + nTmp = *pTmp--; + pTmp[ 1 ] = *pTmp; + *pTmp = nTmp; + } +#endif + aText = rtl::OUString(pBuf, nLen); + delete[] pBuf; + } + } + pOut->DrawText( aPos, aText, pDX, bRecordPath, nGfxMode ); + } + delete[] pDX; + } + break; + + case EMR_POLYBEZIERTO16 : + ReadAndDrawPolygon<sal_Int16>(boost::bind(&WinMtfOutput::DrawPolyBezier, _1, _2, _3, _4), sal_True); + break; + case EMR_POLYBEZIER16 : + ReadAndDrawPolygon<sal_Int16>(boost::bind(&WinMtfOutput::DrawPolyBezier, _1, _2, _3, _4), sal_False); + break; + + case EMR_POLYGON16 : + ReadAndDrawPolygon<sal_Int16>(boost::bind(&WinMtfOutput::DrawPolygon, _1, _2, _3, _4), sal_False); + break; + + case EMR_POLYLINETO16 : + ReadAndDrawPolygon<sal_Int16>(boost::bind(&WinMtfOutput::DrawPolyLine, _1, _2, _3, _4), sal_True); + break; + case EMR_POLYLINE16 : + ReadAndDrawPolygon<sal_Int16>(boost::bind(&WinMtfOutput::DrawPolyLine, _1, _2, _3, _4), sal_False); + break; + + case EMR_POLYPOLYLINE16 : + ReadAndDrawPolyLine<sal_Int16>(); + break; + + case EMR_POLYPOLYGON16 : + ReadAndDrawPolyPolygon<sal_Int16>(); + break; + + case EMR_FILLRGN : + { + sal_uInt32 nLen; + PolyPolygon aPolyPoly; + pWMF->SeekRel( 0x10 ); + *pWMF >> nLen >> nIndex; + + if ( ImplReadRegion( aPolyPoly, *pWMF, nRecSize ) ) + { + pOut->Push(); + pOut->SelectObject( nIndex ); + pOut->DrawPolyPolygon( aPolyPoly, sal_False ); + pOut->Pop(); + } + } + break; + + case EMR_CREATEDIBPATTERNBRUSHPT : + { + sal_uInt32 nStart = pWMF->Tell() - 8; + Bitmap aBitmap; + + *pWMF >> nIndex; + + if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) + { + sal_uInt32 usage, offBmi, cbBmi, offBits, cbBits; + + *pWMF >> usage; + *pWMF >> offBmi; + *pWMF >> cbBmi; + *pWMF >> offBits; + *pWMF >> cbBits; + + if ( (cbBits > (SAL_MAX_UINT32 - 14)) || ((SAL_MAX_UINT32 - 14) - cbBits < cbBmi) ) + bStatus = sal_False; + else if ( offBmi ) + { + sal_uInt32 nSize = cbBmi + cbBits + 14; + if ( nSize <= ( nEndPos - nStartPos ) ) + { + char* pBuf = new char[ nSize ]; + + SvMemoryStream aTmp( pBuf, nSize, STREAM_READ | STREAM_WRITE ); + aTmp.ObjectOwnsMemory( sal_True ); + aTmp << (sal_uInt8)'B' + << (sal_uInt8)'M' + << (sal_uInt32)cbBits + << (sal_uInt16)0 + << (sal_uInt16)0 + << (sal_uInt32)cbBmi + 14; + pWMF->Seek( nStart + offBmi ); + pWMF->Read( pBuf + 14, cbBmi ); + pWMF->Seek( nStart + offBits ); + pWMF->Read( pBuf + 14 + cbBmi, cbBits ); + aTmp.Seek( 0 ); + aBitmap.Read( aTmp, sal_True ); + } + } + } + + pOut->CreateObject( nIndex, GDI_BRUSH, new WinMtfFillStyle( aBitmap ) ); + } + break; + +#ifdef WIN_MTF_ASSERT + default : WinMtfAssertHandler( "Unknown Meta Action" ); break; + case EMR_MASKBLT : WinMtfAssertHandler( "MaskBlt" ); break; + case EMR_PLGBLT : WinMtfAssertHandler( "PlgBlt" ); break; + case EMR_SETDIBITSTODEVICE : WinMtfAssertHandler( "SetDIBitsToDevice" ); break; + case EMR_FRAMERGN : WinMtfAssertHandler( "FrameRgn" ); break; + case EMR_INVERTRGN : WinMtfAssertHandler( "InvertRgn" ); break; + case EMR_PAINTRGN : WinMtfAssertHandler( "PaintRgn" ); break; + case EMR_FLATTENPATH : WinMtfAssertHandler( "FlattenPath" ); break; + case EMR_WIDENPATH : WinMtfAssertHandler( "WidenPath" ); break; + case EMR_POLYDRAW : WinMtfAssertHandler( "Polydraw" ); break; + case EMR_SETARCDIRECTION : WinMtfAssertHandler( "SetArcDirection" ); break; + case EMR_SETPALETTEENTRIES : WinMtfAssertHandler( "SetPaletteEntries" ); break; + case EMR_RESIZEPALETTE : WinMtfAssertHandler( "ResizePalette" ); break; + case EMR_EXTFLOODFILL : WinMtfAssertHandler( "ExtFloodFill" ); break; + case EMR_ANGLEARC : WinMtfAssertHandler( "AngleArc" ); break; + case EMR_SETCOLORADJUSTMENT : WinMtfAssertHandler( "SetColorAdjustment" ); break; + case EMR_POLYDRAW16 : WinMtfAssertHandler( "PolyDraw16" ); break; + case EMR_POLYTEXTOUTA : WinMtfAssertHandler( "PolyTextOutA" ); break; + case EMR_POLYTEXTOUTW : WinMtfAssertHandler( "PolyTextOutW" ); break; + case EMR_CREATECOLORSPACE : WinMtfAssertHandler( "CreateColorSpace" ); break; + case EMR_SETCOLORSPACE : WinMtfAssertHandler( "SetColorSpace" ); break; + case EMR_DELETECOLORSPACE : WinMtfAssertHandler( "DeleteColorSpace" ); break; + case EMR_GLSRECORD : WinMtfAssertHandler( "GlsRecord" ); break; + case EMR_GLSBOUNDEDRECORD : WinMtfAssertHandler( "GlsBoundRecord" ); break; + case EMR_PIXELFORMAT : WinMtfAssertHandler( "PixelFormat" ); break; + case EMR_DRAWESCAPE : WinMtfAssertHandler( "DrawEscape" ); break; + case EMR_EXTESCAPE : WinMtfAssertHandler( "ExtEscape" ); break; + case EMR_STARTDOC : WinMtfAssertHandler( "StartDoc" ); break; + case EMR_SMALLTEXTOUT : WinMtfAssertHandler( "SmallTextOut" ); break; + case EMR_FORCEUFIMAPPING : WinMtfAssertHandler( "ForceUFIMapping" ); break; + case EMR_NAMEDESCAPE : WinMtfAssertHandler( "NamedEscape" ); break; + case EMR_COLORCORRECTPALETTE : WinMtfAssertHandler( "ColorCorrectPalette" ); break; + case EMR_SETICMPROFILEA : WinMtfAssertHandler( "SetICMProfileA" ); break; + case EMR_SETICMPROFILEW : WinMtfAssertHandler( "SetICMProfileW" ); break; + case EMR_ALPHABLEND : WinMtfAssertHandler( "Alphablend" ); break; + case EMR_TRANSPARENTBLT : WinMtfAssertHandler( "TransparenBlt" ); break; + case EMR_TRANSPARENTDIB : WinMtfAssertHandler( "TransparenDib" ); break; + case EMR_GRADIENTFILL : WinMtfAssertHandler( "GradientFill" ); break; + case EMR_SETLINKEDUFIS : WinMtfAssertHandler( "SetLinkedUFIS" ); break; + + case EMR_SETMAPPERFLAGS : WinMtfAssertHandler( "SetMapperFlags", 0 ); break; + case EMR_SETICMMODE : WinMtfAssertHandler( "SetICMMode", 0 ); break; + case EMR_CREATEMONOBRUSH : WinMtfAssertHandler( "CreateMonoBrush", 0 ); break; + case EMR_SETBRUSHORGEX : WinMtfAssertHandler( "SetBrushOrgEx", 0 ); break; + case EMR_SETMETARGN : WinMtfAssertHandler( "SetMetArgn", 0 ); break; + case EMR_SETMITERLIMIT : WinMtfAssertHandler( "SetMiterLimit", 0 ); break; + case EMR_EXCLUDECLIPRECT : WinMtfAssertHandler( "ExcludeClipRect", 0 ); break; + case EMR_REALIZEPALETTE : WinMtfAssertHandler( "RealizePalette", 0 ); break; + case EMR_SELECTPALETTE : WinMtfAssertHandler( "SelectPalette", 0 ); break; + case EMR_CREATEPALETTE : WinMtfAssertHandler( "CreatePalette", 0 ); break; + case EMR_ALPHADIBBLEND : WinMtfAssertHandler( "AlphaDibBlend", 0 ); break; + case EMR_SETTEXTJUSTIFICATION : WinMtfAssertHandler( "SetTextJustification", 0 ); break; + + case EMR_GDICOMMENT : + case EMR_HEADER : // has already been read at ReadHeader() + break; +#endif + } + pWMF->Seek( nNextPos ); + } + if( !aBmpSaveList.empty() ) + pOut->ResolveBitmapActions( aBmpSaveList ); + + if ( bStatus ) + pWMF->Seek(nEndPos); + + return bStatus; +}; + +//----------------------------------------------------------------------------------- + +sal_Bool EnhWMFReader::ReadHeader() +{ + sal_uInt32 nsal_uInt32, nHeaderSize, nPalEntries; + sal_Int32 nLeft, nTop, nRight, nBottom; + + // Spare me the METAFILEHEADER here + // Reading the METAHEADER + *pWMF >> nsal_uInt32 >> nHeaderSize; + if ( nsal_uInt32 != 1 ) // Type + return sal_False; + + // bound size + Rectangle rclBounds; // rectangle in logical units 1/100th mm + *pWMF >> nLeft >> nTop >> nRight >> nBottom; + rclBounds.Left() = nLeft; + rclBounds.Top() = nTop; + rclBounds.Right() = nRight; + rclBounds.Bottom() = nBottom; + + // picture frame size + Rectangle rclFrame; // rectangle in device units + *pWMF >> nLeft >> nTop >> nRight >> nBottom; + rclFrame.Left() = nLeft; + rclFrame.Top() = nTop; + rclFrame.Right() = nRight; + rclFrame.Bottom() = nBottom; + + *pWMF >> nsal_uInt32; // signature + + if ( nsal_uInt32 != 0x464d4520 ) + return sal_False; + + *pWMF >> nsal_uInt32; // nVersion + *pWMF >> nEndPos; // size of metafile + nEndPos += nStartPos; + + sal_uInt32 nStrmPos = pWMF->Tell(); // checking if nEndPos is valid + pWMF->Seek( STREAM_SEEK_TO_END ); + if ( pWMF->Tell() < nEndPos ) + nEndPos = pWMF->Tell(); + pWMF->Seek( nStrmPos ); + + *pWMF >> nRecordCount; + + if ( !nRecordCount ) + return sal_False; + + pWMF->SeekRel( 0xc ); + + sal_Int32 nPixX, nPixY, nMillX, nMillY; + *pWMF >> nPalEntries >> nPixX >> nPixY >> nMillX >> nMillY; + + pOut->SetrclFrame( rclFrame ); + pOut->SetrclBounds( rclBounds ); + pOut->SetRefPix( Size( nPixX, nPixY ) ); + pOut->SetRefMill( Size( nMillX, nMillY ) ); + + pWMF->Seek( nStartPos + nHeaderSize ); + return sal_True; +} + +//----------------------------------------------------------------------------------- + +Rectangle EnhWMFReader::ReadRectangle( sal_Int32 x1, sal_Int32 y1, sal_Int32 x2, sal_Int32 y2 ) +{ + Point aTL ( Point( x1, y1 ) ); + Point aBR( Point( --x2, --y2 ) ); + return Rectangle( aTL, aBR ); +} + +EnhWMFReader::~EnhWMFReader() +{ + +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/winmtf.cxx b/vcl/source/filter/wmf/winmtf.cxx new file mode 100644 index 000000000000..63b0996b24a3 --- /dev/null +++ b/vcl/source/filter/wmf/winmtf.cxx @@ -0,0 +1,2239 @@ +/* -*- 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 "winmtf.hxx" +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <vcl/metaact.hxx> +#include <vcl/graphictools.hxx> +#include <vcl/canvastools.hxx> +#include <vcl/metric.hxx> +#include <vcl/svapp.hxx> +#include <rtl/strbuf.hxx> +#include <rtl/tencinfo.h> + +// ------------------------------------------------------------------------ + +#if OSL_DEBUG_LEVEL > 1 +#define EMFP_DEBUG(x) x +#else +#define EMFP_DEBUG(x) +#endif + +void WinMtfClipPath::intersectClipRect( const Rectangle& rRect ) +{ + maClip.intersectRange( + vcl::unotools::b2DRectangleFromRectangle(rRect)); +} + +void WinMtfClipPath::excludeClipRect( const Rectangle& rRect ) +{ + maClip.subtractRange( + vcl::unotools::b2DRectangleFromRectangle(rRect)); +} + +void WinMtfClipPath::setClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode ) +{ + const basegfx::B2DPolyPolygon& rB2DPoly=rPolyPolygon.getB2DPolyPolygon(); + switch ( nClippingMode ) + { + case RGN_OR : + maClip.unionPolyPolygon(rB2DPoly); + break; + case RGN_XOR : + maClip.xorPolyPolygon(rB2DPoly); + break; + case RGN_DIFF : + maClip.subtractPolyPolygon(rB2DPoly); + break; + case RGN_AND : + maClip.intersectPolyPolygon(rB2DPoly); + break; + case RGN_COPY : + maClip = basegfx::tools::B2DClipState(rB2DPoly); + break; + } +} + +void WinMtfClipPath::moveClipRegion( const Size& rSize ) +{ + // what a weird concept. emulate, don't want this in B2DClipState + // API + basegfx::B2DPolyPolygon aCurrClip=maClip.getClipPoly(); + basegfx::B2DHomMatrix aTranslate; + aTranslate.translate(rSize.Width(), rSize.Height()); + + aCurrClip.transform(aTranslate); + maClip = basegfx::tools::B2DClipState( aCurrClip ); +} + +basegfx::B2DPolyPolygon WinMtfClipPath::getClipPath() const +{ + return maClip.getClipPoly(); +} + +// ------------------------------------------------------------------------ + +void WinMtfPathObj::AddPoint( const Point& rPoint ) +{ + if ( bClosed ) + Insert( Polygon(), POLYPOLY_APPEND ); + Polygon& rPoly = ((PolyPolygon&)*this)[ Count() - 1 ]; + rPoly.Insert( rPoly.GetSize(), rPoint, POLY_NORMAL ); + bClosed = sal_False; +} + +void WinMtfPathObj::AddPolyLine( const Polygon& rPolyLine ) +{ + if ( bClosed ) + Insert( Polygon(), POLYPOLY_APPEND ); + Polygon& rPoly = ((PolyPolygon&)*this)[ Count() - 1 ]; + rPoly.Insert( rPoly.GetSize(), rPolyLine ); + bClosed = sal_False; +} + +void WinMtfPathObj::AddPolygon( const Polygon& rPoly ) +{ + Insert( rPoly, POLYPOLY_APPEND ); + bClosed = sal_True; +} + +void WinMtfPathObj::AddPolyPolygon( const PolyPolygon& rPolyPoly ) +{ + sal_uInt16 i, nCount = rPolyPoly.Count(); + for ( i = 0; i < nCount; i++ ) + Insert( rPolyPoly[ i ], POLYPOLY_APPEND ); + bClosed = sal_True; +} + +void WinMtfPathObj::ClosePath() +{ + if ( Count() ) + { + Polygon& rPoly = ((PolyPolygon&)*this)[ Count() - 1 ]; + if ( rPoly.GetSize() > 2 ) + { + Point aFirst( rPoly[ 0 ] ); + if ( aFirst != rPoly[ rPoly.GetSize() - 1 ] ) + rPoly.Insert( rPoly.GetSize(), aFirst, POLY_NORMAL ); + } + } + bClosed = sal_True; +} + +// ------------------------------------------------------------------------ + +WinMtfFontStyle::WinMtfFontStyle( LOGFONTW& rFont ) +{ + CharSet eCharSet; + if ( ( rFont.lfCharSet == OEM_CHARSET ) || ( rFont.lfCharSet == DEFAULT_CHARSET ) ) + eCharSet = RTL_TEXTENCODING_MS_1252; + else + eCharSet = rtl_getTextEncodingFromWindowsCharset( rFont.lfCharSet ); + if ( eCharSet == RTL_TEXTENCODING_DONTKNOW ) + eCharSet = RTL_TEXTENCODING_MS_1252; + aFont.SetCharSet( eCharSet ); + aFont.SetName( rFont.alfFaceName ); + FontFamily eFamily; + switch ( rFont.lfPitchAndFamily & 0xf0 ) + { + case FF_ROMAN: + eFamily = FAMILY_ROMAN; + break; + + case FF_SWISS: + eFamily = FAMILY_SWISS; + break; + + case FF_MODERN: + eFamily = FAMILY_MODERN; + break; + + case FF_SCRIPT: + eFamily = FAMILY_SCRIPT; + break; + + case FF_DECORATIVE: + eFamily = FAMILY_DECORATIVE; + break; + + default: + eFamily = FAMILY_DONTKNOW; + break; + } + aFont.SetFamily( eFamily ); + + FontPitch ePitch; + switch ( rFont.lfPitchAndFamily & 0x0f ) + { + case FIXED_PITCH: + ePitch = PITCH_FIXED; + break; + + case DEFAULT_PITCH: + case VARIABLE_PITCH: + default: + ePitch = PITCH_VARIABLE; + break; + } + aFont.SetPitch( ePitch ); + + FontWeight eWeight; + if( rFont.lfWeight <= FW_THIN ) + eWeight = WEIGHT_THIN; + else if( rFont.lfWeight <= FW_ULTRALIGHT ) + eWeight = WEIGHT_ULTRALIGHT; + else if( rFont.lfWeight <= FW_LIGHT ) + eWeight = WEIGHT_LIGHT; + else if( rFont.lfWeight < FW_MEDIUM ) + eWeight = WEIGHT_NORMAL; + else if( rFont.lfWeight == FW_MEDIUM ) + eWeight = WEIGHT_MEDIUM; + else if( rFont.lfWeight <= FW_SEMIBOLD ) + eWeight = WEIGHT_SEMIBOLD; + else if( rFont.lfWeight <= FW_BOLD ) + eWeight = WEIGHT_BOLD; + else if( rFont.lfWeight <= FW_ULTRABOLD ) + eWeight = WEIGHT_ULTRABOLD; + else + eWeight = WEIGHT_BLACK; + aFont.SetWeight( eWeight ); + + if( rFont.lfItalic ) + aFont.SetItalic( ITALIC_NORMAL ); + + if( rFont.lfUnderline ) + aFont.SetUnderline( UNDERLINE_SINGLE ); + + if( rFont.lfStrikeOut ) + aFont.SetStrikeout( STRIKEOUT_SINGLE ); + + if ( rFont.lfOrientation ) + aFont.SetOrientation( (short)rFont.lfOrientation ); + else + aFont.SetOrientation( (short)rFont.lfEscapement ); + + Size aFontSize( Size( rFont.lfWidth, rFont.lfHeight ) ); + if ( rFont.lfHeight > 0 ) + { + // converting the cell height into a font height + VirtualDevice aVDev; + aFont.SetSize( aFontSize ); + aVDev.SetFont( aFont ); + FontMetric aMetric( aVDev.GetFontMetric() ); + long nHeight = aMetric.GetAscent() + aMetric.GetDescent(); + if ( nHeight ) + { + double fHeight = ((double)aFontSize.Height() * rFont.lfHeight ) / nHeight; + aFontSize.Height() = (sal_Int32)( fHeight + 0.5 ); + } + } + else if ( aFontSize.Height() < 0 ) + aFontSize.Height() *= -1; + + if ( !rFont.lfWidth ) + { + VirtualDevice aVDev; + aFont.SetSize( aFontSize ); + aVDev.SetFont( aFont ); + FontMetric aMetric( aVDev.GetFontMetric() ); + aFontSize.Width() = aMetric.GetWidth(); + } + + aFont.SetSize( aFontSize ); +}; + +// ------------------------------------------------------------------------ + +#ifdef WIN_MTF_ASSERT +void WinMtfAssertHandler( const sal_Char* pAction, sal_uInt32 nFlags ) +{ + static sal_Bool bOnlyOnce; + static sal_Int32 nAssertCount; + + if ( nFlags & WIN_MTF_ASSERT_INIT ) + nAssertCount = 0; + if ( nFlags & WIN_MTF_ASSERT_ONCE ) + bOnlyOnce = sal_True; + if ( nFlags & WIN_MTF_ASSERT_MIFE ) + { + if ( ( nAssertCount == 0 ) || ( bOnlyOnce == sal_False ) ) + { + rtl::OStringBuffer aText(RTL_CONSTASCII_STRINGPARAM( + "WMF/EMF Import: ")); + if (pAction) + aText.append(pAction); + aText.append(RTL_CONSTASCII_STRINGPARAM( + " needs to be implemented")); + DBG_ASSERT( 0, aText.getStr() ); + } + nAssertCount++; + } +} +#endif + +// ------------------------------------------------------------------------ + +WinMtf::WinMtf( WinMtfOutput* pWinMtfOutput, SvStream& rStreamWMF, FilterConfigItem* pConfigItem ) : + pOut ( pWinMtfOutput ), + pWMF ( &rStreamWMF ), + pFilterConfigItem ( pConfigItem ) +{ +#ifdef WIN_MTF_ASSERT + // we want to assert not implemented features, but we do this + // only once, so that nobody is handicaped by getting too much assertions + // I hope this will bring more testdocuments, without support of these + // testdocuments the implementation of missing features won't be possible. (SJ) + WinMtfAssertHandler( NULL, WIN_MTF_ASSERT_INIT | WIN_MTF_ASSERT_ONCE ); +#endif + + SvLockBytes *pLB = pWMF->GetLockBytes(); + if ( pLB ) + pLB->SetSynchronMode( sal_True ); + + nStartPos = pWMF->Tell(); + + pOut->SetDevOrg( Point() ); + if ( pFilterConfigItem ) + { + xStatusIndicator = pFilterConfigItem->GetStatusIndicator(); + if ( xStatusIndicator.is() ) + { + rtl::OUString aMsg; + xStatusIndicator->start( aMsg, 100 ); + } + } +} + +// ------------------------------------------------------------------------ + +WinMtf::~WinMtf() +{ + delete pOut; + + if ( xStatusIndicator.is() ) + xStatusIndicator->end(); +} + +// ------------------------------------------------------------------------ + +void WinMtf::Callback( sal_uInt16 nPercent ) +{ + if ( xStatusIndicator.is() ) + xStatusIndicator->setValue( nPercent ); +} + +// ------------------------------------------------------------------------ + +Color WinMtf::ReadColor() +{ + sal_uInt32 nColor; + *pWMF >> nColor; + return Color( (sal_uInt8)nColor, (sal_uInt8)( nColor >> 8 ), (sal_uInt8)( nColor >> 16 ) ); +}; + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +Point WinMtfOutput::ImplMap( const Point& rPt ) +{ + if ( mnWinExtX && mnWinExtY ) + { + double fX = rPt.X(); + double fY = rPt.Y(); + + double fX2 = fX * maXForm.eM11 + fY * maXForm.eM21 + maXForm.eDx; + double fY2 = fX * maXForm.eM12 + fY * maXForm.eM22 + maXForm.eDy; + + if ( mnGfxMode == GM_COMPATIBLE ) + { + switch( mnMapMode ) + { + case MM_TEXT: + fX2 -= mnWinOrgX; + fY2 -= mnWinOrgY; + if( mnDevWidth != 1 || mnDevHeight != 1 ) { + fX2 *= 2540.0/mnUnitsPerInch; + fY2 *= 2540.0/mnUnitsPerInch; + } + fX2 += mnDevOrgX; + fY2 += mnDevOrgY; + fX2 *= (double)mnMillX * 100.0 / (double)mnPixX; + fY2 *= (double)mnMillY * 100.0 / (double)mnPixY; + + break; + case MM_LOENGLISH : + { + fX2 -= mnWinOrgX; + fY2 = mnWinOrgY-fY2; + fX2 *= 25.40; + fY2 *= 25.40; + fX2 += mnDevOrgX; + fY2 += mnDevOrgY; + } + break; + case MM_HIENGLISH : + { + fX2 -= mnWinOrgX; + fY2 = mnWinOrgY-fY2; + fX2 *= 2.540; + fY2 *= 2.540; + fX2 += mnDevOrgX; + fY2 += mnDevOrgY; + } + break; + case MM_LOMETRIC : + { + fX2 -= mnWinOrgX; + fY2 = mnWinOrgY-fY2; + fX2 *= 10; + fY2 *= 10; + fX2 += mnDevOrgX; + fY2 += mnDevOrgY; + } + break; + case MM_HIMETRIC : + { + fX2 -= mnWinOrgX; + fY2 = mnWinOrgY-fY2; + fX2 += mnDevOrgX; + fY2 += mnDevOrgY; + } + break; + default : + { + fX2 -= mnWinOrgX; + fY2 -= mnWinOrgY; + fX2 /= mnWinExtX; + fY2 /= mnWinExtY; + fX2 *= mnDevWidth; + fY2 *= mnDevHeight; + fX2 += mnDevOrgX; + fY2 += mnDevOrgY; // fX2, fY2 now in device units + fX2 *= (double)mnMillX * 100.0 / (double)mnPixX; + fY2 *= (double)mnMillY * 100.0 / (double)mnPixY; + } + break; + } + fX2 -= mrclFrame.Left(); + fY2 -= mrclFrame.Top(); + } + return Point( FRound( fX2 ), FRound( fY2 ) ); + } + else + return Point(); +}; + +// ------------------------------------------------------------------------ + +Size WinMtfOutput::ImplMap( const Size& rSz ) +{ + if ( mnWinExtX && mnWinExtY ) + { + double fWidth = rSz.Width() * maXForm.eM11; + double fHeight = rSz.Height() * maXForm.eM22; + + if ( mnGfxMode == GM_COMPATIBLE ) + { + switch( mnMapMode ) + { + case MM_TEXT: + if( mnDevWidth != 1 && mnDevHeight != 1 ) { + fWidth *= 2540.0/mnUnitsPerInch; + fHeight*= 2540.0/mnUnitsPerInch; + } else { + fWidth *= (double)mnMillX * 100 / (double)mnPixX; + fHeight *= (double)mnMillY * 100 / (double)mnPixY; + } + break; + case MM_LOENGLISH : + { + fWidth *= 25.40; + fHeight*=-25.40; + } + break; + case MM_HIENGLISH : + { + fWidth *= 2.540; + fHeight*=-2.540; + } + break; + case MM_LOMETRIC : + { + fWidth *= 10; + fHeight*=-10; + } + break; + case MM_HIMETRIC : + { + fHeight *= -1; + } + break; + default : + { + fWidth /= mnWinExtX; + fHeight /= mnWinExtY; + fWidth *= mnDevWidth; + fHeight *= mnDevHeight; + fWidth *= (double)mnMillX * 100 / (double)mnPixX; + fHeight *= (double)mnMillY * 100 / (double)mnPixY; + } + break; + } + } + return Size( FRound( fWidth ), FRound( fHeight ) ); + } + else + return Size(); +} + +//----------------------------------------------------------------------------------- + +Rectangle WinMtfOutput::ImplMap( const Rectangle& rRect ) +{ + return Rectangle( ImplMap( rRect.TopLeft() ), ImplMap( rRect.GetSize() ) ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ImplMap( Font& rFont ) +{ + // !!! HACK: Wir setzen die Breite jetzt immer auf Null, + // da OS die Breite unterschiedlich interpretieren; + // muss spaeter in SV portabel gemacht werden ( KA 08.02.96 ) + Size aFontSize = ImplMap ( rFont.GetSize() ); + + if( aFontSize.Height() < 0 ) + aFontSize.Height() *= -1; + + rFont.SetSize( aFontSize ); + + if( ( mnWinExtX * mnWinExtY ) < 0 ) + rFont.SetOrientation( 3600 - rFont.GetOrientation() ); +} + +//----------------------------------------------------------------------------------- + +Polygon& WinMtfOutput::ImplMap( Polygon& rPolygon ) +{ + sal_uInt16 nPoints = rPolygon.GetSize(); + for ( sal_uInt16 i = 0; i < nPoints; i++ ) + { + rPolygon[ i ] = ImplMap( rPolygon[ i ] ); + } + return rPolygon; +} + +//----------------------------------------------------------------------------------- + +PolyPolygon& WinMtfOutput::ImplMap( PolyPolygon& rPolyPolygon ) +{ + sal_uInt16 nPolys = rPolyPolygon.Count(); + for ( sal_uInt16 i = 0; i < nPolys; ImplMap( rPolyPolygon[ i++ ] ) ) ; + return rPolyPolygon; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SelectObject( sal_Int32 nIndex ) +{ + GDIObj* pGDIObj = NULL; + + if ( nIndex & ENHMETA_STOCK_OBJECT ) + pGDIObj = new GDIObj(); + else + { + nIndex &= 0xffff; // zur Sicherheit: mehr als 65535 nicht zulassen + + if ( (sal_uInt32)nIndex < vGDIObj.size() ) + pGDIObj = vGDIObj[ nIndex ]; + } + + if( pGDIObj == NULL ) + return; + + if ( nIndex & ENHMETA_STOCK_OBJECT ) + { + sal_uInt16 nStockId = (sal_uInt8)nIndex; + switch( nStockId ) + { + case WHITE_BRUSH : + { + pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ) ) ); + } + break; + case LTGRAY_BRUSH : + { + pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_LIGHTGRAY ) ) ); + } + break; + case GRAY_BRUSH : + case DKGRAY_BRUSH : + { + pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_GRAY ) ) ); + } + break; + case BLACK_BRUSH : + { + pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_BLACK ) ) ); + } + break; + case NULL_BRUSH : + { + pGDIObj->Set( GDI_BRUSH, new WinMtfFillStyle( Color( COL_TRANSPARENT ), sal_True ) ); + } + break; + case WHITE_PEN : + { + pGDIObj->Set( GDI_PEN, new WinMtfLineStyle( Color( COL_WHITE ) ) ); + } + break; + case BLACK_PEN : + { + pGDIObj->Set( GDI_PEN, new WinMtfLineStyle( Color( COL_BLACK ) ) ); + } + break; + case NULL_PEN : + { + pGDIObj->Set( GDI_PEN, new WinMtfLineStyle( Color( COL_TRANSPARENT ), sal_True ) ); + } + break; + default: + break; + } + } + if ( pGDIObj->pStyle ) + { + switch( pGDIObj->eType ) + { + case GDI_PEN : + maLineStyle = (WinMtfLineStyle*)pGDIObj->pStyle; + break; + case GDI_BRUSH : + { + maFillStyle = (WinMtfFillStyle*)pGDIObj->pStyle; + mbFillStyleSelected = sal_True; + } + break; + case GDI_FONT : + maFont = ((WinMtfFontStyle*)pGDIObj->pStyle)->aFont; + break; + default: + break; // -Wall many options not handled. + } + } + if ( nIndex & ENHMETA_STOCK_OBJECT ) + delete pGDIObj; +} + +//----------------------------------------------------------------------------------- + +const Font& WinMtfOutput::GetFont() const +{ + return maFont; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetTextLayoutMode( const sal_uInt32 nTextLayoutMode ) +{ + mnTextLayoutMode = nTextLayoutMode; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetBkMode( sal_uInt32 nMode ) +{ + mnBkMode = nMode; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetBkColor( const Color& rColor ) +{ + maBkColor = rColor; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetTextColor( const Color& rColor ) +{ + maTextColor = rColor; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetTextAlign( sal_uInt32 nAlign ) +{ + mnTextAlign = nAlign; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ImplResizeObjectArry( sal_uInt32 nNewEntrys ) +{ + sal_uInt32 i = vGDIObj.size(); + vGDIObj.resize( nNewEntrys ); + for ( ; i < nNewEntrys ; i++ ) + vGDIObj[ i ] = NULL; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ImplDrawClippedPolyPolygon( const PolyPolygon& rPolyPoly ) +{ + if ( rPolyPoly.Count() ) + { + ImplSetNonPersistentLineColorTransparenz(); + if ( rPolyPoly.Count() == 1 ) + { + if ( rPolyPoly.IsRect() ) + mpGDIMetaFile->AddAction( new MetaRectAction( rPolyPoly.GetBoundRect() ) ); + else + { + Polygon aPoly( rPolyPoly[ 0 ] ); + sal_uInt16 nCount = aPoly.GetSize(); + if ( nCount ) + { + if ( aPoly[ nCount - 1 ] != aPoly[ 0 ] ) + { + Point aPoint( aPoly[ 0 ] ); + aPoly.Insert( nCount, aPoint ); + } + mpGDIMetaFile->AddAction( new MetaPolygonAction( aPoly ) ); + } + } + } + else + mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPoly ) ); + } +} + + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::CreateObject( GDIObjectType eType, void* pStyle ) +{ + if ( pStyle ) + { + if ( eType == GDI_FONT ) + { + ImplMap( ((WinMtfFontStyle*)pStyle)->aFont ); + if (!((WinMtfFontStyle*)pStyle)->aFont.GetHeight() ) + ((WinMtfFontStyle*)pStyle)->aFont.SetHeight( 423 ); // defaulting to 12pt + } + else if ( eType == GDI_PEN ) + { + Size aSize( ((WinMtfLineStyle*)pStyle)->aLineInfo.GetWidth(), 0 ); + ((WinMtfLineStyle*)pStyle)->aLineInfo.SetWidth( ImplMap( aSize ).Width() ); + if ( ((WinMtfLineStyle*)pStyle)->aLineInfo.GetStyle() == LINE_DASH ) + { + aSize.Width() += 1; + long nDotLen = ImplMap( aSize ).Width(); + ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDistance( nDotLen ); + ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDotLen( nDotLen ); + ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDashLen( nDotLen * 4 ); + } + } + } + sal_uInt32 nIndex; + for ( nIndex = 0; nIndex < vGDIObj.size(); nIndex++ ) + { + if ( vGDIObj[ nIndex ] == NULL ) + break; + } + if ( nIndex == vGDIObj.size() ) + ImplResizeObjectArry( vGDIObj.size() + 16 ); + + vGDIObj[ nIndex ] = new GDIObj( eType, pStyle ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::CreateObject( sal_Int32 nIndex, GDIObjectType eType, void* pStyle ) +{ + if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) + { + nIndex &= 0xffff; // zur Sicherheit: mehr als 65535 nicht zulassen + if ( pStyle ) + { + if ( eType == GDI_FONT ) + ImplMap( ((WinMtfFontStyle*)pStyle)->aFont ); + else if ( eType == GDI_PEN ) + { + Size aSize( ((WinMtfLineStyle*)pStyle)->aLineInfo.GetWidth(), 0 ); + ((WinMtfLineStyle*)pStyle)->aLineInfo.SetWidth( ImplMap( aSize ).Width() ); + if ( ((WinMtfLineStyle*)pStyle)->aLineInfo.GetStyle() == LINE_DASH ) + { + aSize.Width() += 1; + long nDotLen = ImplMap( aSize ).Width(); + ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDistance( nDotLen ); + ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDotLen( nDotLen ); + ((WinMtfLineStyle*)pStyle)->aLineInfo.SetDashLen( nDotLen * 4 ); + } + } + } + if ( (sal_uInt32)nIndex >= vGDIObj.size() ) + ImplResizeObjectArry( nIndex + 16 ); + + if ( vGDIObj[ nIndex ] != NULL ) + delete vGDIObj[ nIndex ]; + + vGDIObj[ nIndex ] = new GDIObj( eType, pStyle ); + } + else + { + switch ( eType ) + { + case GDI_PEN : + delete (WinMtfLineStyle*)pStyle; + break; + case GDI_BRUSH : + delete (WinMtfFillStyle*)pStyle; + break; + case GDI_FONT : + delete (WinMtfFontStyle*)pStyle; + break; + + default: + OSL_FAIL( "unsupported style not deleted" ); + break; + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DeleteObject( sal_Int32 nIndex ) +{ + if ( ( nIndex & ENHMETA_STOCK_OBJECT ) == 0 ) + { + if ( (sal_uInt32)nIndex < vGDIObj.size() ) + { + delete vGDIObj[ nIndex ]; + vGDIObj[ nIndex ] = NULL; + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::IntersectClipRect( const Rectangle& rRect ) +{ + mbClipNeedsUpdate=true; + aClipPath.intersectClipRect( ImplMap( rRect ) ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ExcludeClipRect( const Rectangle& rRect ) +{ + mbClipNeedsUpdate=true; + aClipPath.excludeClipRect( ImplMap( rRect ) ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::MoveClipRegion( const Size& rSize ) +{ + mbClipNeedsUpdate=true; + aClipPath.moveClipRegion( ImplMap( rSize ) ); +} + +void WinMtfOutput::SetClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode, sal_Bool bIsMapped ) +{ + mbClipNeedsUpdate=true; + if ( bIsMapped ) + aClipPath.setClipPath( rPolyPolygon, nClippingMode ); + else + { + PolyPolygon aPP( rPolyPolygon ); + aClipPath.setClipPath( ImplMap( aPP ), nClippingMode ); + } +} + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +WinMtfOutput::WinMtfOutput( GDIMetaFile& rGDIMetaFile ) : + mnLatestTextAlign ( 0 ), + mnTextAlign ( TA_LEFT | TA_TOP | TA_NOUPDATECP ), + maLatestBkColor ( 0x12345678 ), + maBkColor ( COL_WHITE ), + mnLatestTextLayoutMode( TEXT_LAYOUT_DEFAULT ), + mnTextLayoutMode ( TEXT_LAYOUT_DEFAULT ), + mnLatestBkMode ( 0 ), + mnBkMode ( OPAQUE ), + meLatestRasterOp ( ROP_INVERT ), + meRasterOp ( ROP_OVERPAINT ), + maActPos ( Point() ), + mbNopMode ( sal_False ), + mbFillStyleSelected ( sal_False ), + mbClipNeedsUpdate ( true ), + mbComplexClip ( false ), + mnGfxMode ( GM_COMPATIBLE ), + mnMapMode ( MM_TEXT ), + mnUnitsPerInch ( 96 ), + mnDevOrgX ( 0 ), + mnDevOrgY ( 0 ), + mnDevWidth ( 1 ), + mnDevHeight ( 1 ), + mnWinOrgX ( 0 ), + mnWinOrgY ( 0 ), + mnWinExtX ( 1 ), + mnWinExtY ( 1 ), + mnPixX ( 100 ), + mnPixY ( 100 ), + mnMillX ( 1 ), + mnMillY ( 1 ), + mpGDIMetaFile ( &rGDIMetaFile ) +{ + mpGDIMetaFile->AddAction( new MetaPushAction( PUSH_CLIPREGION ) ); // The original clipregion has to be on top + // of the stack so it can always be restored + // this is necessary to be able to support + // SetClipRgn( NULL ) and similar ClipRgn actions (SJ) + + maFont.SetName( String( RTL_CONSTASCII_USTRINGPARAM( "Arial" )) ); // sj: #i57205#, we do have some scaling problems if using + maFont.SetCharSet( RTL_TEXTENCODING_MS_1252 ); // the default font then most times a x11 font is used, we + maFont.SetHeight( 423 ); // will prevent this defining a font + + maLatestLineStyle.aLineColor = Color( 0x12, 0x34, 0x56 ); + maLatestFillStyle.aFillColor = Color( 0x12, 0x34, 0x56 ); + + mnRop = R2_BLACK + 1; + SetRasterOp( R2_BLACK ); +}; + +//----------------------------------------------------------------------------------- + +WinMtfOutput::~WinMtfOutput() +{ + mpGDIMetaFile->AddAction( new MetaPopAction() ); + mpGDIMetaFile->SetPrefMapMode( MAP_100TH_MM ); + if ( mrclFrame.IsEmpty() ) + mpGDIMetaFile->SetPrefSize( Size( mnDevWidth, mnDevHeight ) ); + else + mpGDIMetaFile->SetPrefSize( mrclFrame.GetSize() ); + + for ( sal_uInt32 i = 0; i < vGDIObj.size(); i++ ) + delete vGDIObj[ i ]; +}; + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::UpdateClipRegion() +{ + if ( mbClipNeedsUpdate ) + { + mbClipNeedsUpdate = false; + mbComplexClip = false; + + mpGDIMetaFile->AddAction( new MetaPopAction() ); // taking the orignal clipregion + mpGDIMetaFile->AddAction( new MetaPushAction( PUSH_CLIPREGION ) ); // + + // skip for 'no clipping at all' case + if( !aClipPath.isEmpty() ) + { + const basegfx::B2DPolyPolygon& rClipPoly( aClipPath.getClipPath() ); + mpGDIMetaFile->AddAction( + new MetaISectRectClipRegionAction( + vcl::unotools::rectangleFromB2DRectangle( + rClipPoly.getB2DRange()))); + + mbComplexClip = rClipPoly.count() > 1 + || !basegfx::tools::isRectangle(rClipPoly); + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ImplSetNonPersistentLineColorTransparenz() +{ + Color aColor( COL_TRANSPARENT); + WinMtfLineStyle aTransparentLine( aColor, sal_True ); + if ( ! ( maLatestLineStyle == aTransparentLine ) ) + { + maLatestLineStyle = aTransparentLine; + mpGDIMetaFile->AddAction( new MetaLineColorAction( aTransparentLine.aLineColor, !aTransparentLine.bTransparent ) ); + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::UpdateLineStyle() +{ + if (!( maLatestLineStyle == maLineStyle ) ) + { + maLatestLineStyle = maLineStyle; + mpGDIMetaFile->AddAction( new MetaLineColorAction( maLineStyle.aLineColor, !maLineStyle.bTransparent ) ); + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::UpdateFillStyle() +{ + if ( !mbFillStyleSelected ) // SJ: #i57205# taking care of bkcolor if no brush is selected + maFillStyle = WinMtfFillStyle( maBkColor, mnBkMode == TRANSPARENT ); + if (!( maLatestFillStyle == maFillStyle ) ) + { + maLatestFillStyle = maFillStyle; + if (maFillStyle.aType == FillStyleSolid) + mpGDIMetaFile->AddAction( new MetaFillColorAction( maFillStyle.aFillColor, !maFillStyle.bTransparent ) ); + } +} + +//----------------------------------------------------------------------------------- + +sal_uInt32 WinMtfOutput::SetRasterOp( sal_uInt32 nRasterOp ) +{ + sal_uInt32 nRetROP = mnRop; + if ( nRasterOp != mnRop ) + { + mnRop = nRasterOp; + static WinMtfFillStyle aNopFillStyle; + static WinMtfLineStyle aNopLineStyle; + + if ( mbNopMode && ( nRasterOp != R2_NOP ) ) + { // beim uebergang von R2_NOP auf anderen Modus + // gesetzten Pen und Brush aktivieren + maFillStyle = aNopFillStyle; + maLineStyle = aNopLineStyle; + mbNopMode = sal_False; + } + switch( nRasterOp ) + { + case R2_NOT: + meRasterOp = ROP_INVERT; + break; + + case R2_XORPEN: + meRasterOp = ROP_XOR; + break; + + case R2_NOP: + { + meRasterOp = ROP_OVERPAINT; + if( mbNopMode == sal_False ) + { + aNopFillStyle = maFillStyle; + aNopLineStyle = maLineStyle; + maFillStyle = WinMtfFillStyle( Color( COL_TRANSPARENT ), sal_True ); + maLineStyle = WinMtfLineStyle( Color( COL_TRANSPARENT ), sal_True ); + mbNopMode = sal_True; + } + } + break; + + default: + meRasterOp = ROP_OVERPAINT; + break; + } + } + if ( nRetROP != nRasterOp ) + mpGDIMetaFile->AddAction( new MetaRasterOpAction( meRasterOp ) ); + return nRetROP; +}; + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::StrokeAndFillPath( sal_Bool bStroke, sal_Bool bFill ) +{ + if ( aPathObj.Count() ) + { + UpdateClipRegion(); + UpdateLineStyle(); + UpdateFillStyle(); + if ( bFill ) + { + if ( !bStroke ) + { + mpGDIMetaFile->AddAction( new MetaPushAction( PUSH_LINECOLOR ) ); + mpGDIMetaFile->AddAction( new MetaLineColorAction( Color(), sal_False ) ); + } + if ( aPathObj.Count() == 1 ) + mpGDIMetaFile->AddAction( new MetaPolygonAction( aPathObj.GetObject( 0 ) ) ); + else + mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( aPathObj ) ); + + if ( !bStroke ) + mpGDIMetaFile->AddAction( new MetaPopAction() ); + } + else + { + sal_uInt16 i, nCount = aPathObj.Count(); + for ( i = 0; i < nCount; i++ ) + mpGDIMetaFile->AddAction( new MetaPolyLineAction( aPathObj[ i ], maLineStyle.aLineInfo ) ); + } + ClearPath(); + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawPixel( const Point& rSource, const Color& rColor ) +{ + mpGDIMetaFile->AddAction( new MetaPixelAction( ImplMap( rSource), rColor ) ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::MoveTo( const Point& rPoint, sal_Bool bRecordPath ) +{ + Point aDest( ImplMap( rPoint ) ); + if ( bRecordPath ) + { + // fdo#57353 create new subpath for subsequent moves + if ( aPathObj.Count() ) + if ( aPathObj[ aPathObj.Count() - 1 ].GetSize() ) + aPathObj.Insert( Polygon(), POLYPOLY_APPEND ); + aPathObj.AddPoint( aDest ); + } + maActPos = aDest; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::LineTo( const Point& rPoint, sal_Bool bRecordPath ) +{ + UpdateClipRegion(); + + Point aDest( ImplMap( rPoint ) ); + if ( bRecordPath ) + aPathObj.AddPoint( aDest ); + else + { + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaLineAction( maActPos, aDest, maLineStyle.aLineInfo ) ); + } + maActPos = aDest; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawRect( const Rectangle& rRect, sal_Bool bEdge ) +{ + UpdateClipRegion(); + UpdateFillStyle(); + + if ( mbComplexClip ) + { + Polygon aPoly( ImplMap( rRect ) ); + PolyPolygon aPolyPolyRect( aPoly ); + PolyPolygon aDest; + PolyPolygon(aClipPath.getClipPath()).GetIntersection( aPolyPolyRect, aDest ); + ImplDrawClippedPolyPolygon( aDest ); + } + else + { + if ( bEdge ) + { + if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) ) + { + ImplSetNonPersistentLineColorTransparenz(); + mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) ); + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( ImplMap( rRect ) ),maLineStyle.aLineInfo ) ); + } + else + { + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) ); + } + } + else + { + ImplSetNonPersistentLineColorTransparenz(); + mpGDIMetaFile->AddAction( new MetaRectAction( ImplMap( rRect ) ) ); + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawRoundRect( const Rectangle& rRect, const Size& rSize ) +{ + UpdateClipRegion(); + UpdateLineStyle(); + UpdateFillStyle(); + mpGDIMetaFile->AddAction( new MetaRoundRectAction( ImplMap( rRect ), labs( ImplMap( rSize ).Width() ), labs( ImplMap( rSize ).Height() ) ) ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawEllipse( const Rectangle& rRect ) +{ + UpdateClipRegion(); + UpdateFillStyle(); + + if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) ) + { + Point aCenter( ImplMap( rRect.Center() ) ); + Size aRad( ImplMap( Size( rRect.GetWidth() / 2, rRect.GetHeight() / 2 ) ) ); + + ImplSetNonPersistentLineColorTransparenz(); + mpGDIMetaFile->AddAction( new MetaEllipseAction( ImplMap( rRect ) ) ); + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aCenter, aRad.Width(), aRad.Height() ), maLineStyle.aLineInfo ) ); + } + else + { + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaEllipseAction( ImplMap( rRect ) ) ); + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawArc( const Rectangle& rRect, const Point& rStart, const Point& rEnd, sal_Bool bTo ) +{ + UpdateClipRegion(); + UpdateLineStyle(); + UpdateFillStyle(); + + Rectangle aRect( ImplMap( rRect ) ); + Point aStart( ImplMap( rStart ) ); + Point aEnd( ImplMap( rEnd ) ); + + if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) ) + { + if ( aStart == aEnd ) + { // SJ: #i53768# if start & end is identical, then we have to draw a full ellipse + Point aCenter( aRect.Center() ); + Size aRad( aRect.GetWidth() / 2, aRect.GetHeight() / 2 ); + + mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aCenter, aRad.Width(), aRad.Height() ), maLineStyle.aLineInfo ) ); + } + else + mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aRect, aStart, aEnd, POLY_ARC ), maLineStyle.aLineInfo ) ); + } + else + mpGDIMetaFile->AddAction( new MetaArcAction( aRect, aStart, aEnd ) ); + + if ( bTo ) + maActPos = aEnd; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawPie( const Rectangle& rRect, const Point& rStart, const Point& rEnd ) +{ + UpdateClipRegion(); + UpdateFillStyle(); + + Rectangle aRect( ImplMap( rRect ) ); + Point aStart( ImplMap( rStart ) ); + Point aEnd( ImplMap( rEnd ) ); + + if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) ) + { + ImplSetNonPersistentLineColorTransparenz(); + mpGDIMetaFile->AddAction( new MetaPieAction( aRect, aStart, aEnd ) ); + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aRect, aStart, aEnd, POLY_PIE ), maLineStyle.aLineInfo ) ); + } + else + { + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPieAction( aRect, aStart, aEnd ) ); + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawChord( const Rectangle& rRect, const Point& rStart, const Point& rEnd ) +{ + UpdateClipRegion(); + UpdateFillStyle(); + + Rectangle aRect( ImplMap( rRect ) ); + Point aStart( ImplMap( rStart ) ); + Point aEnd( ImplMap( rEnd ) ); + + if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) ) + { + ImplSetNonPersistentLineColorTransparenz(); + mpGDIMetaFile->AddAction( new MetaChordAction( aRect, aStart, aEnd ) ); + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPolyLineAction( Polygon( aRect, aStart, aEnd, POLY_CHORD ), maLineStyle.aLineInfo ) ); + } + else + { + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaChordAction( aRect, aStart, aEnd ) ); + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawPolygon( Polygon& rPolygon, sal_Bool bRecordPath ) +{ + UpdateClipRegion(); + ImplMap( rPolygon ); + if ( bRecordPath ) + aPathObj.AddPolygon( rPolygon ); + else + { + UpdateFillStyle(); + + if ( mbComplexClip ) + { + PolyPolygon aPolyPoly( rPolygon ); + PolyPolygon aDest; + PolyPolygon(aClipPath.getClipPath()).GetIntersection( aPolyPoly, aDest ); + ImplDrawClippedPolyPolygon( aDest ); + } + else + { + if ( maLineStyle.aLineInfo.GetWidth() || ( maLineStyle.aLineInfo.GetStyle() == LINE_DASH ) ) + { + sal_uInt16 nCount = rPolygon.GetSize(); + if ( nCount ) + { + if ( rPolygon[ nCount - 1 ] != rPolygon[ 0 ] ) + { + Point aPoint( rPolygon[ 0 ] ); + rPolygon.Insert( nCount, aPoint ); + } + } + ImplSetNonPersistentLineColorTransparenz(); + mpGDIMetaFile->AddAction( new MetaPolygonAction( rPolygon ) ); + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) ); + } + else + { + UpdateLineStyle(); + + if (maLatestFillStyle.aType != FillStylePattern) + mpGDIMetaFile->AddAction( new MetaPolygonAction( rPolygon ) ); + else { + SvtGraphicFill aFill = SvtGraphicFill( PolyPolygon( rPolygon ), + Color(), + 0.0, + SvtGraphicFill::fillNonZero, + SvtGraphicFill::fillTexture, + SvtGraphicFill::Transform(), + true, + SvtGraphicFill::hatchSingle, + Color(), + SvtGraphicFill::gradientLinear, + Color(), + Color(), + 0, + Graphic (maLatestFillStyle.aBmp) ); + + SvMemoryStream aMemStm; + + aMemStm << aFill; + + mpGDIMetaFile->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_BEGIN", 0, + static_cast<const sal_uInt8*>(aMemStm.GetData()), + aMemStm.Seek( STREAM_SEEK_TO_END ) ) ); + mpGDIMetaFile->AddAction( new MetaCommentAction( "XPATHFILL_SEQ_END" ) ); + } + + } + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawPolyPolygon( PolyPolygon& rPolyPolygon, sal_Bool bRecordPath ) +{ + UpdateClipRegion(); + + ImplMap( rPolyPolygon ); + + if ( bRecordPath ) + aPathObj.AddPolyPolygon( rPolyPolygon ); + else + { + UpdateFillStyle(); + + if ( mbComplexClip ) + { + PolyPolygon aDest; + PolyPolygon(aClipPath.getClipPath()).GetIntersection( rPolyPolygon, aDest ); + ImplDrawClippedPolyPolygon( aDest ); + } + else + { + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPolyPolygonAction( rPolyPolygon ) ); + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawPolyLine( Polygon& rPolygon, sal_Bool bTo, sal_Bool bRecordPath ) +{ + UpdateClipRegion(); + + ImplMap( rPolygon ); + if ( bTo ) + { + rPolygon[ 0 ] = maActPos; + maActPos = rPolygon[ rPolygon.GetSize() - 1 ]; + } + if ( bRecordPath ) + aPathObj.AddPolyLine( rPolygon ); + else + { + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) ); + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawPolyBezier( Polygon& rPolygon, sal_Bool bTo, sal_Bool bRecordPath ) +{ + UpdateClipRegion(); + + sal_uInt16 nPoints = rPolygon.GetSize(); + if ( ( nPoints >= 4 ) && ( ( ( nPoints - 4 ) % 3 ) == 0 ) ) + { + ImplMap( rPolygon ); + if ( bTo ) + { + rPolygon[ 0 ] = maActPos; + maActPos = rPolygon[ nPoints - 1 ]; + } + sal_uInt16 i; + for ( i = 0; ( i + 2 ) < nPoints; ) + { + rPolygon.SetFlags( i++, POLY_NORMAL ); + rPolygon.SetFlags( i++, POLY_CONTROL ); + rPolygon.SetFlags( i++, POLY_CONTROL ); + } + if ( bRecordPath ) + aPathObj.AddPolyLine( rPolygon ); + else + { + UpdateLineStyle(); + mpGDIMetaFile->AddAction( new MetaPolyLineAction( rPolygon, maLineStyle.aLineInfo ) ); + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::DrawText( Point& rPosition, String& rText, sal_Int32* pDXArry, sal_Bool bRecordPath, sal_Int32 nGfxMode ) +{ + UpdateClipRegion(); + + VirtualDevice* pVDev = NULL; + + rPosition = ImplMap( rPosition ); + + sal_Int32 nOldGfxMode = GetGfxMode(); + SetGfxMode( GM_COMPATIBLE ); + if ( pDXArry ) + { + sal_Int32 i, nSum, nLen = rText.Len(); + + for( i = 0, nSum = 0; i < nLen; i++ ) + { + if ( i ) { + pDXArry[ i - 1 ] = ImplMap( Size( nSum, 0 ) ).Width(); + } + nSum += pDXArry[ i ]; + } + } + if ( mnLatestTextLayoutMode != mnTextLayoutMode ) + { + mnLatestTextLayoutMode = mnTextLayoutMode; + mpGDIMetaFile->AddAction( new MetaLayoutModeAction( mnTextLayoutMode ) ); + } + SetGfxMode( nGfxMode ); + sal_Bool bChangeFont = sal_False; + if ( mnLatestTextAlign != mnTextAlign ) + { + bChangeFont = sal_True; + mnLatestTextAlign = mnTextAlign; + TextAlign eTextAlign; + if ( ( mnTextAlign & TA_BASELINE) == TA_BASELINE ) + eTextAlign = ALIGN_BASELINE; + else if( ( mnTextAlign & TA_BOTTOM) == TA_BOTTOM ) + eTextAlign = ALIGN_BOTTOM; + else + eTextAlign = ALIGN_TOP; + mpGDIMetaFile->AddAction( new MetaTextAlignAction( eTextAlign ) ); + } + if ( maLatestTextColor != maTextColor ) + { + bChangeFont = sal_True; + maLatestTextColor = maTextColor; + mpGDIMetaFile->AddAction( new MetaTextColorAction( maTextColor ) ); + } + sal_Bool bChangeFillColor = sal_False; + if ( maLatestBkColor != maBkColor ) + { + bChangeFillColor = sal_True; + maLatestBkColor = maBkColor; + } + if ( mnLatestBkMode != mnBkMode ) + { + bChangeFillColor = sal_True; + mnLatestBkMode = mnBkMode; + } + if ( bChangeFillColor ) + { + bChangeFont = sal_True; + mpGDIMetaFile->AddAction( new MetaTextFillColorAction( maFont.GetFillColor(), !maFont.IsTransparent() ) ); + } + Font aTmp( maFont ); + aTmp.SetColor( maTextColor ); + aTmp.SetFillColor( maBkColor ); + + if( mnBkMode == TRANSPARENT ) + aTmp.SetTransparent( sal_True ); + else + aTmp.SetTransparent( sal_False ); + + if ( ( mnTextAlign & TA_BASELINE) == TA_BASELINE ) + aTmp.SetAlign( ALIGN_BASELINE ); + else if( ( mnTextAlign & TA_BOTTOM) == TA_BOTTOM ) + aTmp.SetAlign( ALIGN_BOTTOM ); + else + aTmp.SetAlign( ALIGN_TOP ); + + if ( nGfxMode == GM_ADVANCED ) + { + // check whether there is a font rotation applied via transformation + Point aP1( ImplMap( Point() ) ); + Point aP2( ImplMap( Point( 0, 100 ) ) ); + aP2.X() -= aP1.X(); + aP2.Y() -= aP1.Y(); + double fX = aP2.X(); + double fY = aP2.Y(); + if ( fX ) + { + double fOrientation = acos( fX / sqrt( fX * fX + fY * fY ) ) * 57.29577951308; + if ( fY > 0 ) + fOrientation = 360 - fOrientation; + fOrientation += 90; + fOrientation *= 10; + fOrientation += aTmp.GetOrientation(); + aTmp.SetOrientation( sal_Int16( fOrientation ) ); + } + } + + if( mnTextAlign & ( TA_UPDATECP | TA_RIGHT_CENTER ) ) + { + if ( !pVDev ) + pVDev = new VirtualDevice; + sal_Int32 nTextWidth; + pVDev->SetMapMode( MapMode( MAP_100TH_MM ) ); + pVDev->SetFont( maFont ); + if( pDXArry ) + { + sal_uInt32 nLen = rText.Len(); + nTextWidth = pVDev->GetTextWidth( rtl::OUString(rText.GetChar( (sal_uInt16)( nLen - 1 ) )) ); + if( nLen > 1 ) + nTextWidth += pDXArry[ nLen - 2 ]; + } + else + nTextWidth = pVDev->GetTextWidth( rText ); + + if( mnTextAlign & TA_UPDATECP ) + rPosition = maActPos; + + if ( mnTextAlign & TA_RIGHT_CENTER ) + { + double fLenght = ( ( mnTextAlign & TA_RIGHT_CENTER ) == TA_RIGHT ) ? nTextWidth : nTextWidth >> 1; + rPosition.X() -= (sal_Int32)( fLenght * cos( maFont.GetOrientation() * F_PI1800 ) ); + rPosition.Y() -= (sal_Int32)(-( fLenght * sin( maFont.GetOrientation() * F_PI1800 ) ) ); + } + + if( mnTextAlign & TA_UPDATECP ) + maActPos.X() = rPosition.X() + nTextWidth; + } + if ( bChangeFont || ( maLatestFont != aTmp ) ) + { + maLatestFont = aTmp; + mpGDIMetaFile->AddAction( new MetaFontAction( aTmp ) ); + mpGDIMetaFile->AddAction( new MetaTextAlignAction( aTmp.GetAlign() ) ); + mpGDIMetaFile->AddAction( new MetaTextColorAction( aTmp.GetColor() ) ); + mpGDIMetaFile->AddAction( new MetaTextFillColorAction( aTmp.GetFillColor(), !aTmp.IsTransparent() ) ); + } + if ( bRecordPath ) + { + // ToDo + } + else + { + /* because text without dx array is badly scaled, we + will create such an array if necessary */ + sal_Int32* pDX = pDXArry; + if ( !pDXArry ) + { + SolarMutexGuard aGuard; + + pDX = new sal_Int32[ rText.Len() ]; + if ( !pVDev ) + pVDev = new VirtualDevice; + pVDev->SetMapMode( MAP_100TH_MM ); + pVDev->SetFont( maLatestFont ); + pVDev->GetTextArray( rText, pDX, 0, STRING_LEN ); + } + mpGDIMetaFile->AddAction( new MetaTextArrayAction( rPosition, rText, pDX, 0, STRING_LEN ) ); + if ( !pDXArry ) // this means we have created our own array + delete[] pDX; // which must be deleted + } + SetGfxMode( nOldGfxMode ); + delete pVDev; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ImplDrawBitmap( const Point& rPos, const Size& rSize, const BitmapEx rBitmap ) +{ + BitmapEx aBmpEx( rBitmap ); + if ( mbComplexClip ) + { + VirtualDevice aVDev; + MapMode aMapMode( MAP_100TH_MM ); + aMapMode.SetOrigin( Point( -rPos.X(), -rPos.Y() ) ); + const Size aOutputSizePixel( aVDev.LogicToPixel( rSize, aMapMode ) ); + const Size aSizePixel( rBitmap.GetSizePixel() ); + if ( aOutputSizePixel.Width() && aOutputSizePixel.Height() ) + { + aMapMode.SetScaleX( Fraction( aSizePixel.Width(), aOutputSizePixel.Width() ) ); + aMapMode.SetScaleY( Fraction( aSizePixel.Height(), aOutputSizePixel.Height() ) ); + } + aVDev.SetMapMode( aMapMode ); + aVDev.SetOutputSizePixel( aSizePixel ); + aVDev.SetFillColor( Color( COL_BLACK ) ); + const PolyPolygon aClip( aClipPath.getClipPath() ); + aVDev.DrawPolyPolygon( aClip ); + const Point aEmptyPoint; + + // #i50672# Extract whole VDev content (to match size of rBitmap) + aVDev.EnableMapMode( sal_False ); + Bitmap aMask( aVDev.GetBitmap( aEmptyPoint, aSizePixel ).CreateMask( Color( COL_WHITE ) ) ); + + if ( aBmpEx.IsTransparent() ) + { + if ( rBitmap.GetTransparentColor() == Color( COL_WHITE ) ) + aMask.CombineSimple( rBitmap.GetMask(), BMP_COMBINE_OR ); + else + aMask.CombineSimple( rBitmap.GetMask(), BMP_COMBINE_AND ); + aBmpEx = BitmapEx( rBitmap.GetBitmap(), aMask ); + } + else + aBmpEx = BitmapEx( rBitmap.GetBitmap(), aMask ); + } + if ( aBmpEx.IsTransparent() ) + mpGDIMetaFile->AddAction( new MetaBmpExScaleAction( rPos, rSize, aBmpEx ) ); + else + mpGDIMetaFile->AddAction( new MetaBmpScaleAction( rPos, rSize, aBmpEx.GetBitmap() ) ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ResolveBitmapActions( BSaveStructList_impl& rSaveList ) +{ + UpdateClipRegion(); + + size_t nObjects = rSaveList.size(); + size_t nObjectsLeft = nObjects; + + while ( nObjectsLeft ) + { + size_t i; + size_t nObjectsOfSameSize = 0; + size_t nObjectStartIndex = nObjects - nObjectsLeft; + + BSaveStruct* pSave = rSaveList[ nObjectStartIndex ]; + Rectangle aRect( pSave->aOutRect ); + + for ( i = nObjectStartIndex; i < nObjects; ) + { + nObjectsOfSameSize++; + if ( ++i < nObjects ) + { + pSave = rSaveList[ i ]; + if ( pSave->aOutRect != aRect ) + break; + } + } + Point aPos( ImplMap( aRect.TopLeft() ) ); + Size aSize( ImplMap( aRect.GetSize() ) ); + + for ( i = nObjectStartIndex; i < ( nObjectStartIndex + nObjectsOfSameSize ); i++ ) + { + pSave = rSaveList[ i ]; + + sal_uInt32 nWinRop = pSave->nWinRop; + sal_uInt8 nRasterOperation = (sal_uInt8)( nWinRop >> 16 ); + + sal_uInt32 nUsed = 0; + if ( ( nRasterOperation & 0xf ) != ( nRasterOperation >> 4 ) ) + nUsed |= 1; // pattern is used + if ( ( nRasterOperation & 0x33 ) != ( ( nRasterOperation & 0xcc ) >> 2 ) ) + nUsed |= 2; // source is used + if ( ( nRasterOperation & 0xaa ) != ( ( nRasterOperation & 0x55 ) << 1 ) ) + nUsed |= 4; // destination is used + + if ( (nUsed & 1) && (( nUsed & 2 ) == 0) && nWinRop != PATINVERT ) + { // patterns aren't well supported yet + sal_uInt32 nOldRop = SetRasterOp( ROP_OVERPAINT ); // in this case nRasterOperation is either 0 or 0xff + UpdateFillStyle(); + DrawRect( aRect, sal_False ); + SetRasterOp( nOldRop ); + } + else + { + sal_Bool bDrawn = sal_False; + + if ( i == nObjectStartIndex ) // optimizing, sometimes it is possible to create just one transparent bitmap + { + if ( nObjectsOfSameSize == 2 ) + { + BSaveStruct* pSave2 = rSaveList[ i + 1 ]; + if ( ( pSave->aBmp.GetPrefSize() == pSave2->aBmp.GetPrefSize() ) && + ( pSave->aBmp.GetPrefMapMode() == pSave2->aBmp.GetPrefMapMode() ) ) + { + // TODO: Strictly speaking, we should + // check whether mask is monochrome, and + // whether image is black (upper branch) + // or white (lower branch). Otherwise, the + // effect is not the same as a masked + // bitmap. + if ( ( nWinRop == SRCPAINT ) && ( pSave2->nWinRop == SRCAND ) ) + { + Bitmap aMask( pSave->aBmp ); aMask.Invert(); + BitmapEx aBmpEx( pSave2->aBmp, aMask ); + ImplDrawBitmap( aPos, aSize, aBmpEx ); + bDrawn = sal_True; + i++; + } + // #i20085# This is just the other way + // around as above. Only difference: mask + // is inverted + else if ( ( nWinRop == SRCAND ) && ( pSave2->nWinRop == SRCPAINT ) ) + { + Bitmap aMask( pSave->aBmp ); + BitmapEx aBmpEx( pSave2->aBmp, aMask ); + ImplDrawBitmap( aPos, aSize, aBmpEx ); + bDrawn = sal_True; + i++; + } + } + } + } + + if ( !bDrawn ) + { + Push(); + sal_uInt32 nOldRop = SetRasterOp( R2_COPYPEN ); + Bitmap aBitmap( pSave->aBmp ); + sal_uInt32 nOperation = ( nRasterOperation & 0xf ); + switch( nOperation ) + { + case 0x1 : + case 0xe : + { + SetRasterOp( R2_XORPEN ); + ImplDrawBitmap( aPos, aSize, aBitmap ); + SetRasterOp( R2_COPYPEN ); + Bitmap aMask( aBitmap ); + aMask.Invert(); + BitmapEx aBmpEx( aBitmap, aMask ); + ImplDrawBitmap( aPos, aSize, aBmpEx ); + if ( nOperation == 0x1 ) + { + SetRasterOp( R2_NOT ); + DrawRect( aRect, sal_False ); + } + } + break; + case 0x7 : + case 0x8 : + { + Bitmap aMask( aBitmap ); + if ( ( nUsed & 1 ) && ( nRasterOperation & 0xb0 ) == 0xb0 ) // pattern used + { + aBitmap.Convert( BMP_CONVERSION_24BIT ); + aBitmap.Erase( maFillStyle.aFillColor ); + } + BitmapEx aBmpEx( aBitmap, aMask ); + ImplDrawBitmap( aPos, aSize, aBmpEx ); + if ( nOperation == 0x7 ) + { + SetRasterOp( R2_NOT ); + DrawRect( aRect, sal_False ); + } + } + break; + + case 0x4 : + case 0xb : + { + SetRasterOp( R2_NOT ); + DrawRect( aRect, sal_False ); + SetRasterOp( R2_COPYPEN ); + Bitmap aMask( aBitmap ); + aBitmap.Invert(); + BitmapEx aBmpEx( aBitmap, aMask ); + ImplDrawBitmap( aPos, aSize, aBmpEx ); + SetRasterOp( R2_XORPEN ); + ImplDrawBitmap( aPos, aSize, aBitmap ); + if ( nOperation == 0xb ) + { + SetRasterOp( R2_NOT ); + DrawRect( aRect, sal_False ); + } + } + break; + + case 0x2 : + case 0xd : + { + Bitmap aMask( aBitmap ); + aMask.Invert(); + BitmapEx aBmpEx( aBitmap, aMask ); + ImplDrawBitmap( aPos, aSize, aBmpEx ); + SetRasterOp( R2_XORPEN ); + ImplDrawBitmap( aPos, aSize, aBitmap ); + if ( nOperation == 0xd ) + { + SetRasterOp( R2_NOT ); + DrawRect( aRect, sal_False ); + } + } + break; + case 0x6 : + case 0x9 : + { + SetRasterOp( R2_XORPEN ); + ImplDrawBitmap( aPos, aSize, aBitmap ); + if ( nOperation == 0x9 ) + { + SetRasterOp( R2_NOT ); + DrawRect( aRect, sal_False ); + } + } + break; + + case 0x0 : // WHITENESS + case 0xf : // BLACKNESS + { // in this case nRasterOperation is either 0 or 0xff + maFillStyle = WinMtfFillStyle( Color( nRasterOperation, nRasterOperation, nRasterOperation ) ); + UpdateFillStyle(); + DrawRect( aRect, sal_False ); + } + break; + + case 0x3 : // only source is used + case 0xc : + { + if ( nRasterOperation == 0x33 ) + aBitmap.Invert(); + ImplDrawBitmap( aPos, aSize, aBitmap ); + } + break; + + case 0x5 : // only destination is used + { + SetRasterOp( R2_NOT ); + DrawRect( aRect, sal_False ); + } + case 0xa : // no operation + break; + } + SetRasterOp( nOldRop ); + Pop(); + } + } + } + nObjectsLeft -= nObjectsOfSameSize; + } + + for( size_t i = 0, n = rSaveList.size(); i < n; ++i ) + delete rSaveList[ i ]; + rSaveList.clear(); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetDevOrg( const Point& rPoint ) +{ + mnDevOrgX = rPoint.X(); + mnDevOrgY = rPoint.Y(); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetDevOrgOffset( sal_Int32 nXAdd, sal_Int32 nYAdd ) +{ + mnDevOrgX += nXAdd; + mnDevOrgY += nYAdd; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetDevExt( const Size& rSize ) +{ + if ( rSize.Width() && rSize.Height() ) + { + switch( mnMapMode ) + { + case MM_ISOTROPIC : + case MM_ANISOTROPIC : + { + mnDevWidth = rSize.Width(); + mnDevHeight = rSize.Height(); + } + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ScaleDevExt( double fX, double fY ) +{ + mnDevWidth = FRound( mnDevWidth * fX ); + mnDevHeight = FRound( mnDevHeight * fY ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetWinOrg( const Point& rPoint ) +{ + mnWinOrgX = rPoint.X(); + mnWinOrgY = rPoint.Y(); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetWinOrgOffset( sal_Int32 nXAdd, sal_Int32 nYAdd ) +{ + mnWinOrgX += nXAdd; + mnWinOrgY += nYAdd; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetWinExt( const Size& rSize ) +{ + + if( rSize.Width() && rSize.Height() ) + { + switch( mnMapMode ) + { + case MM_ISOTROPIC : + case MM_ANISOTROPIC : + { + mnWinExtX = rSize.Width(); + mnWinExtY = rSize.Height(); + } + } + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ScaleWinExt( double fX, double fY ) +{ + mnWinExtX = FRound( mnWinExtX * fX ); + mnWinExtY = FRound( mnWinExtY * fY ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetrclBounds( const Rectangle& rRect ) +{ + mrclBounds = rRect; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetrclFrame( const Rectangle& rRect ) +{ + mrclFrame = rRect; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetRefPix( const Size& rSize ) +{ + mnPixX = rSize.Width(); + mnPixY = rSize.Height(); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetRefMill( const Size& rSize ) +{ + mnMillX = rSize.Width(); + mnMillY = rSize.Height(); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetMapMode( sal_uInt32 nMapMode ) +{ + mnMapMode = nMapMode; + if ( nMapMode == MM_TEXT ) + { + mnWinExtX = mnDevWidth; + mnWinExtY = mnDevHeight; + } + else if ( mnMapMode == MM_HIMETRIC ) + { + mnWinExtX = mnMillX * 100; + mnWinExtY = mnMillY * 100; + } +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetUnitsPerInch( sal_uInt16 nUnitsPerInch ) +{ + if( nUnitsPerInch != 0 ) + mnUnitsPerInch = nUnitsPerInch; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::SetWorldTransform( const XForm& rXForm ) +{ + maXForm.eM11 = rXForm.eM11; + maXForm.eM12 = rXForm.eM12; + maXForm.eM21 = rXForm.eM21; + maXForm.eM22 = rXForm.eM22; + maXForm.eDx = rXForm.eDx; + maXForm.eDy = rXForm.eDy; +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::ModifyWorldTransform( const XForm& rXForm, sal_uInt32 nMode ) +{ + switch( nMode ) + { + case MWT_IDENTITY : + { + maXForm.eM11 = maXForm.eM12 = maXForm.eM21 = maXForm.eM22 = 1.0f; + maXForm.eDx = maXForm.eDy = 0.0f; + } + break; + + case MWT_RIGHTMULTIPLY : + case MWT_LEFTMULTIPLY : + { + const XForm* pLeft; + const XForm* pRight; + + if ( nMode == MWT_LEFTMULTIPLY ) + { + pLeft = &rXForm; + pRight = &maXForm; + } + else + { + pLeft = &maXForm; + pRight = &rXForm; + } + + float aF[3][3]; + float bF[3][3]; + float cF[3][3]; + + aF[0][0] = pLeft->eM11; + aF[0][1] = pLeft->eM12; + aF[0][2] = 0; + aF[1][0] = pLeft->eM21; + aF[1][1] = pLeft->eM22; + aF[1][2] = 0; + aF[2][0] = pLeft->eDx; + aF[2][1] = pLeft->eDy; + aF[2][2] = 1; + + bF[0][0] = pRight->eM11; + bF[0][1] = pRight->eM12; + bF[0][2] = 0; + bF[1][0] = pRight->eM21; + bF[1][1] = pRight->eM22; + bF[1][2] = 0; + bF[2][0] = pRight->eDx; + bF[2][1] = pRight->eDy; + bF[2][2] = 1; + + int i, j, k; + for ( i = 0; i < 3; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + cF[i][j] = 0; + for ( k = 0; k < 3; k++ ) + cF[i][j] += aF[i][k] * bF[k][j]; + } + } + maXForm.eM11 = cF[0][0]; + maXForm.eM12 = cF[0][1]; + maXForm.eM21 = cF[1][0]; + maXForm.eM22 = cF[1][1]; + maXForm.eDx = cF[2][0]; + maXForm.eDy = cF[2][1]; + } + break; + } + } + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::Push() // !! to be able to access the original ClipRegion it +{ // is not allowed to use the MetaPushAction() + UpdateClipRegion(); // (the original clip region is on top of the stack) (SJ) + SaveStructPtr pSave( new SaveStruct ); + + pSave->aLineStyle = maLineStyle; + pSave->aFillStyle = maFillStyle; + + pSave->aFont = maFont; + pSave->aTextColor = maTextColor; + pSave->nTextAlign = mnTextAlign; + pSave->nTextLayoutMode = mnTextLayoutMode; + pSave->nMapMode = mnMapMode; + pSave->nGfxMode = mnGfxMode; + pSave->nBkMode = mnBkMode; + pSave->aBkColor = maBkColor; + pSave->bFillStyleSelected = mbFillStyleSelected; + + pSave->aActPos = maActPos; + pSave->aXForm = maXForm; + pSave->eRasterOp = meRasterOp; + + pSave->nWinOrgX = mnWinOrgX; + pSave->nWinOrgY = mnWinOrgY; + pSave->nWinExtX = mnWinExtX; + pSave->nWinExtY = mnWinExtY; + pSave->nDevOrgX = mnDevOrgX; + pSave->nDevOrgY = mnDevOrgY; + pSave->nDevWidth = mnDevWidth; + pSave->nDevHeight = mnDevHeight; + + pSave->aPathObj = aPathObj; + pSave->aClipPath = aClipPath; + + vSaveStack.push_back( pSave ); +} + +//----------------------------------------------------------------------------------- + +void WinMtfOutput::Pop() +{ + // Die aktuellen Daten vom Stack holen + if( !vSaveStack.empty() ) + { + // Die aktuelle Daten auf dem Stack sichern + SaveStructPtr pSave( vSaveStack.back() ); + + maLineStyle = pSave->aLineStyle; + maFillStyle = pSave->aFillStyle; + + maFont = pSave->aFont; + maTextColor = pSave->aTextColor; + mnTextAlign = pSave->nTextAlign; + mnTextLayoutMode = pSave->nTextLayoutMode; + mnBkMode = pSave->nBkMode; + mnGfxMode = pSave->nGfxMode; + mnMapMode = pSave->nMapMode; + maBkColor = pSave->aBkColor; + mbFillStyleSelected = pSave->bFillStyleSelected; + + maActPos = pSave->aActPos; + maXForm = pSave->aXForm; + meRasterOp = pSave->eRasterOp; + + mnWinOrgX = pSave->nWinOrgX; + mnWinOrgY = pSave->nWinOrgY; + mnWinExtX = pSave->nWinExtX; + mnWinExtY = pSave->nWinExtY; + mnDevOrgX = pSave->nDevOrgX; + mnDevOrgY = pSave->nDevOrgY; + mnDevWidth = pSave->nDevWidth; + mnDevHeight = pSave->nDevHeight; + + aPathObj = pSave->aPathObj; + if ( ! ( aClipPath == pSave->aClipPath ) ) + { + aClipPath = pSave->aClipPath; + mbClipNeedsUpdate = true; + } + if ( meLatestRasterOp != meRasterOp ) + mpGDIMetaFile->AddAction( new MetaRasterOpAction( meRasterOp ) ); + vSaveStack.pop_back(); + } +} + +void WinMtfOutput::AddFromGDIMetaFile( GDIMetaFile& rGDIMetaFile ) +{ + rGDIMetaFile.Play( *mpGDIMetaFile, 0xFFFFFFFF ); +} + +void WinMtfOutput::PassEMFPlusHeaderInfo() +{ + EMFP_DEBUG(printf ("\t\t\tadd EMF_PLUS header info\n")); + + SvMemoryStream mem; + sal_Int32 nLeft, nRight, nTop, nBottom; + + nLeft = mrclFrame.Left(); + nTop = mrclFrame.Top(); + nRight = mrclFrame.Right(); + nBottom = mrclFrame.Bottom(); + + // emf header info + mem << nLeft << nTop << nRight << nBottom; + mem << mnPixX << mnPixY << mnMillX << mnMillY; + + float one, zero; + + one = 1; + zero = 0; + + // add transformation matrix to be used in vcl's metaact.cxx for + // rotate and scale operations + mem << one << zero << zero << one << zero << zero; + + // need to flush the stream, otherwise GetEndOfData will return 0 + // on windows where the function parameters are probably resolved in reverse order + mem.Flush(); + + mpGDIMetaFile->AddAction( new MetaCommentAction( "EMF_PLUS_HEADER_INFO", 0, (const sal_uInt8*) mem.GetData(), mem.GetEndOfData() ) ); + mpGDIMetaFile->UseCanvas( sal_True ); +} + +void WinMtfOutput::PassEMFPlus( void* pBuffer, sal_uInt32 nLength ) +{ + EMFP_DEBUG(printf ("\t\t\tadd EMF_PLUS comment length %04x\n",(unsigned int) nLength)); + mpGDIMetaFile->AddAction( new MetaCommentAction( "EMF_PLUS", 0, static_cast<const sal_uInt8*>(pBuffer), nLength ) ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/winmtf.hxx b/vcl/source/filter/wmf/winmtf.hxx new file mode 100644 index 000000000000..bc368e6e6baa --- /dev/null +++ b/vcl/source/filter/wmf/winmtf.hxx @@ -0,0 +1,890 @@ +/* -*- 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 _WINMTF_HXX +#define _WINMTF_HXX + +#ifdef DBG_UTIL +#define WIN_MTF_ASSERT +#endif + +#include <sot/object.hxx> +#include <boost/shared_ptr.hpp> +#include <vcl/graph.hxx> +#include <vcl/virdev.hxx> +#include <basegfx/tools/b2dclipstate.hxx> +#include <vcl/font.hxx> +#include <vcl/bmpacc.hxx> +#include <vcl/lineinfo.hxx> +#include <svtools/fltcall.hxx> + +#define ERROR 0 +#define NULLREGION 1 +#define SIMPLEREGION 2 +#define COMPLEXREGION 3 + +#define RGN_AND 1 +#define RGN_OR 2 +#define RGN_XOR 3 +#define RGN_DIFF 4 +#define RGN_COPY 5 + +#define TRANSPARENT 1 +#define OPAQUE 2 +#define BKMODE_LAST 2 + +/* xform stuff */ +#define MWT_IDENTITY 1 +#define MWT_LEFTMULTIPLY 2 +#define MWT_RIGHTMULTIPLY 3 + +#define ENHMETA_STOCK_OBJECT 0x80000000 + +/* Stock Logical Objects */ +#define WHITE_BRUSH 0 +#define LTGRAY_BRUSH 1 +#define GRAY_BRUSH 2 +#define DKGRAY_BRUSH 3 +#define BLACK_BRUSH 4 +#define NULL_BRUSH 5 +#define HOLLOW_BRUSH NULL_BRUSH +#define WHITE_PEN 6 +#define BLACK_PEN 7 +#define NULL_PEN 8 +#define OEM_FIXED_FONT 10 +#define ANSI_FIXED_FONT 11 +#define ANSI_VAR_FONT 12 +#define SYSTEM_FONT 13 +#define DEVICE_DEFAULT_FONT 14 +#define DEFAULT_PALETTE 15 +#define SYSTEM_FIXED_FONT 16 + + +#define R2_BLACK 1 +#define R2_NOTMERGEPEN 2 +#define R2_MASKNOTPEN 3 +#define R2_NOTCOPYPEN 4 +#define R2_MASKPENNOT 5 +#define R2_NOT 6 +#define R2_XORPEN 7 +#define R2_NOTMASKPEN 8 +#define R2_MASKPEN 9 +#define R2_NOTXORPEN 10 +#define R2_NOP 11 +#define R2_MERGENOTPEN 12 +#define R2_COPYPEN 13 +#define R2_MERGEPENNOT 14 +#define R2_MERGEPEN 15 +#define R2_WHITE 16 + +/* Mapping Modes */ +#define MM_TEXT 1 +#define MM_LOMETRIC 2 +#define MM_HIMETRIC 3 +#define MM_LOENGLISH 4 +#define MM_HIENGLISH 5 +#define MM_TWIPS 6 +#define MM_ISOTROPIC 7 +#define MM_ANISOTROPIC 8 + + +/* Graphics Modes */ +#define GM_COMPATIBLE 1 +#define GM_ADVANCED 2 +#define GM_LAST 2 + +/* StretchBlt() Modes */ +#define BLACKONWHITE 1 +#define WHITEONBLACK 2 +#define COLORONCOLOR 3 +#define HALFTONE 4 +#define MAXSTRETCHBLTMODE 4 +#define STRETCH_ANDSCANS BLACKONWHITE +#define STRETCH_ORSCANS WHITEONBLACK +#define STRETCH_DELETESCANS COLORONCOLOR +#define STRETCH_HALFTONE HALFTONE + +#define LF_FACESIZE 32 + +struct LOGFONTW +{ + sal_Int32 lfHeight; + sal_Int32 lfWidth; + sal_Int32 lfEscapement; + sal_Int32 lfOrientation; + sal_Int32 lfWeight; + sal_uInt8 lfItalic; + sal_uInt8 lfUnderline; + sal_uInt8 lfStrikeOut; + sal_uInt8 lfCharSet; + sal_uInt8 lfOutPrecision; + sal_uInt8 lfClipPrecision; + sal_uInt8 lfQuality; + sal_uInt8 lfPitchAndFamily; + String alfFaceName; +}; +struct WMF_EXTERNALHEADER; + +#define TA_NOUPDATECP 0x0000 +#define TA_UPDATECP 0x0001 +#define TA_LEFT 0x0000 +#define TA_RIGHT 0x0002 +#define TA_CENTER 0x0006 +#define TA_RIGHT_CENTER (TA_RIGHT | TA_CENTER) +#define TA_TOP 0x0000 +#define TA_BOTTOM 0x0008 +#define TA_BASELINE 0x0018 + +#define SRCCOPY 0x00CC0020L +#define SRCPAINT 0x00EE0086L +#define SRCAND 0x008800C6L +#define SRCINVERT 0x00660046L +#define SRCERASE 0x00440328L +#define NOTSRCCOPY 0x00330008L +#define NOTSRCERASE 0x001100A6L +#define MERGECOPY 0x00C000CAL +#define MERGEPAINT 0x00BB0226L +#define PATCOPY 0x00F00021L +#define PATPAINT 0x00FB0A09L +#define PATINVERT 0x005A0049L +#define DSTINVERT 0x00550009L +#define BLACKNESS 0x00000042L +#define WHITENESS 0x00FF0062L + +#define PS_SOLID 0 +#define PS_DASH 1 +#define PS_DOT 2 +#define PS_DASHDOT 3 +#define PS_DASHDOTDOT 4 +#define PS_NULL 5 +#define PS_INSIDEFRAME 6 +#define PS_USERSTYLE 7 +#define PS_ALTERNATE 8 +#define PS_STYLE_MASK 15 + +#define PS_ENDCAP_ROUND 0x000 +#define PS_ENDCAP_SQUARE 0x100 +#define PS_ENDCAP_FLAT 0x200 +#define PS_ENDCAP_MASK 0xF00 + +#define PS_JOIN_ROUND 0x0000 +#define PS_JOIN_BEVEL 0x1000 +#define PS_JOIN_MITER 0x2000 +#define PS_JOIN_MASK 0xF000 + +#define PS_COSMETIC 0x00000 +#define PS_GEOMETRIC 0x10000 +#define PS_TYPE_MASK 0xF0000 + +#define ANSI_CHARSET 0 +#define DEFAULT_CHARSET 1 +#define SYMBOL_CHARSET 2 +#define SHIFTJIS_CHARSET 128 +#define HANGEUL_CHARSET 129 +#define GB2312_CHARSET 134 +#define CHINESEBIG5_CHARSET 136 +#define OEM_CHARSET 255 +/*WINVER >= 0x0400*/ +#define JOHAB_CHARSET 130 +#define HEBREW_CHARSET 177 +#define ARABIC_CHARSET 178 +#define GREEK_CHARSET 161 +#define TURKISH_CHARSET 162 +#define VIETNAMESE_CHARSET 163 +#define THAI_CHARSET 222 +#define EASTEUROPE_CHARSET 238 +#define RUSSIAN_CHARSET 204 +#define MAC_CHARSET 77 +#define BALTIC_CHARSET 186 + +#define ETO_OPAQUE 0x0002 +#define ETO_CLIPPED 0x0004 +/*WINVER >= 0x0400*/ +#define ETO_GLYPH_INDEX 0x0010 +#define ETO_RTLREADING 0x0080 +#define ETO_NUMERICSLOCAL 0x0400 +#define ETO_NUMERICSLATIN 0x0800 +#define ETO_IGNORELANGUAGE 0x1000 +/*_WIN32_WINNT >= 0x0500*/ +#define ETO_PDY 0x2000 + + +#define DEFAULT_PITCH 0x00 +#define FIXED_PITCH 0x01 +#define VARIABLE_PITCH 0x02 + +/* Font Families */ +#define FF_DONTCARE 0x00 +#define FF_ROMAN 0x10 +#define FF_SWISS 0x20 +#define FF_MODERN 0x30 +#define FF_SCRIPT 0x40 +#define FF_DECORATIVE 0x50 + +#define FW_DONTCARE 0 +#define FW_THIN 100 +#define FW_EXTRALIGHT 200 +#define FW_LIGHT 300 +#define FW_NORMAL 400 +#define FW_MEDIUM 500 +#define FW_SEMIBOLD 600 +#define FW_BOLD 700 +#define FW_EXTRABOLD 800 +#define FW_HEAVY 900 +#define FW_ULTRALIGHT 200 +#define FW_REGULAR 400 +#define FW_DEMIBOLD 600 +#define FW_ULTRABOLD 800 +#define FW_BLACK 900 + +#define BS_SOLID 0 +#define BS_NULL 1 +#define BS_HOLLOW 1 +#define BS_HATCHED 2 +#define BS_PATTERN 3 +#define BS_INDEXED 4 +#define BS_DIBPATTERN 5 +#define BS_DIBPATTERNPT 6 +#define BS_PATTERN8X8 7 +#define BS_DIBPATTERN8X8 8 +#define BS_MONOPATTERN 9 + +#define W_HS_HORIZONTAL 0 +#define W_HS_VERTICAL 1 +#define W_HS_FDIAGONAL 2 +#define W_HS_BDIAGONAL 3 +#define W_HS_CROSS 4 +#define W_HS_DIAGCROSS 5 + +#define RDH_RECTANGLES 1 + +#define W_MFCOMMENT 15 + +#define PRIVATE_ESCAPE_UNICODE 2 + +//============================ WMFReader ================================== + +#ifdef WIN_MTF_ASSERT +#define WIN_MTF_ASSERT_INIT 0x80000000 +#define WIN_MTF_ASSERT_ONCE 0x40000000 +#define WIN_MTF_ASSERT_MIFE 0x20000000 + +void WinMtfAssertHandler( const sal_Char*, sal_uInt32 nFlags = WIN_MTF_ASSERT_MIFE ); +#endif + +class WinMtfClipPath +{ + basegfx::tools::B2DClipState maClip; + +public : + WinMtfClipPath(): maClip() {}; + + void setClipPath( const PolyPolygon& rPolyPolygon, sal_Int32 nClippingMode ); + void intersectClipRect( const Rectangle& rRect ); + void excludeClipRect( const Rectangle& rRect ); + void moveClipRegion( const Size& rSize ); + + bool isEmpty() const { return maClip.isCleared(); } + + basegfx::B2DPolyPolygon getClipPath() const; + + bool operator==( const WinMtfClipPath& rPath ) const + { + return maClip == rPath.maClip; + }; +}; + +class WinMtfPathObj : public PolyPolygon +{ + sal_Bool bClosed; + +public : + + WinMtfPathObj() { bClosed = sal_True; } + void Init() { Clear(); bClosed = sal_True; }; + void ClosePath(); + void AddPoint( const Point& rPoint ); + void AddPolygon( const Polygon& rPoly ); + void AddPolyLine( const Polygon& rPoly ); + void AddPolyPolygon( const PolyPolygon& rPolyPolygon ); +}; + +struct WinMtfFontStyle +{ + Font aFont; + + WinMtfFontStyle( LOGFONTW& rLogFont ); +}; + +// ----------------------------------------------------------------------------- + +typedef enum { + FillStyleSolid, + FillStylePattern +} WinMtfFillStyleType; + +struct WinMtfFillStyle +{ + Color aFillColor; + sal_Bool bTransparent; + WinMtfFillStyleType aType; + Bitmap aBmp; + + WinMtfFillStyle() + : aFillColor(Color(COL_BLACK)) + , bTransparent(sal_False) + , aType(FillStyleSolid) + { + } + + WinMtfFillStyle( const Color& rColor, sal_Bool bTrans = sal_False ) + : aFillColor(rColor) + , bTransparent(bTrans) + , aType(FillStyleSolid) + { + } + + WinMtfFillStyle(Bitmap& rBmp) + : aType(FillStylePattern) + , aBmp(rBmp) + { + } + + sal_Bool operator==( const WinMtfFillStyle& rStyle ) + { + return ( ( aFillColor == rStyle.aFillColor ) + && ( bTransparent == rStyle.bTransparent ) + && ( aType == rStyle.aType ) + ); + } + sal_Bool operator==( WinMtfFillStyle* pStyle ) + { + return ( ( aFillColor == pStyle->aFillColor ) + && ( bTransparent == pStyle->bTransparent ) + && ( aType == pStyle->aType ) + ); + } + WinMtfFillStyle& operator=( const WinMtfFillStyle& rStyle ) + { + aFillColor = rStyle.aFillColor; + bTransparent = rStyle.bTransparent; + aBmp = rStyle.aBmp; + aType = rStyle.aType; + return *this; + } + WinMtfFillStyle& operator=( WinMtfFillStyle* pStyle ) + { + aFillColor = pStyle->aFillColor; + bTransparent = pStyle->bTransparent; + aBmp = pStyle->aBmp; + aType = pStyle->aType; + return *this; + } +}; + +// ----------------------------------------------------------------------------- + +struct WinMtfLineStyle +{ + Color aLineColor; + LineInfo aLineInfo; + sal_Bool bTransparent; + + WinMtfLineStyle() : + aLineColor ( COL_BLACK ), + bTransparent( sal_False ) {} + + WinMtfLineStyle( const Color& rColor, sal_Bool bTrans = sal_False ) : + aLineColor ( rColor ), + bTransparent( bTrans ) {} + + WinMtfLineStyle( const Color& rColor, const LineInfo& rStyle, sal_Bool bTrans = sal_False ) : + aLineColor ( rColor ), + aLineInfo ( rStyle ), + bTransparent( bTrans ) {} + + sal_Bool operator==( const WinMtfLineStyle& rStyle ) + { + return ( ( aLineColor == rStyle.aLineColor ) + && ( bTransparent == rStyle.bTransparent ) + && ( aLineInfo == rStyle.aLineInfo ) + ); + } + sal_Bool operator==( WinMtfLineStyle* pStyle ) + { + return ( ( aLineColor == pStyle->aLineColor ) + && ( bTransparent == pStyle->bTransparent ) + && ( aLineInfo == pStyle->aLineInfo ) + ); + } + WinMtfLineStyle& operator=( const WinMtfLineStyle& rStyle ) + { + aLineColor = rStyle.aLineColor; + bTransparent = rStyle.bTransparent; + aLineInfo = rStyle.aLineInfo; + return *this; + } + + WinMtfLineStyle& operator=( WinMtfLineStyle* pStyle ) + { + aLineColor = pStyle->aLineColor; + bTransparent = pStyle->bTransparent; + aLineInfo = pStyle->aLineInfo; + return *this; + } +}; + +// ----------------------------------------------------------------------------- + +struct XForm +{ + float eM11; + float eM12; + float eM21; + float eM22; + float eDx; + float eDy; + XForm() + { + eM11 = eM22 = 1.0f; + eDx = eDy = eM12 = eM21 = 0.0f; + } + + friend SvStream& operator>>( SvStream& rIn, XForm& rXForm ); +}; + +// ----------------------------------------------------------------------------- + +struct SaveStruct +{ + sal_uInt32 nBkMode, nMapMode, nGfxMode, nTextLayoutMode; + sal_Int32 nWinOrgX, nWinOrgY, nWinExtX, nWinExtY; + sal_Int32 nDevOrgX, nDevOrgY, nDevWidth, nDevHeight; + + WinMtfLineStyle aLineStyle; + WinMtfFillStyle aFillStyle; + + Font aFont; + Color aBkColor; + Color aTextColor; + sal_uInt32 nTextAlign; + RasterOp eRasterOp; + + Point aActPos; + WinMtfPathObj aPathObj; + WinMtfClipPath aClipPath; + XForm aXForm; + + sal_Bool bRecordPath; + sal_Bool bFillStyleSelected; +}; + +typedef ::boost::shared_ptr< SaveStruct > SaveStructPtr; + +// ----------------------------------------------------------------------------- + +struct BSaveStruct +{ + Bitmap aBmp; + Rectangle aOutRect; + sal_uInt32 nWinRop; + WinMtfFillStyle aStyle; + + BSaveStruct( + const Bitmap& rBmp, + const Rectangle& rOutRect, + sal_uInt32 nRop, + WinMtfFillStyle& rStyle + ) + : aBmp( rBmp ) + , aOutRect( rOutRect ) + , nWinRop( nRop ) + , aStyle ( rStyle ) + {} +}; + +typedef ::std::vector< BSaveStruct* > BSaveStructList_impl; + +// ----------------------------------------------------------------------------- + +enum GDIObjectType { + GDI_DUMMY = 0, + GDI_PEN = 1, + GDI_BRUSH = 2, + GDI_FONT = 3, + GDI_PALETTE = 4, + GDI_BITMAP = 5, + GDI_REGION = 6 +}; + +struct GDIObj +{ + void* pStyle; + GDIObjectType eType; + + GDIObj() : + pStyle ( NULL ), + eType ( GDI_DUMMY ) + { + } + + GDIObj( GDIObjectType eT, void* pS ) { pStyle = pS; eType = eT; } + void Set( GDIObjectType eT, void* pS ) { pStyle = pS; eType = eT; } + void Delete() + { + if ( pStyle ) + { + switch ( eType ) + { + case GDI_PEN : + delete (WinMtfLineStyle*)pStyle; + break; + case GDI_BRUSH : + delete (WinMtfFillStyle*)pStyle; + break; + case GDI_FONT : + delete (WinMtfFontStyle*)pStyle; + break; + + default: + OSL_FAIL( "unsupported style deleted" ); + break; + } + pStyle = NULL; + } + } + + ~GDIObj() + { + Delete(); + } +}; + +// ----------------------------------------------------------------------------- + +class WinMtfOutput +{ + + WinMtfPathObj aPathObj; + WinMtfClipPath aClipPath; + + WinMtfLineStyle maLatestLineStyle; + WinMtfLineStyle maLineStyle; + WinMtfFillStyle maLatestFillStyle; + WinMtfFillStyle maFillStyle; + Font maLatestFont; + Font maFont; + sal_uInt32 mnLatestTextAlign; + sal_uInt32 mnTextAlign; + Color maLatestTextColor; + Color maTextColor; + Color maLatestBkColor; + Color maBkColor; + sal_uInt32 mnLatestTextLayoutMode; + sal_uInt32 mnTextLayoutMode; + sal_uInt32 mnLatestBkMode; + sal_uInt32 mnBkMode; + RasterOp meLatestRasterOp; + RasterOp meRasterOp; + + std::vector< GDIObj* > vGDIObj; + + Point maActPos; + + sal_uInt32 mnRop; + sal_Bool mbNopMode; + sal_Bool mbFillStyleSelected; + sal_Bool mbClipNeedsUpdate; + sal_Bool mbComplexClip; + + std::vector< SaveStructPtr > vSaveStack; + + sal_uInt32 mnGfxMode; + sal_uInt32 mnMapMode; + sal_uInt16 mnUnitsPerInch; + + XForm maXForm; + sal_Int32 mnDevOrgX, mnDevOrgY; + sal_Int32 mnDevWidth, mnDevHeight; + sal_Int32 mnWinOrgX, mnWinOrgY; // aktuelles Window-Origin + sal_Int32 mnWinExtX, mnWinExtY; // aktuelles Window-Extent + + sal_Int32 mnPixX, mnPixY; // Reference Device in pixel + sal_Int32 mnMillX, mnMillY; // Reference Device in Mill + Rectangle mrclFrame; // rectangle in logical units 1/100th mm + Rectangle mrclBounds; + + GDIMetaFile* mpGDIMetaFile; + + void UpdateLineStyle(); + void UpdateFillStyle(); + + Point ImplMap( const Point& rPt ); + Size ImplMap( const Size& rSz ); + Rectangle ImplMap( const Rectangle& rRectangle ); + void ImplMap( Font& rFont ); + Polygon& ImplMap( Polygon& rPolygon ); + PolyPolygon& ImplMap( PolyPolygon& rPolyPolygon ); + void ImplResizeObjectArry( sal_uInt32 nNewEntry ); + void ImplSetNonPersistentLineColorTransparenz(); + void ImplDrawClippedPolyPolygon( const PolyPolygon& rPolyPoly ); + void ImplDrawBitmap( const Point& rPos, const Size& rSize, const BitmapEx rBitmap ); + +public: + + void SetDevOrg( const Point& rPoint ); + void SetDevOrgOffset( sal_Int32 nXAdd, sal_Int32 nYAdd ); + void SetDevExt( const Size& rSize ); + void ScaleDevExt( double fX, double fY ); + + void SetWinOrg( const Point& rPoint ); + void SetWinOrgOffset( sal_Int32 nX, sal_Int32 nY ); + void SetWinExt( const Size& rSize ); + void ScaleWinExt( double fX, double fY ); + + void SetrclBounds( const Rectangle& rRect ); + void SetrclFrame( const Rectangle& rRect ); + void SetRefPix( const Size& rSize ); + void SetRefMill( const Size& rSize ); + + sal_uInt32 GetMapMode() const { return mnMapMode; }; + void SetMapMode( sal_uInt32 mnMapMode ); + void SetUnitsPerInch( sal_uInt16 nUnitsPerInch ); + void SetWorldTransform( const XForm& rXForm ); + void ModifyWorldTransform( const XForm& rXForm, sal_uInt32 nMode ); + + void Push(); + void Pop(); + + sal_uInt32 SetRasterOp( sal_uInt32 nRasterOp ); + void StrokeAndFillPath( sal_Bool bStroke, sal_Bool bFill ); + + void SetGfxMode( sal_Int32 nGfxMode ){ mnGfxMode = nGfxMode; }; + sal_Int32 GetGfxMode() const { return mnGfxMode; }; + void SetBkMode( sal_uInt32 nMode ); + void SetBkColor( const Color& rColor ); + void SetTextColor( const Color& rColor ); + void SetTextAlign( sal_uInt32 nAlign ); + void CreateObject( GDIObjectType, void* pStyle = NULL ); + void CreateObject( sal_Int32 nIndex, GDIObjectType, void* pStyle = NULL ); + void DeleteObject( sal_Int32 nIndex ); + void SelectObject( sal_Int32 nIndex ); + CharSet GetCharSet(){ return maFont.GetCharSet(); }; + WinMtfFillStyle& GetFillStyle () { return maFillStyle; } + const Font& GetFont() const; + void SetTextLayoutMode( const sal_uInt32 nLayoutMode ); + + void ClearPath(){ aPathObj.Init(); }; + void ClosePath(){ aPathObj.ClosePath(); }; + const PolyPolygon& GetPathObj(){ return aPathObj; }; + + void MoveTo( const Point& rPoint, sal_Bool bRecordPath = sal_False ); + void LineTo( const Point& rPoint, sal_Bool bRecordPath = sal_False ); + void DrawPixel( const Point& rSource, const Color& rColor ); + void DrawRect( const Rectangle& rRect, sal_Bool bEdge = sal_True ); + void DrawRoundRect( const Rectangle& rRect, const Size& rSize ); + void DrawEllipse( const Rectangle& rRect ); + void DrawArc( + const Rectangle& rRect, + const Point& rStartAngle, + const Point& rEndAngle, + sal_Bool bDrawTo = sal_False + ); + void DrawPie( + const Rectangle& rRect, + const Point& rStartAngle, + const Point& rEndAngle + ); + void DrawChord( + const Rectangle& rRect, + const Point& rStartAngle, + const Point& rEndAngle + ); + void DrawPolygon( Polygon& rPolygon, sal_Bool bRecordPath = sal_False ); + void DrawPolygon( Polygon& rPolygon, sal_Bool /*bDrawTo*/, sal_Bool bRecordPath) + { + //For ReadAndDrawPolygon template compatibility + DrawPolygon(rPolygon, bRecordPath); + } + void DrawPolyPolygon( PolyPolygon& rPolyPolygon, sal_Bool bRecordPath = sal_False ); + void DrawPolyLine( + Polygon& rPolygon, + sal_Bool bDrawTo = sal_False, + sal_Bool bRecordPath = sal_False + ); + void DrawPolyBezier( + Polygon& rPolygin, + sal_Bool bDrawTo = sal_False, + sal_Bool bRecordPath = sal_False + ); + void DrawText( + Point& rPosition, + String& rString, + sal_Int32* pDXArry = NULL, + sal_Bool bRecordPath = sal_False, + sal_Int32 nGraphicsMode = GM_COMPATIBLE + ); + void ResolveBitmapActions( BSaveStructList_impl& rSaveList ); + + void IntersectClipRect( const Rectangle& rRect ); + void ExcludeClipRect( const Rectangle& rRect ); + void MoveClipRegion( const Size& rSize ); + void SetClipPath( + const PolyPolygon& rPolyPoly, + sal_Int32 nClippingMode, + sal_Bool bIsMapped + ); + void UpdateClipRegion(); + void AddFromGDIMetaFile( GDIMetaFile& rGDIMetaFile ); + + void PassEMFPlus( void* pBuffer, sal_uInt32 nLength ); + void PassEMFPlusHeaderInfo(); + + WinMtfOutput( GDIMetaFile& rGDIMetaFile ); + virtual ~WinMtfOutput(); +}; + +// ----------------------------------------------------------------------------- + +class WinMtf +{ +protected: + + WinMtfOutput* pOut; + SvStream* pWMF; // Die einzulesende WMF/EMF-Datei + + sal_uInt32 nStartPos, nEndPos; + BSaveStructList_impl aBmpSaveList; + + FilterConfigItem* pFilterConfigItem; + + com::sun::star::uno::Reference< com::sun::star::task::XStatusIndicator > xStatusIndicator; + + // Sorgt dafuer, das aSampledBrush der aktuelle Brush des GDIMetaFiles ist. + + Color ReadColor(); + void Callback( sal_uInt16 nPercent ); + + WinMtf( + WinMtfOutput* pOut, + SvStream& rStreamWMF, + FilterConfigItem* pConfigItem = NULL + ); + ~WinMtf(); +}; + +//============================ EMFReader ================================== + +class EnhWMFReader : public WinMtf +{ + sal_Bool bRecordPath; + sal_Int32 nRecordCount; + sal_Bool bEMFPlus; + + + sal_Bool ReadHeader(); + // Liesst und konvertiert ein Rechteck + Rectangle ReadRectangle( sal_Int32, sal_Int32, sal_Int32, sal_Int32 ); + void ImplExtTextOut( sal_Bool bWideCharakter ); + +public: + EnhWMFReader( + SvStream& rStreamWMF, + GDIMetaFile& rGDIMetaFile, + FilterConfigItem* pConfigItem = NULL + ) + : WinMtf( new WinMtfOutput( rGDIMetaFile ) + , rStreamWMF + , pConfigItem ) + , bRecordPath( sal_False ) + , bEMFPlus( sal_False ) + {}; + ~EnhWMFReader(); + + sal_Bool ReadEnhWMF(); + void ReadEMFPlusComment(sal_uInt32 length, sal_Bool& bHaveDC); +private: + template <class T> void ReadAndDrawPolyPolygon(); + template <class T> void ReadAndDrawPolyLine(); + template <class T> Polygon ReadPolygon(sal_uInt32 nStartIndex, sal_uInt32 nPoints); + template <class T, class Drawer> void ReadAndDrawPolygon(Drawer drawer, const sal_Bool skipFirst); +}; + +//============================ WMFReader ================================== + +class WMFReader : public WinMtf +{ +private: + + VirtualDevice aVDev; // just for the purpose of "IsFontAvailable" + sal_uInt16 nUnitsPerInch; + sal_uInt32 nRecSize; + + // embedded EMF data + SvMemoryStream* pEMFStream; + + // total number of comment records containing EMF data + sal_uInt32 nEMFRecCount; + + // number of EMF records read + sal_uInt32 nEMFRec; + + // total size of embedded EMF data + sal_uInt32 nEMFSize; + + sal_uInt32 nSkipActions; + sal_uInt32 nCurrentAction; + sal_uInt32 nUnicodeEscapeAction; + + WMF_EXTERNALHEADER* pExternalHeader; + + // Liesst den Kopf der WMF-Datei + sal_Bool ReadHeader(); + + // Liesst die Parameter des Rocords mit der Funktionsnummer nFunction. + void ReadRecordParams( sal_uInt16 nFunction ); + + Point ReadPoint(); // Liesst und konvertiert einen Punkt (erst X dann Y) + Point ReadYX(); // Liesst und konvertiert einen Punkt (erst Y dann X) + Rectangle ReadRectangle(); // Liesst und konvertiert ein Rechteck + Size ReadYXExt(); + sal_Bool GetPlaceableBound( Rectangle& rSize, SvStream* pStrm ); + +public: + + WMFReader( + SvStream& rStreamWMF, + GDIMetaFile& rGDIMetaFile, + FilterConfigItem* pConfigItem = NULL, + WMF_EXTERNALHEADER* pExtHeader = NULL + ) + : WinMtf( new WinMtfOutput( rGDIMetaFile ), rStreamWMF, pConfigItem ) + , pEMFStream(NULL), + pExternalHeader(pExtHeader) + {} + + ~WMFReader(); + + // Liesst aus dem Stream eine WMF-Datei und fuellt das GDIMetaFile + void ReadWMF(); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/winwmf.cxx b/vcl/source/filter/wmf/winwmf.cxx new file mode 100644 index 000000000000..f9f38e09eb92 --- /dev/null +++ b/vcl/source/filter/wmf/winwmf.cxx @@ -0,0 +1,1503 @@ +/* -*- 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 "winmtf.hxx" +#include <boost/scoped_array.hpp> +#include <vcl/gdimtf.hxx> +#include <svtools/wmf.hxx> +#include <rtl/crc.h> +#include <rtl/tencinfo.h> +#include <osl/endian.h> + +//====================== MS-Windows-defines =============================== + +#define W_META_SETBKCOLOR 0x0201 +#define W_META_SETBKMODE 0x0102 +#define W_META_SETMAPMODE 0x0103 +#define W_META_SETROP2 0x0104 +#define W_META_SETRELABS 0x0105 +#define W_META_SETPOLYFILLMODE 0x0106 +#define W_META_SETSTRETCHBLTMODE 0x0107 +#define W_META_SETTEXTCHAREXTRA 0x0108 +#define W_META_SETTEXTCOLOR 0x0209 +#define W_META_SETTEXTJUSTIFICATION 0x020A +#define W_META_SETWINDOWORG 0x020B +#define W_META_SETWINDOWEXT 0x020C +#define W_META_SETVIEWPORTORG 0x020D +#define W_META_SETVIEWPORTEXT 0x020E +#define W_META_OFFSETWINDOWORG 0x020F +#define W_META_SCALEWINDOWEXT 0x0410 +#define W_META_OFFSETVIEWPORTORG 0x0211 +#define W_META_SCALEVIEWPORTEXT 0x0412 +#define W_META_LINETO 0x0213 +#define W_META_MOVETO 0x0214 +#define W_META_EXCLUDECLIPRECT 0x0415 +#define W_META_INTERSECTCLIPRECT 0x0416 +#define W_META_ARC 0x0817 +#define W_META_ELLIPSE 0x0418 +#define W_META_FLOODFILL 0x0419 +#define W_META_PIE 0x081A +#define W_META_RECTANGLE 0x041B +#define W_META_ROUNDRECT 0x061C +#define W_META_PATBLT 0x061D +#define W_META_SAVEDC 0x001E +#define W_META_SETPIXEL 0x041F +#define W_META_OFFSETCLIPRGN 0x0220 +#define W_META_TEXTOUT 0x0521 +#define W_META_BITBLT 0x0922 +#define W_META_STRETCHBLT 0x0B23 +#define W_META_POLYGON 0x0324 +#define W_META_POLYLINE 0x0325 +#define W_META_ESCAPE 0x0626 +#define W_META_RESTOREDC 0x0127 +#define W_META_FILLREGION 0x0228 +#define W_META_FRAMEREGION 0x0429 +#define W_META_INVERTREGION 0x012A +#define W_META_PAINTREGION 0x012B +#define W_META_SELECTCLIPREGION 0x012C +#define W_META_SELECTOBJECT 0x012D +#define W_META_SETTEXTALIGN 0x012E +#define W_META_DRAWTEXT 0x062F +#define W_META_CHORD 0x0830 +#define W_META_SETMAPPERFLAGS 0x0231 +#define W_META_EXTTEXTOUT 0x0a32 +#define W_META_SETDIBTODEV 0x0d33 +#define W_META_SELECTPALETTE 0x0234 +#define W_META_REALIZEPALETTE 0x0035 +#define W_META_ANIMATEPALETTE 0x0436 +#define W_META_SETPALENTRIES 0x0037 +#define W_META_POLYPOLYGON 0x0538 +#define W_META_RESIZEPALETTE 0x0139 +#define W_META_DIBBITBLT 0x0940 +#define W_META_DIBSTRETCHBLT 0x0b41 +#define W_META_DIBCREATEPATTERNBRUSH 0x0142 +#define W_META_STRETCHDIB 0x0f43 +#define W_META_EXTFLOODFILL 0x0548 +#define W_META_RESETDC 0x014C +#define W_META_STARTDOC 0x014D +#define W_META_STARTPAGE 0x004F +#define W_META_ENDPAGE 0x0050 +#define W_META_ABORTDOC 0x0052 +#define W_META_ENDDOC 0x005E +#define W_META_DELETEOBJECT 0x01f0 +#define W_META_CREATEPALETTE 0x00f7 +#define W_META_CREATEBRUSH 0x00F8 +#define W_META_CREATEPATTERNBRUSH 0x01F9 +#define W_META_CREATEPENINDIRECT 0x02FA +#define W_META_CREATEFONTINDIRECT 0x02FB +#define W_META_CREATEBRUSHINDIRECT 0x02FC +#define W_META_CREATEBITMAPINDIRECT 0x02FD +#define W_META_CREATEBITMAP 0x06FE +#define W_META_CREATEREGION 0x06FF + +static void GetWinExtMax( const Point& rSource, Rectangle& rPlaceableBound, const sal_Int16 nMapMode ) +{ + Point aSource( rSource ); + if ( nMapMode == MM_HIMETRIC ) + aSource.Y() = -rSource.Y(); + if ( aSource.X() < rPlaceableBound.Left() ) + rPlaceableBound.Left() = aSource.X(); + if ( aSource.X() > rPlaceableBound.Right() ) + rPlaceableBound.Right() = aSource.X(); + if ( aSource.Y() < rPlaceableBound.Top() ) + rPlaceableBound.Top() = aSource.Y(); + if ( aSource.Y() > rPlaceableBound.Bottom() ) + rPlaceableBound.Bottom() = aSource.Y(); +} + +static void GetWinExtMax( const Rectangle& rSource, Rectangle& rPlaceableBound, const sal_Int16 nMapMode ) +{ + GetWinExtMax( rSource.TopLeft(), rPlaceableBound, nMapMode ); + GetWinExtMax( rSource.BottomRight(), rPlaceableBound, nMapMode ); +} + +//=================== Methods of WMFReader ============================== + +inline Point WMFReader::ReadPoint() +{ + short nX = 0, nY = 0; + *pWMF >> nX >> nY; + return Point( nX, nY ); +} + +// ------------------------------------------------------------------------ + +inline Point WMFReader::ReadYX() +{ + short nX = 0, nY = 0; + *pWMF >> nY >> nX; + return Point( nX, nY ); +} + +// ------------------------------------------------------------------------ + +Rectangle WMFReader::ReadRectangle() +{ + Point aBR, aTL; + aBR = ReadYX(); + aTL = ReadYX(); + aBR.X()--; + aBR.Y()--; + return Rectangle( aTL, aBR ); +} + +// ------------------------------------------------------------------------ + +Size WMFReader::ReadYXExt() +{ + short nW=0, nH=0; + *pWMF >> nH >> nW; + return Size( nW, nH ); +} + +// ------------------------------------------------------------------------ + +void WMFReader::ReadRecordParams( sal_uInt16 nFunc ) +{ + switch( nFunc ) + { + case W_META_SETBKCOLOR: + { + pOut->SetBkColor( ReadColor() ); + } + break; + + case W_META_SETBKMODE: + { + sal_uInt16 nDat = 0; + *pWMF >> nDat; + pOut->SetBkMode( nDat ); + } + break; + + // !!! + case W_META_SETMAPMODE: + { + sal_Int16 nMapMode = 0; + *pWMF >> nMapMode; + pOut->SetMapMode( nMapMode ); + } + break; + + case W_META_SETROP2: + { + sal_uInt16 nROP2 = 0; + *pWMF >> nROP2; + pOut->SetRasterOp( nROP2 ); + } + break; + + case W_META_SETTEXTCOLOR: + { + pOut->SetTextColor( ReadColor() ); + } + break; + + case W_META_SETWINDOWORG: + { + pOut->SetWinOrg( ReadYX() ); + } + break; + + case W_META_SETWINDOWEXT: + { + short nWidth = 0, nHeight = 0; + *pWMF >> nHeight >> nWidth; + pOut->SetWinExt( Size( nWidth, nHeight ) ); + } + break; + + case W_META_OFFSETWINDOWORG: + { + short nXAdd = 0, nYAdd = 0; + *pWMF >> nYAdd >> nXAdd; + pOut->SetWinOrgOffset( nXAdd, nYAdd ); + } + break; + + case W_META_SCALEWINDOWEXT: + { + short nXNum = 0, nXDenom = 0, nYNum = 0, nYDenom = 0; + *pWMF >> nYDenom >> nYNum >> nXDenom >> nXNum; + pOut->ScaleWinExt( (double)nXNum / nXDenom, (double)nYNum / nYDenom ); + } + break; + + case W_META_SETVIEWPORTORG: + case W_META_SETVIEWPORTEXT: + break; + + case W_META_OFFSETVIEWPORTORG: + { + short nXAdd = 0, nYAdd = 0; + *pWMF >> nYAdd >> nXAdd; + pOut->SetDevOrgOffset( nXAdd, nYAdd ); + } + break; + + case W_META_SCALEVIEWPORTEXT: + { + short nXNum = 0, nXDenom = 0, nYNum = 0, nYDenom = 0; + *pWMF >> nYDenom >> nYNum >> nXDenom >> nXNum; + pOut->ScaleDevExt( (double)nXNum / nXDenom, (double)nYNum / nYDenom ); + } + break; + + case W_META_LINETO: + { + pOut->LineTo( ReadYX() ); + } + break; + + case W_META_MOVETO: + { + pOut->MoveTo( ReadYX() ); + } + break; + + case W_META_INTERSECTCLIPRECT: + { + pOut->IntersectClipRect( ReadRectangle() ); + } + break; + + case W_META_RECTANGLE: + { + pOut->DrawRect( ReadRectangle() ); + } + break; + + case W_META_ROUNDRECT: + { + Size aSize( ReadYXExt() ); + pOut->DrawRoundRect( ReadRectangle(), Size( aSize.Width() / 2, aSize.Height() / 2 ) ); + } + break; + + case W_META_ELLIPSE: + { + pOut->DrawEllipse( ReadRectangle() ); + } + break; + + case W_META_ARC: + { + Point aEnd( ReadYX() ); + Point aStart( ReadYX() ); + Rectangle aRect( ReadRectangle() ); + aRect.Justify(); + pOut->DrawArc( aRect, aStart, aEnd ); + } + break; + + case W_META_PIE: + { + Point aEnd( ReadYX() ); + Point aStart( ReadYX() ); + Rectangle aRect( ReadRectangle() ); + aRect.Justify(); + + // #i73608# OutputDevice deviates from WMF + // semantics. start==end means full ellipse here. + if( aStart == aEnd ) + pOut->DrawEllipse( aRect ); + else + pOut->DrawPie( aRect, aStart, aEnd ); + } + break; + + case W_META_CHORD: + { + Point aEnd( ReadYX() ); + Point aStart( ReadYX() ); + Rectangle aRect( ReadRectangle() ); + aRect.Justify(); + pOut->DrawChord( aRect, aStart, aEnd ); + } + break; + + case W_META_POLYGON: + { + sal_uInt16 nPoints = 0; + *pWMF >> nPoints; + Polygon aPoly( nPoints ); + for( sal_uInt16 i = 0; i < nPoints; i++ ) + aPoly[ i ] = ReadPoint(); + pOut->DrawPolygon( aPoly ); + } + break; + + case W_META_POLYPOLYGON: + { + bool bRecordOk = true; + sal_uInt16 nPoly = 0; + Point* pPtAry; + // Number of polygons: + *pWMF >> nPoly; + // Number of points of each polygon. Determine total number of points + boost::scoped_array<sal_uInt16> xPolygonPointCounts(new sal_uInt16[nPoly]); + sal_uInt16* pnPoints = xPolygonPointCounts.get(); + sal_uInt16 nPoints = 0; + for(sal_uInt16 i = 0; i < nPoly; i++ ) + { + *pWMF >> pnPoints[i]; + + if (pnPoints[i] > SAL_MAX_UINT16 - nPoints) + { + bRecordOk = false; + break; + } + + nPoints += pnPoints[i]; + } + + SAL_WARN_IF(!bRecordOk, "svtools.filter", "polypolygon record has more polygons than we can handle"); + + bRecordOk &= pWMF->good(); + + if (!bRecordOk) + { + pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); + break; + } + + // Polygon points are: + boost::scoped_array<Point> xPolygonPoints(new Point[nPoints]); + pPtAry = xPolygonPoints.get(); + for (sal_uInt16 i = 0; i < nPoints; i++ ) + pPtAry[ i ] = ReadPoint(); + + bRecordOk &= pWMF->good(); + + if (!bRecordOk) + { + pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); + break; + } + + // Produce PolyPolygon Actions + PolyPolygon aPolyPoly( nPoly, pnPoints, pPtAry ); + pOut->DrawPolyPolygon( aPolyPoly ); + } + break; + + case W_META_POLYLINE: + { + sal_uInt16 nPoints = 0; + *pWMF >> nPoints; + Polygon aPoly( nPoints ); + for(sal_uInt16 i = 0; i < nPoints; i++ ) + aPoly[ i ] = ReadPoint(); + pOut->DrawPolyLine( aPoly ); + } + break; + + case W_META_SAVEDC: + { + pOut->Push(); + } + break; + + case W_META_RESTOREDC: + { + pOut->Pop(); + } + break; + + case W_META_SETPIXEL: + { + const Color aColor = ReadColor(); + pOut->DrawPixel( ReadYX(), aColor ); + } + break; + + case W_META_OFFSETCLIPRGN: + { + pOut->MoveClipRegion( ReadYXExt() ); + } + break; + + case W_META_TEXTOUT: + { + sal_uInt16 nLength = 0; + *pWMF >> nLength; + if ( nLength ) + { + char* pChar = new char[ ( nLength + 1 ) &~ 1 ]; + pWMF->Read( pChar, ( nLength + 1 ) &~ 1 ); + String aText( pChar, nLength, pOut->GetCharSet() ); + delete[] pChar; + Point aPosition( ReadYX() ); + pOut->DrawText( aPosition, aText ); + } + } + break; + + case W_META_EXTTEXTOUT: + { + sal_uInt16 nLen = 0, nOptions = 0; + sal_Int32 nRecordPos, nRecordSize = 0, nOriginalTextLen, nNewTextLen; + Point aPosition; + Rectangle aRect; + sal_Int32* pDXAry = NULL; + + pWMF->SeekRel(-6); + nRecordPos = pWMF->Tell(); + *pWMF >> nRecordSize; + pWMF->SeekRel(2); + aPosition = ReadYX(); + *pWMF >> nLen >> nOptions; + + sal_Int32 nTextLayoutMode = TEXT_LAYOUT_DEFAULT; + if ( nOptions & ETO_RTLREADING ) + nTextLayoutMode = TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_LEFT; + pOut->SetTextLayoutMode( nTextLayoutMode ); + DBG_ASSERT( ( nOptions & ( ETO_PDY | ETO_GLYPH_INDEX ) ) == 0, "SJ: ETO_PDY || ETO_GLYPH_INDEX in WMF" ); + + // Nur wenn der Text auch Zeichen enthaelt, macht die Ausgabe Sinn + if( nLen ) + { + nOriginalTextLen = nLen; + if( nOptions & ETO_CLIPPED ) + { + const Point aPt1( ReadPoint() ); + const Point aPt2( ReadPoint() ); + aRect = Rectangle( aPt1, aPt2 ); + } + char* pChar = new char[ ( nOriginalTextLen + 1 ) &~ 1 ]; + pWMF->Read( pChar, ( nOriginalTextLen + 1 ) &~ 1 ); + String aText( pChar, (sal_uInt16)nOriginalTextLen, pOut->GetCharSet() );// after this conversion the text may contain + nNewTextLen = aText.Len(); // less character (japanese version), so the + delete[] pChar; // dxAry will not fit + + if ( nNewTextLen ) + { + sal_uInt32 nMaxStreamPos = nRecordPos + ( nRecordSize << 1 ); + sal_Int32 nDxArySize = nMaxStreamPos - pWMF->Tell(); + sal_Int32 nDxAryEntries = nDxArySize >> 1; + sal_Bool bUseDXAry = sal_False; + + if ( ( ( nDxAryEntries % nOriginalTextLen ) == 0 ) && ( nNewTextLen <= nOriginalTextLen ) ) + { + sal_Int16 nDx = 0, nDxTmp = 0; + sal_uInt16 i; //needed just outside the for + pDXAry = new sal_Int32[ nNewTextLen ]; + for (i = 0; i < nNewTextLen; i++ ) + { + if ( pWMF->Tell() >= nMaxStreamPos ) + break; + *pWMF >> nDx; + if ( nNewTextLen != nOriginalTextLen ) + { + sal_Unicode nUniChar = aText.GetChar(i); + rtl::OString aTmp(&nUniChar, 1, pOut->GetCharSet()); + if ( aTmp.getLength() > 1 ) + { + sal_Int32 nDxCount = aTmp.getLength() - 1; + if ( ( ( nDxCount * 2 ) + pWMF->Tell() ) > nMaxStreamPos ) + break; + while ( nDxCount-- ) + { + *pWMF >> nDxTmp; + nDx = nDx + nDxTmp; + } + } + } + pDXAry[ i ] = nDx; + } + if ( i == nNewTextLen ) + bUseDXAry = sal_True; + } + if ( pDXAry && bUseDXAry ) + pOut->DrawText( aPosition, aText, pDXAry ); + else + pOut->DrawText( aPosition, aText ); + } + } + delete[] pDXAry; + + } + break; + + case W_META_SELECTOBJECT: + { + sal_Int16 nObjIndex = 0; + *pWMF >> nObjIndex; + pOut->SelectObject( nObjIndex ); + } + break; + + case W_META_SETTEXTALIGN: + { + sal_uInt16 nAlign = 0; + *pWMF >> nAlign; + pOut->SetTextAlign( nAlign ); + } + break; + + case W_META_BITBLT: + { + // 0-3 : nWinROP #93454# + // 4-5 : y offset of source bitmap + // 6-7 : x offset of source bitmap + // 8-9 : used height of source bitmap + // 10-11 : used width of source bitmap + // 12-13 : destination position y (in pixel) + // 14-15 : destination position x (in pixel) + // 16-17 : dont know + // 18-19 : Width Bitmap in Pixel + // 20-21 : Height Bitmap in Pixel + // 22-23 : bytes per scanline + // 24 : planes + // 25 : bitcount + + sal_Int32 nWinROP = 0; + sal_uInt16 nSx = 0, nSy = 0, nSxe = 0, nSye = 0, nDontKnow = 0, nWidth = 0, nHeight = 0, nBytesPerScan = 0; + sal_uInt8 nPlanes, nBitCount; + + *pWMF >> nWinROP + >> nSy >> nSx >> nSye >> nSxe; + Point aPoint( ReadYX() ); + *pWMF >> nDontKnow >> nWidth >> nHeight >> nBytesPerScan >> nPlanes >> nBitCount; + + if ( nWidth && nHeight && ( nPlanes == 1 ) && ( nBitCount == 1 ) ) + { + Bitmap aBmp( Size( nWidth, nHeight ), nBitCount ); + BitmapWriteAccess* pAcc; + pAcc = aBmp.AcquireWriteAccess(); + if ( pAcc ) + { + for (sal_uInt16 y = 0; y < nHeight; y++ ) + { + sal_uInt16 x = 0; + for (sal_uInt16 scan = 0; scan < nBytesPerScan; scan++ ) + { + sal_Int8 nEightPixels = 0; + *pWMF >> nEightPixels; + for (sal_Int8 i = 7; i >= 0; i-- ) + { + if ( x < nWidth ) + { + pAcc->SetPixel( y, x, (nEightPixels>>i)&1 ); + } + x++; + } + } + } + aBmp.ReleaseAccess( pAcc ); + if ( nSye && nSxe && + ( ( nSx + nSxe ) <= aBmp.GetSizePixel().Width() ) && + ( ( nSy + nSye <= aBmp.GetSizePixel().Height() ) ) ) + { + Rectangle aCropRect( Point( nSx, nSy ), Size( nSxe, nSye ) ); + aBmp.Crop( aCropRect ); + } + Rectangle aDestRect( aPoint, Size( nSxe, nSye ) ); + aBmpSaveList.push_back( new BSaveStruct( aBmp, aDestRect, nWinROP, pOut->GetFillStyle () ) ); + } + } + } + break; + + case W_META_STRETCHBLT: + case W_META_DIBBITBLT: + case W_META_DIBSTRETCHBLT: + case W_META_STRETCHDIB: + { + sal_Int32 nWinROP = 0; + sal_uInt16 nSx = 0, nSy = 0, nSxe = 0, nSye = 0, nUsage = 0; + Bitmap aBmp; + + *pWMF >> nWinROP; + + if( nFunc == W_META_STRETCHDIB ) + *pWMF >> nUsage; + + // nSye and nSxe is the number of pixels that has to been used + // If they are set to zero, it is as indicator not to scale the bitmap later + // + if( nFunc == W_META_STRETCHDIB || nFunc == W_META_STRETCHBLT || nFunc == W_META_DIBSTRETCHBLT ) + *pWMF >> nSye >> nSxe; + + // nSy and nx is the offset of the first pixel + *pWMF >> nSy >> nSx; + + if( nFunc == W_META_STRETCHDIB || nFunc == W_META_DIBBITBLT || nFunc == W_META_DIBSTRETCHBLT ) + { + if ( nWinROP == PATCOPY ) + *pWMF >> nUsage; // i don't know anything of this parameter, so its called nUsage + // pOut->DrawRect( Rectangle( ReadYX(), aDestSize ), sal_False ); + + Size aDestSize( ReadYXExt() ); + if ( aDestSize.Width() && aDestSize.Height() ) // #92623# do not try to read buggy bitmaps + { + Rectangle aDestRect( ReadYX(), aDestSize ); + if ( nWinROP != PATCOPY ) + aBmp.Read( *pWMF, sal_False ); + + // test if it is sensible to crop + if ( nSye && nSxe && + ( ( nSx + nSxe ) <= aBmp.GetSizePixel().Width() ) && + ( ( nSy + nSye <= aBmp.GetSizePixel().Height() ) ) ) + { + Rectangle aCropRect( Point( nSx, nSy ), Size( nSxe, nSye ) ); + aBmp.Crop( aCropRect ); + } + aBmpSaveList.push_back( new BSaveStruct( aBmp, aDestRect, nWinROP, pOut->GetFillStyle () ) ); + } + } + } + break; + + case W_META_DIBCREATEPATTERNBRUSH: + { + Bitmap aBmp; + BitmapReadAccess* pBmp; + sal_uInt32 nRed = 0, nGreen = 0, nBlue = 0, nCount = 1; + sal_uInt16 nFunction = 0; + + *pWMF >> nFunction >> nFunction; + + aBmp.Read( *pWMF, sal_False ); + pBmp = aBmp.AcquireReadAccess(); + if ( pBmp ) + { + for ( sal_Int32 y = 0; y < pBmp->Height(); y++ ) + { + for ( sal_Int32 x = 0; x < pBmp->Width(); x++ ) + { + const BitmapColor aColor( pBmp->GetColor( y, x ) ); + + nRed += aColor.GetRed(); + nGreen += aColor.GetGreen(); + nBlue += aColor.GetBlue(); + } + } + nCount = pBmp->Height() * pBmp->Width(); + if ( !nCount ) + nCount++; + aBmp.ReleaseAccess( pBmp ); + } + Color aColor( (sal_uInt8)( nRed / nCount ), (sal_uInt8)( nGreen / nCount ), (sal_uInt8)( nBlue / nCount ) ); + pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( aColor, sal_False ) ); + } + break; + + case W_META_DELETEOBJECT: + { + sal_Int16 nIndex = 0; + *pWMF >> nIndex; + pOut->DeleteObject( nIndex ); + } + break; + + case W_META_CREATEPALETTE: + { + pOut->CreateObject( GDI_DUMMY ); + } + break; + + case W_META_CREATEBRUSH: + { + pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ), sal_False ) ); + } + break; + + case W_META_CREATEPATTERNBRUSH: + { + pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( Color( COL_WHITE ), sal_False ) ); + } + break; + + case W_META_CREATEPENINDIRECT: + { + LineInfo aLineInfo; + sal_uInt16 nStyle = 0, nWidth = 0, nHeight = 0; + + *pWMF >> nStyle >> nWidth >> nHeight; + + if ( nWidth ) + aLineInfo.SetWidth( nWidth ); + + sal_Bool bTransparent = sal_False; + sal_uInt16 nDashCount = 0; + sal_uInt16 nDotCount = 0; + switch( nStyle ) + { + case PS_DASHDOTDOT : + nDotCount++; + case PS_DASHDOT : + nDashCount++; + case PS_DOT : + nDotCount++; + break; + case PS_DASH : + nDashCount++; + break; + case PS_NULL : + bTransparent = sal_True; + aLineInfo.SetStyle( LINE_NONE ); + break; + default : + case PS_INSIDEFRAME : + case PS_SOLID : + aLineInfo.SetStyle( LINE_SOLID ); + } + if ( nDashCount | nDotCount ) + { + aLineInfo.SetStyle( LINE_DASH ); + aLineInfo.SetDashCount( nDashCount ); + aLineInfo.SetDotCount( nDotCount ); + } + pOut->CreateObject( GDI_PEN, new WinMtfLineStyle( ReadColor(), aLineInfo, bTransparent ) ); + } + break; + + case W_META_CREATEBRUSHINDIRECT: + { + sal_uInt16 nStyle = 0; + *pWMF >> nStyle; + pOut->CreateObject( GDI_BRUSH, new WinMtfFillStyle( ReadColor(), ( nStyle == BS_HOLLOW ) ? sal_True : sal_False ) ); + } + break; + + case W_META_CREATEFONTINDIRECT: + { + Size aFontSize; + char lfFaceName[ LF_FACESIZE ]; + sal_Int16 lfEscapement = 0, lfOrientation = 0, lfWeight = 0; // ( formerly sal_uInt16 ) + + LOGFONTW aLogFont; + aFontSize = ReadYXExt(); + *pWMF >> lfEscapement >> lfOrientation >> lfWeight + >> aLogFont.lfItalic >> aLogFont.lfUnderline >> aLogFont.lfStrikeOut >> aLogFont.lfCharSet >> aLogFont.lfOutPrecision + >> aLogFont.lfClipPrecision >> aLogFont.lfQuality >> aLogFont.lfPitchAndFamily; + pWMF->Read( lfFaceName, LF_FACESIZE ); + aLogFont.lfWidth = aFontSize.Width(); + aLogFont.lfHeight = aFontSize.Height(); + aLogFont.lfEscapement = lfEscapement; + aLogFont.lfOrientation = lfOrientation; + aLogFont.lfWeight = lfWeight; + + CharSet eCharSet; + if ( ( aLogFont.lfCharSet == OEM_CHARSET ) || ( aLogFont.lfCharSet == DEFAULT_CHARSET ) ) + eCharSet = osl_getThreadTextEncoding(); + else + eCharSet = rtl_getTextEncodingFromWindowsCharset( aLogFont.lfCharSet ); + if ( eCharSet == RTL_TEXTENCODING_DONTKNOW ) + eCharSet = osl_getThreadTextEncoding(); + if ( eCharSet == RTL_TEXTENCODING_SYMBOL ) + eCharSet = RTL_TEXTENCODING_MS_1252; + aLogFont.alfFaceName = UniString( lfFaceName, eCharSet ); + + pOut->CreateObject( GDI_FONT, new WinMtfFontStyle( aLogFont ) ); + } + break; + + case W_META_CREATEBITMAPINDIRECT: + { + pOut->CreateObject( GDI_DUMMY ); + } + break; + + case W_META_CREATEBITMAP: + { + pOut->CreateObject( GDI_DUMMY ); + } + break; + + case W_META_CREATEREGION: + { + pOut->CreateObject( GDI_DUMMY ); + } + break; + + case W_META_EXCLUDECLIPRECT : + { + pOut->ExcludeClipRect( ReadRectangle() ); + } + break; + + case W_META_PATBLT: + { + sal_uInt32 nROP = 0, nOldROP = 0; + *pWMF >> nROP; + Size aSize = ReadYXExt(); + nOldROP = pOut->SetRasterOp( nROP ); + pOut->DrawRect( Rectangle( ReadYX(), aSize ), sal_False ); + pOut->SetRasterOp( nOldROP ); + } + break; + + case W_META_SELECTCLIPREGION: + { + sal_Int16 nObjIndex = 0; + *pWMF >> nObjIndex; + if ( !nObjIndex ) + { + PolyPolygon aEmptyPolyPoly; + pOut->SetClipPath( aEmptyPolyPoly, RGN_COPY, sal_True ); + } + } + break; + + case W_META_ESCAPE : + { + // nRecSize has been checked previously to be greater than 3 + sal_uInt64 nMetaRecSize = static_cast< sal_uInt64 >( nRecSize - 2 ) * 2; + sal_uInt64 nMetaRecEndPos = pWMF->Tell() + nMetaRecSize; + + // taking care that nRecSize does not exceed the maximal stream position + if ( nMetaRecEndPos > nEndPos ) + { + pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); + break; + } + if ( nRecSize >= 4 ) // minimal escape lenght + { + sal_uInt16 nMode = 0, nLen = 0; + *pWMF >> nMode + >> nLen; + if ( ( nMode == W_MFCOMMENT ) && ( nLen >= 4 ) ) + { + sal_uInt32 nNewMagic = 0; // we have to read int32 for + *pWMF >> nNewMagic; // META_ESCAPE_ENHANCED_METAFILE CommentIdentifier + + if( nNewMagic == 0x2c2a4f4f && nLen >= 14 ) + { + sal_uInt16 nMagic2 = 0; + *pWMF >> nMagic2; + if( nMagic2 == 0x0a ) // 2nd half of magic + { // continue with private escape + sal_uInt32 nCheck = 0, nEsc = 0; + *pWMF >> nCheck + >> nEsc; + + sal_uInt32 nEscLen = nLen - 14; + if ( nEscLen <= ( nRecSize * 2 ) ) + { +#ifdef OSL_BIGENDIAN + sal_uInt32 nTmp = OSL_SWAPDWORD( nEsc ); + sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 ); +#else + sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 ); +#endif + sal_Int8* pData = NULL; + + if ( ( static_cast< sal_uInt64 >( nEscLen ) + pWMF->Tell() ) > nMetaRecEndPos ) + { + pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); + break; + } + if ( nEscLen > 0 ) + { + pData = new sal_Int8[ nEscLen ]; + pWMF->Read( pData, nEscLen ); + nCheckSum = rtl_crc32( nCheckSum, pData, nEscLen ); + } + if ( nCheck == nCheckSum ) + { + switch( nEsc ) + { + case PRIVATE_ESCAPE_UNICODE : + { // we will use text instead of polygons only if we have the correct font + if ( aVDev.IsFontAvailable( pOut->GetFont().GetName() ) ) + { + Point aPt; + String aString; + sal_uInt32 nStringLen, nDXCount; + sal_Int32* pDXAry = NULL; + SvMemoryStream aMemoryStream( nEscLen ); + aMemoryStream.Write( pData, nEscLen ); + aMemoryStream.Seek( STREAM_SEEK_TO_BEGIN ); + //#fdo39428 SvStream no longer supports operator>>(long&) + sal_Int32 nTmpX(0), nTmpY(0); + aMemoryStream >> nTmpX + >> nTmpY + >> nStringLen; + aPt.X() = nTmpX; + aPt.Y() = nTmpY; + + if ( ( static_cast< sal_uInt64 >( nStringLen ) * sizeof( sal_Unicode ) ) < ( nEscLen - aMemoryStream.Tell() ) ) + { + + aString = read_uInt16s_ToOUString(aMemoryStream, nStringLen); + aMemoryStream >> nDXCount; + if ( ( static_cast< sal_uInt64 >( nDXCount ) * sizeof( sal_Int32 ) ) >= ( nEscLen - aMemoryStream.Tell() ) ) + nDXCount = 0; + if ( nDXCount ) + pDXAry = new sal_Int32[ nDXCount ]; + for (sal_uInt32 i = 0; i < nDXCount; i++ ) + aMemoryStream >> pDXAry[ i ]; + aMemoryStream >> nSkipActions; + pOut->DrawText( aPt, aString, pDXAry ); + delete[] pDXAry; + } + } + } + break; + } + } + delete[] pData; + } + } + } + else if ( (nNewMagic == static_cast< sal_uInt32 >(0x43464D57)) && (nLen >= 34) && ( (sal_Int32)(nLen + 10) <= (sal_Int32)(nRecSize * 2) )) + { + sal_uInt32 nComType = 0, nVersion = 0, nFlags = 0, nComRecCount = 0, + nCurRecSize = 0, nRemainingSize = 0, nEMFTotalSize = 0; + sal_uInt16 nCheck = 0; + + *pWMF >> nComType >> nVersion >> nCheck >> nFlags + >> nComRecCount >> nCurRecSize + >> nRemainingSize >> nEMFTotalSize; // the nRemainingSize is not mentioned in MSDN documentation + // but it seems to be required to read in data produced by OLE + + if( nComType == 0x01 && nVersion == 0x10000 && nComRecCount ) + { + if( !nEMFRec ) + { // first EMF comment + nEMFRecCount = nComRecCount; + nEMFSize = nEMFTotalSize; + pEMFStream = new SvMemoryStream( nEMFSize ); + } + else if( ( nEMFRecCount != nComRecCount ) || ( nEMFSize != nEMFTotalSize ) ) // add additional checks here + { + // total records should be the same as in previous comments + nEMFRecCount = 0xFFFFFFFF; + delete pEMFStream; + pEMFStream = NULL; + } + nEMFRec++; + + if( pEMFStream && nCurRecSize + 34 > nLen ) + { + nEMFRecCount = 0xFFFFFFFF; + delete pEMFStream; + pEMFStream = NULL; + } + + if( pEMFStream ) + { + sal_Int8* pBuf = new sal_Int8[ nCurRecSize ]; + sal_uInt32 nCount = pWMF->Read( pBuf, nCurRecSize ); + if( nCount == nCurRecSize ) + pEMFStream->Write( pBuf, nCount ); + delete[] pBuf; + } + } + } + } + } + } + break; + + case W_META_SETRELABS: + case W_META_SETPOLYFILLMODE: + case W_META_SETSTRETCHBLTMODE: + case W_META_SETTEXTCHAREXTRA: + case W_META_SETTEXTJUSTIFICATION: + case W_META_FLOODFILL : + case W_META_FILLREGION: + case W_META_FRAMEREGION: + case W_META_INVERTREGION: + case W_META_PAINTREGION: + case W_META_DRAWTEXT: + case W_META_SETMAPPERFLAGS: + case W_META_SETDIBTODEV: + case W_META_SELECTPALETTE: + case W_META_REALIZEPALETTE: + case W_META_ANIMATEPALETTE: + case W_META_SETPALENTRIES: + case W_META_RESIZEPALETTE: + case W_META_EXTFLOODFILL: + case W_META_RESETDC: + case W_META_STARTDOC: + case W_META_STARTPAGE: + case W_META_ENDPAGE: + case W_META_ABORTDOC: + case W_META_ENDDOC: + break; + } +} + +// ------------------------------------------------------------------------ + +sal_Bool WMFReader::ReadHeader() +{ + sal_Size nStrmPos = pWMF->Tell(); + + sal_uInt32 nPlaceableMetaKey(0); + // Einlesen des METAFILEHEADER, falls vorhanden + *pWMF >> nPlaceableMetaKey; + if (!pWMF->good()) + return false; + + Rectangle aPlaceableBound; + + if (nPlaceableMetaKey == 0x9ac6cdd7L) + { //TODO do some real error handling here + sal_Int16 nVal; + + // Skip reserved bytes + pWMF->SeekRel(2); + + // BoundRect + *pWMF >> nVal; + aPlaceableBound.Left() = nVal; + *pWMF >> nVal; + aPlaceableBound.Top() = nVal; + *pWMF >> nVal; + aPlaceableBound.Right() = nVal; + *pWMF >> nVal; + aPlaceableBound.Bottom() = nVal; + + // inch + *pWMF >> nUnitsPerInch; + + // reserved + pWMF->SeekRel( 4 ); + + // Skip and don't check the checksum + pWMF->SeekRel( 2 ); + } + else + { + nUnitsPerInch = 96; + pWMF->Seek( nStrmPos + 18 ); // set the streampos to the start of the the metaactions + GetPlaceableBound( aPlaceableBound, pWMF ); + pWMF->Seek( nStrmPos ); + if ( pExternalHeader != NULL && ( pExternalHeader->mapMode == MM_ISOTROPIC + || pExternalHeader->mapMode == MM_ANISOTROPIC ) ) + { + // #n417818#: If we have an external header then overwrite the bounds! + Rectangle aExtRect(0, 0, + pExternalHeader->xExt*567*nUnitsPerInch/1440/1000, + pExternalHeader->yExt*567*nUnitsPerInch/1440/1000); + GetWinExtMax( aExtRect, aPlaceableBound, pExternalHeader->mapMode ); + pOut->SetMapMode( pExternalHeader->mapMode ); + } + } + + pOut->SetUnitsPerInch( nUnitsPerInch ); + pOut->SetWinOrg( aPlaceableBound.TopLeft() ); + Size aWMFSize( labs( aPlaceableBound.GetWidth() ), labs( aPlaceableBound.GetHeight() ) ); + pOut->SetWinExt( aWMFSize ); + + Size aDevExt( 10000, 10000 ); + if( ( labs( aWMFSize.Width() ) > 1 ) && ( labs( aWMFSize.Height() ) > 1 ) ) + { + const Fraction aFrac( 1, nUnitsPerInch ); + MapMode aWMFMap( MAP_INCH, Point(), aFrac, aFrac ); + Size aSize100( OutputDevice::LogicToLogic( aWMFSize, aWMFMap, MAP_100TH_MM ) ); + aDevExt = Size( labs( aSize100.Width() ), labs( aSize100.Height() ) ); + } + pOut->SetDevExt( aDevExt ); + + // Einlesen des METAHEADER + sal_uInt32 nMetaKey(0); + *pWMF >> nMetaKey; // Typ und Headergroesse + if (!pWMF->good()) + return false; + if (nMetaKey != 0x00090001) + { + sal_uInt16 aNextWord(0); + *pWMF >> aNextWord; + if (nMetaKey != 0x10000 || aNextWord != 0x09) + { + pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); + return false; + } + } + + pWMF->SeekRel( 2 ); // Version (von Windows) + pWMF->SeekRel( 4 ); // Size (der Datei in Words) + pWMF->SeekRel( 2 ); // NoObjects (Maximale Anzahl der gleichzeitigen Objekte) + pWMF->SeekRel( 4 ); // MaxRecord (Groesse des groessten Records in Words) + pWMF->SeekRel( 2 ); // NoParameters (Unused + + return pWMF->good(); +} + +void WMFReader::ReadWMF() +{ + sal_uInt16 nFunction; + sal_uLong nPos, nPercent, nLastPercent; + + nSkipActions = 0; + nCurrentAction = 0; + nUnicodeEscapeAction = 0; + + pEMFStream = NULL; + nEMFRecCount = 0; + nEMFRec = 0; + nEMFSize = 0; + + sal_Bool bEMFAvailable = sal_False; + + pOut->SetMapMode( MM_ANISOTROPIC ); + pOut->SetWinOrg( Point() ); + pOut->SetWinExt( Size( 1, 1 ) ); + pOut->SetDevExt( Size( 10000, 10000 ) ); + + nEndPos=pWMF->Seek( STREAM_SEEK_TO_END ); + pWMF->Seek( nStartPos ); + Callback( (sal_uInt16) ( nLastPercent = 0 ) ); + + if ( ReadHeader( ) ) + { + + nPos = pWMF->Tell(); + + if( nEndPos - nStartPos ) + { + while( sal_True ) + { + nCurrentAction++; + nPercent = ( nPos - nStartPos ) * 100 / ( nEndPos - nStartPos ); + + if( nLastPercent + 4 <= nPercent ) + { + Callback( (sal_uInt16) nPercent ); + nLastPercent = nPercent; + } + *pWMF >> nRecSize >> nFunction; + + if( pWMF->GetError() + || ( nRecSize < 3 ) + || ( nRecSize == 3 + && nFunction == 0 + ) + || pWMF->IsEof() + ) + { + if( pWMF->IsEof() ) + pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); + + break; + } + if ( !bEMFAvailable ) + { + if( !aBmpSaveList.empty() + && ( nFunction != W_META_STRETCHDIB ) + && ( nFunction != W_META_DIBBITBLT ) + && ( nFunction != W_META_DIBSTRETCHBLT ) + ) + { + pOut->ResolveBitmapActions( aBmpSaveList ); + } + + if ( !nSkipActions ) + ReadRecordParams( nFunction ); + else + nSkipActions--; + + if( pEMFStream && nEMFRecCount == nEMFRec ) + { + GDIMetaFile aMeta; + pEMFStream->Seek( 0 ); + EnhWMFReader* pEMFReader = new EnhWMFReader ( *pEMFStream, aMeta ); + bEMFAvailable = pEMFReader->ReadEnhWMF(); + delete pEMFReader; // destroy first!!! + + if( bEMFAvailable ) + { + pOut->AddFromGDIMetaFile( aMeta ); + pOut->SetrclFrame( Rectangle( Point(0, 0), aMeta.GetPrefSize())); + + // the stream needs to be set to the wmf end position, + // otherwise the GfxLink that is created will be incorrect + // (leading to graphic loss after swapout/swapin). + // so we will proceed normally, but are ignoring further wmf + // records + } + else + { + // something went wrong + // continue with WMF, don't try this again + delete pEMFStream; + pEMFStream = NULL; + } + } + } + nPos += nRecSize * 2; + if ( nPos <= nEndPos ) + pWMF->Seek( nPos ); + else + pWMF->SetError( SVSTREAM_FILEFORMAT_ERROR ); + } + } + else + pWMF->SetError( SVSTREAM_GENERALERROR ); + + if( !pWMF->GetError() && !aBmpSaveList.empty() ) + pOut->ResolveBitmapActions( aBmpSaveList ); + } + if ( pWMF->GetError() ) + pWMF->Seek( nStartPos ); +} + +// ------------------------------------------------------------------------ + +sal_Bool WMFReader::GetPlaceableBound( Rectangle& rPlaceableBound, SvStream* pStm ) +{ + sal_Bool bRet = sal_True; + + rPlaceableBound.Left() = (sal_Int32)0x7fffffff; + rPlaceableBound.Top() = (sal_Int32)0x7fffffff; + rPlaceableBound.Right() = (sal_Int32)0x80000000; + rPlaceableBound.Bottom() = (sal_Int32)0x80000000; + + sal_uInt32 nPos = pStm->Tell(); + sal_uInt32 nEnd = pStm->Seek( STREAM_SEEK_TO_END ); + + pStm->Seek( nPos ); + + if( nEnd - nPos ) + { + sal_Int16 nMapMode = MM_ANISOTROPIC; + sal_uInt16 nFunction; + sal_uInt32 nRSize; + + while( bRet ) + { + *pStm >> nRSize >> nFunction; + + if( pStm->GetError() || ( nRSize < 3 ) || ( nRSize==3 && nFunction==0 ) || pStm->IsEof() ) + { + if( pStm->IsEof() ) + { + pStm->SetError( SVSTREAM_FILEFORMAT_ERROR ); + bRet = sal_False; + } + break; + } + switch( nFunction ) + { + case W_META_SETWINDOWORG: + { + Point aWinOrg; + aWinOrg = ReadYX(); + rPlaceableBound.SetPos( aWinOrg ); + } + break; + + case W_META_SETWINDOWEXT: + { + sal_Int16 nWidth(0), nHeight(0); + *pStm >> nHeight >> nWidth; + rPlaceableBound.SetSize( Size( nWidth, nHeight ) ); + } + break; + + case W_META_SETMAPMODE : + *pStm >> nMapMode; + break; + + case W_META_MOVETO: + case W_META_LINETO: + GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode ); + break; + + case W_META_RECTANGLE: + case W_META_INTERSECTCLIPRECT: + case W_META_EXCLUDECLIPRECT : + case W_META_ELLIPSE: + GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode ); + break; + + case W_META_ROUNDRECT: + ReadYXExt(); // size + GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode ); + break; + + case W_META_ARC: + case W_META_PIE: + case W_META_CHORD: + ReadYX(); // end + ReadYX(); // start + GetWinExtMax( ReadRectangle(), rPlaceableBound, nMapMode ); + break; + + case W_META_POLYGON: + { + sal_uInt16 nPoints; + *pStm >> nPoints; + for(sal_uInt16 i = 0; i < nPoints; i++ ) + GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode ); + } + break; + + case W_META_POLYPOLYGON: + { + bool bRecordOk = true; + sal_uInt16 nPoly, nPoints = 0; + *pStm >> nPoly; + for(sal_uInt16 i = 0; i < nPoly; i++ ) + { + sal_uInt16 nP = 0; + *pStm >> nP; + if (nP > SAL_MAX_UINT16 - nPoints) + { + bRecordOk = false; + break; + } + nPoints += nP; + } + + SAL_WARN_IF(!bRecordOk, "svtools.filter", "polypolygon record has more polygons than we can handle"); + + bRecordOk &= pStm->good(); + + if (!bRecordOk) + { + pStm->SetError( SVSTREAM_FILEFORMAT_ERROR ); + bRet = sal_False; + break; + } + + for (sal_uInt16 i = 0; i < nPoints; i++ ) + GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode ); + + bRecordOk &= pStm->good(); + + if (!bRecordOk) + { + pStm->SetError( SVSTREAM_FILEFORMAT_ERROR ); + bRet = sal_False; + break; + } + } + break; + + case W_META_POLYLINE: + { + sal_uInt16 nPoints; + *pStm >> nPoints; + for(sal_uInt16 i = 0; i < nPoints; i++ ) + GetWinExtMax( ReadPoint(), rPlaceableBound, nMapMode ); + } + break; + + case W_META_SETPIXEL: + { + ReadColor(); + GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode ); + } + break; + + case W_META_TEXTOUT: + { + sal_uInt16 nLength; + *pStm >> nLength; + // todo: we also have to take care of the text width + if ( nLength ) + { + pStm->SeekRel( ( nLength + 1 ) &~ 1 ); + GetWinExtMax( ReadYX(), rPlaceableBound, nMapMode ); + } + } + break; + + case W_META_EXTTEXTOUT: + { + sal_uInt16 nLen, nOptions; + Point aPosition; + + aPosition = ReadYX(); + *pStm >> nLen >> nOptions; + // todo: we also have to take care of the text width + if( nLen ) + GetWinExtMax( aPosition, rPlaceableBound, nMapMode ); + } + break; + case W_META_BITBLT: + case W_META_STRETCHBLT: + case W_META_DIBBITBLT: + case W_META_DIBSTRETCHBLT: + case W_META_STRETCHDIB: + { + sal_Int32 nWinROP; + sal_uInt16 nSx, nSy, nSxe, nSye, nUsage; + *pStm >> nWinROP; + + if( nFunction == W_META_STRETCHDIB ) + *pStm >> nUsage; + + // nSye and nSxe is the number of pixels that has to been used + if( nFunction == W_META_STRETCHDIB || nFunction == W_META_STRETCHBLT || nFunction == W_META_DIBSTRETCHBLT ) + *pStm >> nSye >> nSxe; + else + nSye = nSxe = 0; // set this to zero as indicator not to scale the bitmap later + + // nSy and nx is the offset of the first pixel + *pStm >> nSy >> nSx; + + if( nFunction == W_META_STRETCHDIB || nFunction == W_META_DIBBITBLT || nFunction == W_META_DIBSTRETCHBLT ) + { + if ( nWinROP == PATCOPY ) + *pStm >> nUsage; // i don't know anything of this parameter, so its called nUsage + // pOut->DrawRect( Rectangle( ReadYX(), aDestSize ), sal_False ); + + Size aDestSize( ReadYXExt() ); + if ( aDestSize.Width() && aDestSize.Height() ) // #92623# do not try to read buggy bitmaps + { + Rectangle aDestRect( ReadYX(), aDestSize ); + GetWinExtMax( aDestRect, rPlaceableBound, nMapMode ); + } + } + } + break; + + case W_META_PATBLT: + { + sal_uInt32 nROP; + *pStm >> nROP; + Size aSize = ReadYXExt(); + GetWinExtMax( Rectangle( ReadYX(), aSize ), rPlaceableBound, nMapMode ); + } + break; + } + nPos += nRSize * 2; + if ( nPos <= nEnd ) + pStm->Seek( nPos ); + else + { + pStm->SetError( SVSTREAM_FILEFORMAT_ERROR ); + bRet = sal_False; + } + + } + } + else + { + pStm->SetError( SVSTREAM_GENERALERROR ); + bRet = sal_False; + } + return bRet; +} + +WMFReader::~WMFReader() +{ + if( pEMFStream ) + delete pEMFStream; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/wmf.cxx b/vcl/source/filter/wmf/wmf.cxx new file mode 100644 index 000000000000..9c3b7e6dc0e7 --- /dev/null +++ b/vcl/source/filter/wmf/wmf.cxx @@ -0,0 +1,110 @@ +/* -*- 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 "winmtf.hxx" +#include "emfwr.hxx" +#include "wmfwr.hxx" +#include <svtools/wmf.hxx> +#include <comphelper/scopeguard.hxx> + +// ----------------------------------------------------------------------------- + +sal_Bool ConvertWMFToGDIMetaFile( SvStream & rStreamWMF, GDIMetaFile & rGDIMetaFile, FilterConfigItem* pConfigItem, WMF_EXTERNALHEADER *pExtHeader ) +{ + sal_uInt32 nMetaType; + sal_uInt32 nOrgPos = rStreamWMF.Tell(); + sal_uInt16 nOrigNumberFormat = rStreamWMF.GetNumberFormatInt(); + rStreamWMF.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + rStreamWMF.Seek( 0x28 ); + rStreamWMF >> nMetaType; + rStreamWMF.Seek( nOrgPos ); + if ( nMetaType == 0x464d4520 ) + { + if ( EnhWMFReader( rStreamWMF, rGDIMetaFile, pConfigItem ).ReadEnhWMF() == sal_False ) + rStreamWMF.SetError( SVSTREAM_FILEFORMAT_ERROR ); + } + else + { + WMFReader( rStreamWMF, rGDIMetaFile, pConfigItem, pExtHeader ).ReadWMF( ); + } + rStreamWMF.SetNumberFormatInt( nOrigNumberFormat ); + return !rStreamWMF.GetError(); +} + +// ----------------------------------------------------------------------------- + +sal_Bool ReadWindowMetafile( SvStream& rStream, GDIMetaFile& rMTF, FilterConfigItem* pFilterConfigItem ) +{ + sal_uInt32 nMetaType(0); + sal_uInt32 nOrgPos = rStream.Tell(); + + sal_uInt16 nOrigNumberFormat = rStream.GetNumberFormatInt(); + rStream.SetNumberFormatInt( NUMBERFORMAT_INT_LITTLEENDIAN ); + //exception-safe reset nOrigNumberFormat at end of scope + const ::comphelper::ScopeGuard aScopeGuard( + boost::bind(&SvStream::SetNumberFormatInt, ::boost::ref(rStream), + nOrigNumberFormat)); + + rStream.Seek( 0x28 ); + rStream >> nMetaType; + rStream.Seek( nOrgPos ); + + if (!rStream.good()) + return false; + + if ( nMetaType == 0x464d4520 ) + { + if ( EnhWMFReader( rStream, rMTF, NULL ).ReadEnhWMF() == sal_False ) + rStream.SetError( SVSTREAM_FILEFORMAT_ERROR ); + } + else + { + WMFReader( rStream, rMTF, pFilterConfigItem ).ReadWMF(); + } + + return rStream.good(); +} + +// ----------------------------------------------------------------------------- + +sal_Bool ConvertGDIMetaFileToWMF( const GDIMetaFile & rMTF, SvStream & rTargetStream, + FilterConfigItem* pConfigItem, sal_Bool bPlaceable) +{ + WMFWriter aWMFWriter; + return aWMFWriter.WriteWMF( rMTF, rTargetStream, pConfigItem, bPlaceable ); +} + +// ----------------------------------------------------------------------------- + +sal_Bool ConvertGDIMetaFileToEMF( const GDIMetaFile & rMTF, SvStream & rTargetStream, + FilterConfigItem* pConfigItem ) +{ + EMFWriter aEMFWriter(rTargetStream); + return aEMFWriter.WriteEMF( rMTF, pConfigItem ); +} + +// ----------------------------------------------------------------------------- + +sal_Bool WriteWindowMetafileBits( SvStream& rStream, const GDIMetaFile& rMTF ) +{ + return WMFWriter().WriteWMF( rMTF, rStream, NULL, sal_False ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/wmfwr.cxx b/vcl/source/filter/wmf/wmfwr.cxx new file mode 100644 index 000000000000..c9baef6b36f5 --- /dev/null +++ b/vcl/source/filter/wmf/wmfwr.cxx @@ -0,0 +1,2052 @@ +/* -*- 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 "wmfwr.hxx" +#include <unotools/fontcvt.hxx> +#include "emfwr.hxx" +#include <rtl/crc.h> +#include <rtl/tencinfo.h> +#include <tools/bigint.hxx> +#include <tools/helpers.hxx> +#include <tools/tenccvt.hxx> +#include <osl/endian.h> +#include <i18nutil/unicode.hxx> //unicode::getUnicodeScriptType + +#include <vcl/metric.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> + +//====================== MS-Windows-defines =============================== + +#define W_META_SETBKCOLOR 0x0201 +#define W_META_SETBKMODE 0x0102 +#define W_META_SETMAPMODE 0x0103 +#define W_META_SETROP2 0x0104 +#define W_META_SETRELABS 0x0105 +#define W_META_SETPOLYFILLMODE 0x0106 +#define W_META_SETSTRETCHBLTMODE 0x0107 +#define W_META_SETTEXTCHAREXTRA 0x0108 +#define W_META_SETTEXTCOLOR 0x0209 +#define W_META_SETTEXTJUSTIFICATION 0x020A +#define W_META_SETWINDOWORG 0x020B +#define W_META_SETWINDOWEXT 0x020C +#define W_META_SETVIEWPORTORG 0x020D +#define W_META_SETVIEWPORTEXT 0x020E +#define W_META_OFFSETWINDOWORG 0x020F +#define W_META_SCALEWINDOWEXT 0x0410 +#define W_META_OFFSETVIEWPORTORG 0x0211 +#define W_META_SCALEVIEWPORTEXT 0x0412 +#define W_META_LINETO 0x0213 +#define W_META_MOVETO 0x0214 +#define W_META_EXCLUDECLIPRECT 0x0415 +#define W_META_INTERSECTCLIPRECT 0x0416 +#define W_META_ARC 0x0817 +#define W_META_ELLIPSE 0x0418 +#define W_META_FLOODFILL 0x0419 +#define W_META_PIE 0x081A +#define W_META_RECTANGLE 0x041B +#define W_META_ROUNDRECT 0x061C +#define W_META_PATBLT 0x061D +#define W_META_SAVEDC 0x001E +#define W_META_SETPIXEL 0x041F +#define W_META_OFFSETCLIPRGN 0x0220 +#define W_META_TEXTOUT 0x0521 +#define W_META_BITBLT 0x0922 +#define W_META_STRETCHBLT 0x0B23 +#define W_META_POLYGON 0x0324 +#define W_META_POLYLINE 0x0325 +#define W_META_ESCAPE 0x0626 +#define W_META_RESTOREDC 0x0127 +#define W_META_FILLREGION 0x0228 +#define W_META_FRAMEREGION 0x0429 +#define W_META_INVERTREGION 0x012A +#define W_META_PAINTREGION 0x012B +#define W_META_SELECTCLIPREGION 0x012C +#define W_META_SELECTOBJECT 0x012D +#define W_META_SETTEXTALIGN 0x012E +#define W_META_DRAWTEXT 0x062F +#define W_META_CHORD 0x0830 +#define W_META_SETMAPPERFLAGS 0x0231 +#define W_META_EXTTEXTOUT 0x0a32 +#define W_META_SETDIBTODEV 0x0d33 +#define W_META_SELECTPALETTE 0x0234 +#define W_META_REALIZEPALETTE 0x0035 +#define W_META_ANIMATEPALETTE 0x0436 +#define W_META_SETPALENTRIES 0x0037 +#define W_META_POLYPOLYGON 0x0538 +#define W_META_RESIZEPALETTE 0x0139 +#define W_META_DIBBITBLT 0x0940 +#define W_META_DIBSTRETCHBLT 0x0b41 +#define W_META_DIBCREATEPATTERNBRUSH 0x0142 +#define W_META_STRETCHDIB 0x0f43 +#define W_META_EXTFLOODFILL 0x0548 +#define W_META_RESETDC 0x014C +#define W_META_STARTDOC 0x014D +#define W_META_STARTPAGE 0x004F +#define W_META_ENDPAGE 0x0050 +#define W_META_ABORTDOC 0x0052 +#define W_META_ENDDOC 0x005E +#define W_META_DELETEOBJECT 0x01f0 +#define W_META_CREATEPALETTE 0x00f7 +#define W_META_CREATEBRUSH 0x00F8 +#define W_META_CREATEPATTERNBRUSH 0x01F9 +#define W_META_CREATEPENINDIRECT 0x02FA +#define W_META_CREATEFONTINDIRECT 0x02FB +#define W_META_CREATEBRUSHINDIRECT 0x02FC +#define W_META_CREATEBITMAPINDIRECT 0x02FD +#define W_META_CREATEBITMAP 0x06FE +#define W_META_CREATEREGION 0x06FF + +#define W_TRANSPARENT 1 +#define W_OPAQUE 2 + +#define W_R2_BLACK 1 +#define W_R2_NOTMERGEPEN 2 +#define W_R2_MASKNOTPEN 3 +#define W_R2_NOTCOPYPEN 4 +#define W_R2_MASKPENNOT 5 +#define W_R2_NOT 6 +#define W_R2_XORPEN 7 +#define W_R2_NOTMASKPEN 8 +#define W_R2_MASKPEN 9 +#define W_R2_NOTXORPEN 10 +#define W_R2_NOP 11 +#define W_R2_MERGENOTPEN 12 +#define W_R2_COPYPEN 13 +#define W_R2_MERGEPENNOT 14 +#define W_R2_MERGEPEN 15 +#define W_R2_WHITE 16 + +#define W_TA_NOUPDATECP 0x0000 +#define W_TA_UPDATECP 0x0001 +#define W_TA_LEFT 0x0000 +#define W_TA_RIGHT 0x0002 +#define W_TA_CENTER 0x0006 +#define W_TA_TOP 0x0000 +#define W_TA_BOTTOM 0x0008 +#define W_TA_BASELINE 0x0018 +#define W_TA_RTLREADING 0x0100 + +#define W_SRCCOPY 0x00CC0020L +#define W_SRCPAINT 0x00EE0086L +#define W_SRCAND 0x008800C6L +#define W_SRCINVERT 0x00660046L +#define W_SRCERASE 0x00440328L +#define W_NOTSRCCOPY 0x00330008L +#define W_NOTSRCERASE 0x001100A6L +#define W_MERGECOPY 0x00C000CAL +#define W_MERGEPAINT 0x00BB0226L +#define W_PATCOPY 0x00F00021L +#define W_PATPAINT 0x00FB0A09L +#define W_PATINVERT 0x005A0049L +#define W_DSTINVERT 0x00550009L +#define W_BLACKNESS 0x00000042L +#define W_WHITENESS 0x00FF0062L + +#define W_PS_SOLID 0 +#define W_PS_DASH 1 +#define W_PS_DOT 2 +#define W_PS_DASHDOT 3 +#define W_PS_DASHDOTDOT 4 +#define W_PS_NULL 5 +#define W_PS_INSIDEFRAME 6 + +#define W_LF_FACESIZE 32 + +#define W_ANSI_CHARSET 0 +#define W_DEFAULT_CHARSET 1 +#define W_SYMBOL_CHARSET 2 +#define W_SHIFTJIS_CHARSET 128 +#define W_HANGEUL_CHARSET 129 +#define W_GB2312_CHARSET 134 +#define W_CHINESEBIG5_CHARSET 136 +#define W_OEM_CHARSET 255 +/*WINVER >= 0x0400*/ +#define W_JOHAB_CHARSET 130 +#define W_HEBREW_CHARSET 177 +#define W_ARABIC_CHARSET 178 +#define W_GREEK_CHARSET 161 +#define W_TURKISH_CHARSET 162 +#define W_VIETNAMESE_CHARSET 163 +#define W_THAI_CHARSET 222 +#define W_EASTEUROPE_CHARSET 238 +#define W_RUSSIAN_CHARSET 204 +#define W_MAC_CHARSET 77 +#define W_BALTIC_CHARSET 186 + +#define W_DEFAULT_PITCH 0x00 +#define W_FIXED_PITCH 0x01 +#define W_VARIABLE_PITCH 0x02 + +#define W_FF_DONTCARE 0x00 +#define W_FF_ROMAN 0x10 +#define W_FF_SWISS 0x20 +#define W_FF_MODERN 0x30 +#define W_FF_SCRIPT 0x40 +#define W_FF_DECORATIVE 0x50 + +#define W_FW_DONTCARE 0 +#define W_FW_THIN 100 +#define W_FW_EXTRALIGHT 200 +#define W_FW_LIGHT 300 +#define W_FW_NORMAL 400 +#define W_FW_MEDIUM 500 +#define W_FW_SEMIBOLD 600 +#define W_FW_BOLD 700 +#define W_FW_EXTRABOLD 800 +#define W_FW_HEAVY 900 +#define W_FW_ULTRALIGHT 200 +#define W_FW_REGULAR 400 +#define W_FW_DEMIBOLD 600 +#define W_FW_ULTRABOLD 800 +#define W_FW_BLACK 900 + +#define W_BS_SOLID 0 +#define W_BS_HOLLOW 1 +#define W_BS_HATCHED 2 +#define W_BS_PATTERN 3 +#define W_BS_INDEXED 4 +#define W_BS_DIBPATTERN 5 + +#define W_HS_HORIZONTAL 0 +#define W_HS_VERTICAL 1 +#define W_HS_FDIAGONAL 2 +#define W_HS_BDIAGONAL 3 +#define W_HS_CROSS 4 +#define W_HS_DIAGCROSS 5 + +#define W_MFCOMMENT 15 + +#define PRIVATE_ESCAPE_UNICODE 2 + +//========================== Methoden von WMFWriter ========================== + +void WMFWriter::MayCallback() +{ + if ( xStatusIndicator.is() ) + { + sal_uLong nPercent; + + // Wir gehen mal einfach so davon aus, dass 16386 Actions einer Bitmap entsprechen + // (in der Regel wird ein Metafile entweder nur Actions oder einige Bitmaps und fast + // keine Actions enthalten. Dann ist das Verhaeltnis ziemlich unwichtig) + + nPercent=((nWrittenBitmaps<<14)+(nActBitmapPercent<<14)/100+nWrittenActions) + *100 + /((nNumberOfBitmaps<<14)+nNumberOfActions); + + if ( nPercent >= nLastPercent + 3 ) + { + nLastPercent = nPercent; + if( nPercent <= 100 ) + xStatusIndicator->setValue( nPercent ); + } + } +} + +void WMFWriter::CountActionsAndBitmaps( const GDIMetaFile & rMTF ) +{ + size_t nAction, nActionCount; + + nActionCount = rMTF.GetActionSize(); + + for ( nAction=0; nAction < nActionCount; nAction++ ) + { + MetaAction* pMA = rMTF.GetAction( nAction ); + + switch( pMA->GetType() ) + { + case META_BMP_ACTION: + case META_BMPSCALE_ACTION: + case META_BMPSCALEPART_ACTION: + case META_BMPEX_ACTION: + case META_BMPEXSCALE_ACTION: + case META_BMPEXSCALEPART_ACTION: + nNumberOfBitmaps++; + break; + } + nNumberOfActions++; + } +} + + +void WMFWriter::WritePointXY(const Point & rPoint) +{ + Point aPt( pVirDev->LogicToLogic(rPoint,aSrcMapMode,aTargetMapMode) ); + *pWMF << ((short)aPt.X()) << ((short)aPt.Y()); +} + + +void WMFWriter::WritePointYX(const Point & rPoint) +{ + Point aPt( pVirDev->LogicToLogic(rPoint,aSrcMapMode,aTargetMapMode) ); + *pWMF << ((short)aPt.Y()) << ((short)aPt.X()); +} + + +sal_Int32 WMFWriter::ScaleWidth( sal_Int32 nDX ) +{ + Size aSz( pVirDev->LogicToLogic(Size(nDX,0),aSrcMapMode,aTargetMapMode) ); + return aSz.Width(); +} + + +void WMFWriter::WriteSize(const Size & rSize) +{ + Size aSz( pVirDev->LogicToLogic(rSize,aSrcMapMode,aTargetMapMode) ); + *pWMF << ((short)aSz.Width()) << ((short)aSz.Height()); +} + + +void WMFWriter::WriteHeightWidth(const Size & rSize) +{ + Size aSz( pVirDev->LogicToLogic(rSize,aSrcMapMode,aTargetMapMode) ); + *pWMF << ((short)aSz.Height()) << ((short)aSz.Width()); +} + + +void WMFWriter::WriteRectangle(const Rectangle & rRect) +{ + WritePointYX(Point(rRect.Right()+1,rRect.Bottom()+1)); + WritePointYX(rRect.TopLeft()); +} + + +void WMFWriter::WriteColor(const Color & rColor) +{ + *pWMF << (sal_uInt8) rColor.GetRed() << (sal_uInt8) rColor.GetGreen() << (sal_uInt8) rColor.GetBlue() << (sal_uInt8) 0; +} + + +void WMFWriter::WriteRecordHeader(sal_uInt32 nSizeWords, sal_uInt16 nType) +{ + nActRecordPos=pWMF->Tell(); + if (nSizeWords>nMaxRecordSize) nMaxRecordSize=nSizeWords; + *pWMF << nSizeWords << nType; +} + + +void WMFWriter::UpdateRecordHeader() +{ + sal_uLong nPos; + sal_uInt32 nSize; + + nPos=pWMF->Tell(); nSize=nPos-nActRecordPos; + if ((nSize & 1)!=0) { + *pWMF << (sal_uInt8)0; + nPos++; nSize++; + } + nSize/=2; + if (nSize>nMaxRecordSize) nMaxRecordSize=nSize; + pWMF->Seek(nActRecordPos); + *pWMF << nSize; + pWMF->Seek(nPos); +} + + +void WMFWriter::WMFRecord_Arc(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt) +{ + WriteRecordHeader(0x0000000b,W_META_ARC); + WritePointYX(rEndPt); + WritePointYX(rStartPt); + WriteRectangle(rRect); +} + +void WMFWriter::WMFRecord_Chord(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt) +{ + WriteRecordHeader(0x0000000b,W_META_CHORD); + WritePointYX(rEndPt); + WritePointYX(rStartPt); + WriteRectangle(rRect); +} + + +void WMFWriter::WMFRecord_CreateBrushIndirect(const Color& rColor) +{ + WriteRecordHeader(0x00000007,W_META_CREATEBRUSHINDIRECT); + + if( rColor==Color(COL_TRANSPARENT) ) + *pWMF << (sal_uInt16) W_BS_HOLLOW; + else + *pWMF << (sal_uInt16) W_BS_SOLID; + + WriteColor( rColor ); + *pWMF << (sal_uInt16) 0; +} + + +void WMFWriter::WMFRecord_CreateFontIndirect(const Font & rFont) +{ + sal_uInt16 nWeight,i; + sal_uInt8 nPitchFamily; + + WriteRecordHeader(0x00000000,W_META_CREATEFONTINDIRECT); + WriteHeightWidth(Size(rFont.GetSize().Width(),-rFont.GetSize().Height())); + *pWMF << (short)rFont.GetOrientation() << (short)rFont.GetOrientation(); + + switch (rFont.GetWeight()) { + case WEIGHT_THIN: nWeight=W_FW_THIN; break; + case WEIGHT_ULTRALIGHT: nWeight=W_FW_ULTRALIGHT; break; + case WEIGHT_LIGHT: nWeight=W_FW_LIGHT; break; + case WEIGHT_SEMILIGHT: nWeight=W_FW_LIGHT; break; + case WEIGHT_NORMAL: nWeight=W_FW_NORMAL; break; + case WEIGHT_MEDIUM: nWeight=W_FW_MEDIUM; break; + case WEIGHT_SEMIBOLD: nWeight=W_FW_SEMIBOLD; break; + case WEIGHT_BOLD: nWeight=W_FW_BOLD; break; + case WEIGHT_ULTRABOLD: nWeight=W_FW_ULTRABOLD; break; + case WEIGHT_BLACK: nWeight=W_FW_BLACK; break; + default: nWeight=W_FW_DONTCARE; + } + *pWMF << nWeight; + + if (rFont.GetItalic()==ITALIC_NONE) *pWMF << (sal_uInt8)0; else *pWMF << (sal_uInt8)1; + if (rFont.GetUnderline()==UNDERLINE_NONE) *pWMF << (sal_uInt8)0; else *pWMF << (sal_uInt8)1; + if (rFont.GetStrikeout()==STRIKEOUT_NONE) *pWMF << (sal_uInt8)0; else *pWMF << (sal_uInt8)1; + + CharSet eFontNameEncoding = rFont.GetCharSet(); + sal_uInt8 nCharSet = rtl_getBestWindowsCharsetFromTextEncoding( eFontNameEncoding ); + if ( eFontNameEncoding == RTL_TEXTENCODING_SYMBOL ) + eFontNameEncoding = RTL_TEXTENCODING_MS_1252; + if ( nCharSet == 1 ) + nCharSet = W_ANSI_CHARSET; + *pWMF << nCharSet; + + *pWMF << (sal_uInt8)0 << (sal_uInt8)0 << (sal_uInt8)0; + + switch (rFont.GetPitch()) { + case PITCH_FIXED: nPitchFamily=W_FIXED_PITCH; break; + case PITCH_VARIABLE: nPitchFamily=W_VARIABLE_PITCH; break; + default: nPitchFamily=W_DEFAULT_PITCH; + } + switch (rFont.GetFamily()) { + case FAMILY_DECORATIVE: nPitchFamily|=W_FF_DECORATIVE; break; + case FAMILY_MODERN: nPitchFamily|=W_FF_MODERN; break; + case FAMILY_ROMAN: nPitchFamily|=W_FF_ROMAN; break; + case FAMILY_SCRIPT: nPitchFamily|=W_FF_SCRIPT; break; + case FAMILY_SWISS: nPitchFamily|=W_FF_SWISS; break; + default: nPitchFamily|=W_FF_DONTCARE; + } + *pWMF << nPitchFamily; + + rtl::OString aFontName(rtl::OUStringToOString(rFont.GetName(), eFontNameEncoding)); + for ( i = 0; i < W_LF_FACESIZE; i++ ) + { + sal_Char nChar = ( i < aFontName.getLength() ) ? aFontName[i] : 0; + *pWMF << nChar; + } + UpdateRecordHeader(); +} + +void WMFWriter::WMFRecord_CreatePenIndirect(const Color& rColor, const LineInfo& rLineInfo ) +{ + WriteRecordHeader(0x00000008,W_META_CREATEPENINDIRECT); + sal_uInt16 nStyle = rColor == Color( COL_TRANSPARENT ) ? W_PS_NULL : W_PS_SOLID; + switch( rLineInfo.GetStyle() ) + { + case LINE_DASH : + { + if ( rLineInfo.GetDotCount() ) + { + if ( !rLineInfo.GetDashCount() ) + nStyle = W_PS_DOT; + else + { + if ( !rLineInfo.GetDotCount() == 1 ) + nStyle = W_PS_DASHDOT; + else + nStyle = W_PS_DASHDOTDOT; + } + } + else + nStyle = W_PS_DASH; + } + break; + case LINE_NONE : + nStyle = W_PS_NULL; + break; + default: + break; + } + *pWMF << nStyle; + + WriteSize( Size( rLineInfo.GetWidth(), 0 ) ); + WriteColor( rColor ); +} + +void WMFWriter::WMFRecord_DeleteObject(sal_uInt16 nObjectHandle) +{ + WriteRecordHeader(0x00000004,W_META_DELETEOBJECT); + *pWMF << nObjectHandle; +} + + +void WMFWriter::WMFRecord_Ellipse(const Rectangle & rRect) +{ + WriteRecordHeader(0x00000007,W_META_ELLIPSE); + WriteRectangle(rRect); +} + +bool IsStarSymbol(const String &rStr) +{ + return rStr.EqualsIgnoreCaseAscii("starsymbol") || + rStr.EqualsIgnoreCaseAscii("opensymbol"); +} + +void WMFWriter::WMFRecord_Escape( sal_uInt32 nEsc, sal_uInt32 nLen, const sal_Int8* pData ) +{ +#ifdef OSL_BIGENDIAN + sal_uInt32 nTmp = OSL_SWAPDWORD( nEsc ); + sal_uInt32 nCheckSum = rtl_crc32( 0, &nTmp, 4 ); +#else + sal_uInt32 nCheckSum = rtl_crc32( 0, &nEsc, 4 ); +#endif + if ( nLen ) + nCheckSum = rtl_crc32( nCheckSum, pData, nLen ); + + WriteRecordHeader( 3 + 9 + ( ( nLen + 1 ) >> 1 ), W_META_ESCAPE ); + *pWMF << (sal_uInt16)W_MFCOMMENT + << (sal_uInt16)( nLen + 14 ) // we will always have a fourteen byte escape header: + << (sal_uInt16)0x4f4f // OO + << (sal_uInt32)0xa2c2a // evil magic number + << (sal_uInt32)nCheckSum // crc32 checksum about nEsc & pData + << (sal_uInt32)nEsc; // escape number + pWMF->Write( pData, nLen ); + if ( nLen & 1 ) + *pWMF << (sal_uInt8)0; // pad byte +} + +/* if return value is true, then a complete unicode string and also a polygon replacement has been written, + so there is no more action necessary +*/ +sal_Bool WMFWriter::WMFRecord_Escape_Unicode( const Point& rPoint, const String& rUniStr, const sal_Int32* pDXAry ) +{ + sal_Bool bEscapeUsed = sal_False; + + sal_uInt32 i, nStringLen = rUniStr.Len(); + if ( nStringLen ) + { + // first we will check if a comment is necessary + if ( aSrcFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL ) // symbol is always byte character, so there is no unicode loss + { + const sal_Unicode* pBuf = rUniStr.GetBuffer(); + const rtl_TextEncoding aTextEncodingOrg = aSrcFont.GetCharSet(); + rtl::OString aByteStr(rtl::OUStringToOString(rUniStr, aTextEncodingOrg)); + rtl::OUString aUniStr2(rtl::OStringToOUString(aByteStr, aTextEncodingOrg)); + const sal_Unicode* pConversion = aUniStr2.getStr(); // this is the unicode array after bytestring <-> unistring conversion + for ( i = 0; i < nStringLen; i++ ) + { + if ( *pBuf++ != *pConversion++ ) + break; + } + + if ( i != nStringLen ) // after conversion the characters are not original, + { // try again, with determining a better charset from unicode char + pBuf = rUniStr.GetBuffer(); + const sal_Unicode* pCheckChar = pBuf; + rtl_TextEncoding aTextEncoding = getBestMSEncodingByChar(*pCheckChar); // try the first character + for ( i = 1; i < nStringLen; i++) + { + if (aTextEncoding != aTextEncodingOrg) // found something + break; + pCheckChar++; + aTextEncoding = getBestMSEncodingByChar(*pCheckChar); // try the next character + } + + aByteStr = rtl::OUStringToOString(rUniStr, aTextEncoding); + aUniStr2 = rtl::OStringToOUString(aByteStr, aTextEncoding); + pConversion = aUniStr2.getStr(); // this is the unicode array after bytestring <-> unistring conversion + for ( i = 0; i < nStringLen; i++ ) + { + if ( *pBuf++ != *pConversion++ ) + break; + } + if (i == nStringLen) + { + aSrcFont.SetCharSet (aTextEncoding); + SetAllAttr(); + } + } + + if ( ( i != nStringLen ) || IsStarSymbol( aSrcFont.GetName() ) ) // after conversion the characters are not original, so we + { // will store the unicode string and a polypoly replacement + Color aOldFillColor( aSrcFillColor ); + Color aOldLineColor( aSrcLineColor ); + aSrcLineInfo = LineInfo(); + aSrcFillColor = aSrcTextColor; + aSrcLineColor = Color( COL_TRANSPARENT ); + SetLineAndFillAttr(); + pVirDev->SetFont( aSrcFont ); + std::vector<PolyPolygon> aPolyPolyVec; + if ( pVirDev->GetTextOutlines( aPolyPolyVec, rUniStr ) ) + { + sal_uInt32 nDXCount = pDXAry ? nStringLen : 0; + sal_uInt32 nSkipActions = aPolyPolyVec.size(); + sal_Int32 nStrmLen = 8 + + + sizeof( nStringLen ) + ( nStringLen * 2 ) + + sizeof( nDXCount ) + ( nDXCount * 4 ) + + sizeof( nSkipActions ); + + SvMemoryStream aMemoryStream( nStrmLen ); + Point aPt( pVirDev->LogicToLogic( rPoint, aSrcMapMode, aTargetMapMode ) ); + aMemoryStream << static_cast<sal_Int32>(aPt.X()) + << static_cast<sal_Int32>(aPt.Y()) + << nStringLen; + for ( i = 0; i < nStringLen; i++ ) + aMemoryStream << rUniStr.GetChar( (sal_uInt16)i ); + aMemoryStream << nDXCount; + for ( i = 0; i < nDXCount; i++ ) + aMemoryStream << pDXAry[ i ]; + aMemoryStream << nSkipActions; + WMFRecord_Escape( PRIVATE_ESCAPE_UNICODE, nStrmLen, (const sal_Int8*)aMemoryStream.GetData() ); + + std::vector<PolyPolygon>::iterator aIter( aPolyPolyVec.begin() ); + while ( aIter != aPolyPolyVec.end() ) + { + PolyPolygon aPolyPoly( *aIter++ ); + aPolyPoly.Move( rPoint.X(), rPoint.Y() ); + WMFRecord_PolyPolygon( aPolyPoly ); + } + aSrcFillColor = aOldFillColor; + aSrcLineColor = aOldLineColor; + bEscapeUsed = sal_True; + } + } + } + } + return bEscapeUsed; +} + +void WMFWriter::WMFRecord_ExtTextOut( const Point & rPoint, + const String & rString, const sal_Int32 * pDXAry ) +{ + sal_uInt16 nOriginalTextLen = rString.Len(); + + if ( (nOriginalTextLen <= 1) || (pDXAry == NULL) ) + { + WMFRecord_TextOut(rPoint, rString); + return; + } + rtl_TextEncoding eChrSet = aSrcFont.GetCharSet(); + rtl::OString aByteString(rtl::OUStringToOString(rString, eChrSet)); + TrueExtTextOut(rPoint,rString,aByteString,pDXAry); +} + +void WMFWriter::TrueExtTextOut( const Point & rPoint, const String & rString, + const rtl::OString& rByteString, const sal_Int32 * pDXAry ) +{ + WriteRecordHeader( 0, W_META_EXTTEXTOUT ); + WritePointYX( rPoint ); + sal_uInt16 nNewTextLen = static_cast<sal_uInt16>(rByteString.getLength()); + *pWMF << nNewTextLen << (sal_uInt16)0; + write_uInt8s_FromOString(*pWMF, rByteString, nNewTextLen); + if ( nNewTextLen & 1 ) + *pWMF << (sal_uInt8)0; + + sal_uInt16 nOriginalTextLen = rString.Len(); + sal_Int16* pConvertedDXAry = new sal_Int16[ nOriginalTextLen ]; + sal_Int32 j = 0; + pConvertedDXAry[ j++ ] = (sal_Int16)ScaleWidth( pDXAry[ 0 ] ); + for (sal_uInt16 i = 1; i < ( nOriginalTextLen - 1 ); ++i) + pConvertedDXAry[ j++ ] = (sal_Int16)ScaleWidth( pDXAry[ i ] - pDXAry[ i - 1 ] ); + pConvertedDXAry[ j ] = (sal_Int16)ScaleWidth( pDXAry[ nOriginalTextLen - 2 ] / ( nOriginalTextLen - 1 ) ); + + for (sal_uInt16 i = 0; i < nOriginalTextLen; ++i) + { + sal_Int16 nDx = pConvertedDXAry[ i ]; + *pWMF << nDx; + if ( nOriginalTextLen < nNewTextLen ) + { + sal_Unicode nUniChar = rString.GetChar(i); + rtl::OString aTemp(&nUniChar, 1, aSrcFont.GetCharSet()); + j = aTemp.getLength(); + while ( --j > 0 ) + *pWMF << (sal_uInt16)0; + } + } + delete[] pConvertedDXAry; + UpdateRecordHeader(); +} + +void WMFWriter::WMFRecord_LineTo(const Point & rPoint) +{ + WriteRecordHeader(0x00000005,W_META_LINETO); + WritePointYX(rPoint); +} + + +void WMFWriter::WMFRecord_MoveTo(const Point & rPoint) +{ + WriteRecordHeader(0x00000005,W_META_MOVETO); + WritePointYX(rPoint); +} + + +void WMFWriter::WMFRecord_Pie(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt) +{ + WriteRecordHeader(0x0000000b,W_META_PIE); + WritePointYX(rEndPt); + WritePointYX(rStartPt); + WriteRectangle(rRect); +} + + +void WMFWriter::WMFRecord_Polygon(const Polygon & rPoly) +{ + sal_uInt16 nSize,i; + + Polygon aSimplePoly; + if ( rPoly.HasFlags() ) + rPoly.AdaptiveSubdivide( aSimplePoly ); + else + aSimplePoly = rPoly; + nSize = aSimplePoly.GetSize(); + WriteRecordHeader(((sal_uLong)nSize)*2+4,W_META_POLYGON); + *pWMF << nSize; + for (i=0; i<nSize; i++) WritePointXY(aSimplePoly.GetPoint(i)); +} + + +void WMFWriter::WMFRecord_PolyLine(const Polygon & rPoly) +{ + sal_uInt16 nSize,i; + Polygon aSimplePoly; + if ( rPoly.HasFlags() ) + rPoly.AdaptiveSubdivide( aSimplePoly ); + else + aSimplePoly = rPoly; + nSize=aSimplePoly.GetSize(); + WriteRecordHeader(((sal_uLong)nSize)*2+4,W_META_POLYLINE); + *pWMF << nSize; + for (i=0; i<nSize; i++) WritePointXY(aSimplePoly.GetPoint(i)); +} + + +void WMFWriter::WMFRecord_PolyPolygon(const PolyPolygon & rPolyPoly) +{ + const Polygon * pPoly; + sal_uInt16 nCount,nSize,i,j; + + nCount=rPolyPoly.Count(); + PolyPolygon aSimplePolyPoly( rPolyPoly ); + for ( i = 0; i < nCount; i++ ) + { + if ( aSimplePolyPoly[ i ].HasFlags() ) + { + Polygon aSimplePoly; + aSimplePolyPoly[ i ].AdaptiveSubdivide( aSimplePoly ); + aSimplePolyPoly[ i ] = aSimplePoly; + } + } + WriteRecordHeader(0,W_META_POLYPOLYGON); + *pWMF << nCount; + for (i=0; i<nCount; i++) *pWMF << ((sal_uInt16)(aSimplePolyPoly.GetObject(i).GetSize())); + for (i=0; i<nCount; i++) { + pPoly=&(aSimplePolyPoly.GetObject(i)); + nSize=pPoly->GetSize(); + for (j=0; j<nSize; j++) WritePointXY(pPoly->GetPoint(j)); + } + UpdateRecordHeader(); +} + + +void WMFWriter::WMFRecord_Rectangle(const Rectangle & rRect) +{ + WriteRecordHeader( 0x00000007,W_META_RECTANGLE ); + WriteRectangle( rRect ); +} + + +void WMFWriter::WMFRecord_RestoreDC() +{ + WriteRecordHeader(0x00000004,W_META_RESTOREDC); + *pWMF << (short)-1; +} + + +void WMFWriter::WMFRecord_RoundRect(const Rectangle & rRect, long nHorzRound, long nVertRound) +{ + WriteRecordHeader(0x00000009,W_META_ROUNDRECT); + WriteHeightWidth(Size(nHorzRound,nVertRound)); + WriteRectangle(rRect); +} + + +void WMFWriter::WMFRecord_SaveDC() +{ + WriteRecordHeader(0x00000003,W_META_SAVEDC); +} + + +void WMFWriter::WMFRecord_SelectObject(sal_uInt16 nObjectHandle) +{ + WriteRecordHeader(0x00000004,W_META_SELECTOBJECT); + *pWMF << nObjectHandle; +} + + +void WMFWriter::WMFRecord_SetBkMode(sal_Bool bTransparent) +{ + WriteRecordHeader(0x00000004,W_META_SETBKMODE); + if (bTransparent==sal_True) *pWMF << (sal_uInt16)W_TRANSPARENT; + else *pWMF << (sal_uInt16)W_OPAQUE; +} + +void WMFWriter::WMFRecord_SetStretchBltMode() +{ + WriteRecordHeader( 0x00000004, W_META_SETSTRETCHBLTMODE ); + *pWMF << (sal_uInt16) 3; // STRETCH_DELETESCANS +} + +void WMFWriter::WMFRecord_SetPixel(const Point & rPoint, const Color & rColor) +{ + WriteRecordHeader(0x00000007,W_META_SETPIXEL); + WriteColor(rColor); + WritePointYX(rPoint); +} + + +void WMFWriter::WMFRecord_SetROP2(RasterOp eROP) +{ + sal_uInt16 nROP2; + + switch (eROP) { + case ROP_INVERT: nROP2=W_R2_NOT; break; + case ROP_XOR: nROP2=W_R2_XORPEN; break; + default: nROP2=W_R2_COPYPEN; + } + WriteRecordHeader(0x00000004,W_META_SETROP2); + *pWMF << nROP2; +} + + +void WMFWriter::WMFRecord_SetTextAlign(FontAlign eFontAlign, sal_uInt32 eHorTextAlign) +{ + sal_uInt16 nAlign; + + switch (eFontAlign) { + case ALIGN_TOP: nAlign=W_TA_TOP; break; + case ALIGN_BOTTOM: nAlign=W_TA_BOTTOM; break; + default: nAlign=W_TA_BASELINE; + } + nAlign|=eHorTextAlign; + nAlign|=W_TA_NOUPDATECP; + + WriteRecordHeader(0x00000004,W_META_SETTEXTALIGN); + *pWMF << nAlign; +} + + +void WMFWriter::WMFRecord_SetTextColor(const Color & rColor) +{ + WriteRecordHeader(0x00000005,W_META_SETTEXTCOLOR); + WriteColor(rColor); +} + + +void WMFWriter::WMFRecord_SetWindowExt(const Size & rSize) +{ + WriteRecordHeader(0x00000005,W_META_SETWINDOWEXT); + WriteHeightWidth(rSize); +} + + +void WMFWriter::WMFRecord_SetWindowOrg(const Point & rPoint) +{ + WriteRecordHeader(0x00000005,W_META_SETWINDOWORG); + WritePointYX(rPoint); +} + + +void WMFWriter::WMFRecord_StretchDIB( const Point & rPoint, const Size & rSize, + const Bitmap & rBitmap, sal_uInt32 nROP ) +{ + sal_uLong nPosAnf,nPosEnd; + + nActBitmapPercent=50; + MayCallback(); + + WriteRecordHeader(0x00000000,W_META_STRETCHDIB); + + // Die Reihenfolge im Metafile soll jetzt sein: + // einige Parameter (laenge 22), dann die Bitmap ohne FILEHEADER. + // Da aber *pWMF << rBitmap einen FILEHEADER der Laenge 14 + // erzeugt, schreiben wir zuerst die Bitmap an die richtige Position + // Und ueberschreiben hinterher den FILEHEADER mit den Parametern. + nPosAnf=pWMF->Tell(); // Position merken, wo Parameter hin sollen + *pWMF << (sal_Int32)0 << (sal_Int32)0; // 8 bytes auffuellen (diese 8 bytes + + // 14 bytes ueberfluessigen FILEHEADER + // = 22 bytes Parameter) + *pWMF << rBitmap; // Bitmap schreiben + + // Parameter schreiben: + nPosEnd=pWMF->Tell(); + pWMF->Seek(nPosAnf); + + // Raster-Op bestimmen, falls nichts uebergeben wurde + if( !nROP ) + { + switch( eSrcRasterOp ) + { + case ROP_INVERT: nROP = W_DSTINVERT; break; + case ROP_XOR: nROP = W_SRCINVERT; break; + default: nROP = W_SRCCOPY; + } + } + + *pWMF << nROP << + (short) 0 << + (short) rBitmap.GetSizePixel().Height() << + (short) rBitmap.GetSizePixel().Width() << + (short) 0 << + (short) 0; + + WriteHeightWidth(rSize); + WritePointYX(rPoint); + pWMF->Seek(nPosEnd); + + UpdateRecordHeader(); + + nWrittenBitmaps++; + nActBitmapPercent=0; +} + + +void WMFWriter::WMFRecord_TextOut(const Point & rPoint, const String & rStr) +{ + rtl_TextEncoding eChrSet = aSrcFont.GetCharSet(); + rtl::OString aString(rtl::OUStringToOString(rStr, eChrSet)); + TrueTextOut(rPoint, aString); +} + +void WMFWriter::TrueTextOut(const Point & rPoint, const rtl::OString& rString) +{ + WriteRecordHeader(0,W_META_TEXTOUT); + + write_lenPrefixed_uInt8s_FromOString<sal_uInt16>(*pWMF, rString); + sal_Int32 nLen = rString.getLength(); + if ((nLen&1)!=0) *pWMF << (sal_uInt8)0; + WritePointYX(rPoint); + UpdateRecordHeader(); +} + +void WMFWriter::WMFRecord_EndOfFile() +{ + WriteRecordHeader(0x00000003,0x0000); +} + + +void WMFWriter::WMFRecord_IntersectClipRect( const Rectangle& rRect ) +{ + WriteRecordHeader( 0x00000007, W_META_INTERSECTCLIPRECT ); + WriteRectangle(rRect); +} + + +sal_uInt16 WMFWriter::AllocHandle() +{ + sal_uInt16 i; + + for (i=0; i<MAXOBJECTHANDLES; i++) { + if (bHandleAllocated[i]==sal_False) { + bHandleAllocated[i]=sal_True; + return i; + } + } + bStatus=sal_False; + return 0xffff; +} + + +void WMFWriter::FreeHandle(sal_uInt16 nObjectHandle) +{ + if (nObjectHandle<MAXOBJECTHANDLES) bHandleAllocated[nObjectHandle]=sal_False; +} + + +void WMFWriter::CreateSelectDeletePen( const Color& rColor, const LineInfo& rLineInfo ) +{ + sal_uInt16 nOldHandle; + + nOldHandle=nDstPenHandle; + nDstPenHandle=AllocHandle(); + WMFRecord_CreatePenIndirect( rColor, rLineInfo ); + WMFRecord_SelectObject(nDstPenHandle); + if (nOldHandle<MAXOBJECTHANDLES) { + WMFRecord_DeleteObject(nOldHandle); + FreeHandle(nOldHandle); + } +} + + +void WMFWriter::CreateSelectDeleteFont(const Font & rFont) +{ + sal_uInt16 nOldHandle; + + nOldHandle=nDstFontHandle; + nDstFontHandle=AllocHandle(); + WMFRecord_CreateFontIndirect(rFont); + WMFRecord_SelectObject(nDstFontHandle); + if (nOldHandle<MAXOBJECTHANDLES) { + WMFRecord_DeleteObject(nOldHandle); + FreeHandle(nOldHandle); + } +} + + +void WMFWriter::CreateSelectDeleteBrush(const Color& rColor) +{ + sal_uInt16 nOldHandle; + + nOldHandle=nDstBrushHandle; + nDstBrushHandle=AllocHandle(); + WMFRecord_CreateBrushIndirect(rColor); + WMFRecord_SelectObject(nDstBrushHandle); + if (nOldHandle<MAXOBJECTHANDLES) { + WMFRecord_DeleteObject(nOldHandle); + FreeHandle(nOldHandle); + } +} + + +void WMFWriter::SetLineAndFillAttr() +{ + if ( eDstROP2 != eSrcRasterOp ) + { + eDstROP2=eSrcRasterOp; + WMFRecord_SetROP2(eDstROP2); + } + if ( ( aDstLineColor != aSrcLineColor ) || ( aDstLineInfo != aSrcLineInfo ) ) + { + aDstLineColor = aSrcLineColor; + aDstLineInfo = aSrcLineInfo; + CreateSelectDeletePen( aDstLineColor, aDstLineInfo ); + } + if ( aDstFillColor != aSrcFillColor ) + { + aDstFillColor = aSrcFillColor; + CreateSelectDeleteBrush( aDstFillColor ); + } + if ( bDstIsClipping != bSrcIsClipping || + (bSrcIsClipping==sal_True && aDstClipRegion!=aSrcClipRegion)) { + bDstIsClipping=bSrcIsClipping; + aDstClipRegion=aSrcClipRegion; + } +} + +void WMFWriter::SetAllAttr() +{ + SetLineAndFillAttr(); + if ( aDstTextColor != aSrcTextColor ) + { + aDstTextColor = aSrcTextColor; + WMFRecord_SetTextColor(aDstTextColor); + } + if ( eDstTextAlign != eSrcTextAlign || eDstHorTextAlign != eSrcHorTextAlign ) + { + eDstTextAlign = eSrcTextAlign; + eDstHorTextAlign = eSrcHorTextAlign; + WMFRecord_SetTextAlign( eDstTextAlign, eDstHorTextAlign ); + } + if ( aDstFont != aSrcFont ) + { + pVirDev->SetFont(aSrcFont); + if ( aDstFont.GetName() != aSrcFont.GetName() ) + { + FontCharMap aFontCharMap; + if ( pVirDev->GetFontCharMap( aFontCharMap ) ) + { + if ( ( aFontCharMap.GetFirstChar() & 0xff00 ) == 0xf000 ) + aSrcFont.SetCharSet( RTL_TEXTENCODING_SYMBOL ); + else if ( aSrcFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL ) + aSrcFont.SetCharSet( RTL_TEXTENCODING_MS_1252 ); + } + } + aDstFont = aSrcFont; + CreateSelectDeleteFont(aDstFont); + } +} + + +void WMFWriter::HandleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon) +{ + if(rLinePolygon.count()) + { + basegfx::B2DPolyPolygon aLinePolyPolygon(rLinePolygon); + basegfx::B2DPolyPolygon aFillPolyPolygon; + + rInfo.applyToB2DPolyPolygon(aLinePolyPolygon, aFillPolyPolygon); + + if(aLinePolyPolygon.count()) + { + aSrcLineInfo = rInfo; + SetLineAndFillAttr(); + + for(sal_uInt32 a(0); a < aLinePolyPolygon.count(); a++) + { + const basegfx::B2DPolygon aCandidate(aLinePolyPolygon.getB2DPolygon(a)); + WMFRecord_PolyLine(Polygon(aCandidate)); + } + } + + if(aFillPolyPolygon.count()) + { + const Color aOldLineColor(aSrcLineColor); + const Color aOldFillColor(aSrcFillColor); + + aSrcLineColor = Color( COL_TRANSPARENT ); + aSrcFillColor = aOldLineColor; + SetLineAndFillAttr(); + + for(sal_uInt32 a(0); a < aFillPolyPolygon.count(); a++) + { + const Polygon aPolygon(aFillPolyPolygon.getB2DPolygon(a)); + WMFRecord_Polygon(Polygon(aPolygon)); + } + + aSrcLineColor = aOldLineColor; + aSrcFillColor = aOldFillColor; + SetLineAndFillAttr(); + } + } +} + +void WMFWriter::WriteRecords( const GDIMetaFile & rMTF ) +{ + MetaAction* pMA; + + if( bStatus ) + { + size_t nACount = rMTF.GetActionSize(); + + WMFRecord_SetStretchBltMode(); + + for( size_t nA = 0; nA < nACount; nA++ ) + { + pMA = rMTF.GetAction( nA ); + + switch( pMA->GetType() ) + { + case META_PIXEL_ACTION: + { + const MetaPixelAction* pA = (const MetaPixelAction *) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_SetPixel( pA->GetPoint(), pA->GetColor() ); + } + break; + + case META_POINT_ACTION: + { + const MetaPointAction* pA = (const MetaPointAction*) pMA; + const Point& rPt = pA->GetPoint(); + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_MoveTo( rPt); + WMFRecord_LineTo( rPt ); + } + break; + + case META_LINE_ACTION: + { + const MetaLineAction* pA = (const MetaLineAction *) pMA; + if(pA->GetLineInfo().IsDefault()) + { + aSrcLineInfo = pA->GetLineInfo(); + SetLineAndFillAttr(); + WMFRecord_MoveTo( pA->GetStartPoint() ); + WMFRecord_LineTo( pA->GetEndPoint() ); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + basegfx::B2DPolygon aPolygon; + aPolygon.append(basegfx::B2DPoint(pA->GetStartPoint().X(), pA->GetStartPoint().Y())); + aPolygon.append(basegfx::B2DPoint(pA->GetEndPoint().X(), pA->GetEndPoint().Y())); + HandleLineInfoPolyPolygons(pA->GetLineInfo(), aPolygon); + } + } + break; + + case META_RECT_ACTION: + { + const MetaRectAction* pA = (const MetaRectAction*) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_Rectangle( pA->GetRect() ); + } + break; + + case META_ROUNDRECT_ACTION: + { + const MetaRoundRectAction* pA = (const MetaRoundRectAction*) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_RoundRect( pA->GetRect(), pA->GetHorzRound(), pA->GetVertRound() ); + } + break; + + case META_ELLIPSE_ACTION: + { + const MetaEllipseAction* pA = (const MetaEllipseAction*) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_Ellipse( pA->GetRect() ); + } + break; + + case META_ARC_ACTION: + { + const MetaArcAction* pA = (const MetaArcAction*) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_Arc( pA->GetRect(),pA->GetStartPoint(),pA->GetEndPoint() ); + } + break; + + case META_PIE_ACTION: + { + const MetaPieAction* pA = (const MetaPieAction*) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_Pie( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() ); + } + break; + + + case META_CHORD_ACTION: + { + const MetaChordAction* pA = (const MetaChordAction*) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_Chord( pA->GetRect(), pA->GetStartPoint(), pA->GetEndPoint() ); + } + break; + + case META_POLYLINE_ACTION: + { + const MetaPolyLineAction* pA = (const MetaPolyLineAction*) pMA; + const Polygon& rPoly = pA->GetPolygon(); + + if( rPoly.GetSize() ) + { + if(pA->GetLineInfo().IsDefault()) + { + aSrcLineInfo = pA->GetLineInfo(); + SetLineAndFillAttr(); + WMFRecord_PolyLine( rPoly ); + } + else + { + // LineInfo used; handle Dash/Dot and fat lines + HandleLineInfoPolyPolygons(pA->GetLineInfo(), rPoly.getB2DPolygon()); + } + } + } + break; + + case META_POLYGON_ACTION: + { + const MetaPolygonAction* pA = (const MetaPolygonAction*) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_Polygon( pA->GetPolygon() ); + } + break; + + case META_POLYPOLYGON_ACTION: + { + const MetaPolyPolygonAction* pA = (const MetaPolyPolygonAction*) pMA; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_PolyPolygon( pA->GetPolyPolygon() ); + } + break; + + case META_TEXTRECT_ACTION: + { + const MetaTextRectAction * pA = (const MetaTextRectAction*)pMA; + String aTemp( pA->GetText() ); + aSrcLineInfo = LineInfo(); + SetAllAttr(); + + Point aPos( pA->GetRect().TopLeft() ); + if ( !WMFRecord_Escape_Unicode( aPos, aTemp, NULL ) ) + WMFRecord_TextOut( aPos, aTemp ); + } + break; + + case META_TEXT_ACTION: + { + const MetaTextAction * pA = (const MetaTextAction*) pMA; + String aTemp( pA->GetText(), pA->GetIndex(), pA->GetLen() ); + aSrcLineInfo = LineInfo(); + SetAllAttr(); + if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, NULL ) ) + WMFRecord_TextOut( pA->GetPoint(), aTemp ); + } + break; + + case META_TEXTARRAY_ACTION: + { + const MetaTextArrayAction* pA = (const MetaTextArrayAction*) pMA; + + String aTemp( pA->GetText(), pA->GetIndex(), pA->GetLen() ); + aSrcLineInfo = LineInfo(); + SetAllAttr(); + if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, pA->GetDXArray() ) ) + WMFRecord_ExtTextOut( pA->GetPoint(), aTemp, pA->GetDXArray() ); + } + break; + + case META_STRETCHTEXT_ACTION: + { + const MetaStretchTextAction* pA = (const MetaStretchTextAction *) pMA; + String aTemp( pA->GetText(), pA->GetIndex(), pA->GetLen() ); + + sal_uInt16 nLen,i; + sal_Int32 nNormSize; + + pVirDev->SetFont( aSrcFont ); + nLen = aTemp.Len(); + sal_Int32* pDXAry = nLen ? new sal_Int32[ nLen ] : NULL; + nNormSize = pVirDev->GetTextArray( aTemp, pDXAry ); + for ( i = 0; i < ( nLen - 1 ); i++ ) + pDXAry[ i ] = pDXAry[ i ] * (sal_Int32)pA->GetWidth() / nNormSize; + if ( ( nLen <= 1 ) || ( (sal_Int32)pA->GetWidth() == nNormSize ) ) + delete[] pDXAry, pDXAry = NULL; + aSrcLineInfo = LineInfo(); + SetAllAttr(); + if ( !WMFRecord_Escape_Unicode( pA->GetPoint(), aTemp, pDXAry ) ) + WMFRecord_ExtTextOut( pA->GetPoint(), aTemp, pDXAry ); + delete[] pDXAry; + } + break; + + case META_BMP_ACTION: + { + const MetaBmpAction* pA = (const MetaBmpAction *) pMA; + WMFRecord_StretchDIB( pA->GetPoint(), pA->GetBitmap().GetSizePixel(), pA->GetBitmap() ); + } + break; + + case META_BMPSCALE_ACTION: + { + const MetaBmpScaleAction* pA = (const MetaBmpScaleAction*) pMA; + WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), pA->GetBitmap() ); + } + break; + + case META_BMPSCALEPART_ACTION: + { + const MetaBmpScalePartAction* pA = (const MetaBmpScalePartAction*) pMA; + Bitmap aTmp( pA->GetBitmap() ); + + if( aTmp.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ) ) + WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aTmp ); + } + break; + + case META_BMPEX_ACTION: + { + const MetaBmpExAction* pA = (const MetaBmpExAction *) pMA; + Bitmap aBmp( pA->GetBitmapEx().GetBitmap() ); + Bitmap aMsk( pA->GetBitmapEx().GetMask() ); + + if( !!aMsk ) + { + aBmp.Replace( aMsk, COL_WHITE ); + aMsk.Invert(); + WMFRecord_StretchDIB( pA->GetPoint(), aMsk.GetSizePixel(), aBmp, W_SRCPAINT ); + WMFRecord_StretchDIB( pA->GetPoint(), aBmp.GetSizePixel(), aBmp, W_SRCAND ); + } + else + WMFRecord_StretchDIB( pA->GetPoint(), aBmp.GetSizePixel(), aBmp ); + } + break; + + case META_BMPEXSCALE_ACTION: + { + const MetaBmpExScaleAction* pA = (const MetaBmpExScaleAction*) pMA; + Bitmap aBmp( pA->GetBitmapEx().GetBitmap() ); + Bitmap aMsk( pA->GetBitmapEx().GetMask() ); + + if( !!aMsk ) + { + aBmp.Replace( aMsk, COL_WHITE ); + aMsk.Invert(); + WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aMsk, W_SRCPAINT ); + WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aBmp, W_SRCAND ); + } + else + WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), aBmp ); + } + break; + + case META_BMPEXSCALEPART_ACTION: + { + const MetaBmpExScalePartAction* pA = (const MetaBmpExScalePartAction*) pMA; + BitmapEx aBmpEx( pA->GetBitmapEx() ); + aBmpEx.Crop( Rectangle( pA->GetSrcPoint(), pA->GetSrcSize() ) ); + Bitmap aBmp( aBmpEx.GetBitmap() ); + Bitmap aMsk( aBmpEx.GetMask() ); + + if( !!aMsk ) + { + aBmp.Replace( aMsk, COL_WHITE ); + aMsk.Invert(); + WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aMsk, W_SRCPAINT ); + WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aBmp, W_SRCAND ); + } + else + WMFRecord_StretchDIB( pA->GetDestPoint(), pA->GetDestSize(), aBmp ); + } + break; + + case META_GRADIENT_ACTION: + { + const MetaGradientAction* pA = (const MetaGradientAction*) pMA; + GDIMetaFile aTmpMtf; + + pVirDev->AddGradientActions( pA->GetRect(), pA->GetGradient(), aTmpMtf ); + WriteRecords( aTmpMtf ); + } + break; + + case META_HATCH_ACTION: + { + const MetaHatchAction* pA = (const MetaHatchAction*) pMA; + GDIMetaFile aTmpMtf; + + pVirDev->AddHatchActions( pA->GetPolyPolygon(), pA->GetHatch(), aTmpMtf ); + WriteRecords( aTmpMtf ); + } + break; + + case META_WALLPAPER_ACTION: + { + const MetaWallpaperAction* pA = (const MetaWallpaperAction*) pMA; + const Color& rColor = pA->GetWallpaper().GetColor(); + const Color aOldLineColor( aSrcLineColor ); + const Color aOldFillColor( aSrcFillColor ); + + aSrcLineColor = rColor; + aSrcFillColor = rColor; + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_Rectangle( pA->GetRect() ); + aSrcLineColor = aOldLineColor; + aSrcFillColor = aOldFillColor; + } + break; + + case META_ISECTRECTCLIPREGION_ACTION: + { + const MetaISectRectClipRegionAction* pA = (const MetaISectRectClipRegionAction*) pMA; + WMFRecord_IntersectClipRect( pA->GetRect() ); + } + break; + + case META_LINECOLOR_ACTION: + { + const MetaLineColorAction* pA = (const MetaLineColorAction*) pMA; + + if( pA->IsSetting() ) + aSrcLineColor = pA->GetColor(); + else + aSrcLineColor = Color( COL_TRANSPARENT ); + } + break; + + case META_FILLCOLOR_ACTION: + { + const MetaFillColorAction* pA = (const MetaFillColorAction*) pMA; + + if( pA->IsSetting() ) + aSrcFillColor = pA->GetColor(); + else + aSrcFillColor = Color( COL_TRANSPARENT ); + } + break; + + case META_TEXTCOLOR_ACTION: + { + const MetaTextColorAction* pA = (const MetaTextColorAction*) pMA; + aSrcTextColor = pA->GetColor(); + } + break; + + case META_TEXTFILLCOLOR_ACTION: + { + const MetaTextFillColorAction* pA = (const MetaTextFillColorAction*) pMA; + if( pA->IsSetting() ) + aSrcFont.SetFillColor( pA->GetColor() ); + else + aSrcFont.SetFillColor( Color( COL_TRANSPARENT ) ); + } + break; + + case META_TEXTALIGN_ACTION: + { + const MetaTextAlignAction* pA = (const MetaTextAlignAction*) pMA; + eSrcTextAlign = pA->GetTextAlign(); + } + break; + + case META_MAPMODE_ACTION: + { + const MetaMapModeAction* pA = (const MetaMapModeAction*) pMA; + + if (aSrcMapMode!=pA->GetMapMode()) + { + if( pA->GetMapMode().GetMapUnit() == MAP_RELATIVE ) + { + MapMode aMM = pA->GetMapMode(); + Fraction aScaleX = aMM.GetScaleX(); + Fraction aScaleY = aMM.GetScaleY(); + + Point aOrigin = aSrcMapMode.GetOrigin(); + BigInt aX( aOrigin.X() ); + aX *= BigInt( aScaleX.GetDenominator() ); + if( aOrigin.X() >= 0 ) + if( aScaleX.GetNumerator() >= 0 ) + aX += BigInt( aScaleX.GetNumerator()/2 ); + else + aX -= BigInt( (aScaleX.GetNumerator()+1)/2 ); + else + if( aScaleX.GetNumerator() >= 0 ) + aX -= BigInt( (aScaleX.GetNumerator()-1)/2 ); + else + aX += BigInt( aScaleX.GetNumerator()/2 ); + aX /= BigInt( aScaleX.GetNumerator() ); + aOrigin.X() = (long)aX + aMM.GetOrigin().X(); + BigInt aY( aOrigin.Y() ); + aY *= BigInt( aScaleY.GetDenominator() ); + if( aOrigin.Y() >= 0 ) + if( aScaleY.GetNumerator() >= 0 ) + aY += BigInt( aScaleY.GetNumerator()/2 ); + else + aY -= BigInt( (aScaleY.GetNumerator()+1)/2 ); + else + if( aScaleY.GetNumerator() >= 0 ) + aY -= BigInt( (aScaleY.GetNumerator()-1)/2 ); + else + aY += BigInt( aScaleY.GetNumerator()/2 ); + aY /= BigInt( aScaleY.GetNumerator() ); + aOrigin.Y() = (long)aY + aMM.GetOrigin().Y(); + aSrcMapMode.SetOrigin( aOrigin ); + + aScaleX *= aSrcMapMode.GetScaleX(); + aScaleY *= aSrcMapMode.GetScaleY(); + aSrcMapMode.SetScaleX( aScaleX ); + aSrcMapMode.SetScaleY( aScaleY ); + } + else + aSrcMapMode=pA->GetMapMode(); + } + } + break; + + case META_FONT_ACTION: + { + const MetaFontAction* pA = (const MetaFontAction*) pMA; + aSrcFont = pA->GetFont(); + + if ( (aSrcFont.GetCharSet() == RTL_TEXTENCODING_DONTKNOW) + || (aSrcFont.GetCharSet() == RTL_TEXTENCODING_UNICODE) ) + { + aSrcFont.SetCharSet( RTL_TEXTENCODING_MS_1252 ); + } + eSrcTextAlign = aSrcFont.GetAlign(); + aSrcTextColor = aSrcFont.GetColor(); + aSrcFont.SetAlign( ALIGN_BASELINE ); + aSrcFont.SetColor( COL_WHITE ); + } + break; + + case META_PUSH_ACTION: + { + const MetaPushAction* pA = (const MetaPushAction*)pMA; + + WMFWriterAttrStackMember* pAt = new WMFWriterAttrStackMember; + pAt->nFlags = pA->GetFlags(); + pAt->aClipRegion = aSrcClipRegion; + pAt->aLineColor=aSrcLineColor; + pAt->aFillColor=aSrcFillColor; + pAt->eRasterOp=eSrcRasterOp; + pAt->aFont=aSrcFont; + pAt->eTextAlign=eSrcTextAlign; + pAt->aTextColor=aSrcTextColor; + pAt->aMapMode=aSrcMapMode; + pAt->aLineInfo=aDstLineInfo; + pAt->pSucc=pAttrStack; + pAttrStack=pAt; + + SetAllAttr(); // update ( now all source attributes are equal to the destination attributes ) + WMFRecord_SaveDC(); + + } + break; + + case META_POP_ACTION: + { + WMFWriterAttrStackMember * pAt=pAttrStack; + + if( pAt ) + { + aDstLineInfo = pAt->aLineInfo; + aDstLineColor = pAt->aLineColor; + if ( pAt->nFlags & PUSH_LINECOLOR ) + aSrcLineColor = pAt->aLineColor; + aDstFillColor = pAt->aFillColor; + if ( pAt->nFlags & PUSH_FILLCOLOR ) + aSrcFillColor = pAt->aFillColor; + eDstROP2 = pAt->eRasterOp; + if ( pAt->nFlags & PUSH_RASTEROP ) + eSrcRasterOp = pAt->eRasterOp; + aDstFont = pAt->aFont; + if ( pAt->nFlags & PUSH_FONT ) + aSrcFont = pAt->aFont; + eDstTextAlign = pAt->eTextAlign; + if ( pAt->nFlags & ( PUSH_FONT | PUSH_TEXTALIGN ) ) + eSrcTextAlign = pAt->eTextAlign; + aDstTextColor = pAt->aTextColor; + if ( pAt->nFlags & ( PUSH_FONT | PUSH_TEXTCOLOR ) ) + aSrcTextColor = pAt->aTextColor; + if ( pAt->nFlags & PUSH_MAPMODE ) + aSrcMapMode = pAt->aMapMode; + aDstClipRegion = pAt->aClipRegion; + if ( pAt->nFlags & PUSH_CLIPREGION ) + aSrcClipRegion = pAt->aClipRegion; + + WMFRecord_RestoreDC(); + pAttrStack = pAt->pSucc; + delete pAt; + } + } + break; + + case META_EPS_ACTION : + { + const MetaEPSAction* pA = (const MetaEPSAction*)pMA; + const GDIMetaFile aGDIMetaFile( pA->GetSubstitute() ); + + size_t nCount = aGDIMetaFile.GetActionSize(); + for ( size_t i = 0; i < nCount; i++ ) + { + const MetaAction* pMetaAct = aGDIMetaFile.GetAction( i ); + if ( pMetaAct->GetType() == META_BMPSCALE_ACTION ) + { + const MetaBmpScaleAction* pBmpScaleAction = (const MetaBmpScaleAction*)pMetaAct; + WMFRecord_StretchDIB( pA->GetPoint(), pA->GetSize(), pBmpScaleAction->GetBitmap() ); + break; + } + } + } + break; + + case META_RASTEROP_ACTION: + { + const MetaRasterOpAction* pA = (const MetaRasterOpAction*) pMA; + eSrcRasterOp=pA->GetRasterOp(); + } + break; + + case META_TRANSPARENT_ACTION: + { + aSrcLineInfo = LineInfo(); + SetLineAndFillAttr(); + WMFRecord_PolyPolygon( ( (MetaTransparentAction*) pMA )->GetPolyPolygon() ); + } + break; + + case META_FLOATTRANSPARENT_ACTION: + { + const MetaFloatTransparentAction* pA = (const MetaFloatTransparentAction*) pMA; + + GDIMetaFile aTmpMtf( pA->GetGDIMetaFile() ); + Point aSrcPt( aTmpMtf.GetPrefMapMode().GetOrigin() ); + const Size aSrcSize( aTmpMtf.GetPrefSize() ); + const Point aDestPt( pA->GetPoint() ); + const Size aDestSize( pA->GetSize() ); + const double fScaleX = aSrcSize.Width() ? (double) aDestSize.Width() / aSrcSize.Width() : 1.0; + const double fScaleY = aSrcSize.Height() ? (double) aDestSize.Height() / aSrcSize.Height() : 1.0; + long nMoveX, nMoveY; + + aSrcLineInfo = LineInfo(); + SetAllAttr(); + + if( fScaleX != 1.0 || fScaleY != 1.0 ) + { + aTmpMtf.Scale( fScaleX, fScaleY ); + aSrcPt.X() = FRound( aSrcPt.X() * fScaleX ), aSrcPt.Y() = FRound( aSrcPt.Y() * fScaleY ); + } + + nMoveX = aDestPt.X() - aSrcPt.X(), nMoveY = aDestPt.Y() - aSrcPt.Y(); + + if( nMoveX || nMoveY ) + aTmpMtf.Move( nMoveX, nMoveY ); + + WriteRecords( aTmpMtf ); + } + break; + + case( META_LAYOUTMODE_ACTION ): + { + sal_uInt32 nLayoutMode = ( (MetaLayoutModeAction*) pMA )->GetLayoutMode(); + eSrcHorTextAlign = 0; // TA_LEFT + if (nLayoutMode & TEXT_LAYOUT_BIDI_RTL) + { + eSrcHorTextAlign = W_TA_RIGHT | W_TA_RTLREADING; + } + if (nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_RIGHT) + eSrcHorTextAlign |= W_TA_RIGHT; + else if (nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT) + eSrcHorTextAlign &= ~W_TA_RIGHT; + break; + } + + // Unsupported Actions + case META_MASK_ACTION: + case META_MASKSCALE_ACTION: + case META_MASKSCALEPART_ACTION: + { + OSL_FAIL( "Unsupported action: MetaMask...Action!" ); + } + break; + + case META_CLIPREGION_ACTION: + break; + + case META_ISECTREGIONCLIPREGION_ACTION: + { + OSL_FAIL( "Unsupported action: MetaISectRegionClipRegionAction!" ); + } + break; + + case META_MOVECLIPREGION_ACTION: + { + OSL_FAIL( "Unsupported action: MetaMoveClipRegionAction!" ); + } + break; + + default: + { + OSL_FAIL( "Unsupported meta action!" ); + } + break; + } + + nWrittenActions++; + MayCallback(); + + if (pWMF->GetError()) + bStatus=sal_False; + + if(bStatus==sal_False) + break; + } + } +} + +// ------------------------------------------------------------------------ + +void WMFWriter::WriteHeader( const GDIMetaFile &, sal_Bool bPlaceable ) +{ + if( bPlaceable ) + { + sal_uInt16 nCheckSum, nValue; + Size aSize( pVirDev->LogicToLogic(Size(1,1),MapMode(MAP_INCH), aTargetMapMode) ); + sal_uInt16 nUnitsPerInch = (sal_uInt16) ( ( aSize.Width() + aSize.Height() ) >> 1 ); + + nCheckSum=0; + nValue=0xcdd7; nCheckSum^=nValue; *pWMF << nValue; + nValue=0x9ac6; nCheckSum^=nValue; *pWMF << nValue; + nValue=0x0000; nCheckSum^=nValue; *pWMF << nValue; + nValue=0x0000; nCheckSum^=nValue; *pWMF << nValue; + nValue=0x0000; nCheckSum^=nValue; *pWMF << nValue; + nValue=(sal_uInt16) aTargetSize.Width(); nCheckSum^=nValue; *pWMF << nValue; + nValue=(sal_uInt16) aTargetSize.Height(); nCheckSum^=nValue; *pWMF << nValue; + nValue=nUnitsPerInch; nCheckSum^=nValue; *pWMF << nValue; + nValue=0x0000; nCheckSum^=nValue; *pWMF << nValue; + nValue=0x0000; nCheckSum^=nValue; *pWMF << nValue; + *pWMF << nCheckSum; + } + + nMetafileHeaderPos=pWMF->Tell(); + *pWMF << (sal_uInt16)0x0001 // Typ: Datei + << (sal_uInt16)0x0009 // Headerlaenge in Worten + << (sal_uInt16)0x0300 // Version als BCD-Zahl + << (sal_uInt32) 0x00000000 // Dateilaenge (ohne 1. Header), wird spaeter durch UpdateHeader() berichtigt + << (sal_uInt16)MAXOBJECTHANDLES // Maximalezahl der gleichzeitigen Objekte + << (sal_uInt32) 0x00000000 // Maximale Record-laenge, wird spaeter durch UpdateHeader() berichtigt + << (sal_uInt16)0x0000; // Reserved +} + +// ------------------------------------------------------------------------ + +void WMFWriter::UpdateHeader() +{ + sal_uLong nPos; + sal_uInt32 nFileSize; + + nPos=pWMF->Tell(); // Endposition = Gesammtgroesse der Datei + nFileSize=nPos-nMetafileHeaderPos; // Groesse des 1. Headers abziehen + if ((nFileSize&1)!=0) { // ggf. auf ganze Worte aufrunden + *pWMF << (sal_uInt8)0; + nPos++; + nFileSize++; + } + nFileSize>>=1; // In Anzahl Worte umrechnen + pWMF->Seek(nMetafileHeaderPos+6); // Zum Dateigroessen-Eintrag im zweiten Header + *pWMF << nFileSize; // Dateigroesse berichtigen + pWMF->SeekRel(2); // Zum Max-Record-Laenge-Eintrag im zweiten Header + *pWMF << nMaxRecordSize; // und berichtigen + pWMF->Seek(nPos); +} + +// ------------------------------------------------------------------------ + +sal_Bool WMFWriter::WriteWMF( const GDIMetaFile& rMTF, SvStream& rTargetStream, + FilterConfigItem* pFConfigItem, sal_Bool bPlaceable ) +{ + WMFWriterAttrStackMember * pAt; + + bEmbedEMF = sal_True; + bStatus=sal_True; + pConvert = 0; + pVirDev = new VirtualDevice; + + pFilterConfigItem = pFConfigItem; + if ( pFilterConfigItem ) + { + xStatusIndicator = pFilterConfigItem->GetStatusIndicator(); + if ( xStatusIndicator.is() ) + { + rtl::OUString aMsg; + xStatusIndicator->start( aMsg, 100 ); + } + } + nLastPercent=0; + + pWMF=&rTargetStream; + pWMF->SetNumberFormatInt(NUMBERFORMAT_INT_LITTLEENDIAN); + + nMaxRecordSize=0; + + aSrcMapMode=rMTF.GetPrefMapMode(); + + if( bPlaceable ) + { + aTargetMapMode = aSrcMapMode; + aTargetSize = rMTF.GetPrefSize(); + nTargetDivisor = CalcSaveTargetMapMode(aTargetMapMode, aTargetSize); + aTargetSize.Width() /= nTargetDivisor; + aTargetSize.Height() /= nTargetDivisor; + } + else + { + aTargetMapMode = MapMode( MAP_INCH ); + + const long nUnit = pVirDev->LogicToPixel( Size( 1, 1 ), aTargetMapMode ).Width(); + const Fraction aFrac( 1, nUnit ); + + aTargetMapMode.SetScaleX( aFrac ); + aTargetMapMode.SetScaleY( aFrac ); + aTargetSize = pVirDev->LogicToLogic( rMTF.GetPrefSize(), aSrcMapMode, aTargetMapMode ); + } + + pVirDev->SetMapMode( aTargetMapMode ); + + pAttrStack=NULL; + + for (sal_uInt16 i=0; i<MAXOBJECTHANDLES; i++) + bHandleAllocated[i]=sal_False; + + nDstPenHandle=0xffff; + nDstFontHandle=0xffff; + nDstBrushHandle=0xffff; + + nNumberOfActions=0; + nNumberOfBitmaps=0; + nWrittenActions=0; + nWrittenBitmaps=0; + nActBitmapPercent=0; + + CountActionsAndBitmaps(rMTF); + + WriteHeader(rMTF,bPlaceable); + if( bEmbedEMF ) + WriteEmbeddedEMF( rMTF ); + WMFRecord_SetWindowOrg(Point(0,0)); + WMFRecord_SetWindowExt(rMTF.GetPrefSize()); + WMFRecord_SetBkMode( sal_True ); + + eDstROP2 = eSrcRasterOp = ROP_OVERPAINT; + WMFRecord_SetROP2(eDstROP2); + + aDstLineInfo = LineInfo(); + aDstLineColor = aSrcLineColor = Color( COL_BLACK ); + CreateSelectDeletePen( aDstLineColor, aDstLineInfo ); + + aDstFillColor = aSrcFillColor = Color( COL_WHITE ); + CreateSelectDeleteBrush( aDstFillColor ); + + aDstClipRegion = aSrcClipRegion = Region(); + bDstIsClipping = bSrcIsClipping = sal_False; + + Font aFont; + aFont.SetCharSet( GetExtendedTextEncoding( RTL_TEXTENCODING_MS_1252 ) ); + aFont.SetColor( Color( COL_WHITE ) ); + aFont.SetAlign( ALIGN_BASELINE ); + aDstFont = aSrcFont = aFont; + CreateSelectDeleteFont(aDstFont); + + eDstTextAlign = eSrcTextAlign = ALIGN_BASELINE; + eDstHorTextAlign = eSrcHorTextAlign = W_TA_LEFT; + WMFRecord_SetTextAlign( eDstTextAlign, eDstHorTextAlign ); + + aDstTextColor = aSrcTextColor = Color( COL_WHITE ); + WMFRecord_SetTextColor(aDstTextColor); + + // Write records + WriteRecords(rMTF); + + WMFRecord_EndOfFile(); + UpdateHeader(); + + while(pAttrStack) + { + pAt=pAttrStack; + pAttrStack=pAt->pSucc; + delete pAt; + } + + delete pVirDev; + delete pConvert; + + if ( xStatusIndicator.is() ) + xStatusIndicator->end(); + + return bStatus; +} + +// ------------------------------------------------------------------------ + +sal_uInt16 WMFWriter::CalcSaveTargetMapMode(MapMode& rMapMode, + const Size& rPrefSize) +{ + Fraction aDivFrac(2, 1); + sal_uInt16 nDivisor = 1; + + Size aSize = pVirDev->LogicToLogic( rPrefSize, aSrcMapMode, rMapMode ); + + while( nDivisor <= 64 && (aSize.Width() > 32767 || aSize.Height() > 32767) ) + { + Fraction aFrac = rMapMode.GetScaleX(); + + aFrac *= aDivFrac; + rMapMode.SetScaleX(aFrac); + aFrac = rMapMode.GetScaleY(); + aFrac *= aDivFrac; + rMapMode.SetScaleY(aFrac); + nDivisor <<= 1; + aSize = pVirDev->LogicToLogic( rPrefSize, aSrcMapMode, rMapMode ); + } + + return nDivisor; +} + +// ------------------------------------------------------------------------ + +void WMFWriter::WriteEmbeddedEMF( const GDIMetaFile& rMTF ) +{ + SvMemoryStream aStream; + EMFWriter aEMFWriter(aStream); + + if( aEMFWriter.WriteEMF( rMTF ) ) + { + sal_Size nTotalSize = aStream.Tell(); + if( nTotalSize > SAL_MAX_UINT32 ) + return; + aStream.Seek( 0 ); + sal_uInt32 nRemainingSize = static_cast< sal_uInt32 >( nTotalSize ); + sal_uInt32 nRecCounts = ( (nTotalSize - 1) / 0x2000 ) + 1; + sal_uInt16 nCheckSum = 0, nWord; + + sal_uInt32 nPos = 0; + + while( nPos + 1 < nTotalSize ) + { + aStream >> nWord; + nCheckSum ^= nWord; + nPos += 2; + } + + nCheckSum = static_cast< sal_uInt16 >( nCheckSum * -1 ); + + aStream.Seek( 0 ); + while( nRemainingSize > 0 ) + { + sal_uInt32 nCurSize; + if( nRemainingSize > 0x2000 ) + { + nCurSize = 0x2000; + nRemainingSize -= 0x2000; + } + else + { + nCurSize = nRemainingSize; + nRemainingSize = 0; + } + WriteEMFRecord( aStream, + nCurSize, + nRemainingSize, + nTotalSize, + nRecCounts, + nCheckSum ); + nCheckSum = 0; + } + } +} + +// ------------------------------------------------------------------------ + +void WMFWriter::WriteEMFRecord( SvMemoryStream& rStream, sal_uInt32 nCurSize, sal_uInt32 nRemainingSize, + sal_uInt32 nTotalSize, sal_uInt32 nRecCounts, sal_uInt16 nCheckSum ) +{ + // according to http://msdn.microsoft.com/en-us/library/dd366152%28PROT.13%29.aspx + WriteRecordHeader( 0, W_META_ESCAPE ); + *pWMF << (sal_uInt16)W_MFCOMMENT // same as META_ESCAPE_ENHANCED_METAFILE + << (sal_uInt16)( nCurSize + 34 ) // we will always have a 34 byte escape header: + << (sal_uInt32) 0x43464D57 // WMFC + << (sal_uInt32) 0x00000001 // Comment type + << (sal_uInt32) 0x00010000 // version + << nCheckSum // check sum + << (sal_uInt32) 0 // flags = 0 + << nRecCounts // total number of records + << nCurSize // size of this record's data + << nRemainingSize // remaining size of data in following records, missing in MSDN documentation + << nTotalSize; // total size of EMF stream + + pWMF->Write( static_cast< const sal_Char* >( rStream.GetData() ) + rStream.Tell(), nCurSize ); + rStream.SeekRel( nCurSize ); + UpdateRecordHeader(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/filter/wmf/wmfwr.hxx b/vcl/source/filter/wmf/wmfwr.hxx new file mode 100644 index 000000000000..f71abaa8ea93 --- /dev/null +++ b/vcl/source/filter/wmf/wmfwr.hxx @@ -0,0 +1,220 @@ +/* -*- 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 _WMFWR_HXX +#define _WMFWR_HXX + +#include <vcl/metaact.hxx> +#include <vcl/graph.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/virdev.hxx> +#include <svtools/fltcall.hxx> + +// ----------------------------------------------------------------------------- + +#define MAXOBJECTHANDLES 16 + +// ----------------------------------------------------------------------------- + +struct WMFWriterAttrStackMember +{ + struct WMFWriterAttrStackMember * pSucc; + Color aLineColor; + Color aFillColor; + Color aTextColor; + LineInfo aLineInfo; + TextAlign eTextAlign; + RasterOp eRasterOp; + Font aFont; + MapMode aMapMode; + Region aClipRegion; + sal_uInt16 nFlags; +}; + +// ------------- +// - WMFWriter - +// ------------- + +class StarSymbolToMSMultiFont; +class LineInfo; +namespace basegfx { class B2DPolygon; } + +class WMFWriter +{ +private: + + sal_Bool bStatus; + + sal_uLong nLastPercent; // Mit welcher Zahl pCallback zuletzt aufgerufen wurde. + FilterConfigItem* pFilterConfigItem; + + com::sun::star::uno::Reference< com::sun::star::task::XStatusIndicator > xStatusIndicator; + + SvStream* pWMF; + VirtualDevice* pVirDev; + StarSymbolToMSMultiFont *pConvert; + MapMode aTargetMapMode; + Size aTargetSize; + sal_uInt16 nTargetDivisor; + + sal_uLong nMetafileHeaderPos; + sal_uInt32 nMaxRecordSize; // in Worten + sal_uLong nActRecordPos; + + // Aktuelle Attribute im Quell-Metafile: + Color aSrcLineColor; + Color aSrcFillColor; + Color aSrcTextColor; + LineInfo aSrcLineInfo; + RasterOp eSrcRasterOp; + FontAlign eSrcTextAlign; + Font aSrcFont; + MapMode aSrcMapMode; + sal_Bool bSrcIsClipping; + Region aSrcClipRegion; + WMFWriterAttrStackMember * pAttrStack; + + sal_uInt32 eSrcHorTextAlign; + + // Aktuelle Attribute im Ziel-Metafile: + Color aDstLineColor; + Color aDstFillColor; + Color aDstTextColor; + LineInfo aDstLineInfo; + RasterOp eDstROP2; + FontAlign eDstTextAlign; + Font aDstFont; + + sal_uInt32 eDstHorTextAlign; + + sal_Bool bDstIsClipping; // ???: derzeit unberuecksichtigt + Region aDstClipRegion; // ???: derzeit unberuecksichtigt + sal_Bool bHandleAllocated[MAXOBJECTHANDLES]; // Welche Handles vergeben sind + sal_uInt16 nDstPenHandle,nDstFontHandle,nDstBrushHandle; // Welche Handles die jeweiligen + // Selected-Objects besitzen + // 0xffff = keines: + + // Damit nicht bei jeder Operation alle Attribute verglichen werden muessen: + + sal_uLong nNumberOfActions; // Anzahl der Actions im GDIMetafile + sal_uLong nNumberOfBitmaps; // Anzahl der Bitmaps + sal_uLong nWrittenActions; // Anzahl der bereits verarbeiteten Actions beim Schreiben der Orders + sal_uLong nWrittenBitmaps; // Anzahl der bereits geschriebenen Bitmaps + sal_uLong nActBitmapPercent; // Wieviel Prozent die naechste Bitmap schon geschrieben ist. + + sal_Bool bEmbedEMF; // optionally embedd EMF data into WMF + + void MayCallback(); + // Berechnet anhand der obigen 5 Parameter eine Prozentzahl + // und macht dann ggf. einen Callback. Setzt bStatus auf FALSE wenn User abbrechen + // moechte. + + void CountActionsAndBitmaps(const GDIMetaFile & rMTF); + // Zaehlt die Bitmaps und Actions (nNumberOfActions und nNumberOfBitmaps muessen + // zu Anfang auf 0 gesetzt werden, weil diese Methode rekursiv ist) + + void WritePointXY(const Point & rPoint); + void WritePointYX(const Point & rPoint); + sal_Int32 ScaleWidth( sal_Int32 nDX ); + void WriteSize(const Size & rSize); + void WriteHeightWidth(const Size & rSize); + void WriteRectangle(const Rectangle & rRect); + void WriteColor(const Color & rColor); + + void WriteRecordHeader(sal_uInt32 nSizeWords, sal_uInt16 nType); + // nSizeWords ist die Groesse des gesammten Records in Anzahl Worte. + // Wenn nSizeWords unbekannt ist, dann 0 einsetzen (siehe UpdateRecordHeader()). + + void UpdateRecordHeader(); + // berichtig die Groesse des Records nach dem Schreiben der Parameter, wenn + // nSizeWords bei Aufruf von WriteRecordHeader(..) unbekannt war. + // fuegt ggf. noch ein BYTE 0 ein damit Anzahl Bytes immer gerade. + + void WMFRecord_Arc(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt); + void WMFRecord_Chord(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt); + void WMFRecord_CreateBrushIndirect(const Color& rColor); + void WMFRecord_CreateFontIndirect(const Font & rFont); + void WMFRecord_CreatePenIndirect(const Color& rColor, const LineInfo& rLineInfo ); + void WMFRecord_DeleteObject(sal_uInt16 nObjectHandle); + void WMFRecord_Ellipse(const Rectangle & rRect); + void WMFRecord_Escape( sal_uInt32 nEsc, sal_uInt32 nLen, const sal_Int8* pData ); + sal_Bool WMFRecord_Escape_Unicode( const Point& rPoint, const String& rStr, const sal_Int32 * pDXAry ); + void WMFRecord_ExtTextOut(const Point & rPoint, const String & rString, const sal_Int32 * pDXAry); + + void TrueExtTextOut(const Point & rPoint, const String & rString, + const rtl::OString& rByteString, const sal_Int32 * pDXAry); + void TrueTextOut(const Point & rPoint, const rtl::OString& rString); + void WMFRecord_LineTo(const Point & rPoint); + void WMFRecord_MoveTo(const Point & rPoint); + void WMFRecord_Pie(const Rectangle & rRect, const Point & rStartPt, const Point & rEndPt); + void WMFRecord_Polygon(const Polygon & rPoly); + void WMFRecord_PolyLine(const Polygon & rPoly); + void WMFRecord_PolyPolygon(const PolyPolygon & rPolyPoly); + void WMFRecord_Rectangle(const Rectangle & rRect); + void WMFRecord_RestoreDC(); + void WMFRecord_RoundRect(const Rectangle & rRect, long nHorzRound, long nVertRound); + void WMFRecord_SaveDC(); + void WMFRecord_SelectObject(sal_uInt16 nObjectHandle); + void WMFRecord_SetBkMode(sal_Bool bTransparent); + void WMFRecord_SetStretchBltMode(); + void WMFRecord_SetPixel(const Point & rPoint, const Color & rColor); + void WMFRecord_SetROP2(RasterOp eROP); + void WMFRecord_SetTextAlign(FontAlign eFontAlign, sal_uInt32 eHorTextAlign); + void WMFRecord_SetTextColor(const Color & rColor); + void WMFRecord_SetWindowExt(const Size & rSize); + void WMFRecord_SetWindowOrg(const Point & rPoint); + void WMFRecord_StretchDIB(const Point & rPoint, const Size & rSize, const Bitmap & rBitmap, sal_uInt32 nROP = 0UL ); + void WMFRecord_TextOut(const Point & rPoint, const String & rString); + void WMFRecord_EndOfFile(); + void WMFRecord_IntersectClipRect( const Rectangle& rRect); + + sal_uInt16 AllocHandle(); + void FreeHandle(sal_uInt16 nObjectHandle); + void CreateSelectDeletePen( const Color& rColor, const LineInfo& rLineInfo ); + void CreateSelectDeleteFont(const Font & rFont); + void CreateSelectDeleteBrush(const Color& rColor); + + void SetLineAndFillAttr(); + void SetAllAttr(); + + void HandleLineInfoPolyPolygons(const LineInfo& rInfo, const basegfx::B2DPolygon& rLinePolygon); + void WriteRecords(const GDIMetaFile & rMTF); + + void WriteHeader(const GDIMetaFile & rMTF, sal_Bool bPlaceable); + void UpdateHeader(); + + void WriteEmbeddedEMF( const GDIMetaFile& rMTF ); + void WriteEMFRecord( SvMemoryStream& rStream, sal_uInt32 nCurSize, + sal_uInt32 nRemainingSize, + sal_uInt32 nTotalSize, + sal_uInt32 nRecCounts, + sal_uInt16 nCheckSum ); + + sal_uInt16 CalcSaveTargetMapMode(MapMode& rMapMode, const Size& rPrefSize); + +public: + + WMFWriter() {} + + sal_Bool WriteWMF(const GDIMetaFile & rMTF, SvStream & rTargetStream, FilterConfigItem* pFilterConfigItem, sal_Bool bPlaceable=sal_True); +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |