diff options
author | Ivo Hinkelmann <ihi@openoffice.org> | 2010-11-30 17:00:37 +0100 |
---|---|---|
committer | Ivo Hinkelmann <ihi@openoffice.org> | 2010-11-30 17:00:37 +0100 |
commit | a5509a421f2f3d43aad1ba5d32e6c7bf1c015b3b (patch) | |
tree | 2b149629e818baec741e85a72159851e99a32832 | |
parent | 65df21598fe975ffefd8f8e6951f8d3b331c2b29 (diff) | |
parent | 8cbc2d0363811781f5de45b3a11b3614feec4a9a (diff) |
CWS-TOOLING: integrate CWS pl08
Notes
Notes:
split repo tag: libs-gui_ooo/DEV300_m95
27 files changed, 2082 insertions, 825 deletions
diff --git a/comphelper/inc/comphelper/docpasswordhelper.hxx b/comphelper/inc/comphelper/docpasswordhelper.hxx index dbbb68372a07..7e9f06318a26 100644 --- a/comphelper/inc/comphelper/docpasswordhelper.hxx +++ b/comphelper/inc/comphelper/docpasswordhelper.hxx @@ -28,6 +28,7 @@ #ifndef COMPHELPER_DOCPASSWORDHELPR_HXX #define COMPHELPER_DOCPASSWORDHELPR_HXX +#include <com/sun/star/beans/NamedValue.hpp> #include "comphelper/comphelperdllapi.h" #include <vector> #include "comphelper/docpasswordrequest.hxx" @@ -53,7 +54,7 @@ enum DocPasswordVerifierResult /** Base class for a password verifier used by the DocPasswordHelper class below. - Users have to implement the virtual function and pass an instance of the + Users have to implement the virtual functions and pass an instance of the verifier to one of the password request functions. */ class COMPHELPER_DLLPUBLIC IDocPasswordVerifier @@ -63,6 +64,14 @@ public: /** Will be called everytime a password needs to be verified. + @param rPassword + The password to be verified + + @param o_rEncryptionData + Output parameter, that is filled with the EncryptionData generated + from the password. The data is filled only if the validation was + successful. + @return The result of the verification. - DocPasswordVerifierResult_OK, if and only if the passed password is valid and can be used to process the related document. @@ -72,7 +81,23 @@ public: occured while password verification. The password request loop will be aborted. */ - virtual DocPasswordVerifierResult verifyPassword( const ::rtl::OUString& rPassword ) = 0; + virtual DocPasswordVerifierResult verifyPassword( const ::rtl::OUString& rPassword, ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& o_rEncryptionData ) = 0; + + /** Will be called everytime an encryption data needs to be verified. + + @param rEncryptionData + The data will be validated + + @return The result of the verification. + - DocPasswordVerifierResult_OK, if and only if the passed encryption data + is valid and can be used to process the related document. + - DocPasswordVerifierResult_WRONG_PASSWORD, if the encryption data is + wrong. + - DocPasswordVerifierResult_ABORT, if an unrecoverable error + occured while data verification. The password request loop + will be aborted. + */ + virtual DocPasswordVerifierResult verifyEncryptionData( const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& o_rEncryptionData ) = 0; }; @@ -195,6 +220,35 @@ public: // ------------------------------------------------------------------------ + /** This helper function generates a random sequence of bytes of + requested length. + */ + + static ::com::sun::star::uno::Sequence< sal_Int8 > GenerateRandomByteSequence( + sal_Int32 nLength ); + + // ------------------------------------------------------------------------ + + /** This helper function generates a byte sequence representing the + key digest value used by MSCodec_Std97 codec. + */ + + static ::com::sun::star::uno::Sequence< sal_Int8 > GenerateStd97Key( + const ::rtl::OUString& aPassword, + const ::com::sun::star::uno::Sequence< sal_Int8 >& aDocId ); + + // ------------------------------------------------------------------------ + + /** This helper function generates a byte sequence representing the + key digest value used by MSCodec_Std97 codec. + */ + + static ::com::sun::star::uno::Sequence< sal_Int8 > GenerateStd97Key( + const sal_uInt16 pPassData[16], + const ::com::sun::star::uno::Sequence< sal_Int8 >& aDocId ); + + // ------------------------------------------------------------------------ + /** This helper function tries to request and verify a password to load a protected document. @@ -248,8 +302,9 @@ public: passed password verifier. If empty, no valid password has been found, or the user has chossen to cancel password input. */ - static ::rtl::OUString requestAndVerifyDocPassword( + static ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > requestAndVerifyDocPassword( IDocPasswordVerifier& rVerifier, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& rMediaEncData, const ::rtl::OUString& rMediaPassword, const ::com::sun::star::uno::Reference< ::com::sun::star::task::XInteractionHandler >& rxInteractHandler, @@ -300,7 +355,7 @@ public: passed password verifier. If empty, no valid password has been found, or the user has chossen to cancel password input. */ - static ::rtl::OUString requestAndVerifyDocPassword( + static ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > requestAndVerifyDocPassword( IDocPasswordVerifier& rVerifier, MediaDescriptor& rMediaDesc, DocPasswordRequestType eRequestType, diff --git a/comphelper/inc/comphelper/mediadescriptor.hxx b/comphelper/inc/comphelper/mediadescriptor.hxx index 7d2333045390..01fa8059b284 100644 --- a/comphelper/inc/comphelper/mediadescriptor.hxx +++ b/comphelper/inc/comphelper/mediadescriptor.hxx @@ -78,6 +78,7 @@ class COMPHELPER_DLLPUBLIC MediaDescriptor : public SequenceAsHashMap static const ::rtl::OUString& PROP_DEEPDETECTION(); static const ::rtl::OUString& PROP_DETECTSERVICE(); static const ::rtl::OUString& PROP_DOCUMENTSERVICE(); + static const ::rtl::OUString& PROP_ENCRYPTIONDATA(); static const ::rtl::OUString& PROP_EXTENSION(); static const ::rtl::OUString& PROP_FILENAME(); static const ::rtl::OUString& PROP_FILTERNAME(); diff --git a/comphelper/inc/comphelper/storagehelper.hxx b/comphelper/inc/comphelper/storagehelper.hxx index b7e5704c4d68..9d44b42e9514 100644 --- a/comphelper/inc/comphelper/storagehelper.hxx +++ b/comphelper/inc/comphelper/storagehelper.hxx @@ -33,6 +33,7 @@ #include <com/sun/star/lang/XSingleServiceFactory.hpp> #include <com/sun/star/embed/XStorage.hpp> #include <com/sun/star/embed/ElementModes.hpp> +#include <com/sun/star/beans/NamedValue.hpp> #include <com/sun/star/io/XInputStream.hpp> #include <com/sun/star/io/XOutputStream.hpp> #include <com/sun/star/io/XStream.hpp> @@ -43,6 +44,9 @@ #define ZIP_STORAGE_FORMAT_STRING ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ZipFormat" ) ) #define OFOPXML_STORAGE_FORMAT_STRING ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OFOPXMLFormat" ) ) +#define PACKAGE_ENCRYPTIONDATA_SHA1UTF8 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PackageSHA1UTF8EncryptionKey" ) ) +#define PACKAGE_ENCRYPTIONDATA_SHA1MS1252 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PackageSHA1MS1252EncryptionKey" ) ) + namespace comphelper { class COMPHELPER_DLLPUBLIC OStorageHelper @@ -112,9 +116,9 @@ public: = ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >() ) throw ( ::com::sun::star::uno::Exception ); - static void SetCommonStoragePassword( + static void SetCommonStorageEncryptionData( const ::com::sun::star::uno::Reference< ::com::sun::star::embed::XStorage >& xStorage, - const ::rtl::OUString& aPass ) + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& aEncryptionData ) throw ( ::com::sun::star::uno::Exception ); // the following method supports only storages of OOo formats @@ -159,6 +163,9 @@ public: sal_Bool bRepairStorage = sal_False ) throw ( ::com::sun::star::uno::Exception ); + static ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > + CreatePackageEncryptionData( const ::rtl::OUString& aPassword ); + static sal_Bool IsValidZipEntryFileName( const ::rtl::OUString& aName, sal_Bool bSlashAllowed ); static sal_Bool IsValidZipEntryFileName( const sal_Unicode *pChar, sal_Int32 nLength, sal_Bool bSlashAllowed ); diff --git a/comphelper/source/misc/docpasswordhelper.cxx b/comphelper/source/misc/docpasswordhelper.cxx index 37941352ae28..3c8d66bd57e4 100644 --- a/comphelper/source/misc/docpasswordhelper.cxx +++ b/comphelper/source/misc/docpasswordhelper.cxx @@ -84,16 +84,9 @@ uno::Sequence< beans::PropertyValue > DocPasswordHelper::GenerateNewModifyPasswo { uno::Sequence< beans::PropertyValue > aResult; - uno::Sequence< sal_Int8 > aSalt( 16 ); + uno::Sequence< sal_Int8 > aSalt = GenerateRandomByteSequence( 16 ); sal_Int32 nCount = 1024; - TimeValue aTime; - osl_getSystemTime( &aTime ); - rtlRandomPool aRandomPool = rtl_random_createPool (); - rtl_random_addBytes ( aRandomPool, &aTime, 8 ); - - rtl_random_getBytes ( aRandomPool, aSalt.getArray(), 16 ); - uno::Sequence< sal_Int8 > aNewHash = GeneratePBKDF2Hash( aPassword, aSalt, nCount, 16 ); if ( aNewHash.getLength() ) { @@ -108,9 +101,6 @@ uno::Sequence< beans::PropertyValue > DocPasswordHelper::GenerateNewModifyPasswo aResult[3].Value <<= aNewHash; } - // Clean up random pool memory - rtl_random_destroyPool ( aRandomPool ); - return aResult; } @@ -282,9 +272,98 @@ Sequence< sal_Int8 > DocPasswordHelper::GetXLHashAsSequence( } // ============================================================================ +/*static*/ uno::Sequence< sal_Int8 > DocPasswordHelper::GenerateRandomByteSequence( sal_Int32 nLength ) +{ + uno::Sequence< sal_Int8 > aResult( nLength ); + + TimeValue aTime; + osl_getSystemTime( &aTime ); + rtlRandomPool aRandomPool = rtl_random_createPool (); + rtl_random_addBytes ( aRandomPool, &aTime, 8 ); + rtl_random_getBytes ( aRandomPool, aResult.getArray(), nLength ); + rtl_random_destroyPool ( aRandomPool ); -/*static*/ OUString DocPasswordHelper::requestAndVerifyDocPassword( + return aResult; +} + + +// ============================================================================ +/*static*/ uno::Sequence< sal_Int8 > DocPasswordHelper::GenerateStd97Key( const ::rtl::OUString& aPassword, const uno::Sequence< sal_Int8 >& aDocId ) +{ + uno::Sequence< sal_Int8 > aResultKey; + if ( aPassword.getLength() && aDocId.getLength() == 16 ) + { + sal_uInt16 pPassData[16]; + rtl_zeroMemory( pPassData, sizeof(pPassData) ); + + sal_Int32 nPassLen = ::std::min< sal_Int32 >( aPassword.getLength(), 15 ); + rtl_copyMemory( pPassData, aPassword.getStr(), nPassLen * sizeof(pPassData[0]) ); + + aResultKey = GenerateStd97Key( pPassData, aDocId ); + } + + return aResultKey; +} + +// ============================================================================ +/*static*/ uno::Sequence< sal_Int8 > DocPasswordHelper::GenerateStd97Key( const sal_uInt16 pPassData[16], const uno::Sequence< sal_Int8 >& aDocId ) +{ + uno::Sequence< sal_Int8 > aResultKey; + if ( pPassData[0] && aDocId.getLength() == 16 ) + { + sal_uInt8 pKeyData[64]; + rtl_zeroMemory( pKeyData, sizeof(pKeyData) ); + + sal_Int32 nInd = 0; + + // Fill PassData into KeyData. + for ( nInd = 0; nInd < 16 && pPassData[nInd]; nInd++) + { + pKeyData[2*nInd] = sal::static_int_cast< sal_uInt8 >( (pPassData[nInd] >> 0) & 0xff ); + pKeyData[2*nInd + 1] = sal::static_int_cast< sal_uInt8 >( (pPassData[nInd] >> 8) & 0xff ); + } + + pKeyData[2*nInd] = 0x80; + pKeyData[56] = sal::static_int_cast< sal_uInt8 >( nInd << 4 ); + + // Fill raw digest of KeyData into KeyData. + rtlDigest hDigest = rtl_digest_create ( rtl_Digest_AlgorithmMD5 ); + (void)rtl_digest_updateMD5 ( + hDigest, pKeyData, sizeof(pKeyData)); + (void)rtl_digest_rawMD5 ( + hDigest, pKeyData, RTL_DIGEST_LENGTH_MD5); + + // Update digest with KeyData and Unique. + for ( nInd = 0; nInd < 16; nInd++ ) + { + rtl_digest_updateMD5( hDigest, pKeyData, 5 ); + rtl_digest_updateMD5( hDigest, (const sal_uInt8*)aDocId.getConstArray(), aDocId.getLength() ); + } + + // Update digest with padding. + pKeyData[16] = 0x80; + rtl_zeroMemory( pKeyData + 17, sizeof(pKeyData) - 17 ); + pKeyData[56] = 0x80; + pKeyData[57] = 0x0a; + + rtl_digest_updateMD5( hDigest, &(pKeyData[16]), sizeof(pKeyData) - 16 ); + + // Fill raw digest of above updates + aResultKey.realloc( RTL_DIGEST_LENGTH_MD5 ); + rtl_digest_rawMD5 ( hDigest, (sal_uInt8*)aResultKey.getArray(), aResultKey.getLength() ); + + // Erase KeyData array and leave. + rtl_zeroMemory( pKeyData, sizeof(pKeyData) ); + } + + return aResultKey; +} + +// ============================================================================ + +/*static*/ ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > DocPasswordHelper::requestAndVerifyDocPassword( IDocPasswordVerifier& rVerifier, + const ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue >& rMediaEncData, const OUString& rMediaPassword, const Reference< XInteractionHandler >& rxInteractHandler, const OUString& rDocumentName, @@ -292,7 +371,7 @@ Sequence< sal_Int8 > DocPasswordHelper::GetXLHashAsSequence( const ::std::vector< OUString >* pDefaultPasswords, bool* pbIsDefaultPassword ) { - OUString aPassword; + ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > aEncData; DocPasswordVerifierResult eResult = DocPasswordVerifierResult_WRONG_PASSWORD; // first, try provided default passwords @@ -302,23 +381,32 @@ Sequence< sal_Int8 > DocPasswordHelper::GetXLHashAsSequence( { for( ::std::vector< OUString >::const_iterator aIt = pDefaultPasswords->begin(), aEnd = pDefaultPasswords->end(); (eResult == DocPasswordVerifierResult_WRONG_PASSWORD) && (aIt != aEnd); ++aIt ) { - aPassword = *aIt; - OSL_ENSURE( aPassword.getLength() > 0, "DocPasswordHelper::requestAndVerifyDocPassword - unexpected empty default password" ); - if( aPassword.getLength() > 0 ) + OSL_ENSURE( aIt->getLength() > 0, "DocPasswordHelper::requestAndVerifyDocPassword - unexpected empty default password" ); + if( aIt->getLength() > 0 ) { - eResult = rVerifier.verifyPassword( aPassword ); + eResult = rVerifier.verifyPassword( *aIt, aEncData ); if( pbIsDefaultPassword ) *pbIsDefaultPassword = eResult == DocPasswordVerifierResult_OK; } } } + // try media encryption data (skip, if result is OK or ABORT) + if( eResult == DocPasswordVerifierResult_WRONG_PASSWORD ) + { + if( rMediaEncData.getLength() > 0 ) + { + eResult = rVerifier.verifyEncryptionData( rMediaEncData ); + if( eResult == DocPasswordVerifierResult_OK ) + aEncData = rMediaEncData; + } + } + // try media password (skip, if result is OK or ABORT) if( eResult == DocPasswordVerifierResult_WRONG_PASSWORD ) { - aPassword = rMediaPassword; - if( aPassword.getLength() > 0 ) - eResult = rVerifier.verifyPassword( aPassword ); + if( rMediaPassword.getLength() > 0 ) + eResult = rVerifier.verifyPassword( rMediaPassword, aEncData ); } // request a password (skip, if result is OK or ABORT) @@ -332,9 +420,8 @@ Sequence< sal_Int8 > DocPasswordHelper::GetXLHashAsSequence( rxInteractHandler->handle( xRequest ); if( pRequest->isPassword() ) { - aPassword = pRequest->getPassword(); - if( aPassword.getLength() > 0 ) - eResult = rVerifier.verifyPassword( aPassword ); + if( pRequest->getPassword().getLength() > 0 ) + eResult = rVerifier.verifyPassword( pRequest->getPassword(), aEncData ); } else { @@ -347,15 +434,17 @@ Sequence< sal_Int8 > DocPasswordHelper::GetXLHashAsSequence( { } - return (eResult == DocPasswordVerifierResult_OK) ? aPassword : OUString(); + return (eResult == DocPasswordVerifierResult_OK) ? aEncData : uno::Sequence< beans::NamedValue >(); } -/*static*/ OUString DocPasswordHelper::requestAndVerifyDocPassword( +/*static*/ ::com::sun::star::uno::Sequence< ::com::sun::star::beans::NamedValue > DocPasswordHelper::requestAndVerifyDocPassword( IDocPasswordVerifier& rVerifier, MediaDescriptor& rMediaDesc, DocPasswordRequestType eRequestType, const ::std::vector< OUString >* pDefaultPasswords ) { + uno::Sequence< beans::NamedValue > aMediaEncData = rMediaDesc.getUnpackedValueOrDefault( + MediaDescriptor::PROP_ENCRYPTIONDATA(), uno::Sequence< beans::NamedValue >() ); OUString aMediaPassword = rMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_PASSWORD(), OUString() ); Reference< XInteractionHandler > xInteractHandler = rMediaDesc.getUnpackedValueOrDefault( @@ -364,14 +453,17 @@ Sequence< sal_Int8 > DocPasswordHelper::GetXLHashAsSequence( MediaDescriptor::PROP_URL(), OUString() ); bool bIsDefaultPassword = false; - OUString aPassword = requestAndVerifyDocPassword( - rVerifier, aMediaPassword, xInteractHandler, aDocumentName, eRequestType, pDefaultPasswords, &bIsDefaultPassword ); + uno::Sequence< beans::NamedValue > aEncryptionData = requestAndVerifyDocPassword( + rVerifier, aMediaEncData, aMediaPassword, xInteractHandler, aDocumentName, eRequestType, pDefaultPasswords, &bIsDefaultPassword ); + + rMediaDesc.erase( MediaDescriptor::PROP_PASSWORD() ); + rMediaDesc.erase( MediaDescriptor::PROP_ENCRYPTIONDATA() ); // insert valid password into media descriptor (but not a default password) - if( (aPassword.getLength() > 0) && !bIsDefaultPassword ) - rMediaDesc[ MediaDescriptor::PROP_PASSWORD() ] <<= aPassword; + if( (aEncryptionData.getLength() > 0) && !bIsDefaultPassword ) + rMediaDesc[ MediaDescriptor::PROP_ENCRYPTIONDATA() ] <<= aEncryptionData; - return aPassword; + return aEncryptionData; } // ============================================================================ diff --git a/comphelper/source/misc/mediadescriptor.cxx b/comphelper/source/misc/mediadescriptor.cxx index 9e02afe8c56c..143f8ba4dfa2 100644 --- a/comphelper/source/misc/mediadescriptor.cxx +++ b/comphelper/source/misc/mediadescriptor.cxx @@ -112,6 +112,12 @@ const ::rtl::OUString& MediaDescriptor::PROP_DOCUMENTSERVICE() return sProp; } +const ::rtl::OUString& MediaDescriptor::PROP_ENCRYPTIONDATA() +{ + static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("EncryptionData")); + return sProp; +} + const ::rtl::OUString& MediaDescriptor::PROP_EXTENSION() { static const ::rtl::OUString sProp(RTL_CONSTASCII_USTRINGPARAM("Extension")); diff --git a/comphelper/source/misc/storagehelper.cxx b/comphelper/source/misc/storagehelper.cxx index db5ba71cd876..60ffa965fcf1 100644 --- a/comphelper/source/misc/storagehelper.cxx +++ b/comphelper/source/misc/storagehelper.cxx @@ -28,12 +28,15 @@ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_comphelper.hxx" #include <com/sun/star/embed/ElementModes.hpp> -#include <com/sun/star/embed/XEncryptionProtectedSource.hpp> +#include <com/sun/star/embed/XEncryptionProtectedSource2.hpp> #include <com/sun/star/ucb/XSimpleFileAccess.hpp> #include <com/sun/star/beans/XPropertySet.hpp> #include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/NamedValue.hpp> #include <com/sun/star/beans/IllegalTypeException.hpp> +#include <rtl/digest.h> + #include <ucbhelper/content.hxx> #include <comphelper/fileformat.h> @@ -236,16 +239,16 @@ uno::Reference< io::XInputStream > OStorageHelper::GetInputStreamFromURL( } // ---------------------------------------------------------------------- -void OStorageHelper::SetCommonStoragePassword( +void OStorageHelper::SetCommonStorageEncryptionData( const uno::Reference< embed::XStorage >& xStorage, - const ::rtl::OUString& aPass ) + const uno::Sequence< beans::NamedValue >& aEncryptionData ) throw ( uno::Exception ) { - uno::Reference< embed::XEncryptionProtectedSource > xEncrSet( xStorage, uno::UNO_QUERY ); + uno::Reference< embed::XEncryptionProtectedSource2 > xEncrSet( xStorage, uno::UNO_QUERY ); if ( !xEncrSet.is() ) throw io::IOException(); // TODO - xEncrSet->setEncryptionPassword( aPass ); + xEncrSet->setEncryptionData( aEncryptionData ); } // ---------------------------------------------------------------------- @@ -419,6 +422,45 @@ uno::Reference< embed::XStorage > OStorageHelper::GetStorageOfFormatFromStream( } // ---------------------------------------------------------------------- +uno::Sequence< beans::NamedValue > OStorageHelper::CreatePackageEncryptionData( const ::rtl::OUString& aPassword ) +{ + // TODO/LATER: Should not the method be part of DocPasswordHelper? + uno::Sequence< beans::NamedValue > aEncryptionData; + if ( aPassword.getLength() ) + { + // MS_1252 encoding was used for SO60 document format password encoding, + // this encoding supports only a minor subset of nonascii characters, + // but for compatibility reasons it has to be used for old document formats + aEncryptionData.realloc( 2 ); + aEncryptionData[0].Name = PACKAGE_ENCRYPTIONDATA_SHA1UTF8; + aEncryptionData[1].Name = PACKAGE_ENCRYPTIONDATA_SHA1MS1252; + + rtl_TextEncoding pEncoding[2] = { RTL_TEXTENCODING_UTF8, RTL_TEXTENCODING_MS_1252 }; + + for ( sal_Int32 nInd = 0; nInd < 2; nInd++ ) + { + ::rtl::OString aByteStrPass = ::rtl::OUStringToOString( aPassword, pEncoding[nInd] ); + + sal_uInt8 pBuffer[RTL_DIGEST_LENGTH_SHA1]; + rtlDigestError nError = rtl_digest_SHA1( aByteStrPass.getStr(), + aByteStrPass.getLength(), + pBuffer, + RTL_DIGEST_LENGTH_SHA1 ); + + if ( nError != rtl_Digest_E_None ) + { + aEncryptionData.realloc( 0 ); + break; + } + + aEncryptionData[nInd].Value <<= uno::Sequence< sal_Int8 >( (sal_Int8*)pBuffer, RTL_DIGEST_LENGTH_SHA1 ); + } + } + + return aEncryptionData; +} + +// ---------------------------------------------------------------------- sal_Bool OStorageHelper::IsValidZipEntryFileName( const ::rtl::OUString& aName, sal_Bool bSlashAllowed ) { return IsValidZipEntryFileName( aName.getStr(), aName.getLength(), bSlashAllowed ); diff --git a/vcl/inc/vcl/arrange.hxx b/vcl/inc/vcl/arrange.hxx index f98197231be9..327494b216e4 100644 --- a/vcl/inc/vcl/arrange.hxx +++ b/vcl/inc/vcl/arrange.hxx @@ -76,11 +76,13 @@ namespace vcl Element( Window* i_pWin, boost::shared_ptr<WindowArranger> const & i_pChild = boost::shared_ptr<WindowArranger>(), - sal_Int32 i_nExpandPriority = 0 + sal_Int32 i_nExpandPriority = 0, + const Size& i_rMinSize = Size() ) : m_pElement( i_pWin ) , m_pChild( i_pChild ) , m_nExpandPriority( i_nExpandPriority ) + , m_aMinSize( i_rMinSize ) , m_bHidden( false ) , m_nLeftBorder( 0 ) , m_nTopBorder( 0 ) @@ -101,12 +103,19 @@ namespace vcl Rectangle m_aManagedArea; long m_nOuterBorder; + rtl::OUString m_aIdentifier; + virtual Element* getElement( size_t i_nIndex ) = 0; const Element* getConstElement( size_t i_nIndex ) const { return const_cast<WindowArranger*>(this)->getElement( i_nIndex ); } public: + static long getDefaultBorder(); + + static long getBorderValue( long nBorder ) + { return nBorder >= 0 ? nBorder : -nBorder * getDefaultBorder(); } + WindowArranger( WindowArranger* i_pParent = NULL ) : m_pParentWindow( i_pParent ? i_pParent->m_pParentWindow : NULL ) , m_pParentArranger( i_pParent ) @@ -141,6 +150,9 @@ namespace vcl virtual bool isVisible() const; // true if any element is visible + virtual com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > getProperties() const; + virtual void setProperties( const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& ); + sal_Int32 getExpandPriority( size_t i_nIndex ) const { const Element* pEle = getConstElement( i_nIndex ); @@ -173,6 +185,19 @@ namespace vcl } } + void getBorders( size_t i_nIndex, long* i_pLeft = NULL, long* i_pTop = NULL, long* i_pRight = NULL, long* i_pBottom = NULL ) const + { + const Element* pEle = getConstElement( i_nIndex ); + if( pEle ) + { + if( i_pLeft ) *i_pLeft = pEle->m_nLeftBorder; + if( i_pTop ) *i_pTop = pEle->m_nTopBorder; + if( i_pRight ) *i_pRight = pEle->m_nRightBorder; + if( i_pBottom ) *i_pBottom = pEle->m_nBottomBorder; + } + } + + void show( bool i_bShow = true, bool i_bImmediateUpdate = true ); void setManagedArea( const Rectangle& i_rArea ) @@ -187,6 +212,12 @@ namespace vcl m_nOuterBorder = i_nBorder; resize(); } + + const rtl::OUString getIdentifier() const + { return m_aIdentifier; } + + void setIdentifier( const rtl::OUString& i_rId ) + { m_aIdentifier = i_rId; } }; class VCL_DLLPUBLIC RowOrColumn : public WindowArranger @@ -204,7 +235,7 @@ namespace vcl public: RowOrColumn( WindowArranger* i_pParent = NULL, - bool bColumn = true, long i_nBorderWidth = 5 ) + bool bColumn = true, long i_nBorderWidth = -1 ) : WindowArranger( i_pParent ) , m_nBorderWidth( i_nBorderWidth ) , m_bColumn( bColumn ) @@ -218,7 +249,7 @@ namespace vcl // add a managed window at the given index // an index smaller than zero means add the window at the end - size_t addWindow( Window*, sal_Int32 i_nExpandPrio = 0, size_t i_nIndex = ~0 ); + size_t addWindow( Window*, sal_Int32 i_nExpandPrio = 0, const Size& i_rMinSize = Size(), size_t i_nIndex = ~0 ); void remove( Window* ); size_t addChild( boost::shared_ptr<WindowArranger> const &, sal_Int32 i_nExpandPrio = 0, size_t i_nIndex = ~0 ); @@ -248,7 +279,7 @@ namespace vcl } public: - LabeledElement( WindowArranger* i_pParent = NULL, int i_nLabelStyle = 0, long i_nDistance = 5 ) + LabeledElement( WindowArranger* i_pParent = NULL, int i_nLabelStyle = 0, long i_nDistance = -1 ) : WindowArranger( i_pParent ) , m_nDistance( i_nDistance ) , m_nLabelColumnWidth( 0 ) @@ -278,7 +309,7 @@ namespace vcl { long getLabelWidth() const; public: - LabelColumn( WindowArranger* i_pParent = NULL, long i_nBorderWidth = 5 ) + LabelColumn( WindowArranger* i_pParent = NULL, long i_nBorderWidth = -1 ) : RowOrColumn( i_pParent, true, i_nBorderWidth ) {} virtual ~LabelColumn(); @@ -288,7 +319,7 @@ namespace vcl // returns the index of the added label size_t addRow( Window* i_pLabel, boost::shared_ptr<WindowArranger> const& i_rElement, long i_nIndent = 0 ); - size_t addRow( Window* i_pLabel, Window* i_pElement, long i_nIndent = 0 ); + size_t addRow( Window* i_pLabel, Window* i_pElement, long i_nIndent = 0, const Size& i_rElementMinSize = Size() ); }; class VCL_DLLPUBLIC Indenter : public WindowArranger @@ -301,7 +332,7 @@ namespace vcl { return i_nIndex == 0 ? &m_aElement : NULL; } public: - Indenter( WindowArranger* i_pParent = NULL, long i_nIndent = 15 ) + Indenter( WindowArranger* i_pParent = NULL, long i_nIndent = 3*getDefaultBorder() ) : WindowArranger( i_pParent ) , m_nIndent( i_nIndent ) {} @@ -370,9 +401,10 @@ namespace vcl MatrixElement( Window* i_pWin, sal_uInt32 i_nX, sal_uInt32 i_nY, boost::shared_ptr<WindowArranger> const & i_pChild = boost::shared_ptr<WindowArranger>(), - sal_Int32 i_nExpandPriority = 0 + sal_Int32 i_nExpandPriority = 0, + const Size& i_rMinSize = Size() ) - : WindowArranger::Element( i_pWin, i_pChild, i_nExpandPriority ) + : WindowArranger::Element( i_pWin, i_pChild, i_nExpandPriority, i_rMinSize ) , m_nX( i_nX ) , m_nY( i_nY ) { @@ -397,8 +429,8 @@ namespace vcl public: MatrixArranger( WindowArranger* i_pParent = NULL, - long i_nBorderX = 5, - long i_nBorderY = 5 ) + long i_nBorderX = -1, + long i_nBorderY = -1 ) : WindowArranger( i_pParent ) , m_nBorderX( i_nBorderX ) , m_nBorderY( i_nBorderY ) @@ -411,7 +443,7 @@ namespace vcl virtual size_t countElements() const { return m_aElements.size(); } // add a managed window at the given matrix position - size_t addWindow( Window*, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio = 0 ); + size_t addWindow( Window*, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio = 0, const Size& i_rMinSize = Size() ); void remove( Window* ); size_t addChild( boost::shared_ptr<WindowArranger> const &, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio = 0 ); diff --git a/vcl/inc/vcl/pdfwriter.hxx b/vcl/inc/vcl/pdfwriter.hxx index 27dbbfc80c72..52e4b5014120 100644 --- a/vcl/inc/vcl/pdfwriter.hxx +++ b/vcl/inc/vcl/pdfwriter.hxx @@ -38,7 +38,8 @@ #include <vcl/font.hxx> #include <vcl/graphictools.hxx> -#include <com/sun/star/io/XOutputStream.hpp> +#include "com/sun/star/io/XOutputStream.hpp" +#include "com/sun/star/beans/XMaterialHolder.hpp" #include <list> #include <vector> @@ -64,16 +65,6 @@ namespace vcl class PDFExtOutDevData; -struct PDFDocInfo -{ - String Title; // document title - String Author; // document author - String Subject; // subject - String Keywords; // keywords - String Creator; // application that created the original document - String Producer; // OpenOffice -}; - struct PDFNote { String Title; // optional title for the popup containing the note @@ -471,7 +462,7 @@ public: FitVisible, ActionZoom }; -// These emuns are treated as integer while reading/writing to configuration +// These enums are treated as integer while reading/writing to configuration enum PDFPageLayout { DefaultLayout, @@ -492,20 +483,35 @@ public: /* The following structure describes the permissions used in PDF security */ - struct PDFSecPermissions + struct PDFEncryptionProperties { -//for both 40 and 128 bit security, see 3.5.2 PDF v 1.4 table 3.15, v 1.5 and v 1.6 table 3.20. - bool CanPrintTheDocument; + + bool Security128bit; // true to select 128 bit encryption, false for 40 bit + //for both 40 and 128 bit security, see 3.5.2 PDF v 1.4 table 3.15, v 1.5 and v 1.6 table 3.20. + bool CanPrintTheDocument; bool CanModifyTheContent; bool CanCopyOrExtract; bool CanAddOrModify; -//for revision 3 (bit 128 security) only + //for revision 3 (bit 128 security) only bool CanFillInteractive; bool CanExtractForAccessibility; bool CanAssemble; bool CanPrintFull; -//permission default set for 128 bit, accessibility only - PDFSecPermissions() : + + // encryption will only happen if EncryptionKey is not empty + // EncryptionKey is actually a construct out of OValue, UValue and DocumentIdentifier + // if these do not match, behavior is undefined, most likely an invalid PDF will be produced + // OValue, UValue, EncryptionKey and DocumentIdentifier can be computed from + // PDFDocInfo, Owner password and User password used the InitEncryption method which + // implements the algorithms described in the PDF reference chapter 3.5: Encryption + std::vector<sal_uInt8> OValue; + std::vector<sal_uInt8> UValue; + std::vector<sal_uInt8> EncryptionKey; + std::vector<sal_uInt8> DocumentIdentifier; + + //permission default set for 128 bit, accessibility only + PDFEncryptionProperties() : + Security128bit ( true ), CanPrintTheDocument ( false ), CanModifyTheContent ( false ), CanCopyOrExtract ( false ), @@ -515,6 +521,20 @@ The following structure describes the permissions used in PDF security CanAssemble ( false ), CanPrintFull ( false ) {} + + + bool Encrypt() const + { return ! OValue.empty() && ! UValue.empty() && ! DocumentIdentifier.empty(); } + }; + + struct PDFDocInfo + { + String Title; // document title + String Author; // document author + String Subject; // subject + String Keywords; // keywords + String Creator; // application that created the original document + String Producer; // OpenOffice }; struct PDFWriterContext @@ -573,12 +593,8 @@ The following structure describes the permissions used in PDF security sal_Int32 InitialPage; sal_Int32 OpenBookmarkLevels; // -1 means all levels - struct PDFSecPermissions AccessPermissions; - - bool Encrypt; // main encryption flag, must be true to encript - bool Security128bit; // true to select 128 bit encryption, false for 40 bit - rtl::OUString OwnerPassword; // owner password for PDF, in clear text - rtl::OUString UserPassword; // user password for PDF, in clear text + PDFWriter::PDFEncryptionProperties Encryption; + PDFWriter::PDFDocInfo DocumentInfo; com::sun::star::lang::Locale DocumentLocale; // defines the document default language sal_uInt32 DPIx, DPIy; // how to handle MapMode( MAP_PIXEL ) @@ -609,15 +625,13 @@ The following structure describes the permissions used in PDF security FirstPageLeft( false ), InitialPage( 1 ), OpenBookmarkLevels( -1 ), - AccessPermissions( ), - Encrypt( false ), - Security128bit( true ), + Encryption(), DPIx( 0 ), DPIy( 0 ) {} }; - PDFWriter( const PDFWriterContext& rContext ); + PDFWriter( const PDFWriterContext& rContext, const com::sun::star::uno::Reference< com::sun::star::beans::XMaterialHolder >& ); ~PDFWriter(); /** Returns an OutputDevice for formatting @@ -661,17 +675,6 @@ The following structure describes the permissions used in PDF security }; void PlayMetafile( const GDIMetaFile&, const PlayMetafileContext&, vcl::PDFExtOutDevData* pDevDat = NULL ); - /* - * set document info; due to the use of document information in building the PDF document ID, must be called before - * emitting anything. - */ - void SetDocInfo( const PDFDocInfo& rInfo ); - - /* - * get currently set document info - */ - const PDFDocInfo& GetDocInfo() const; - /* sets the document locale originally passed with the context to a new value * only affects the output if used before calling <code>Emit/code>. */ @@ -689,6 +692,12 @@ The following structure describes the permissions used in PDF security PDFVersion GetVersion() const; + static com::sun::star::uno::Reference< com::sun::star::beans::XMaterialHolder > + InitEncryption( const rtl::OUString& i_rOwnerPassword, + const rtl::OUString& i_rUserPassword, + bool b128Bit + ); + /* functions for graphics state */ /* flag values: see vcl/outdev.hxx */ void Push( USHORT nFlags = 0xffff ); diff --git a/vcl/inc/vcl/prndlg.hxx b/vcl/inc/vcl/prndlg.hxx index d53354c40b4a..1d16a2241485 100644 --- a/vcl/inc/vcl/prndlg.hxx +++ b/vcl/inc/vcl/prndlg.hxx @@ -128,7 +128,6 @@ namespace vcl // border around each page CheckBox maBorderCB; - vcl::RowOrColumn maLayout; boost::shared_ptr< vcl::RowOrColumn > mxBrochureDep; boost::shared_ptr< vcl::LabeledElement >mxPagesBtnLabel; @@ -144,7 +143,7 @@ namespace vcl void showAdvancedControls( bool ); - virtual void Resize(); + // virtual void Resize(); }; class JobTabPage : public TabPage @@ -176,7 +175,6 @@ namespace vcl long mnCollateUIMode; - vcl::RowOrColumn maLayout; boost::shared_ptr<vcl::RowOrColumn> mxPrintRange; boost::shared_ptr<vcl::WindowArranger> mxDetails; @@ -186,7 +184,7 @@ namespace vcl void readFromSettings(); void storeToSettings(); - virtual void Resize(); + // virtual void Resize(); void setupLayout(); }; @@ -199,7 +197,6 @@ namespace vcl CheckBox maCollateSingleJobsBox; CheckBox maReverseOrderBox; - vcl::RowOrColumn maLayout; boost::shared_ptr<vcl::RowOrColumn> mxOptGroup; OutputOptPage( Window*, const ResId& ); @@ -208,7 +205,7 @@ namespace vcl void readFromSettings(); void storeToSettings(); - virtual void Resize(); + // virtual void Resize(); void setupLayout(); }; @@ -253,7 +250,6 @@ namespace vcl rtl::OUString maPrintText; rtl::OUString maDefPrtText; - vcl::RowOrColumn maLayout; boost::shared_ptr<vcl::RowOrColumn> mxPreviewCtrls; Size maDetailsCollapsedSize; diff --git a/vcl/inc/vcl/svdata.hxx b/vcl/inc/vcl/svdata.hxx index a4ce806a7e8a..67aa6806be49 100644 --- a/vcl/inc/vcl/svdata.hxx +++ b/vcl/inc/vcl/svdata.hxx @@ -167,6 +167,8 @@ struct ImplSVAppData BOOL mbDialogCancel; // TRUE: Alle Dialog::Execute()-Aufrufe werden mit return FALSE sofort beendet BOOL mbNoYield; // Application::Yield will not wait for events if the queue is empty // essentially that makes it the same as Application::Reschedule + long mnDefaultLayoutBorder; // default value in pixel for layout distances used + // in window arrangers /** Controls whether showing any IME status window is toggled on or off. diff --git a/vcl/inc/vcl/window.h b/vcl/inc/vcl/window.h index ff76874de11a..4a7f1c644400 100644 --- a/vcl/inc/vcl/window.h +++ b/vcl/inc/vcl/window.h @@ -99,7 +99,10 @@ namespace dnd { class XDropTarget; } } } } } -namespace vcl { struct ControlLayoutData; } +namespace vcl { + struct ControlLayoutData; + struct ExtWindowImpl; +} @@ -237,6 +240,7 @@ public: ImplDelData* mpFirstDel; void* mpUserData; + vcl::ExtWindowImpl* mpExtImpl; Cursor* mpCursor; Pointer maPointer; Fraction maZoom; diff --git a/vcl/inc/vcl/window.hxx b/vcl/inc/vcl/window.hxx index d209becfb4ae..700a87695085 100644..100755 --- a/vcl/inc/vcl/window.hxx +++ b/vcl/inc/vcl/window.hxx @@ -50,6 +50,7 @@ #include <rtl/ustring.hxx> #include <cppuhelper/weakref.hxx> #include <com/sun/star/uno/Reference.hxx> +#include <boost/shared_ptr.hpp> class VirtualDevice; struct ImplDelData; @@ -94,6 +95,13 @@ namespace accessibility { namespace com { namespace sun { namespace star { +namespace beans { + struct PropertyValue; +}}}} + +namespace com { +namespace sun { +namespace star { namespace rendering { class XCanvas; class XSpriteCanvas; @@ -121,7 +129,11 @@ namespace dnd { class XDropTarget; } } } } } -namespace vcl { struct ControlLayoutData; } +namespace vcl { + struct ControlLayoutData; + class WindowArranger; + struct ExtWindowImpl; +} namespace svt { class PopupWindowControllerImpl; } @@ -475,6 +487,10 @@ public: SAL_DLLPRIVATE BOOL ImplUpdatePos(); SAL_DLLPRIVATE void ImplUpdateSysObjPos(); SAL_DLLPRIVATE WindowImpl* ImplGetWindowImpl() const { return mpWindowImpl; } + SAL_DLLPRIVATE void ImplFreeExtWindowImpl(); + // creates ExtWindowImpl on demand, but may return NULL (e.g. if mbInDtor) + SAL_DLLPRIVATE vcl::ExtWindowImpl* ImplGetExtWindowImpl() const; + SAL_DLLPRIVATE void ImplDeleteOwnedChildren(); /** check whether a font is suitable for UI The font to be tested will be checked whether it could display a @@ -540,6 +556,7 @@ public: SAL_DLLPRIVATE BOOL ImplRegisterAccessibleNativeFrame(); SAL_DLLPRIVATE void ImplRevokeAccessibleNativeFrame(); SAL_DLLPRIVATE void ImplCallResize(); + SAL_DLLPRIVATE void ImplExtResize(); SAL_DLLPRIVATE void ImplCallMove(); SAL_DLLPRIVATE Rectangle ImplOutputToUnmirroredAbsoluteScreenPixel( const Rectangle& rRect ) const; SAL_DLLPRIVATE void ImplMirrorFramePos( Point &pt ) const; @@ -1099,6 +1116,56 @@ public: virtual XubString GetSurroundingText() const; virtual Selection GetSurroundingTextSelection() const; + + // ExtImpl + + // layouting + boost::shared_ptr< vcl::WindowArranger > getLayout(); + + /* add a child Window + addWindow will do the following things + - insert the passed window into the child list (equivalent to i_pWin->SetParent( this )) + - mark the window as "owned", meaning that the added Window will be destroyed by + the parent's desctructor. + This means: do not pass in member windows or stack objects here. Do not cause + the destructor of the added window to be called in any way. + + to avoid ownership pass i_bTakeOwnership as "false" + */ + void addWindow( Window* i_pWin, bool i_bTakeOwnership = true ); + + /* remove a child Window + the remove window functions will + - reparent the searched window (equivalent to i_pWin->SetParent( i_pNewParent )) + - return a pointer to the removed window or NULL if i_pWin was not found + caution: ownership passes to the new parent or the caller, if the new parent was NULL + */ + Window* removeWindow( Window* i_pWin, Window* i_pNewParent = NULL ); + + /* return the identifier of this window + */ + const rtl::OUString& getIdentifier() const; + /* set an identifier + identifiers have only loosely defined rules per se + in context of Window they must be unique over the window + hierarchy you'd like to find them again using the findWindow method + */ + void setIdentifier( const rtl::OUString& ); + + /* returns the first found descendant that matches + the passed identifier or NULL + */ + Window* findWindow( const rtl::OUString& ) const; + + /* get/set properties + this will contain window properties (like visible, enabled) + as well as properties of derived classes (e.g. text of Edit fields) + */ + virtual com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue > getProperties() const; + /* + */ + virtual void setProperties( const com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValue >& ); + }; diff --git a/vcl/inc/vcl/wpropset.hxx b/vcl/inc/vcl/wpropset.hxx new file mode 100644 index 000000000000..409b629496e6 --- /dev/null +++ b/vcl/inc/vcl/wpropset.hxx @@ -0,0 +1,66 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef VCL_WPROPSET_HXX +#define VCL_WPROPSET_HXX + +#include "vcl/dllapi.h" + +#include "tools/link.hxx" +#include "vcl/arrange.hxx" + +#include "com/sun/star/beans/XPropertySet.hpp" + +class VclWindowEvent; + +namespace vcl +{ + class WindowPropertySetData; + class WindowPropertySetListener; + + class VCL_DLLPUBLIC WindowPropertySet + { + WindowPropertySetData* mpImpl; + + void addWindowToSet( Window* ); + void addLayoutToSet( const boost::shared_ptr<WindowArranger>& ); + void setupProperties(); + + DECL_LINK( ChildEventListener, VclWindowEvent* ); + + void propertyChange( const com::sun::star::beans::PropertyChangeEvent& ); + friend class vcl::WindowPropertySetListener; + + public: + WindowPropertySet( Window* i_pTopWindow, bool i_bTakeOwnership ); + ~WindowPropertySet(); + + com::sun::star::uno::Reference< com::sun::star::beans::XPropertySet > getPropertySet() const; + }; +} + +#endif diff --git a/vcl/prj/d.lst b/vcl/prj/d.lst index 9e6d39d925c0..6d452e8ee43f 100644 --- a/vcl/prj/d.lst +++ b/vcl/prj/d.lst @@ -154,4 +154,7 @@ mkdir: %_DEST%\inc%_EXT%\vcl ..\inc\vcl\helper.hxx %_DEST%\inc%_EXT%\vcl\helper.hxx ..\inc\vcl\strhelper.hxx %_DEST%\inc%_EXT%\vcl\strhelper.hxx ..\inc\vcl\lazydelete.hxx %_DEST%\inc%_EXT%\vcl\lazydelete.hxx +..\inc\vcl\arrange.hxx %_DEST%\inc%_EXT%\vcl\arrange.hxx +..\inc\vcl\wpropset.hxx %_DEST%\inc%_EXT%\vcl\wpropset.hxx ..\%__SRC%\misc\vcl.component %_DEST%\xml%_EXT%\vcl.component + diff --git a/vcl/source/app/svdata.cxx b/vcl/source/app/svdata.cxx index 03b0365cff63..935d2c1894ea 100644 --- a/vcl/source/app/svdata.cxx +++ b/vcl/source/app/svdata.cxx @@ -129,6 +129,9 @@ void ImplInitSVData() break; } } + + // mark default layout border as unitialized + pImplSVData->maAppData.mnDefaultLayoutBorder = -1; } // ----------------------------------------------------------------------- diff --git a/vcl/source/gdi/pdfwriter.cxx b/vcl/source/gdi/pdfwriter.cxx index 969bc51b3cac..23ce1dfa6169 100644 --- a/vcl/source/gdi/pdfwriter.cxx +++ b/vcl/source/gdi/pdfwriter.cxx @@ -38,9 +38,9 @@ PDFWriter::AnyWidget::~AnyWidget() { } -PDFWriter::PDFWriter( const PDFWriter::PDFWriterContext& rContext ) +PDFWriter::PDFWriter( const PDFWriter::PDFWriterContext& rContext, const com::sun::star::uno::Reference< com::sun::star::beans::XMaterialHolder >& xEnc ) : - pImplementation( new PDFWriterImpl( rContext, *this ) ) + pImplementation( new PDFWriterImpl( rContext, xEnc, *this ) ) { } @@ -69,16 +69,6 @@ PDFWriter::PDFVersion PDFWriter::GetVersion() const return ((PDFWriterImpl*)pImplementation)->getVersion(); } -void PDFWriter::SetDocInfo( const PDFDocInfo& rInfo ) -{ - ((PDFWriterImpl*)pImplementation)->setDocInfo( rInfo ); -} - -const PDFDocInfo& PDFWriter::GetDocInfo() const -{ - return ((PDFWriterImpl*)pImplementation)->getDocInfo(); -} - void PDFWriter::SetDocumentLocale( const com::sun::star::lang::Locale& rLoc ) { ((PDFWriterImpl*)pImplementation)->setDocumentLocale( rLoc ); @@ -570,7 +560,17 @@ std::set< PDFWriter::ErrorCode > PDFWriter::GetErrors() return ((PDFWriterImpl*)pImplementation)->getErrors(); } +com::sun::star::uno::Reference< com::sun::star::beans::XMaterialHolder > +PDFWriter::InitEncryption( const rtl::OUString& i_rOwnerPassword, + const rtl::OUString& i_rUserPassword, + bool b128Bit + ) +{ + return PDFWriterImpl::initEncryption( i_rOwnerPassword, i_rUserPassword, b128Bit ); +} + void PDFWriter::PlayMetafile( const GDIMetaFile& i_rMTF, const vcl::PDFWriter::PlayMetafileContext& i_rPlayContext, PDFExtOutDevData* i_pData ) { ((PDFWriterImpl*)pImplementation)->playMetafile( i_rMTF, i_pData, i_rPlayContext, NULL); } + diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index bf8ca03711b3..325ccef1c3a6 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -113,12 +113,10 @@ void doTestCode() aContext.Version = PDFWriter::PDF_1_4; aContext.Tagged = true; aContext.InitialPage = 2; + aContext.DocumentInfo.Title = OUString( RTL_CONSTASCII_USTRINGPARAM( "PDF export test document" ) ); + aContext.DocumentInfo.Producer = OUString( RTL_CONSTASCII_USTRINGPARAM( "VCL" ) ); PDFWriter aWriter( aContext ); - PDFDocInfo aDocInfo; - aDocInfo.Title = OUString( RTL_CONSTASCII_USTRINGPARAM( "PDF export test document" ) ); - aDocInfo.Producer = OUString( RTL_CONSTASCII_USTRINGPARAM( "VCL" ) ); - aWriter.SetDocInfo( aDocInfo ); aWriter.NewPage( 595, 842 ); aWriter.BeginStructureElement( PDFWriter::Document ); // set duration of 3 sec for first page @@ -496,6 +494,12 @@ static inline double pixelToPoint( sal_Int32 px ) { return double(px)/fDivisor; static inline double pixelToPoint( double px ) { return px/fDivisor; } static inline sal_Int32 pointToPixel( double pt ) { return sal_Int32(pt*fDivisor); } +const sal_uInt8 PDFWriterImpl::s_nPadString[32] = +{ + 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, + 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A +}; + static void appendHex( sal_Int8 nInt, OStringBuffer& rBuffer ) { static const sal_Char pHexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', @@ -1693,7 +1697,9 @@ void PDFWriterImpl::PDFPage::appendWaveLine( sal_Int32 nWidth, sal_Int32 nY, sal * class PDFWriterImpl */ -PDFWriterImpl::PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext, PDFWriter& i_rOuterFace ) + PDFWriterImpl::PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext, + const com::sun::star::uno::Reference< com::sun::star::beans::XMaterialHolder >& xEnc, + PDFWriter& i_rOuterFace) : m_pReferenceDevice( NULL ), m_aMapMode( MAP_POINT, Point(), Fraction( 1L, pointToPixel(1) ), Fraction( 1L, pointToPixel(1) ) ), @@ -1714,9 +1720,6 @@ PDFWriterImpl::PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext, PDFWr m_aCipher( (rtlCipher)NULL ), m_aDigest( NULL ), m_bEncryptThisStream( false ), - m_aDocID( 32 ), - m_aCreationDateString( 64 ), - m_aCreationMetaDateString( 64 ), m_pEncryptionBuffer( NULL ), m_nEncryptionBufferSize( 0 ), m_bIsPDF_A1( false ), @@ -1759,14 +1762,37 @@ PDFWriterImpl::PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext, PDFWr m_bOpen = true; -/* prepare the cypher engine, can be done in CTOR, free in DTOR */ + // setup DocInfo + setupDocInfo(); + /* prepare the cypher engine, can be done in CTOR, free in DTOR */ m_aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream ); m_aDigest = rtl_digest_createMD5(); -/* the size of the Codec default maximum */ + /* the size of the Codec default maximum */ checkEncryptionBufferSize( 0x4000 ); + if( xEnc.is() ) + prepareEncryption( xEnc ); + + if( m_aContext.Encryption.Encrypt() ) + { + // sanity check + if( m_aContext.Encryption.OValue.size() != ENCRYPTED_PWD_SIZE || + m_aContext.Encryption.UValue.size() != ENCRYPTED_PWD_SIZE || + m_aContext.Encryption.EncryptionKey.size() != MAXIMUM_RC4_KEY_LENGTH + ) + { + // the field lengths are invalid ? This was not setup by initEncryption. + // do not encrypt after all + m_aContext.Encryption.OValue.clear(); + m_aContext.Encryption.UValue.clear(); + OSL_ENSURE( 0, "encryption data failed sanity check, encryption disabled" ); + } + else // setup key lengths + m_nAccessPermissions = computeAccessPermissions( m_aContext.Encryption, m_nKeyLength, m_nRC4KeyLength ); + } + // write header OStringBuffer aBuffer( 20 ); aBuffer.append( "%PDF-" ); @@ -1812,139 +1838,138 @@ PDFWriterImpl::~PDFWriterImpl() rtl_freeMemory( m_pEncryptionBuffer ); } -void PDFWriterImpl::setDocInfo( const PDFDocInfo& rInfo ) +void PDFWriterImpl::setupDocInfo() { - m_aDocInfo.Title = rInfo.Title; - m_aDocInfo.Author = rInfo.Author; - m_aDocInfo.Subject = rInfo.Subject; - m_aDocInfo.Keywords = rInfo.Keywords; - m_aDocInfo.Creator = rInfo.Creator; - m_aDocInfo.Producer = rInfo.Producer; + std::vector< sal_uInt8 > aId; + computeDocumentIdentifier( aId, m_aContext.DocumentInfo, m_aCreationDateString, m_aCreationMetaDateString ); + if( m_aContext.Encryption.DocumentIdentifier.empty() ) + m_aContext.Encryption.DocumentIdentifier = aId; +} -//build the document id +void PDFWriterImpl::computeDocumentIdentifier( std::vector< sal_uInt8 >& o_rIdentifier, + const vcl::PDFWriter::PDFDocInfo& i_rDocInfo, + rtl::OString& o_rCString1, + rtl::OString& o_rCString2 + ) +{ + o_rIdentifier.clear(); + + //build the document id rtl::OString aInfoValuesOut; OStringBuffer aID( 1024 ); - if( m_aDocInfo.Title.Len() ) - appendUnicodeTextString( m_aDocInfo.Title, aID ); - if( m_aDocInfo.Author.Len() ) - appendUnicodeTextString( m_aDocInfo.Author, aID ); - if( m_aDocInfo.Subject.Len() ) - appendUnicodeTextString( m_aDocInfo.Subject, aID ); - if( m_aDocInfo.Keywords.Len() ) - appendUnicodeTextString( m_aDocInfo.Keywords, aID ); - if( m_aDocInfo.Creator.Len() ) - appendUnicodeTextString( m_aDocInfo.Creator, aID ); - if( m_aDocInfo.Producer.Len() ) - appendUnicodeTextString( m_aDocInfo.Producer, aID ); + if( i_rDocInfo.Title.Len() ) + appendUnicodeTextString( i_rDocInfo.Title, aID ); + if( i_rDocInfo.Author.Len() ) + appendUnicodeTextString( i_rDocInfo.Author, aID ); + if( i_rDocInfo.Subject.Len() ) + appendUnicodeTextString( i_rDocInfo.Subject, aID ); + if( i_rDocInfo.Keywords.Len() ) + appendUnicodeTextString( i_rDocInfo.Keywords, aID ); + if( i_rDocInfo.Creator.Len() ) + appendUnicodeTextString( i_rDocInfo.Creator, aID ); + if( i_rDocInfo.Producer.Len() ) + appendUnicodeTextString( i_rDocInfo.Producer, aID ); TimeValue aTVal, aGMT; oslDateTime aDT; osl_getSystemTime( &aGMT ); osl_getLocalTimeFromSystemTime( &aGMT, &aTVal ); osl_getDateTimeFromTimeValue( &aTVal, &aDT ); - m_aCreationDateString.append( "D:" ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) ); -//--> i59651, we fill the Metadata date string as well, if PDF/A is requested - if( m_bIsPDF_A1 ) - { -// according to ISO 19005-1:2005 6.7.3 the date is corrected for -// local time zone offset UTC only, whereas Acrobat 8 seems -// to use the localtime notation only -// according to a raccomandation in XMP Specification (Jan 2004, page 75) -// the Acrobat way seems the right approach - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) ); - m_aCreationMetaDateString.append( "-" ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) ); - m_aCreationMetaDateString.append( "-" ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) ); - m_aCreationMetaDateString.append( "T" ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) ); - m_aCreationMetaDateString.append( ":" ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) ); - m_aCreationMetaDateString.append( ":" ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) ); - } + rtl::OStringBuffer aCreationDateString(64), aCreationMetaDateString(64); + aCreationDateString.append( "D:" ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) ); + + //--> i59651, we fill the Metadata date string as well, if PDF/A is requested + // according to ISO 19005-1:2005 6.7.3 the date is corrected for + // local time zone offset UTC only, whereas Acrobat 8 seems + // to use the localtime notation only + // according to a raccomandation in XMP Specification (Jan 2004, page 75) + // the Acrobat way seems the right approach + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/1000)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/100)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year/10)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Year)%10)) ); + aCreationMetaDateString.append( "-" ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month/10)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Month)%10)) ); + aCreationMetaDateString.append( "-" ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day/10)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Day)%10)) ); + aCreationMetaDateString.append( "T" ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours/10)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Hours)%10)) ); + aCreationMetaDateString.append( ":" ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes/10)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Minutes)%10)) ); + aCreationMetaDateString.append( ":" ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds/10)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((aDT.Seconds)%10)) ); + sal_uInt32 nDelta = 0; if( aGMT.Seconds > aTVal.Seconds ) { - m_aCreationDateString.append( "-" ); + aCreationDateString.append( "-" ); nDelta = aGMT.Seconds-aTVal.Seconds; - if( m_bIsPDF_A1 ) - m_aCreationMetaDateString.append( "-" ); + aCreationMetaDateString.append( "-" ); } else if( aGMT.Seconds < aTVal.Seconds ) { - m_aCreationDateString.append( "+" ); + aCreationDateString.append( "+" ); nDelta = aTVal.Seconds-aGMT.Seconds; - if( m_bIsPDF_A1 ) - m_aCreationMetaDateString.append( "+" ); + aCreationMetaDateString.append( "+" ); } else { - m_aCreationDateString.append( "Z" ); - if( m_bIsPDF_A1 ) - m_aCreationMetaDateString.append( "Z" ); + aCreationDateString.append( "Z" ); + aCreationMetaDateString.append( "Z" ); } if( nDelta ) { - m_aCreationDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) ); - m_aCreationDateString.append( "'" ); - m_aCreationDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) ); - m_aCreationDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) ); - if( m_bIsPDF_A1 ) - { - m_aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) ); - m_aCreationMetaDateString.append( ":" ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) ); - m_aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) ); - } + aCreationDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) ); + aCreationDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) ); + aCreationDateString.append( "'" ); + aCreationDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) ); + aCreationDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) ); + + aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/36000)%10)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/3600)%10)) ); + aCreationMetaDateString.append( ":" ); + aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/600)%6)) ); + aCreationMetaDateString.append( (sal_Char)('0' + ((nDelta/60)%10)) ); } - m_aCreationDateString.append( "'" ); - aID.append( m_aCreationDateString.getStr(), m_aCreationDateString.getLength() ); + aCreationDateString.append( "'" ); + aID.append( aCreationDateString.getStr(), aCreationDateString.getLength() ); aInfoValuesOut = aID.makeStringAndClear(); + o_rCString1 = aCreationDateString.makeStringAndClear(); + o_rCString2 = aCreationMetaDateString.makeStringAndClear(); - DBG_ASSERT( m_aDigest != NULL, "PDFWrite_Impl::setDocInfo: cannot obtain a digest object !" ); - - m_aDocID.setLength( 0 ); - if( m_aDigest ) + rtlDigest aDigest = rtl_digest_createMD5(); + OSL_ENSURE( aDigest != NULL, "PDFWriterImpl::computeDocumentIdentifier: cannot obtain a digest object !" ); + if( aDigest ) { - osl_getSystemTime( &aGMT ); - rtlDigestError nError = rtl_digest_updateMD5( m_aDigest, &aGMT, sizeof( aGMT ) ); - if( nError == rtl_Digest_E_None ) - nError = rtl_digest_updateMD5( m_aDigest, m_aContext.URL.getStr(), m_aContext.URL.getLength()*sizeof(sal_Unicode) ); + rtlDigestError nError = rtl_digest_updateMD5( aDigest, &aGMT, sizeof( aGMT ) ); if( nError == rtl_Digest_E_None ) - nError = rtl_digest_updateMD5( m_aDigest, aInfoValuesOut.getStr(), aInfoValuesOut.getLength() ); + nError = rtl_digest_updateMD5( aDigest, aInfoValuesOut.getStr(), aInfoValuesOut.getLength() ); if( nError == rtl_Digest_E_None ) { -//the binary form of the doc id is needed for encryption stuff - rtl_digest_getMD5( m_aDigest, m_nDocID, 16 ); - for( unsigned int i = 0; i < 16; i++ ) - appendHex( m_nDocID[i], m_aDocID ); + o_rIdentifier = std::vector< sal_uInt8 >( 16, 0 ); + //the binary form of the doc id is needed for encryption stuff + rtl_digest_getMD5( aDigest, &o_rIdentifier[0], 16 ); } } } @@ -1957,7 +1982,7 @@ append the string as unicode hex, encrypted if needed inline void PDFWriterImpl::appendUnicodeTextStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, OStringBuffer& rOutBuffer ) { rOutBuffer.append( "<" ); - if( m_aContext.Encrypt ) + if( m_aContext.Encryption.Encrypt() ) { const sal_Unicode* pStr = rInString.getStr(); sal_Int32 nLen = rInString.getLength(); @@ -1994,7 +2019,7 @@ inline void PDFWriterImpl::appendLiteralStringEncrypt( rtl::OStringBuffer& rInSt rOutBuffer.append( "(" ); sal_Int32 nChars = rInString.getLength(); //check for encryption, if ok, encrypt the string, then convert with appndLiteralString - if( m_aContext.Encrypt && checkEncryptionBufferSize( nChars ) ) + if( m_aContext.Encryption.Encrypt() && checkEncryptionBufferSize( nChars ) ) { //encrypt the string in a buffer, then append it enableStringEncryption( nInObjectNumber ); @@ -2384,9 +2409,6 @@ SalLayout* PDFWriterImpl::GetTextLayout( ImplLayoutArgs& rArgs, ImplFontSelectDa sal_Int32 PDFWriterImpl::newPage( sal_Int32 nPageWidth, sal_Int32 nPageHeight, PDFWriter::Orientation eOrientation ) { - if( m_aContext.Encrypt && m_aPages.empty() ) - initEncryption(); - endPage(); m_nCurrentPage = m_aPages.size(); m_aPages.push_back( PDFPage(this, nPageWidth, nPageHeight, eOrientation ) ); @@ -5881,7 +5903,7 @@ bool PDFWriterImpl::emitCatalog() } // viewer preferences, if we had some, then emit if( m_aContext.HideViewerToolbar || - ( m_aContext.Version > PDFWriter::PDF_1_3 && m_aDocInfo.Title.Len() && m_aContext.DisplayPDFDocumentTitle ) || + ( m_aContext.Version > PDFWriter::PDF_1_3 && m_aContext.DocumentInfo.Title.Len() && m_aContext.DisplayPDFDocumentTitle ) || m_aContext.HideViewerMenubar || m_aContext.HideViewerWindowControls || m_aContext.FitWindow || m_aContext.CenterWindow || (m_aContext.FirstPageLeft && m_aContext.PageLayout == PDFWriter::ContinuousFacing ) || @@ -5898,7 +5920,7 @@ bool PDFWriterImpl::emitCatalog() aLine.append( "/FitWindow true\n" ); if( m_aContext.CenterWindow ) aLine.append( "/CenterWindow true\n" ); - if( m_aContext.Version > PDFWriter::PDF_1_3 && m_aDocInfo.Title.Len() && m_aContext.DisplayPDFDocumentTitle ) + if( m_aContext.Version > PDFWriter::PDF_1_3 && m_aContext.DocumentInfo.Title.Len() && m_aContext.DisplayPDFDocumentTitle ) aLine.append( "/DisplayDocTitle true\n" ); if( m_aContext.FirstPageLeft && m_aContext.PageLayout == PDFWriter::ContinuousFacing ) aLine.append( "/Direction/R2L\n" ); @@ -6002,40 +6024,40 @@ sal_Int32 PDFWriterImpl::emitInfoDict( ) aLine.append( nObject ); aLine.append( " 0 obj\n" "<<" ); - if( m_aDocInfo.Title.Len() ) + if( m_aContext.DocumentInfo.Title.Len() ) { aLine.append( "/Title" ); - appendUnicodeTextStringEncrypt( m_aDocInfo.Title, nObject, aLine ); + appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Title, nObject, aLine ); aLine.append( "\n" ); } - if( m_aDocInfo.Author.Len() ) + if( m_aContext.DocumentInfo.Author.Len() ) { aLine.append( "/Author" ); - appendUnicodeTextStringEncrypt( m_aDocInfo.Author, nObject, aLine ); + appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Author, nObject, aLine ); aLine.append( "\n" ); } - if( m_aDocInfo.Subject.Len() ) + if( m_aContext.DocumentInfo.Subject.Len() ) { aLine.append( "/Subject" ); - appendUnicodeTextStringEncrypt( m_aDocInfo.Subject, nObject, aLine ); + appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Subject, nObject, aLine ); aLine.append( "\n" ); } - if( m_aDocInfo.Keywords.Len() ) + if( m_aContext.DocumentInfo.Keywords.Len() ) { aLine.append( "/Keywords" ); - appendUnicodeTextStringEncrypt( m_aDocInfo.Keywords, nObject, aLine ); + appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Keywords, nObject, aLine ); aLine.append( "\n" ); } - if( m_aDocInfo.Creator.Len() ) + if( m_aContext.DocumentInfo.Creator.Len() ) { aLine.append( "/Creator" ); - appendUnicodeTextStringEncrypt( m_aDocInfo.Creator, nObject, aLine ); + appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Creator, nObject, aLine ); aLine.append( "\n" ); } - if( m_aDocInfo.Producer.Len() ) + if( m_aContext.DocumentInfo.Producer.Len() ) { aLine.append( "/Producer" ); - appendUnicodeTextStringEncrypt( m_aDocInfo.Producer, nObject, aLine ); + appendUnicodeTextStringEncrypt( m_aContext.DocumentInfo.Producer, nObject, aLine ); aLine.append( "\n" ); } @@ -6281,45 +6303,45 @@ sal_Int32 PDFWriterImpl::emitDocumentMetadata() aMetadataStream.append( " <pdfaid:conformance>A</pdfaid:conformance>\n" ); aMetadataStream.append( " </rdf:Description>\n" ); //... Dublin Core properties go here - if( m_aDocInfo.Title.Len() || - m_aDocInfo.Author.Len() || - m_aDocInfo.Subject.Len() ) + if( m_aContext.DocumentInfo.Title.Len() || + m_aContext.DocumentInfo.Author.Len() || + m_aContext.DocumentInfo.Subject.Len() ) { aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" ); aMetadataStream.append( " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n" ); - if( m_aDocInfo.Title.Len() ) + if( m_aContext.DocumentInfo.Title.Len() ) { // this is according to PDF/A-1, technical corrigendum 1 (2007-04-01) aMetadataStream.append( " <dc:title>\n" ); aMetadataStream.append( " <rdf:Alt>\n" ); aMetadataStream.append( " <rdf:li xml:lang=\"x-default\">" ); rtl::OUString aTitle; - escapeStringXML( m_aDocInfo.Title, aTitle ); + escapeStringXML( m_aContext.DocumentInfo.Title, aTitle ); aMetadataStream.append( OUStringToOString( aTitle, RTL_TEXTENCODING_UTF8 ) ); aMetadataStream.append( "</rdf:li>\n" ); aMetadataStream.append( " </rdf:Alt>\n" ); aMetadataStream.append( " </dc:title>\n" ); } - if( m_aDocInfo.Author.Len() ) + if( m_aContext.DocumentInfo.Author.Len() ) { aMetadataStream.append( " <dc:creator>\n" ); aMetadataStream.append( " <rdf:Seq>\n" ); aMetadataStream.append( " <rdf:li>" ); rtl::OUString aAuthor; - escapeStringXML( m_aDocInfo.Author, aAuthor ); + escapeStringXML( m_aContext.DocumentInfo.Author, aAuthor ); aMetadataStream.append( OUStringToOString( aAuthor , RTL_TEXTENCODING_UTF8 ) ); aMetadataStream.append( "</rdf:li>\n" ); aMetadataStream.append( " </rdf:Seq>\n" ); aMetadataStream.append( " </dc:creator>\n" ); } - if( m_aDocInfo.Subject.Len() ) + if( m_aContext.DocumentInfo.Subject.Len() ) { // this is according to PDF/A-1, technical corrigendum 1 (2007-04-01) aMetadataStream.append( " <dc:description>\n" ); aMetadataStream.append( " <rdf:Alt>\n" ); aMetadataStream.append( " <rdf:li xml:lang=\"x-default\">" ); rtl::OUString aSubject; - escapeStringXML( m_aDocInfo.Subject, aSubject ); + escapeStringXML( m_aContext.DocumentInfo.Subject, aSubject ); aMetadataStream.append( OUStringToOString( aSubject , RTL_TEXTENCODING_UTF8 ) ); aMetadataStream.append( "</rdf:li>\n" ); aMetadataStream.append( " </rdf:Alt>\n" ); @@ -6329,24 +6351,24 @@ sal_Int32 PDFWriterImpl::emitDocumentMetadata() } //... PDF properties go here - if( m_aDocInfo.Producer.Len() || - m_aDocInfo.Keywords.Len() ) + if( m_aContext.DocumentInfo.Producer.Len() || + m_aContext.DocumentInfo.Keywords.Len() ) { aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" ); aMetadataStream.append( " xmlns:pdf=\"http://ns.adobe.com/pdf/1.3/\">\n" ); - if( m_aDocInfo.Producer.Len() ) + if( m_aContext.DocumentInfo.Producer.Len() ) { aMetadataStream.append( " <pdf:Producer>" ); rtl::OUString aProducer; - escapeStringXML( m_aDocInfo.Producer, aProducer ); + escapeStringXML( m_aContext.DocumentInfo.Producer, aProducer ); aMetadataStream.append( OUStringToOString( aProducer , RTL_TEXTENCODING_UTF8 ) ); aMetadataStream.append( "</pdf:Producer>\n" ); } - if( m_aDocInfo.Keywords.Len() ) + if( m_aContext.DocumentInfo.Keywords.Len() ) { aMetadataStream.append( " <pdf:Keywords>" ); rtl::OUString aKeywords; - escapeStringXML( m_aDocInfo.Keywords, aKeywords ); + escapeStringXML( m_aContext.DocumentInfo.Keywords, aKeywords ); aMetadataStream.append( OUStringToOString( aKeywords , RTL_TEXTENCODING_UTF8 ) ); aMetadataStream.append( "</pdf:Keywords>\n" ); } @@ -6355,11 +6377,11 @@ sal_Int32 PDFWriterImpl::emitDocumentMetadata() aMetadataStream.append( " <rdf:Description rdf:about=\"\"\n" ); aMetadataStream.append( " xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\n" ); - if( m_aDocInfo.Creator.Len() ) + if( m_aContext.DocumentInfo.Creator.Len() ) { aMetadataStream.append( " <xmp:CreatorTool>" ); rtl::OUString aCreator; - escapeStringXML( m_aDocInfo.Creator, aCreator ); + escapeStringXML( m_aContext.DocumentInfo.Creator, aCreator ); aMetadataStream.append( OUStringToOString( aCreator , RTL_TEXTENCODING_UTF8 ) ); aMetadataStream.append( "</xmp:CreatorTool>\n" ); } @@ -6415,7 +6437,7 @@ bool PDFWriterImpl::emitTrailer() sal_Int32 nSecObject = 0; - if( m_aContext.Encrypt == true ) + if( m_aContext.Encryption.Encrypt() ) { //emit the security information //must be emitted as indirect dictionary object, since @@ -6429,16 +6451,16 @@ bool PDFWriterImpl::emitTrailer() aLineS.append( " 0 obj\n" "<</Filter/Standard/V " ); // check the version - if( m_aContext.Security128bit == true ) + if( m_aContext.Encryption.Security128bit ) aLineS.append( "2/Length 128/R 3" ); else aLineS.append( "1/R 2" ); // emit the owner password, must not be encrypted aLineS.append( "/O(" ); - appendLiteralString( (const sal_Char*)m_nEncryptedOwnerPassword, 32, aLineS ); + appendLiteralString( (const sal_Char*)&m_aContext.Encryption.OValue[0], sal_Int32(m_aContext.Encryption.OValue.size()), aLineS ); aLineS.append( ")/U(" ); - appendLiteralString( (const sal_Char*)m_nEncryptedUserPassword, 32, aLineS ); + appendLiteralString( (const sal_Char*)&m_aContext.Encryption.UValue[0], sal_Int32(m_aContext.Encryption.UValue.size()), aLineS ); aLineS.append( ")/P " );// the permission set aLineS.append( m_nAccessPermissions ); aLineS.append( ">>\nendobj\n\n" ); @@ -6504,13 +6526,21 @@ bool PDFWriterImpl::emitTrailer() aLine.append( nDocInfoObject ); aLine.append( " 0 R\n" ); } - if( m_aDocID.getLength() ) + if( ! m_aContext.Encryption.DocumentIdentifier.empty() ) { aLine.append( "/ID [ <" ); - aLine.append( m_aDocID.getStr(), m_aDocID.getLength() ); + for( std::vector< sal_uInt8 >::const_iterator it = m_aContext.Encryption.DocumentIdentifier.begin(); + it != m_aContext.Encryption.DocumentIdentifier.end(); ++it ) + { + appendHex( sal_Int8(*it), aLine ); + } aLine.append( ">\n" "<" ); - aLine.append( m_aDocID.getStr(), m_aDocID.getLength() ); + for( std::vector< sal_uInt8 >::const_iterator it = m_aContext.Encryption.DocumentIdentifier.begin(); + it != m_aContext.Encryption.DocumentIdentifier.end(); ++it ) + { + appendHex( sal_Int8(*it), aLine ); + } aLine.append( "> ]\n" ); } if( aDocChecksum.getLength() ) @@ -9668,7 +9698,7 @@ bool PDFWriterImpl::writeBitmapObject( BitmapEmit& rObject, bool bMask ) aLine.append( "[ /Indexed/DeviceRGB " ); aLine.append( (sal_Int32)(pAccess->GetPaletteEntryCount()-1) ); aLine.append( "\n<" ); - if( m_aContext.Encrypt ) + if( m_aContext.Encryption.Encrypt() ) { enableStringEncryption( rObject.m_nObject ); //check encryption buffer size @@ -12054,268 +12084,5 @@ void PDFWriterImpl::addStream( const String& rMimeType, PDFOutputStream* pStream } } -/************************************************************* -begin i12626 methods - -Implements Algorithm 3.2, step 1 only -*/ -void PDFWriterImpl::padPassword( rtl::OUString aPassword, sal_uInt8 *paPasswordTarget ) -{ -// get ansi-1252 version of the password string CHECKIT ! i12626 - rtl::OString aString = rtl::OUStringToOString( aPassword, RTL_TEXTENCODING_MS_1252 ); - -//copy the string to the target - sal_Int32 nToCopy = ( aString.getLength() < 32 ) ? aString.getLength() : 32; - sal_Int32 nCurrentChar; - - for( nCurrentChar = 0; nCurrentChar < nToCopy; nCurrentChar++ ) - paPasswordTarget[nCurrentChar] = (sal_uInt8)( aString.getStr()[nCurrentChar] ); - -//pad it - if( nCurrentChar < 32 ) - {//fill with standard byte string - sal_Int32 i,y; - for( i = nCurrentChar, y = 0 ; i < 32; i++, y++ ) - paPasswordTarget[i] = m_nPadString[y]; - } -} - -/********************************** -Algorithm 3.2 Compute the encryption key used - -step 1 should already be done before calling, the paThePaddedPassword parameter should contain -the padded password and must be 32 byte long, the encryption key is returned into the paEncryptionKey parameter, -it will be 16 byte long for 128 bit security; for 40 bit security only the first 5 bytes are used - -TODO: in pdf ver 1.5 and 1.6 the step 6 is different, should be implemented. See spec. - -*/ -void PDFWriterImpl::computeEncryptionKey(sal_uInt8 *paThePaddedPassword, sal_uInt8 *paEncryptionKey ) -{ -//step 2 - if( m_aDigest ) - { - rtlDigestError nError = rtl_digest_updateMD5( m_aDigest, paThePaddedPassword, ENCRYPTED_PWD_SIZE ); -//step 3 - if( nError == rtl_Digest_E_None ) - nError = rtl_digest_updateMD5( m_aDigest, m_nEncryptedOwnerPassword , sizeof( m_nEncryptedOwnerPassword ) ); -//Step 4 - sal_uInt8 nPerm[4]; - - nPerm[0] = (sal_uInt8)m_nAccessPermissions; - nPerm[1] = (sal_uInt8)( m_nAccessPermissions >> 8 ); - nPerm[2] = (sal_uInt8)( m_nAccessPermissions >> 16 ); - nPerm[3] = (sal_uInt8)( m_nAccessPermissions >> 24 ); - - if( nError == rtl_Digest_E_None ) - nError = rtl_digest_updateMD5( m_aDigest, nPerm , sizeof( nPerm ) ); - -//step 5, get the document ID, binary form - if( nError == rtl_Digest_E_None ) - nError = rtl_digest_updateMD5( m_aDigest, m_nDocID , sizeof( m_nDocID ) ); -//get the digest - sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; - if( nError == rtl_Digest_E_None ) - { - rtl_digest_getMD5( m_aDigest, nMD5Sum, sizeof( nMD5Sum ) ); - -//step 6, only if 128 bit - if( m_aContext.Security128bit ) - { - for( sal_Int32 i = 0; i < 50; i++ ) - { - nError = rtl_digest_updateMD5( m_aDigest, &nMD5Sum, sizeof( nMD5Sum ) ); - if( nError != rtl_Digest_E_None ) - break; - rtl_digest_getMD5( m_aDigest, nMD5Sum, sizeof( nMD5Sum ) ); - } - } - } -//Step 7 - for( sal_Int32 i = 0; i < MD5_DIGEST_SIZE; i++ ) - paEncryptionKey[i] = nMD5Sum[i]; - } -} - -/********************************** -Algorithm 3.3 Compute the encryption dictionary /O value, save into the class data member -the step numbers down here correspond to the ones in PDF v.1.4 specfication -*/ -void PDFWriterImpl::computeODictionaryValue() -{ -//step 1 already done, data is in m_nPaddedOwnerPassword -//step 2 - if( m_aDigest ) - { - rtlDigestError nError = rtl_digest_updateMD5( m_aDigest, &m_nPaddedOwnerPassword, sizeof( m_nPaddedOwnerPassword ) ); - if( nError == rtl_Digest_E_None ) - { - sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; - - rtl_digest_getMD5( m_aDigest, nMD5Sum, sizeof(nMD5Sum) ); -//step 3, only if 128 bit - if( m_aContext.Security128bit ) - { - sal_Int32 i; - for( i = 0; i < 50; i++ ) - { - nError = rtl_digest_updateMD5( m_aDigest, nMD5Sum, sizeof( nMD5Sum ) ); - if( nError != rtl_Digest_E_None ) - break; - rtl_digest_getMD5( m_aDigest, nMD5Sum, sizeof( nMD5Sum ) ); - } - } -//Step 4, the key is in nMD5Sum -//step 5 already done, data is in m_nPaddedUserPassword -//step 6 - rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, - nMD5Sum, m_nKeyLength , NULL, 0 ); -// encrypt the user password using the key set above - rtl_cipher_encodeARCFOUR( m_aCipher, m_nPaddedUserPassword, sizeof( m_nPaddedUserPassword ), // the data to be encrypted - m_nEncryptedOwnerPassword, sizeof( m_nEncryptedOwnerPassword ) ); //encrypted data, stored in class data member -//Step 7, only if 128 bit - if( m_aContext.Security128bit ) - { - sal_uInt32 i, y; - sal_uInt8 nLocalKey[ SECUR_128BIT_KEY ]; // 16 = 128 bit key - for( i = 1; i <= 19; i++ ) // do it 19 times, start with 1 - { - for( y = 0; y < sizeof( nLocalKey ); y++ ) - nLocalKey[y] = (sal_uInt8)( nMD5Sum[y] ^ i ); - - rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, - nLocalKey, SECUR_128BIT_KEY, NULL, 0 ); //destination data area, on init can be NULL - rtl_cipher_encodeARCFOUR( m_aCipher, m_nEncryptedOwnerPassword, sizeof( m_nEncryptedOwnerPassword ), // the data to be encrypted - m_nEncryptedOwnerPassword, sizeof( m_nEncryptedOwnerPassword ) ); // encrypted data, can be the same as the input, encrypt "in place" -//step 8, store in class data member - } - } - } - } -} - -/********************************** -Algorithms 3.4 and 3.5 Compute the encryption dictionary /U value, save into the class data member, revision 2 (40 bit) or 3 (128 bit) -*/ -void PDFWriterImpl::computeUDictionaryValue() -{ -//step 1, common to both 3.4 and 3.5 - computeEncryptionKey( m_nPaddedUserPassword , m_nEncryptionKey ); - - if( m_aContext.Security128bit == false ) - { -//3.4 -//step 2 and 3 - rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, - m_nEncryptionKey, 5 , // key and key length - NULL, 0 ); //destination data area -// encrypt the user password using the key set above, save for later use - rtl_cipher_encodeARCFOUR( m_aCipher, m_nPadString, sizeof( m_nPadString ), // the data to be encrypted - m_nEncryptedUserPassword, sizeof( m_nEncryptedUserPassword ) ); //encrypted data, stored in class data member - } - else - { -//or 3.5, for 128 bit security -//step6, initilize the last 16 bytes of the encrypted user password to 0 - for(sal_uInt32 i = MD5_DIGEST_SIZE; i < sizeof( m_nEncryptedUserPassword ); i++) - m_nEncryptedUserPassword[i] = 0; -//step 2 - if( m_aDigest ) - { - rtlDigestError nError = rtl_digest_updateMD5( m_aDigest, m_nPadString, sizeof( m_nPadString ) ); -//step 3 - if( nError == rtl_Digest_E_None ) - nError = rtl_digest_updateMD5( m_aDigest, m_nDocID , sizeof(m_nDocID) ); - - sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; - rtl_digest_getMD5( m_aDigest, nMD5Sum, sizeof(nMD5Sum) ); -//Step 4 - rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, - m_nEncryptionKey, SECUR_128BIT_KEY, NULL, 0 ); //destination data area - rtl_cipher_encodeARCFOUR( m_aCipher, nMD5Sum, sizeof( nMD5Sum ), // the data to be encrypted - m_nEncryptedUserPassword, sizeof( nMD5Sum ) ); //encrypted data, stored in class data member -//step 5 - sal_uInt32 i, y; - sal_uInt8 nLocalKey[SECUR_128BIT_KEY]; - - for( i = 1; i <= 19; i++ ) // do it 19 times, start with 1 - { - for( y = 0; y < sizeof( nLocalKey ) ; y++ ) - nLocalKey[y] = (sal_uInt8)( m_nEncryptionKey[y] ^ i ); - - rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, - nLocalKey, SECUR_128BIT_KEY, // key and key length - NULL, 0 ); //destination data area, on init can be NULL - rtl_cipher_encodeARCFOUR( m_aCipher, m_nEncryptedUserPassword, SECUR_128BIT_KEY, // the data to be encrypted - m_nEncryptedUserPassword, SECUR_128BIT_KEY ); // encrypted data, can be the same as the input, encrypt "in place" - } - } - } -} - -/* init the encryption engine -1. init the document id, used both for building the document id and for building the encryption key(s) -2. build the encryption key following algorithms described in the PDF specification - */ -void PDFWriterImpl::initEncryption() -{ - m_aOwnerPassword = m_aContext.OwnerPassword; - m_aUserPassword = m_aContext.UserPassword; -/* password stuff computing, before sending out anything */ - DBG_ASSERT( m_aCipher != NULL, "PDFWriterImpl::initEncryption: a cipher (ARCFOUR) object is not available !" ); - DBG_ASSERT( m_aDigest != NULL, "PDFWriterImpl::initEncryption: a digest (MD5) object is not available !" ); - - if( m_aCipher && m_aDigest ) - { -//if there is no owner password, force it to the user password - if( m_aOwnerPassword.getLength() == 0 ) - m_aOwnerPassword = m_aUserPassword; - - initPadString(); -/* -1) pad passwords -*/ - padPassword( m_aOwnerPassword, m_nPaddedOwnerPassword ); - padPassword( m_aUserPassword, m_nPaddedUserPassword ); -/* -2) compute the access permissions, in numerical form - -the default value depends on the revision 2 (40 bit) or 3 (128 bit security): -- for 40 bit security the unused bit must be set to 1, since they are not used -- for 128 bit security the same bit must be preset to 0 and set later if needed -according to the table 3.15, pdf v 1.4 */ - m_nAccessPermissions = ( m_aContext.Security128bit ) ? 0xfffff0c0 : 0xffffffc0 ; - -/* check permissions for 40 bit security case */ - m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanPrintTheDocument ) ? 1 << 2 : 0; - m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanModifyTheContent ) ? 1 << 3 : 0; - m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanCopyOrExtract ) ? 1 << 4 : 0; - m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanAddOrModify ) ? 1 << 5 : 0; - m_nKeyLength = SECUR_40BIT_KEY; - m_nRC4KeyLength = SECUR_40BIT_KEY+5; // for this value see PDF spec v 1.4, algorithm 3.1 step 4, where n is 5 - - if( m_aContext.Security128bit ) - { - m_nKeyLength = SECUR_128BIT_KEY; - m_nRC4KeyLength = 16; // for this value see PDF spec v 1.4, algorithm 3.1 step 4, where n is 16, thus maximum - // permitted value is 16 - m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanFillInteractive ) ? 1 << 8 : 0; - m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanExtractForAccessibility ) ? 1 << 9 : 0; - m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanAssemble ) ? 1 << 10 : 0; - m_nAccessPermissions |= ( m_aContext.AccessPermissions.CanPrintFull ) ? 1 << 11 : 0; - } - computeODictionaryValue(); - computeUDictionaryValue(); - -//clear out exceding key values, prepares for generation number default to 0 as well -// see checkAndEnableStreamEncryption in pdfwriter_impl.hxx - sal_Int32 i, y; - for( i = m_nKeyLength, y = 0; y < 5 ; y++ ) - m_nEncryptionKey[i++] = 0; - } - else //either no cipher or no digest or both, something is wrong with memory or something else - m_aContext.Encrypt = false; //then turn the encryption off -} -/* end i12626 methods */ diff --git a/vcl/source/gdi/pdfwriter_impl.hxx b/vcl/source/gdi/pdfwriter_impl.hxx index 9457aea5f0c2..5702bee23ea5 100644 --- a/vcl/source/gdi/pdfwriter_impl.hxx +++ b/vcl/source/gdi/pdfwriter_impl.hxx @@ -58,6 +58,7 @@ class ImplFontSelectData; class ImplFontMetricData; class FontSubsetInfo; class ZCodec; +class EncHashTransporter; // the maximum password length #define ENCRYPTED_PWD_SIZE 32 @@ -595,7 +596,6 @@ private: MapMode m_aMapMode; // PDFWriterImpl scaled units std::vector< PDFPage > m_aPages; - PDFDocInfo m_aDocInfo; /* maps object numbers to file offsets (needed for xref) */ std::vector< sal_uInt64 > m_aObjects; /* contains Bitmaps until they are written to the @@ -796,116 +796,37 @@ i12626 /* used to cipher the stream data and for password management */ rtlCipher m_aCipher; rtlDigest m_aDigest; -/* pad string used for password in Standard security handler */ - sal_uInt8 m_nPadString[ENCRYPTED_PWD_SIZE]; -/* the owner password, in clear text */ - rtl::OUString m_aOwnerPassword; -/* the padded owner password */ - sal_uInt8 m_nPaddedOwnerPassword[ENCRYPTED_PWD_SIZE]; -/* the encryption dictionary owner password, according to algorithm 3.3 */ - sal_uInt8 m_nEncryptedOwnerPassword[ENCRYPTED_PWD_SIZE]; -/* the user password, in clear text */ - rtl::OUString m_aUserPassword; -/* the padded user password */ - sal_uInt8 m_nPaddedUserPassword[ENCRYPTED_PWD_SIZE]; -/* the encryption dictionary user password, according to algorithm 3.4 or 3.5 depending on the - security handler revision */ - sal_uInt8 m_nEncryptedUserPassword[ENCRYPTED_PWD_SIZE]; - -/* the encryption key, formed with the user password according to algorithm 3.2, maximum length is 16 bytes + 3 + 2 - for 128 bit security */ - sal_uInt8 m_nEncryptionKey[MAXIMUM_RC4_KEY_LENGTH]; + /* pad string used for password in Standard security handler */ + static const sal_uInt8 s_nPadString[ENCRYPTED_PWD_SIZE]; + + /* the encryption key, formed with the user password according to algorithm 3.2, maximum length is 16 bytes + 3 + 2 + for 128 bit security */ sal_Int32 m_nKeyLength; // key length, 16 or 5 sal_Int32 m_nRC4KeyLength; // key length, 16 or 10, to be input to the algorith 3.1 -/* set to true if the following stream must be encrypted, used inside writeBuffer() */ + /* set to true if the following stream must be encrypted, used inside writeBuffer() */ sal_Bool m_bEncryptThisStream; -/* the numerical value of the access permissions, according to PDF spec, must be signed */ + /* the numerical value of the access permissions, according to PDF spec, must be signed */ sal_Int32 m_nAccessPermissions; -/* the document ID, the raw MD5 hash */ - sal_uInt8 m_nDocID[MD5_DIGEST_SIZE]; -/* string buffer to hold document ID, this is the output string */ - rtl::OStringBuffer m_aDocID; -/* string to hold the PDF creation date */ - rtl::OStringBuffer m_aCreationDateString; -/* string to hold the PDF creation date, for PDF/A metadata */ - rtl::OStringBuffer m_aCreationMetaDateString; -/* the buffer where the data are encrypted, dynamically allocated */ + /* string to hold the PDF creation date */ + rtl::OString m_aCreationDateString; + /* string to hold the PDF creation date, for PDF/A metadata */ + rtl::OString m_aCreationMetaDateString; + /* the buffer where the data are encrypted, dynamically allocated */ sal_uInt8 *m_pEncryptionBuffer; -/* size of the buffer */ + /* size of the buffer */ sal_Int32 m_nEncryptionBufferSize; -/* check and reallocate the buffer for encryption */ - sal_Bool checkEncryptionBufferSize( register sal_Int32 newSize ) - { - if( m_nEncryptionBufferSize < newSize ) - { -/* reallocate the buffer, the used function allocate as rtl_allocateMemory - if the pointer parameter is NULL */ - m_pEncryptionBuffer = (sal_uInt8*)rtl_reallocateMemory( m_pEncryptionBuffer, newSize ); - if( m_pEncryptionBuffer ) - m_nEncryptionBufferSize = newSize; - else - m_nEncryptionBufferSize = 0; - } - return ( m_nEncryptionBufferSize != 0 ); - } -/* init the internal pad string */ - void initPadString() - { - static const sal_uInt8 nPadString[32] = - { - 0x28, 0xBF, 0x4E, 0x5E, 0x4E, 0x75, 0x8A, 0x41, 0x64, 0x00, 0x4E, 0x56, 0xFF, 0xFA, 0x01, 0x08, - 0x2E, 0x2E, 0x00, 0xB6, 0xD0, 0x68, 0x3E, 0x80, 0x2F, 0x0C, 0xA9, 0xFE, 0x64, 0x53, 0x69, 0x7A - }; - - for(sal_uInt32 i = 0; i < sizeof( nPadString ); i++ ) - m_nPadString[i] = nPadString[i]; - - }; -/* initialize the encryption engine */ - void initEncryption(); - -/* this function implements part of the PDF spec algorithm 3.1 in encryption, the rest (the actual encryption) is in PDFWriterImpl::writeBuffer */ - void checkAndEnableStreamEncryption( register sal_Int32 nObject ) - { - if( m_aContext.Encrypt ) - { - m_bEncryptThisStream = true; - register sal_Int32 i = m_nKeyLength; - m_nEncryptionKey[i++] = (sal_uInt8)nObject; - m_nEncryptionKey[i++] = (sal_uInt8)( nObject >> 8 ); - m_nEncryptionKey[i++] = (sal_uInt8)( nObject >> 16 ); -//the other location of m_nEncryptionKey are already set to 0, our fixed generation number -// do the MD5 hash - sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; - // the i+2 to take into account the generation number, always zero - rtl_digest_MD5( &m_nEncryptionKey, i+2, nMD5Sum, sizeof(nMD5Sum) ); -// initialize the RC4 with the key -// key legth: see algoritm 3.1, step 4: (N+5) max 16 - rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum, m_nRC4KeyLength, NULL, 0 ); - } - }; + /* check and reallocate the buffer for encryption */ + sal_Bool checkEncryptionBufferSize( register sal_Int32 newSize ); + /* this function implements part of the PDF spec algorithm 3.1 in encryption, the rest (the actual encryption) is in PDFWriterImpl::writeBuffer */ + void checkAndEnableStreamEncryption( register sal_Int32 nObject ); void disableStreamEncryption() { m_bEncryptThisStream = false; }; -/* */ - void enableStringEncryption( register sal_Int32 nObject ) - { - register sal_Int32 i = m_nKeyLength; - m_nEncryptionKey[i++] = (sal_uInt8)nObject; - m_nEncryptionKey[i++] = (sal_uInt8)( nObject >> 8 ); - m_nEncryptionKey[i++] = (sal_uInt8)( nObject >> 16 ); -//the other location of m_nEncryptionKey are already set to 0, our fixed generation number -// do the MD5 hash - sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; - // the i+2 to take into account the generation number, always zero - rtl_digest_MD5( &m_nEncryptionKey, i+2, nMD5Sum, sizeof(nMD5Sum) ); -// initialize the RC4 with the key -// key legth: see algoritm 3.1, step 4: (N+5) max 16 - rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum, m_nRC4KeyLength, NULL, 0 ); - }; + /* */ + void enableStringEncryption( register sal_Int32 nObject ); // test if the encryption is active, if yes than encrypt the unicode string and add to the OStringBuffer parameter void appendUnicodeTextStringEncrypt( const rtl::OUString& rInString, const sal_Int32 nInObjectNumber, rtl::OStringBuffer& rOutBuffer ); @@ -1097,18 +1018,38 @@ i12626 sal_Bool m_bIsPDF_A1; PDFWriter& m_rOuterFace; -/* -i12626 -methods for PDF security - - pad a password according algorithm 3.2, step 1 */ - void padPassword( const rtl::OUString aPassword, sal_uInt8 *paPasswordTarget ); -/* algorithm 3.2: compute an encryption key */ - void computeEncryptionKey( sal_uInt8 *paThePaddedPassword, sal_uInt8 *paEncryptionKey ); -/* algorithm 3.3: computing the encryption dictionary'ss owner password value ( /O ) */ - void computeODictionaryValue(); -/* algorithm 3.4 or 3.5: computing the encryption dictionary's user password value ( /U ) revision 2 or 3 of the standard security handler */ - void computeUDictionaryValue(); + /* + i12626 + methods for PDF security + + pad a password according algorithm 3.2, step 1 */ + static void padPassword( const rtl::OUString& i_rPassword, sal_uInt8* o_pPaddedPW ); + /* algorithm 3.2: compute an encryption key */ + static bool computeEncryptionKey( EncHashTransporter*, + vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, + sal_Int32 i_nAccessPermissions + ); + /* algorithm 3.3: computing the encryption dictionary'ss owner password value ( /O ) */ + static bool computeODictionaryValue( const sal_uInt8* i_pPaddedOwnerPassword, const sal_uInt8* i_pPaddedUserPassword, + std::vector< sal_uInt8 >& io_rOValue, + sal_Int32 i_nKeyLength + ); + /* algorithm 3.4 or 3.5: computing the encryption dictionary's user password value ( /U ) revision 2 or 3 of the standard security handler */ + static bool computeUDictionaryValue( EncHashTransporter* i_pTransporter, + vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, + sal_Int32 i_nKeyLength, + sal_Int32 i_nAccessPermissions + ); + + static void computeDocumentIdentifier( std::vector< sal_uInt8 >& o_rIdentifier, + const vcl::PDFWriter::PDFDocInfo& i_rDocInfo, + rtl::OString& o_rCString1, + rtl::OString& o_rCString2 + ); + static sal_Int32 computeAccessPermissions( const vcl::PDFWriter::PDFEncryptionProperties& i_rProperties, + sal_Int32& o_rKeyLength, sal_Int32& o_rRC4KeyLength ); + void setupDocInfo(); + bool prepareEncryption( const com::sun::star::uno::Reference< com::sun::star::beans::XMaterialHolder >& ); // helper for playMetafile void implWriteGradient( const PolyPolygon& rPolyPoly, const Gradient& rGradient, @@ -1117,9 +1058,14 @@ methods for PDF security VirtualDevice* pDummyVDev, const vcl::PDFWriter::PlayMetafileContext& ); public: - PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext, PDFWriter& ); + PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext, const com::sun::star::uno::Reference< com::sun::star::beans::XMaterialHolder >&, PDFWriter& ); ~PDFWriterImpl(); + static com::sun::star::uno::Reference< com::sun::star::beans::XMaterialHolder > + initEncryption( const rtl::OUString& i_rOwnerPassword, + const rtl::OUString& i_rUserPassword, + bool b128Bit ); + /* for OutputDevice so the reference device can have a list * that contains only suitable fonts (subsettable or builtin) * produces a new font list @@ -1152,8 +1098,6 @@ public: } PDFWriter::PDFVersion getVersion() const { return m_aContext.Version; } - void setDocInfo( const PDFDocInfo& rInfo ); - const PDFDocInfo& getDocInfo() const { return m_aDocInfo; } void setDocumentLocale( const com::sun::star::lang::Locale& rLoc ) { m_aContext.DocumentLocale = rLoc; } diff --git a/vcl/source/gdi/pdfwriter_impl2.cxx b/vcl/source/gdi/pdfwriter_impl2.cxx index c01b8a9771d8..ee1fe1cc6bc5 100644 --- a/vcl/source/gdi/pdfwriter_impl2.cxx +++ b/vcl/source/gdi/pdfwriter_impl2.cxx @@ -28,6 +28,7 @@ #include "precompiled_vcl.hxx" #include "pdfwriter_impl.hxx" + #include "vcl/pdfextoutdevdata.hxx" #include "vcl/virdev.hxx" #include "vcl/gdimtf.hxx" @@ -36,12 +37,16 @@ #include "vcl/svdata.hxx" #include "unotools/streamwrap.hxx" #include "unotools/processfactory.hxx" - #include "comphelper/processfactory.hxx" + #include "com/sun/star/beans/PropertyValue.hpp" #include "com/sun/star/io/XSeekable.hpp" #include "com/sun/star/graphic/XGraphicProvider.hpp" +#include "cppuhelper/implbase1.hxx" + +#include <rtl/digest.h> + using namespace vcl; using namespace rtl; using namespace com::sun::star; @@ -1032,4 +1037,504 @@ void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevDa delete pPrivateDevice; } +// Encryption methods + +/* a crutch to transport an rtlDigest safely though UNO API + this is needed for the PDF export dialog, which otherwise would have to pass + clear text passwords down till they can be used in PDFWriter. Unfortunately + the MD5 sum of the password (which is needed to create the PDF encryption key) + is not sufficient, since an rtl MD5 digest cannot be created in an arbitrary state + which would be needed in PDFWriterImpl::computeEncryptionKey. +*/ +class EncHashTransporter : public cppu::WeakImplHelper1 < com::sun::star::beans::XMaterialHolder > +{ + rtlDigest maUDigest; + sal_IntPtr maID; + std::vector< sal_uInt8 > maOValue; + + static std::map< sal_IntPtr, EncHashTransporter* > sTransporters; +public: + EncHashTransporter() + : maUDigest( rtl_digest_createMD5() ) + { + maID = reinterpret_cast< sal_IntPtr >(this); + while( sTransporters.find( maID ) != sTransporters.end() ) // paranoia mode + maID++; + sTransporters[ maID ] = this; + } + + virtual ~EncHashTransporter() + { + sTransporters.erase( maID ); + if( maUDigest ) + rtl_digest_destroyMD5( maUDigest ); + OSL_TRACE( "EncHashTransporter freed\n" ); + } + + rtlDigest getUDigest() const { return maUDigest; }; + std::vector< sal_uInt8 >& getOValue() { return maOValue; } + void invalidate() + { + if( maUDigest ) + { + rtl_digest_destroyMD5( maUDigest ); + maUDigest = NULL; + } + } + + // XMaterialHolder + virtual uno::Any SAL_CALL getMaterial() throw() + { + return uno::makeAny( sal_Int64(maID) ); + } + + static EncHashTransporter* getEncHashTransporter( const uno::Reference< beans::XMaterialHolder >& ); + +}; + +std::map< sal_IntPtr, EncHashTransporter* > EncHashTransporter::sTransporters; + +EncHashTransporter* EncHashTransporter::getEncHashTransporter( const uno::Reference< beans::XMaterialHolder >& xRef ) +{ + EncHashTransporter* pResult = NULL; + if( xRef.is() ) + { + uno::Any aMat( xRef->getMaterial() ); + sal_Int64 nMat = 0; + if( aMat >>= nMat ) + { + std::map< sal_IntPtr, EncHashTransporter* >::iterator it = sTransporters.find( static_cast<sal_IntPtr>(nMat) ); + if( it != sTransporters.end() ) + pResult = it->second; + } + } + return pResult; +} + +sal_Bool PDFWriterImpl::checkEncryptionBufferSize( register sal_Int32 newSize ) +{ + if( m_nEncryptionBufferSize < newSize ) + { + /* reallocate the buffer, the used function allocate as rtl_allocateMemory + if the pointer parameter is NULL */ + m_pEncryptionBuffer = (sal_uInt8*)rtl_reallocateMemory( m_pEncryptionBuffer, newSize ); + if( m_pEncryptionBuffer ) + m_nEncryptionBufferSize = newSize; + else + m_nEncryptionBufferSize = 0; + } + return ( m_nEncryptionBufferSize != 0 ); +} + +void PDFWriterImpl::checkAndEnableStreamEncryption( register sal_Int32 nObject ) +{ + if( m_aContext.Encryption.Encrypt() ) + { + m_bEncryptThisStream = true; + sal_Int32 i = m_nKeyLength; + m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)nObject; + m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)( nObject >> 8 ); + m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)( nObject >> 16 ); + //the other location of m_nEncryptionKey are already set to 0, our fixed generation number + // do the MD5 hash + sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; + // the i+2 to take into account the generation number, always zero + rtl_digest_MD5( &m_aContext.Encryption.EncryptionKey[0], i+2, nMD5Sum, sizeof(nMD5Sum) ); + // initialize the RC4 with the key + // key legth: see algoritm 3.1, step 4: (N+5) max 16 + rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum, m_nRC4KeyLength, NULL, 0 ); + } +} + +void PDFWriterImpl::enableStringEncryption( register sal_Int32 nObject ) +{ + if( m_aContext.Encryption.Encrypt() ) + { + sal_Int32 i = m_nKeyLength; + m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)nObject; + m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)( nObject >> 8 ); + m_aContext.Encryption.EncryptionKey[i++] = (sal_uInt8)( nObject >> 16 ); + //the other location of m_nEncryptionKey are already set to 0, our fixed generation number + // do the MD5 hash + sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; + // the i+2 to take into account the generation number, always zero + rtl_digest_MD5( &m_aContext.Encryption.EncryptionKey[0], i+2, nMD5Sum, sizeof(nMD5Sum) ); + // initialize the RC4 with the key + // key legth: see algoritm 3.1, step 4: (N+5) max 16 + rtl_cipher_initARCFOUR( m_aCipher, rtl_Cipher_DirectionEncode, nMD5Sum, m_nRC4KeyLength, NULL, 0 ); + } +} + +/* init the encryption engine +1. init the document id, used both for building the document id and for building the encryption key(s) +2. build the encryption key following algorithms described in the PDF specification + */ +uno::Reference< beans::XMaterialHolder > PDFWriterImpl::initEncryption( const rtl::OUString& i_rOwnerPassword, + const rtl::OUString& i_rUserPassword, + bool b128Bit + ) +{ + uno::Reference< beans::XMaterialHolder > xResult; + if( i_rOwnerPassword.getLength() || i_rUserPassword.getLength() ) + { + EncHashTransporter* pTransporter = new EncHashTransporter; + xResult = pTransporter; + + // get padded passwords + sal_uInt8 aPadUPW[ENCRYPTED_PWD_SIZE], aPadOPW[ENCRYPTED_PWD_SIZE]; + padPassword( i_rOwnerPassword.getLength() ? i_rOwnerPassword : i_rUserPassword, aPadOPW ); + padPassword( i_rUserPassword, aPadUPW ); + sal_Int32 nKeyLength = SECUR_40BIT_KEY; + if( b128Bit ) + nKeyLength = SECUR_128BIT_KEY; + + if( computeODictionaryValue( aPadOPW, aPadUPW, pTransporter->getOValue(), nKeyLength ) ) + { + rtlDigest aDig = pTransporter->getUDigest(); + if( rtl_digest_updateMD5( aDig, aPadUPW, ENCRYPTED_PWD_SIZE ) != rtl_Digest_E_None ) + xResult.clear(); + } + else + xResult.clear(); + + // trash temporary padded cleartext PWDs + rtl_zeroMemory( aPadOPW, sizeof(aPadOPW) ); + rtl_zeroMemory( aPadUPW, sizeof(aPadUPW) ); + + } + return xResult; +} + +bool PDFWriterImpl::prepareEncryption( const uno::Reference< beans::XMaterialHolder >& xEnc ) +{ + bool bSuccess = false; + EncHashTransporter* pTransporter = EncHashTransporter::getEncHashTransporter( xEnc ); + if( pTransporter ) + { + sal_Int32 nKeyLength = 0, nRC4KeyLength = 0; + sal_Int32 nAccessPermissions = computeAccessPermissions( m_aContext.Encryption, nKeyLength, nRC4KeyLength ); + m_aContext.Encryption.OValue = pTransporter->getOValue(); + bSuccess = computeUDictionaryValue( pTransporter, m_aContext.Encryption, nKeyLength, nAccessPermissions ); + } + if( ! bSuccess ) + { + m_aContext.Encryption.OValue.clear(); + m_aContext.Encryption.UValue.clear(); + m_aContext.Encryption.EncryptionKey.clear(); + } + return bSuccess; +} + +sal_Int32 PDFWriterImpl::computeAccessPermissions( const vcl::PDFWriter::PDFEncryptionProperties& i_rProperties, + sal_Int32& o_rKeyLength, sal_Int32& o_rRC4KeyLength ) +{ + /* + 2) compute the access permissions, in numerical form + + the default value depends on the revision 2 (40 bit) or 3 (128 bit security): + - for 40 bit security the unused bit must be set to 1, since they are not used + - for 128 bit security the same bit must be preset to 0 and set later if needed + according to the table 3.15, pdf v 1.4 */ + sal_Int32 nAccessPermissions = ( i_rProperties.Security128bit ) ? 0xfffff0c0 : 0xffffffc0 ; + + /* check permissions for 40 bit security case */ + nAccessPermissions |= ( i_rProperties.CanPrintTheDocument ) ? 1 << 2 : 0; + nAccessPermissions |= ( i_rProperties.CanModifyTheContent ) ? 1 << 3 : 0; + nAccessPermissions |= ( i_rProperties.CanCopyOrExtract ) ? 1 << 4 : 0; + nAccessPermissions |= ( i_rProperties.CanAddOrModify ) ? 1 << 5 : 0; + o_rKeyLength = SECUR_40BIT_KEY; + o_rRC4KeyLength = SECUR_40BIT_KEY+5; // for this value see PDF spec v 1.4, algorithm 3.1 step 4, where n is 5 + + if( i_rProperties.Security128bit ) + { + o_rKeyLength = SECUR_128BIT_KEY; + o_rRC4KeyLength = 16; // for this value see PDF spec v 1.4, algorithm 3.1 step 4, where n is 16, thus maximum + // permitted value is 16 + nAccessPermissions |= ( i_rProperties.CanFillInteractive ) ? 1 << 8 : 0; + nAccessPermissions |= ( i_rProperties.CanExtractForAccessibility ) ? 1 << 9 : 0; + nAccessPermissions |= ( i_rProperties.CanAssemble ) ? 1 << 10 : 0; + nAccessPermissions |= ( i_rProperties.CanPrintFull ) ? 1 << 11 : 0; + } + return nAccessPermissions; +} + +/************************************************************* +begin i12626 methods + +Implements Algorithm 3.2, step 1 only +*/ +void PDFWriterImpl::padPassword( const rtl::OUString& i_rPassword, sal_uInt8* o_pPaddedPW ) +{ + // get ansi-1252 version of the password string CHECKIT ! i12626 + rtl::OString aString( rtl::OUStringToOString( i_rPassword, RTL_TEXTENCODING_MS_1252 ) ); + + //copy the string to the target + sal_Int32 nToCopy = ( aString.getLength() < ENCRYPTED_PWD_SIZE ) ? aString.getLength() : ENCRYPTED_PWD_SIZE; + sal_Int32 nCurrentChar; + + for( nCurrentChar = 0; nCurrentChar < nToCopy; nCurrentChar++ ) + o_pPaddedPW[nCurrentChar] = (sal_uInt8)( aString.getStr()[nCurrentChar] ); + + //pad it with standard byte string + sal_Int32 i,y; + for( i = nCurrentChar, y = 0 ; i < ENCRYPTED_PWD_SIZE; i++, y++ ) + o_pPaddedPW[i] = s_nPadString[y]; + + // trash memory of temporary clear text password + rtl_zeroMemory( (sal_Char*)aString.getStr(), aString.getLength() ); +} + +/********************************** +Algorithm 3.2 Compute the encryption key used + +step 1 should already be done before calling, the paThePaddedPassword parameter should contain +the padded password and must be 32 byte long, the encryption key is returned into the paEncryptionKey parameter, +it will be 16 byte long for 128 bit security; for 40 bit security only the first 5 bytes are used + +TODO: in pdf ver 1.5 and 1.6 the step 6 is different, should be implemented. See spec. + +*/ +bool PDFWriterImpl::computeEncryptionKey( EncHashTransporter* i_pTransporter, vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, sal_Int32 i_nAccessPermissions ) +{ + bool bSuccess = true; + sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; + + // transporter contains an MD5 digest with the padded user password already + rtlDigest aDigest = i_pTransporter->getUDigest(); + rtlDigestError nError = rtl_Digest_E_None; + if( aDigest ) + { + //step 3 + if( ! io_rProperties.OValue.empty() ) + nError = rtl_digest_updateMD5( aDigest, &io_rProperties.OValue[0] , sal_Int32(io_rProperties.OValue.size()) ); + else + bSuccess = false; + //Step 4 + sal_uInt8 nPerm[4]; + + nPerm[0] = (sal_uInt8)i_nAccessPermissions; + nPerm[1] = (sal_uInt8)( i_nAccessPermissions >> 8 ); + nPerm[2] = (sal_uInt8)( i_nAccessPermissions >> 16 ); + nPerm[3] = (sal_uInt8)( i_nAccessPermissions >> 24 ); + + if( nError == rtl_Digest_E_None ) + nError = rtl_digest_updateMD5( aDigest, nPerm , sizeof( nPerm ) ); + + //step 5, get the document ID, binary form + if( nError == rtl_Digest_E_None ) + nError = rtl_digest_updateMD5( aDigest, &io_rProperties.DocumentIdentifier[0], sal_Int32(io_rProperties.DocumentIdentifier.size()) ); + //get the digest + if( nError == rtl_Digest_E_None ) + { + rtl_digest_getMD5( aDigest, nMD5Sum, sizeof( nMD5Sum ) ); + + //step 6, only if 128 bit + if( io_rProperties.Security128bit ) + { + for( sal_Int32 i = 0; i < 50; i++ ) + { + nError = rtl_digest_updateMD5( aDigest, &nMD5Sum, sizeof( nMD5Sum ) ); + if( nError != rtl_Digest_E_None ) + { + bSuccess = false; + break; + } + rtl_digest_getMD5( aDigest, nMD5Sum, sizeof( nMD5Sum ) ); + } + } + } + } + else + bSuccess = false; + + i_pTransporter->invalidate(); + + //Step 7 + if( bSuccess ) + { + io_rProperties.EncryptionKey.resize( MAXIMUM_RC4_KEY_LENGTH ); + for( sal_Int32 i = 0; i < MD5_DIGEST_SIZE; i++ ) + io_rProperties.EncryptionKey[i] = nMD5Sum[i]; + } + else + io_rProperties.EncryptionKey.clear(); + + return bSuccess; +} + +/********************************** +Algorithm 3.3 Compute the encryption dictionary /O value, save into the class data member +the step numbers down here correspond to the ones in PDF v.1.4 specfication +*/ +bool PDFWriterImpl::computeODictionaryValue( const sal_uInt8* i_pPaddedOwnerPassword, + const sal_uInt8* i_pPaddedUserPassword, + std::vector< sal_uInt8 >& io_rOValue, + sal_Int32 i_nKeyLength + ) +{ + bool bSuccess = true; + + io_rOValue.resize( ENCRYPTED_PWD_SIZE ); + + rtlDigest aDigest = rtl_digest_createMD5(); + rtlCipher aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream ); + if( aDigest && aCipher) + { + //step 1 already done, data is in i_pPaddedOwnerPassword + //step 2 + + rtlDigestError nError = rtl_digest_updateMD5( aDigest, i_pPaddedOwnerPassword, ENCRYPTED_PWD_SIZE ); + if( nError == rtl_Digest_E_None ) + { + sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; + + rtl_digest_getMD5( aDigest, nMD5Sum, sizeof(nMD5Sum) ); +//step 3, only if 128 bit + if( i_nKeyLength == SECUR_128BIT_KEY ) + { + sal_Int32 i; + for( i = 0; i < 50; i++ ) + { + nError = rtl_digest_updateMD5( aDigest, nMD5Sum, sizeof( nMD5Sum ) ); + if( nError != rtl_Digest_E_None ) + { + bSuccess = false; + break; + } + rtl_digest_getMD5( aDigest, nMD5Sum, sizeof( nMD5Sum ) ); + } + } + //Step 4, the key is in nMD5Sum + //step 5 already done, data is in i_pPaddedUserPassword + //step 6 + rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode, + nMD5Sum, i_nKeyLength , NULL, 0 ); + // encrypt the user password using the key set above + rtl_cipher_encodeARCFOUR( aCipher, i_pPaddedUserPassword, ENCRYPTED_PWD_SIZE, // the data to be encrypted + &io_rOValue[0], sal_Int32(io_rOValue.size()) ); //encrypted data + //Step 7, only if 128 bit + if( i_nKeyLength == SECUR_128BIT_KEY ) + { + sal_uInt32 i, y; + sal_uInt8 nLocalKey[ SECUR_128BIT_KEY ]; // 16 = 128 bit key + + for( i = 1; i <= 19; i++ ) // do it 19 times, start with 1 + { + for( y = 0; y < sizeof( nLocalKey ); y++ ) + nLocalKey[y] = (sal_uInt8)( nMD5Sum[y] ^ i ); + + rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode, + nLocalKey, SECUR_128BIT_KEY, NULL, 0 ); //destination data area, on init can be NULL + rtl_cipher_encodeARCFOUR( aCipher, &io_rOValue[0], sal_Int32(io_rOValue.size()), // the data to be encrypted + &io_rOValue[0], sal_Int32(io_rOValue.size()) ); // encrypted data, can be the same as the input, encrypt "in place" + //step 8, store in class data member + } + } + } + else + bSuccess = false; + } + else + bSuccess = false; + + if( aDigest ) + rtl_digest_destroyMD5( aDigest ); + if( aCipher ) + rtl_cipher_destroyARCFOUR( aCipher ); + + if( ! bSuccess ) + io_rOValue.clear(); + return bSuccess; +} + +/********************************** +Algorithms 3.4 and 3.5 Compute the encryption dictionary /U value, save into the class data member, revision 2 (40 bit) or 3 (128 bit) +*/ +bool PDFWriterImpl::computeUDictionaryValue( EncHashTransporter* i_pTransporter, + vcl::PDFWriter::PDFEncryptionProperties& io_rProperties, + sal_Int32 i_nKeyLength, + sal_Int32 i_nAccessPermissions + ) +{ + bool bSuccess = true; + + io_rProperties.UValue.resize( ENCRYPTED_PWD_SIZE ); + + rtlDigest aDigest = rtl_digest_createMD5(); + rtlCipher aCipher = rtl_cipher_createARCFOUR( rtl_Cipher_ModeStream ); + if( aDigest && aCipher ) + { + //step 1, common to both 3.4 and 3.5 + if( computeEncryptionKey( i_pTransporter, io_rProperties, i_nAccessPermissions ) ) + { + // prepare encryption key for object + for( sal_Int32 i = i_nKeyLength, y = 0; y < 5 ; y++ ) + io_rProperties.EncryptionKey[i++] = 0; + + if( io_rProperties.Security128bit == false ) + { + //3.4 + //step 2 and 3 + rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode, + &io_rProperties.EncryptionKey[0], 5 , // key and key length + NULL, 0 ); //destination data area + // encrypt the user password using the key set above, save for later use + rtl_cipher_encodeARCFOUR( aCipher, s_nPadString, sizeof( s_nPadString ), // the data to be encrypted + &io_rProperties.UValue[0], sal_Int32(io_rProperties.UValue.size()) ); //encrypted data, stored in class data member + } + else + { + //or 3.5, for 128 bit security + //step6, initilize the last 16 bytes of the encrypted user password to 0 + for(sal_uInt32 i = MD5_DIGEST_SIZE; i < sal_uInt32(io_rProperties.UValue.size()); i++) + io_rProperties.UValue[i] = 0; + //step 2 + rtlDigestError nError = rtl_digest_updateMD5( aDigest, s_nPadString, sizeof( s_nPadString ) ); + //step 3 + if( nError == rtl_Digest_E_None ) + nError = rtl_digest_updateMD5( aDigest, &io_rProperties.DocumentIdentifier[0], sal_Int32(io_rProperties.DocumentIdentifier.size()) ); + else + bSuccess = false; + + sal_uInt8 nMD5Sum[ RTL_DIGEST_LENGTH_MD5 ]; + rtl_digest_getMD5( aDigest, nMD5Sum, sizeof(nMD5Sum) ); + //Step 4 + rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode, + &io_rProperties.EncryptionKey[0], SECUR_128BIT_KEY, NULL, 0 ); //destination data area + rtl_cipher_encodeARCFOUR( aCipher, nMD5Sum, sizeof( nMD5Sum ), // the data to be encrypted + &io_rProperties.UValue[0], sizeof( nMD5Sum ) ); //encrypted data, stored in class data member + //step 5 + sal_uInt32 i, y; + sal_uInt8 nLocalKey[SECUR_128BIT_KEY]; + + for( i = 1; i <= 19; i++ ) // do it 19 times, start with 1 + { + for( y = 0; y < sizeof( nLocalKey ) ; y++ ) + nLocalKey[y] = (sal_uInt8)( io_rProperties.EncryptionKey[y] ^ i ); + + rtl_cipher_initARCFOUR( aCipher, rtl_Cipher_DirectionEncode, + nLocalKey, SECUR_128BIT_KEY, // key and key length + NULL, 0 ); //destination data area, on init can be NULL + rtl_cipher_encodeARCFOUR( aCipher, &io_rProperties.UValue[0], SECUR_128BIT_KEY, // the data to be encrypted + &io_rProperties.UValue[0], SECUR_128BIT_KEY ); // encrypted data, can be the same as the input, encrypt "in place" + } + } + } + else + bSuccess = false; + } + else + bSuccess = false; + + if( aDigest ) + rtl_digest_destroyMD5( aDigest ); + if( aCipher ) + rtl_cipher_destroyARCFOUR( aCipher ); + + if( ! bSuccess ) + io_rProperties.UValue.clear(); + return bSuccess; +} + +/* end i12626 methods */ diff --git a/vcl/source/gdi/print2.cxx b/vcl/source/gdi/print2.cxx index 25ba80003fd7..5c2a742a10ba 100644 --- a/vcl/source/gdi/print2.cxx +++ b/vcl/source/gdi/print2.cxx @@ -407,6 +407,7 @@ static Rectangle ImplCalcActionBounds( const MetaAction& rAct, const OutputDevic { const MetaLineAction& rMetaLineAction = static_cast<const MetaLineAction&>(rAct); aActionBounds = Rectangle( rMetaLineAction.GetStartPoint(), rMetaLineAction.GetEndPoint() ); + aActionBounds.Justify(); const long nLineWidth(rMetaLineAction.GetLineInfo().GetWidth()); if(nLineWidth) { diff --git a/vcl/source/window/arrange.cxx b/vcl/source/window/arrange.cxx index 9749299d4d6b..f016ef2c053b 100644 --- a/vcl/source/window/arrange.cxx +++ b/vcl/source/window/arrange.cxx @@ -29,15 +29,37 @@ #include "vcl/arrange.hxx" #include "vcl/edit.hxx" +#include "vcl/svdata.hxx" +#include "vcl/svapp.hxx" + +#include "com/sun/star/beans/PropertyValue.hpp" +#include "com/sun/star/awt/Rectangle.hpp" #include "osl/diagnose.h" using namespace vcl; +using namespace com::sun::star; // ---------------------------------------- // vcl::WindowArranger //----------------------------------------- +long WindowArranger::getDefaultBorder() +{ + ImplSVData* pSVData = ImplGetSVData(); + long nResult = pSVData->maAppData.mnDefaultLayoutBorder; + if( nResult < 0 ) + { + OutputDevice* pDefDev = Application::GetDefaultDevice(); + if( pDefDev ) + { + Size aBorder( pDefDev->LogicToPixel( Size( 3, 3 ), MapMode( MAP_APPFONT ) ) ); + nResult = pSVData->maAppData.mnDefaultLayoutBorder = aBorder.Height(); + } + } + return nResult > 0 ? nResult : 0; +} + WindowArranger::~WindowArranger() {} @@ -156,16 +178,26 @@ Size WindowArranger::Element::getOptimalSize( WindowSizeType i_eType ) const Size aResult; if( ! m_bHidden ) { + bool bVisible = false; if( m_pElement && m_pElement->IsVisible() ) + { aResult = m_pElement->GetOptimalSize( i_eType ); - else if( m_pChild ) + bVisible = true; + } + else if( m_pChild && m_pChild->isVisible() ) + { aResult = m_pChild->getOptimalSize( i_eType ); - if( aResult.Width() < m_aMinSize.Width() ) - aResult.Width() = m_aMinSize.Width(); - if( aResult.Height() < m_aMinSize.Height() ) - aResult.Height() = m_aMinSize.Height(); - aResult.Width() += m_nLeftBorder + m_nRightBorder; - aResult.Height() += m_nTopBorder + m_nBottomBorder; + bVisible = true; + } + if( bVisible ) + { + if( aResult.Width() < m_aMinSize.Width() ) + aResult.Width() = m_aMinSize.Width(); + if( aResult.Height() < m_aMinSize.Height() ) + aResult.Height() = m_aMinSize.Height(); + aResult.Width() += getBorderValue( m_nLeftBorder ) + getBorderValue( m_nRightBorder ); + aResult.Height() += getBorderValue( m_nTopBorder ) + getBorderValue( m_nBottomBorder ); + } } return aResult; @@ -175,16 +207,74 @@ void WindowArranger::Element::setPosSize( const Point& i_rPos, const Size& i_rSi { Point aPoint( i_rPos ); Size aSize( i_rSize ); - aPoint.X() += m_nLeftBorder; - aPoint.Y() += m_nTopBorder; - aSize.Width() -= m_nLeftBorder + m_nRightBorder; - aSize.Height() -= m_nTopBorder + m_nBottomBorder; + aPoint.X() += getBorderValue( m_nLeftBorder ); + aPoint.Y() += getBorderValue( m_nTopBorder ); + aSize.Width() -= getBorderValue( m_nLeftBorder ) + getBorderValue( m_nRightBorder ); + aSize.Height() -= getBorderValue( m_nTopBorder ) + getBorderValue( m_nBottomBorder ); if( m_pElement ) m_pElement->SetPosSizePixel( aPoint, aSize ); else if( m_pChild ) m_pChild->setManagedArea( Rectangle( aPoint, aSize ) ); } +uno::Sequence< beans::PropertyValue > WindowArranger::getProperties() const +{ + uno::Sequence< beans::PropertyValue > aRet( 3 ); + aRet[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "OuterBorder" ) ); + aRet[0].Value = uno::makeAny( sal_Int32( getBorderValue( m_nOuterBorder ) ) ); + aRet[1].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ManagedArea" ) ); + awt::Rectangle aArea( m_aManagedArea.getX(), m_aManagedArea.getY(), m_aManagedArea.getWidth(), m_aManagedArea.getHeight() ); + aRet[1].Value = uno::makeAny( aArea ); + aRet[2].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Visible" ) ); + aRet[2].Value = uno::makeAny( sal_Bool( isVisible() ) ); + return aRet; +} + +void WindowArranger::setProperties( const uno::Sequence< beans::PropertyValue >& i_rProps ) +{ + const beans::PropertyValue* pProps = i_rProps.getConstArray(); + bool bResize = false; + for( sal_Int32 i = 0; i < i_rProps.getLength(); i++ ) + { + if( pProps[i].Name.equalsAscii( "OuterBorder" ) ) + { + sal_Int32 nVal = 0; + if( pProps[i].Value >>= nVal ) + { + if( getBorderValue( m_nOuterBorder ) != nVal ) + { + m_nOuterBorder = nVal; + bResize = true; + } + } + } + else if( pProps[i].Name.equalsAscii( "ManagedArea" ) ) + { + awt::Rectangle aArea( 0, 0, 0, 0 ); + if( pProps[i].Value >>= aArea ) + { + m_aManagedArea.setX( aArea.X ); + m_aManagedArea.setY( aArea.Y ); + m_aManagedArea.setWidth( aArea.Width ); + m_aManagedArea.setHeight( aArea.Height ); + bResize = true; + } + } + else if( pProps[i].Name.equalsAscii( "Visible" ) ) + { + sal_Bool bVal = sal_False; + if( pProps[i].Value >>= bVal ) + { + show( bVal, false ); + bResize = true; + } + } + } + if( bResize ) + resize(); +} + + // ---------------------------------------- // vcl::RowOrColumn //----------------------------------------- @@ -201,6 +291,7 @@ RowOrColumn::~RowOrColumn() Size RowOrColumn::getOptimalSize( WindowSizeType i_eType ) const { Size aRet( 0, 0 ); + long nDistance = getBorderValue( m_nBorderWidth ); for( std::vector< WindowArranger::Element >::const_iterator it = m_aElements.begin(); it != m_aElements.end(); ++it ) { @@ -211,7 +302,7 @@ Size RowOrColumn::getOptimalSize( WindowSizeType i_eType ) const if( m_bColumn ) { // add the distance between elements - aRet.Height() += m_nBorderWidth; + aRet.Height() += nDistance; // check if the width needs adjustment if( aRet.Width() < aElementSize.Width() ) aRet.Width() = aElementSize.Width(); @@ -220,7 +311,7 @@ Size RowOrColumn::getOptimalSize( WindowSizeType i_eType ) const else { // add the distance between elements - aRet.Width() += m_nBorderWidth; + aRet.Width() += nDistance; // check if the height needs adjustment if( aRet.Height() < aElementSize.Height() ) aRet.Height() = aElementSize.Height(); @@ -233,13 +324,14 @@ Size RowOrColumn::getOptimalSize( WindowSizeType i_eType ) const { // subtract the border for the first element if( m_bColumn ) - aRet.Height() -= m_nBorderWidth; + aRet.Height() -= nDistance; else - aRet.Width() -= m_nBorderWidth; + aRet.Width() -= nDistance; // add the outer border - aRet.Width() += 2*m_nOuterBorder; - aRet.Height() += 2*m_nOuterBorder; + long nOuterBorder = getBorderValue( m_nOuterBorder ); + aRet.Width() += 2*nOuterBorder; + aRet.Height() += 2*nOuterBorder; } return aRet; @@ -344,7 +436,9 @@ void RowOrColumn::resize() size_t nElements = m_aElements.size(); // get all element sizes for sizing std::vector<Size> aElementSizes( nElements ); - long nUsedWidth = 2*m_nOuterBorder - (nElements ? m_nBorderWidth : 0); + long nDistance = getBorderValue( m_nBorderWidth ); + long nOuterBorder = getBorderValue( m_nOuterBorder ); + long nUsedWidth = 2*nOuterBorder - (nElements ? nDistance : 0); for( size_t i = 0; i < nElements; i++ ) { if( m_aElements[i].isVisible() ) @@ -352,13 +446,13 @@ void RowOrColumn::resize() aElementSizes[i] = m_aElements[i].getOptimalSize( eType ); if( m_bColumn ) { - aElementSizes[i].Width() = m_aManagedArea.GetWidth() - 2* m_nOuterBorder; - nUsedWidth += aElementSizes[i].Height() + m_nBorderWidth; + aElementSizes[i].Width() = m_aManagedArea.GetWidth() - 2 * nOuterBorder; + nUsedWidth += aElementSizes[i].Height() + nDistance; } else { - aElementSizes[i].Height() = m_aManagedArea.GetHeight() - 2* m_nOuterBorder; - nUsedWidth += aElementSizes[i].Width() + m_nBorderWidth; + aElementSizes[i].Height() = m_aManagedArea.GetHeight() - 2 * nOuterBorder; + nUsedWidth += aElementSizes[i].Width() + nDistance; } } } @@ -375,8 +469,8 @@ void RowOrColumn::resize() // get starting position Point aElementPos( m_aManagedArea.TopLeft() ); // outer border - aElementPos.X() += m_nOuterBorder; - aElementPos.Y() += m_nOuterBorder; + aElementPos.X() += nOuterBorder; + aElementPos.Y() += nOuterBorder; // position managed windows for( size_t i = 0; i < nElements; i++ ) @@ -386,27 +480,27 @@ void RowOrColumn::resize() { m_aElements[i].setPosSize( aElementPos, aElementSizes[i] ); if( m_bColumn ) - aElementPos.Y() += m_nBorderWidth + aElementSizes[i].Height(); + aElementPos.Y() += nDistance + aElementSizes[i].Height(); else - aElementPos.X() += m_nBorderWidth + aElementSizes[i].Width(); + aElementPos.X() += nDistance + aElementSizes[i].Width(); } } } -size_t RowOrColumn::addWindow( Window* i_pWindow, sal_Int32 i_nExpandPrio, size_t i_nIndex ) +size_t RowOrColumn::addWindow( Window* i_pWindow, sal_Int32 i_nExpandPrio, const Size& i_rMinSize, size_t i_nIndex ) { size_t nIndex = i_nIndex; if( i_nIndex >= m_aElements.size() ) { nIndex = m_aElements.size(); - m_aElements.push_back( WindowArranger::Element( i_pWindow, boost::shared_ptr<WindowArranger>(), i_nExpandPrio ) ); + m_aElements.push_back( WindowArranger::Element( i_pWindow, boost::shared_ptr<WindowArranger>(), i_nExpandPrio, i_rMinSize ) ); } else { std::vector< WindowArranger::Element >::iterator it = m_aElements.begin(); while( i_nIndex-- ) ++it; - m_aElements.insert( it, WindowArranger::Element( i_pWindow, boost::shared_ptr<WindowArranger>(), i_nExpandPrio ) ); + m_aElements.insert( it, WindowArranger::Element( i_pWindow, boost::shared_ptr<WindowArranger>(), i_nExpandPrio, i_rMinSize ) ); } return nIndex; } @@ -479,14 +573,14 @@ Size LabeledElement::getOptimalSize( WindowSizeType i_eType ) const if( m_nLabelColumnWidth != 0 ) aRet.Width() = m_nLabelColumnWidth; else - aRet.Width() += m_nDistance; + aRet.Width() += getBorderValue( m_nDistance ); } Size aElementSize( m_aElement.getOptimalSize( i_eType ) ); aRet.Width() += aElementSize.Width(); if( aElementSize.Height() > aRet.Height() ) aRet.Height() = aElementSize.Height(); if( aRet.Height() != 0 ) - aRet.Height() += 2*m_nOuterBorder; + aRet.Height() += 2 * getBorderValue( m_nOuterBorder ); return aRet; } @@ -495,23 +589,25 @@ void LabeledElement::resize() { Size aLabelSize( m_aLabel.getOptimalSize( WINDOWSIZE_MINIMUM ) ); Size aElementSize( m_aElement.getOptimalSize( WINDOWSIZE_PREFERRED ) ); - if( m_nDistance + aLabelSize.Width() + aElementSize.Width() > m_aManagedArea.GetWidth() ) + long nDistance = getBorderValue( m_nDistance ); + long nOuterBorder = getBorderValue( m_nOuterBorder ); + if( nDistance + aLabelSize.Width() + aElementSize.Width() > m_aManagedArea.GetWidth() ) aElementSize = m_aElement.getOptimalSize( WINDOWSIZE_MINIMUM ); // align label and element vertically in LabeledElement - long nYOff = (m_aManagedArea.GetHeight() - 2*m_nOuterBorder - aLabelSize.Height()) / 2; + long nYOff = (m_aManagedArea.GetHeight() - 2*nOuterBorder - aLabelSize.Height()) / 2; Point aPos( m_aManagedArea.Left(), - m_aManagedArea.Top() + m_nOuterBorder + nYOff ); + m_aManagedArea.Top() + nOuterBorder + nYOff ); Size aSize( aLabelSize ); if( m_nLabelColumnWidth != 0 ) aSize.Width() = m_nLabelColumnWidth; m_aLabel.setPosSize( aPos, aSize ); - aPos.X() += aSize.Width() + m_nDistance; - nYOff = (m_aManagedArea.GetHeight() - 2*m_nOuterBorder - aElementSize.Height()) / 2; - aPos.Y() = m_aManagedArea.Top() + m_nOuterBorder + nYOff; + aPos.X() += aSize.Width() + nDistance; + nYOff = (m_aManagedArea.GetHeight() - 2*nOuterBorder - aElementSize.Height()) / 2; + aPos.Y() = m_aManagedArea.Top() + nOuterBorder + nYOff; aSize.Width() = aElementSize.Width(); - aSize.Height() = m_aManagedArea.GetHeight() - 2*m_nOuterBorder; + aSize.Height() = m_aManagedArea.GetHeight() - 2*nOuterBorder; // label style // 0: position left and right @@ -578,18 +674,22 @@ long LabelColumn::getLabelWidth() const if( pLW ) { Size aLabSize( pLW->GetOptimalSize( WINDOWSIZE_MINIMUM ) ); + long nLB = 0; + pLabel->getBorders(0, &nLB); + aLabSize.Width() += getBorderValue( nLB ); if( aLabSize.Width() > nWidth ) nWidth = aLabSize.Width(); } } } } - return nWidth + getBorderWidth(); + return nWidth + getBorderValue( getBorderWidth() ); } Size LabelColumn::getOptimalSize( WindowSizeType i_eType ) const { long nWidth = getLabelWidth(); + long nOuterBorder = getBorderValue( m_nOuterBorder ); Size aColumnSize; // every child is a LabeledElement @@ -622,19 +722,19 @@ Size LabelColumn::getOptimalSize( WindowSizeType i_eType ) const } if( aElementSize.Width() ) { - aElementSize.Width() += 2*m_nOuterBorder; + aElementSize.Width() += 2*nOuterBorder; if( aElementSize.Width() > aColumnSize.Width() ) aColumnSize.Width() = aElementSize.Width(); } if( aElementSize.Height() ) { - aColumnSize.Height() += getBorderWidth() + aElementSize.Height(); + aColumnSize.Height() += getBorderValue( getBorderWidth() ) + aElementSize.Height(); } } if( nEle > 0 && aColumnSize.Height() ) { - aColumnSize.Height() -= getBorderWidth(); // for the first element - aColumnSize.Height() += 2*m_nOuterBorder; + aColumnSize.Height() -= getBorderValue( getBorderWidth() ); // for the first element + aColumnSize.Height() += 2*nOuterBorder; } return aColumnSize; } @@ -667,12 +767,13 @@ size_t LabelColumn::addRow( Window* i_pLabel, boost::shared_ptr<WindowArranger> return nIndex; } -size_t LabelColumn::addRow( Window* i_pLabel, Window* i_pElement, long i_nIndent ) +size_t LabelColumn::addRow( Window* i_pLabel, Window* i_pElement, long i_nIndent, const Size& i_rElementMinSize ) { boost::shared_ptr< LabeledElement > xLabel( new LabeledElement( this, 1 ) ); xLabel->setLabel( i_pLabel ); xLabel->setBorders( 0, i_nIndent, 0, 0, 0 ); xLabel->setElement( i_pElement ); + xLabel->setMinimumSize( 1, i_rElementMinSize ); size_t nIndex = addChild( xLabel ); resize(); return nIndex; @@ -690,19 +791,23 @@ Indenter::~Indenter() Size Indenter::getOptimalSize( WindowSizeType i_eType ) const { Size aSize( m_aElement.getOptimalSize( i_eType ) ); - aSize.Width() += 2*m_nOuterBorder + m_nIndent; - aSize.Height() += 2*m_nOuterBorder; + long nOuterBorder = getBorderValue( m_nOuterBorder ); + long nIndent = getBorderValue( m_nIndent ); + aSize.Width() += 2*nOuterBorder + nIndent; + aSize.Height() += 2*nOuterBorder; return aSize; } void Indenter::resize() { + long nOuterBorder = getBorderValue( m_nOuterBorder ); + long nIndent = getBorderValue( m_nIndent ); Point aPt( m_aManagedArea.TopLeft() ); - aPt.X() += m_nOuterBorder + m_nIndent; - aPt.Y() += m_nOuterBorder; + aPt.X() += nOuterBorder + nIndent; + aPt.Y() += nOuterBorder; Size aSz( m_aManagedArea.GetSize() ); - aSz.Width() -= 2*m_nOuterBorder + m_nIndent; - aSz.Height() -= 2*m_nOuterBorder; + aSz.Width() -= 2*nOuterBorder + nIndent; + aSz.Height() -= 2*nOuterBorder; m_aElement.setPosSize( aPt, aSz ); } @@ -733,7 +838,8 @@ Size MatrixArranger::getOptimalSize( WindowSizeType i_eType, std::vector<sal_Int32>& o_rColumnPrio, std::vector<sal_Int32>& o_rRowPrio ) const { - Size aMatrixSize( 2*m_nOuterBorder, 2*m_nOuterBorder ); + long nOuterBorder = getBorderValue( m_nOuterBorder ); + Size aMatrixSize( 2*nOuterBorder, 2*nOuterBorder ); // first find out the current number of rows and columns sal_uInt32 nRows = 0, nColumns = 0; @@ -768,15 +874,17 @@ Size MatrixArranger::getOptimalSize( WindowSizeType i_eType, } // add up sizes + long nDistanceX = getBorderValue( m_nBorderX ); + long nDistanceY = getBorderValue( m_nBorderY ); for( sal_uInt32 i = 0; i < nColumns; i++ ) - aMatrixSize.Width() += o_rColumnWidths[i] + m_nBorderX; + aMatrixSize.Width() += o_rColumnWidths[i] + nDistanceX; if( nColumns > 0 ) - aMatrixSize.Width() -= m_nBorderX; + aMatrixSize.Width() -= nDistanceX; for( sal_uInt32 i = 0; i < nRows; i++ ) - aMatrixSize.Height() += o_rRowHeights[i] + m_nBorderY; + aMatrixSize.Height() += o_rRowHeights[i] + nDistanceY; if( nRows > 0 ) - aMatrixSize.Height() -= m_nBorderY; + aMatrixSize.Height() -= nDistanceY; return aMatrixSize; } @@ -860,15 +968,18 @@ void MatrixArranger::resize() distributeExtraSize( aRowHeights, aRowPrio, nExtraSize ); // prepare offsets + long nDistanceX = getBorderValue( m_nBorderX ); + long nDistanceY = getBorderValue( m_nBorderY ); + long nOuterBorder = getBorderValue( m_nOuterBorder ); std::vector<long> aColumnX( aColumnWidths.size() ); - aColumnX[0] = m_aManagedArea.Left() + m_nOuterBorder; + aColumnX[0] = m_aManagedArea.Left() + nOuterBorder; for( size_t i = 1; i < aColumnX.size(); i++ ) - aColumnX[i] = aColumnX[i-1] + aColumnWidths[i-1] + m_nBorderX; + aColumnX[i] = aColumnX[i-1] + aColumnWidths[i-1] + nDistanceX; std::vector<long> aRowY( aRowHeights.size() ); - aRowY[0] = m_aManagedArea.Top() + m_nOuterBorder; + aRowY[0] = m_aManagedArea.Top() + nOuterBorder; for( size_t i = 1; i < aRowY.size(); i++ ) - aRowY[i] = aRowY[i-1] + aRowHeights[i-1] + m_nBorderY; + aRowY[i] = aRowY[i-1] + aRowHeights[i-1] + nDistanceY; // now iterate over the elements and assign their positions for( std::vector< MatrixElement >::iterator it = m_aElements.begin(); @@ -880,7 +991,7 @@ void MatrixArranger::resize() } } -size_t MatrixArranger::addWindow( Window* i_pWindow, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio ) +size_t MatrixArranger::addWindow( Window* i_pWindow, sal_uInt32 i_nX, sal_uInt32 i_nY, sal_Int32 i_nExpandPrio, const Size& i_rMinSize ) { sal_uInt64 nMapValue = getMap( i_nX, i_nY ); std::map< sal_uInt64, size_t >::const_iterator it = m_aMatrixMap.find( nMapValue ); @@ -888,7 +999,7 @@ size_t MatrixArranger::addWindow( Window* i_pWindow, sal_uInt32 i_nX, sal_uInt32 if( it == m_aMatrixMap.end() ) { m_aMatrixMap[ nMapValue ] = nIndex = m_aElements.size(); - m_aElements.push_back( MatrixElement( i_pWindow, i_nX, i_nY, boost::shared_ptr<WindowArranger>(), i_nExpandPrio ) ); + m_aElements.push_back( MatrixElement( i_pWindow, i_nX, i_nY, boost::shared_ptr<WindowArranger>(), i_nExpandPrio, i_rMinSize ) ); } else { @@ -896,6 +1007,7 @@ size_t MatrixArranger::addWindow( Window* i_pWindow, sal_uInt32 i_nX, sal_uInt32 rEle.m_pElement = i_pWindow; rEle.m_pChild.reset(); rEle.m_nExpandPriority = i_nExpandPrio; + rEle.m_aMinSize = i_rMinSize; rEle.m_nX = i_nX; rEle.m_nY = i_nY; nIndex = it->second; diff --git a/vcl/source/window/makefile.mk b/vcl/source/window/makefile.mk index 82ce26f8e78e..1c63376dfda5 100644 --- a/vcl/source/window/makefile.mk +++ b/vcl/source/window/makefile.mk @@ -85,6 +85,8 @@ SLOFILES= \ $(SLO)$/winproc.obj \ $(SLO)$/window2.obj \ $(SLO)$/window3.obj \ + $(SLO)$/window4.obj \ + $(SLO)$/wpropset.obj \ $(SLO)$/wrkwin.obj # --- Targets ------------------------------------------------------ diff --git a/vcl/source/window/printdlg.cxx b/vcl/source/window/printdlg.cxx index 5e4e0d59ccc6..73420e6ef8b5 100644 --- a/vcl/source/window/printdlg.cxx +++ b/vcl/source/window/printdlg.cxx @@ -533,22 +533,21 @@ void PrintDialog::NUpTabPage::showAdvancedControls( bool i_bShow ) maSheetMarginTxt2.Show( i_bShow ); maNupOrientationTxt.Show( i_bShow ); maNupOrientationBox.Show( i_bShow ); - maLayout.resize(); + getLayout()->resize(); } void PrintDialog::NUpTabPage::setupLayout() { + boost::shared_ptr<vcl::RowOrColumn> xLayout = + boost::dynamic_pointer_cast<vcl::RowOrColumn>( getLayout() ); Size aBorder( LogicToPixel( Size( 6, 6 ), MapMode( MAP_APPFONT ) ) ); /* According to OOo style guide, the horizontal indentation of child elements to their parent element should always be 6 map units. */ long nIndent = aBorder.Width(); - maLayout.setParentWindow( this ); - maLayout.setOuterBorder( aBorder.Width() ); - - maLayout.addWindow( &maNupLine ); - boost::shared_ptr< vcl::RowOrColumn > xRow( new vcl::RowOrColumn( &maLayout, false ) ); - maLayout.addChild( xRow ); + xLayout->addWindow( &maNupLine ); + boost::shared_ptr< vcl::RowOrColumn > xRow( new vcl::RowOrColumn( xLayout.get(), false ) ); + xLayout->addChild( xRow ); boost::shared_ptr< vcl::Indenter > xIndent( new vcl::Indenter( xRow.get() ) ); xRow->addChild( xIndent ); @@ -584,7 +583,7 @@ void PrintDialog::NUpTabPage::setupLayout() xMainCol->addRow( &maNupOrderTxt, &maNupOrderBox, nIndent ); xMainCol->setBorders( xMainCol->addWindow( &maBorderCB ), nIndent, 0, 0, 0 ); - xSpacer.reset( new vcl::Spacer( xMainCol.get(), 0, Size( 10, aBorder.Width() ) ) ); + xSpacer.reset( new vcl::Spacer( xMainCol.get(), 0, Size( 10, WindowArranger::getDefaultBorder() ) ) ); xMainCol->addChild( xSpacer ); xRow.reset( new vcl::RowOrColumn( xMainCol.get(), false ) ); @@ -596,11 +595,6 @@ void PrintDialog::NUpTabPage::setupLayout() showAdvancedControls( false ); } -void PrintDialog::NUpTabPage::Resize() -{ - maLayout.setManagedArea( Rectangle( Point( 0, 0 ), GetOutputSizePixel() ) ); -} - void PrintDialog::NUpTabPage::initFromMultiPageSetup( const vcl::PrinterController::MultiPageSetup& i_rMPS ) { maSheetMarginEdt.SetValue( maSheetMarginEdt.Normalize( i_rMPS.nLeftMargin ), FUNIT_100TH_MM ); @@ -641,7 +635,6 @@ PrintDialog::JobTabPage::JobTabPage( Window* i_pParent, const ResId& rResId ) , maNoCollateImg( VclResId( SV_PRINT_NOCOLLATE_IMG ) ) , maNoCollateHCImg( VclResId( SV_PRINT_NOCOLLATE_HC_IMG ) ) , mnCollateUIMode( 0 ) - , maLayout( NULL, true ) { FreeResource(); @@ -681,39 +674,37 @@ void PrintDialog::JobTabPage::setupLayout() // sets the results of GetOptimalSize in a normal ListBox maPrinters.SetDropDownLineCount( 4 ); - Size aBorder( LogicToPixel( Size( 5, 5 ), MapMode( MAP_APPFONT ) ) ); - - maLayout.setParentWindow( this ); - maLayout.setOuterBorder( aBorder.Width() ); + boost::shared_ptr<vcl::RowOrColumn> xLayout = + boost::dynamic_pointer_cast<vcl::RowOrColumn>( getLayout() ); // add printer fixed line - maLayout.addWindow( &maPrinterFL ); + xLayout->addWindow( &maPrinterFL ); // add print LB - maLayout.addWindow( &maPrinters, 3 ); + xLayout->addWindow( &maPrinters, 3 ); // create a row for details button/text and properties button - boost::shared_ptr< vcl::RowOrColumn > xDetRow( new vcl::RowOrColumn( &maLayout, false ) ); - maLayout.addChild( xDetRow ); + boost::shared_ptr< vcl::RowOrColumn > xDetRow( new vcl::RowOrColumn( xLayout.get(), false ) ); + xLayout->addChild( xDetRow ); xDetRow->addWindow( &maDetailsBtn ); xDetRow->addChild( new vcl::Spacer( xDetRow.get(), 2 ) ); xDetRow->addWindow( &maSetupButton ); // create an indent for details - boost::shared_ptr< vcl::Indenter > xIndent( new vcl::Indenter( &maLayout ) ); - maLayout.addChild( xIndent ); + boost::shared_ptr< vcl::Indenter > xIndent( new vcl::Indenter( xLayout.get() ) ); + xLayout->addChild( xIndent ); // remember details controls mxDetails = xIndent; // create a column for the details - boost::shared_ptr< vcl::LabelColumn > xLabelCol( new vcl::LabelColumn( xIndent.get(), aBorder.Height() ) ); + boost::shared_ptr< vcl::LabelColumn > xLabelCol( new vcl::LabelColumn( xIndent.get() ) ); xIndent->setChild( xLabelCol ); xLabelCol->addRow( &maStatusLabel, &maStatusTxt ); xLabelCol->addRow( &maLocationLabel, &maLocationTxt ); xLabelCol->addRow( &maCommentLabel, &maCommentTxt ); // add print range and copies columns - maLayout.addWindow( &maCopies ); - boost::shared_ptr< vcl::RowOrColumn > xRangeRow( new vcl::RowOrColumn( &maLayout, false, aBorder.Width() ) ); - maLayout.addChild( xRangeRow ); + xLayout->addWindow( &maCopies ); + boost::shared_ptr< vcl::RowOrColumn > xRangeRow( new vcl::RowOrColumn( xLayout.get(), false ) ); + xLayout->addChild( xRangeRow ); // create print range and add to range row mxPrintRange.reset( new vcl::RowOrColumn( xRangeRow.get() ) ); @@ -780,11 +771,6 @@ void PrintDialog::JobTabPage::storeToSettings() rtl::OUString::createFromAscii( maCollateBox.IsChecked() ? "true" : "false" ) ); } -void PrintDialog::JobTabPage::Resize() -{ - maLayout.setManagedArea( Rectangle( Point( 0, 0 ), GetSizePixel() ) ); -} - PrintDialog::OutputOptPage::OutputOptPage( Window* i_pParent, const ResId& i_rResId ) : TabPage( i_pParent, i_rResId ) , maOptionsLine( this, VclResId( SV_PRINT_OPT_PRINT_FL ) ) @@ -808,15 +794,13 @@ PrintDialog::OutputOptPage::~OutputOptPage() void PrintDialog::OutputOptPage::setupLayout() { - Size aBorder( LogicToPixel( Size( 5, 5 ), MapMode( MAP_APPFONT ) ) ); + boost::shared_ptr<vcl::RowOrColumn> xLayout = + boost::dynamic_pointer_cast<vcl::RowOrColumn>( getLayout() ); - maLayout.setParentWindow( this ); - maLayout.setOuterBorder( aBorder.Width() ); - - maLayout.addWindow( &maOptionsLine ); - boost::shared_ptr<vcl::Indenter> xIndent( new vcl::Indenter( &maLayout, aBorder.Width() ) ); - maLayout.addChild( xIndent ); - boost::shared_ptr<vcl::RowOrColumn> xCol( new vcl::RowOrColumn( xIndent.get(), aBorder.Height() ) ); + xLayout->addWindow( &maOptionsLine ); + boost::shared_ptr<vcl::Indenter> xIndent( new vcl::Indenter( xLayout.get(), -1 ) ); + xLayout->addChild( xIndent ); + boost::shared_ptr<vcl::RowOrColumn> xCol( new vcl::RowOrColumn( xIndent.get() ) ); xIndent->setChild( xCol ); mxOptGroup = xCol; xCol->addWindow( &maToFileBox ); @@ -844,12 +828,6 @@ void PrintDialog::OutputOptPage::storeToSettings() rtl::OUString::createFromAscii( maToFileBox.IsChecked() ? "true" : "false" ) ); } -void PrintDialog::OutputOptPage::Resize() -{ - maLayout.setManagedArea( Rectangle( Point( 0, 0 ), GetSizePixel() ) ); -} - - PrintDialog::PrintDialog( Window* i_pParent, const boost::shared_ptr<PrinterController>& i_rController ) : ModalDialog( i_pParent, VclResId( SV_DLG_PRINT ) ) , maOKButton( this, VclResId( SV_PRINT_OK ) ) @@ -1057,13 +1035,14 @@ PrintDialog::~PrintDialog() void PrintDialog::setupLayout() { - Size aBorder( LogicToPixel( Size( 5, 5 ), MapMode( MAP_APPFONT ) ) ); + boost::shared_ptr<vcl::RowOrColumn> xLayout = + boost::dynamic_pointer_cast<vcl::RowOrColumn>( getLayout() ); + xLayout->setOuterBorder( 0 ); - maLayout.setParentWindow( this ); - boost::shared_ptr< vcl::RowOrColumn > xPreviewAndTab( new vcl::RowOrColumn( &maLayout, false ) ); - size_t nIndex = maLayout.addChild( xPreviewAndTab, 5 ); - maLayout.setBorders( nIndex, aBorder.Width(), aBorder.Width(), aBorder.Width(), 0 ); + boost::shared_ptr< vcl::RowOrColumn > xPreviewAndTab( new vcl::RowOrColumn( xLayout.get(), false ) ); + size_t nIndex = xLayout->addChild( xPreviewAndTab, 5 ); + xLayout->setBorders( nIndex, -1, -1, -1, 0 ); // setup column for preview and sub controls boost::shared_ptr< vcl::RowOrColumn > xPreview( new vcl::RowOrColumn( xPreviewAndTab.get() ) ); @@ -1087,12 +1066,12 @@ void PrintDialog::setupLayout() xPreviewAndTab->addWindow( &maTabCtrl ); // add the button line - maLayout.addWindow( &maButtonLine ); + xLayout->addWindow( &maButtonLine ); // add the row for the buttons - boost::shared_ptr< vcl::RowOrColumn > xButtons( new vcl::RowOrColumn( &maLayout, false ) ); - nIndex = maLayout.addChild( xButtons ); - maLayout.setBorders( nIndex, aBorder.Width(), 0, aBorder.Width(), aBorder.Width() ); + boost::shared_ptr< vcl::RowOrColumn > xButtons( new vcl::RowOrColumn( xLayout.get(), false ) ); + nIndex = xLayout->addChild( xButtons ); + xLayout->setBorders( nIndex, -1, 0, -1, -1 ); Size aMinSize( maCancelButton.GetSizePixel() ); // insert help button @@ -1210,17 +1189,15 @@ void updateMaxSize( const Size& i_rCheckSize, Size& o_rMaxSize ) void PrintDialog::setupOptionalUI() { - Size aBorder( LogicToPixel( Size( 5, 5 ), MapMode( MAP_APPFONT ) ) ); - - std::vector<vcl::RowOrColumn*> aDynamicColumns; - vcl::RowOrColumn* pCurColumn = 0; + std::vector< boost::shared_ptr<vcl::RowOrColumn> > aDynamicColumns; + boost::shared_ptr< vcl::RowOrColumn > pCurColumn; Window* pCurParent = 0, *pDynamicPageParent = 0; USHORT nOptPageId = 9, nCurSubGroup = 0; bool bOnStaticPage = false; bool bSubgroupOnStaticPage = false; - std::multimap< rtl::OUString, vcl::RowOrColumn* > aPropertyToDependencyRowMap; + std::multimap< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> > aPropertyToDependencyRowMap; const Sequence< PropertyValue >& rOptions( maPController->getUIOptions() ); for( int i = 0; i < rOptions.getLength(); i++ ) @@ -1331,37 +1308,40 @@ void PrintDialog::setupOptionalUI() { // restore to dynamic pCurParent = pDynamicPageParent; - pCurColumn = aDynamicColumns.empty() ? NULL : aDynamicColumns.back(); + if( ! aDynamicColumns.empty() ) + pCurColumn = aDynamicColumns.back(); + else + pCurColumn.reset(); bOnStaticPage = false; bSubgroupOnStaticPage = false; if( aGroupingHint.equalsAscii( "PrintRange" ) ) { - pCurColumn = maJobPage.mxPrintRange.get(); + pCurColumn = maJobPage.mxPrintRange; pCurParent = &maJobPage; // set job page as current parent bOnStaticPage = true; } else if( aGroupingHint.equalsAscii( "OptionsPage" ) ) { - pCurColumn = &maOptionsPage.maLayout; + pCurColumn = boost::dynamic_pointer_cast<vcl::RowOrColumn>(maOptionsPage.getLayout()); pCurParent = &maOptionsPage; // set options page as current parent bOnStaticPage = true; } else if( aGroupingHint.equalsAscii( "OptionsPageOptGroup" ) ) { - pCurColumn = maOptionsPage.mxOptGroup.get(); + pCurColumn = maOptionsPage.mxOptGroup; pCurParent = &maOptionsPage; // set options page as current parent bOnStaticPage = true; } else if( aGroupingHint.equalsAscii( "LayoutPage" ) ) { - pCurColumn = &maNUpPage.maLayout; + pCurColumn = boost::dynamic_pointer_cast<vcl::RowOrColumn>(maNUpPage.getLayout()); pCurParent = &maNUpPage; // set layout page as current parent bOnStaticPage = true; } else if( aGroupingHint.getLength() ) { - pCurColumn = &maJobPage.maLayout; + pCurColumn = boost::dynamic_pointer_cast<vcl::RowOrColumn>(maJobPage.getLayout()); pCurParent = &maJobPage; // set job page as current parent bOnStaticPage = true; } @@ -1386,10 +1366,9 @@ void PrintDialog::setupOptionalUI() // reset subgroup counter nCurSubGroup = 0; - aDynamicColumns.push_back( new vcl::RowOrColumn( NULL, true, aBorder.Width() ) ); + aDynamicColumns.push_back( boost::dynamic_pointer_cast<vcl::RowOrColumn>(pNewGroup->getLayout()) ); pCurColumn = aDynamicColumns.back(); pCurColumn->setParentWindow( pNewGroup ); - pCurColumn->setOuterBorder( aBorder.Width() ); bSubgroupOnStaticPage = false; bOnStaticPage = false; } @@ -1419,10 +1398,10 @@ void PrintDialog::setupOptionalUI() } // add an indent to the current column - vcl::Indenter* pIndent = new vcl::Indenter( pCurColumn, aBorder.Width() ); + vcl::Indenter* pIndent = new vcl::Indenter( pCurColumn.get(), -1 ); pCurColumn->addChild( pIndent ); // and create a column inside the indent - pCurColumn = new vcl::RowOrColumn( pIndent ); + pCurColumn.reset( new vcl::RowOrColumn( pIndent ) ); pIndent->setChild( pCurColumn ); } // EVIL @@ -1446,17 +1425,17 @@ void PrintDialog::setupOptionalUI() maPropertyToWindowMap[ aPropertyName ].push_back( &maNUpPage.maBrochureBtn ); maControlToPropertyMap[&maNUpPage.maBrochureBtn] = aPropertyName; - aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, vcl::RowOrColumn* >( aPropertyName, maNUpPage.mxBrochureDep.get() ) ); + aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >( aPropertyName, maNUpPage.mxBrochureDep ) ); } else { - vcl::RowOrColumn* pSaveCurColumn = pCurColumn; + boost::shared_ptr<vcl::RowOrColumn> pSaveCurColumn( pCurColumn ); if( bUseDependencyRow ) { // find the correct dependency row (if any) - std::pair< std::multimap< rtl::OUString, vcl::RowOrColumn* >::iterator, - std::multimap< rtl::OUString, vcl::RowOrColumn* >::iterator > aDepRange; + std::pair< std::multimap< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >::iterator, + std::multimap< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >::iterator > aDepRange; aDepRange = aPropertyToDependencyRowMap.equal_range( aDependsOnName ); if( aDepRange.first != aDepRange.second ) { @@ -1495,16 +1474,16 @@ void PrintDialog::setupOptionalUI() // set help text setHelpText( pNewBox, aHelpTexts, 0 ); - vcl::RowOrColumn* pDependencyRow = new vcl::RowOrColumn( pCurColumn, false ); + boost::shared_ptr<vcl::RowOrColumn> pDependencyRow( new vcl::RowOrColumn( pCurColumn.get(), false ) ); pCurColumn->addChild( pDependencyRow ); - aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, vcl::RowOrColumn* >( aPropertyName, pDependencyRow ) ); + aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >( aPropertyName, pDependencyRow ) ); // add checkbox to current column pDependencyRow->addWindow( pNewBox ); } else if( aCtrlType.equalsAscii( "Radio" ) && pCurParent ) { - vcl::RowOrColumn* pRadioColumn = pCurColumn; + boost::shared_ptr<vcl::RowOrColumn> pRadioColumn( pCurColumn ); if( aText.getLength() ) { // add a FixedText: @@ -1520,10 +1499,10 @@ void PrintDialog::setupOptionalUI() // add fixed text to current column pCurColumn->addWindow( pHeading ); // add an indent to the current column - vcl::Indenter* pIndent = new vcl::Indenter( pCurColumn, 15 ); + vcl::Indenter* pIndent = new vcl::Indenter( pCurColumn.get(), 15 ); pCurColumn->addChild( pIndent ); // and create a column inside the indent - pRadioColumn = new vcl::RowOrColumn( pIndent ); + pRadioColumn.reset( new vcl::RowOrColumn( pIndent ) ); pIndent->setChild( pRadioColumn ); } // iterate options @@ -1533,11 +1512,11 @@ void PrintDialog::setupOptionalUI() pVal->Value >>= nSelectVal; for( sal_Int32 m = 0; m < aChoices.getLength(); m++ ) { - boost::shared_ptr<vcl::LabeledElement> pLabel( new vcl::LabeledElement( pRadioColumn, 1 ) ); + boost::shared_ptr<vcl::LabeledElement> pLabel( new vcl::LabeledElement( pRadioColumn.get(), 1 ) ); pRadioColumn->addChild( pLabel ); boost::shared_ptr<vcl::RowOrColumn> pDependencyRow( new vcl::RowOrColumn( pLabel.get(), false ) ); pLabel->setElement( pDependencyRow ); - aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, vcl::RowOrColumn* >( aPropertyName, pDependencyRow.get() ) ); + aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >( aPropertyName, pDependencyRow ) ); RadioButton* pBtn = new RadioButton( pCurParent, m == 0 ? WB_GROUP : 0 ); maControls.push_front( pBtn ); @@ -1565,9 +1544,9 @@ void PrintDialog::setupOptionalUI() ) && pCurParent ) { // create a row in the current column - vcl::RowOrColumn* pFieldColumn = new vcl::RowOrColumn( pCurColumn, false ); + boost::shared_ptr<vcl::RowOrColumn> pFieldColumn( new vcl::RowOrColumn( pCurColumn.get(), false ) ); pCurColumn->addChild( pFieldColumn ); - aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, vcl::RowOrColumn* >( aPropertyName, pFieldColumn ) ); + aPropertyToDependencyRowMap.insert( std::pair< rtl::OUString, boost::shared_ptr<vcl::RowOrColumn> >( aPropertyName, pFieldColumn ) ); vcl::LabeledElement* pLabel = NULL; if( aText.getLength() ) @@ -1582,7 +1561,7 @@ void PrintDialog::setupOptionalUI() setSmartId( pHeading, "FixedText", -1, aPropertyName ); // add to row - pLabel = new vcl::LabeledElement( pFieldColumn, 2 ); + pLabel = new vcl::LabeledElement( pFieldColumn.get(), 2 ); pFieldColumn->addChild( pLabel ); pLabel->setLabel( pHeading ); } @@ -1717,11 +1696,11 @@ void PrintDialog::setupOptionalUI() // FIXME: the GetNativeControlRegion call on Windows has some issues // (which skew the results of GetOptimalSize()) // however fixing this thoroughly needs to take interaction with paint into - // acoount, making the right fix less simple. Fix this the right way + // account, making the right fix less simple. Fix this the right way // at some point. For now simply add some space at the lowest element - size_t nIndex = maJobPage.maLayout.countElements(); + size_t nIndex = maJobPage.getLayout()->countElements(); if( nIndex > 0 ) // sanity check - maJobPage.maLayout.setBorders( nIndex-1, 0, 0, 0, aBorder.Width() ); + maJobPage.getLayout()->setBorders( nIndex-1, 0, 0, 0, -1 ); #endif // create auto mnemomnics now so they can be calculated in layout @@ -1731,13 +1710,13 @@ void PrintDialog::setupOptionalUI() ImplWindowAutoMnemonic( this ); // calculate job page - Size aMaxSize = maJobPage.maLayout.getOptimalSize( WINDOWSIZE_PREFERRED ); + Size aMaxSize = maJobPage.getLayout()->getOptimalSize( WINDOWSIZE_PREFERRED ); // and layout page - updateMaxSize( maNUpPage.maLayout.getOptimalSize( WINDOWSIZE_PREFERRED ), aMaxSize ); + updateMaxSize( maNUpPage.getLayout()->getOptimalSize( WINDOWSIZE_PREFERRED ), aMaxSize ); // and options page - updateMaxSize( maOptionsPage.maLayout.getOptimalSize( WINDOWSIZE_PREFERRED ), aMaxSize ); + updateMaxSize( maOptionsPage.getLayout()->getOptimalSize( WINDOWSIZE_PREFERRED ), aMaxSize ); - for( std::vector< vcl::RowOrColumn* >::iterator it = aDynamicColumns.begin(); + for( std::vector< boost::shared_ptr<vcl::RowOrColumn> >::iterator it = aDynamicColumns.begin(); it != aDynamicColumns.end(); ++it ) { Size aPageSize( (*it)->getOptimalSize( WINDOWSIZE_PREFERRED ) ); @@ -1765,19 +1744,7 @@ void PrintDialog::setupOptionalUI() maTabCtrl.SetMinimumSizePixel( maTabCtrl.GetSizePixel() ); } - // and finally arrange controls - for( std::vector< vcl::RowOrColumn* >::iterator it = aDynamicColumns.begin(); - it != aDynamicColumns.end(); ++it ) - { - (*it)->setManagedArea( Rectangle( Point(), aTabSize ) ); - delete *it; - *it = NULL; - } - maJobPage.Resize(); - maNUpPage.Resize(); - maOptionsPage.Resize(); - - Size aSz = maLayout.getOptimalSize( WINDOWSIZE_PREFERRED ); + Size aSz = getLayout()->getOptimalSize( WINDOWSIZE_PREFERRED ); SetOutputSizePixel( aSz ); } @@ -1812,7 +1779,7 @@ void PrintDialog::checkControlDependencies() maJobPage.maCollateImage.SetSizePixel( aImgSize ); maJobPage.maCollateImage.SetImage( bHC ? aHCImg : aImg ); maJobPage.maCollateImage.SetModeImage( aHCImg, BMP_COLOR_HIGHCONTRAST ); - maJobPage.maLayout.resize(); + maJobPage.getLayout()->resize(); // enable setup button only for printers that can be setup bool bHaveSetup = maPController->getPrinter()->HasSupport( SUPPORT_SETUPDIALOG ); @@ -1827,7 +1794,7 @@ void PrintDialog::checkControlDependencies() aPrinterSize.Width() = aSetupPos.X() - aPrinterPos.X() - LogicToPixel( Size( 5, 5 ), MapMode( MAP_APPFONT ) ).Width(); maJobPage.maPrinters.SetSizePixel( aPrinterSize ); maJobPage.maSetupButton.Show(); - maLayout.resize(); + getLayout()->resize(); } } else @@ -1841,7 +1808,7 @@ void PrintDialog::checkControlDependencies() aPrinterSize.Width() = aSetupPos.X() + aSetupSize.Width() - aPrinterPos.X(); maJobPage.maPrinters.SetSizePixel( aPrinterSize ); maJobPage.maSetupButton.Hide(); - maLayout.resize(); + getLayout()->resize(); } } } @@ -2082,7 +2049,7 @@ void PrintDialog::updateNupFromPages() if( bCustom ) { // see if we have to enlarge the dialog to make the tab page fit - Size aCurSize( maNUpPage.maLayout.getOptimalSize( WINDOWSIZE_PREFERRED ) ); + Size aCurSize( maNUpPage.getLayout()->getOptimalSize( WINDOWSIZE_PREFERRED ) ); Size aTabSize( maTabCtrl.GetTabPageSizePixel() ); if( aTabSize.Height() < aCurSize.Height() ) { @@ -2205,7 +2172,7 @@ IMPL_LINK( PrintDialog, ClickHdl, Button*, pButton ) else if( pButton == &maOptionsPage.maToFileBox ) { maOKButton.SetText( maOptionsPage.maToFileBox.IsChecked() ? maPrintToFileText : maPrintText ); - maLayout.resize(); + getLayout()->resize(); } else if( pButton == &maNUpPage.maBrochureBtn ) { @@ -2241,7 +2208,7 @@ IMPL_LINK( PrintDialog, ClickHdl, Button*, pButton ) { maDetailsCollapsedSize = GetOutputSizePixel(); // enlarge dialog if necessary - Size aMinSize( maJobPage.maLayout.getOptimalSize( WINDOWSIZE_MINIMUM ) ); + Size aMinSize( maJobPage.getLayout()->getOptimalSize( WINDOWSIZE_MINIMUM ) ); Size aCurSize( maJobPage.GetSizePixel() ); if( aCurSize.Height() < aMinSize.Height() ) { @@ -2515,7 +2482,7 @@ void PrintDialog::Command( const CommandEvent& rEvt ) void PrintDialog::Resize() { - maLayout.setManagedArea( Rectangle( Point( 0, 0 ), GetSizePixel() ) ); + // maLayout.setManagedArea( Rectangle( Point( 0, 0 ), GetSizePixel() ) ); // and do the preview; however the metafile does not need to be gotten anew preparePreview( false ); diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx index 77da205131ea..f6bedc1bfa25 100755 --- a/vcl/source/window/window.cxx +++ b/vcl/source/window/window.cxx @@ -295,6 +295,8 @@ void Window::ImplUpdateGlobalSettings( AllSettings& rSettings, BOOL bCallHdl ) aTmpSt.SetHighContrastMode( FALSE ); rSettings.SetStyleSettings( aTmpSt ); ImplGetFrame()->UpdateSettings( rSettings ); + // reset default border width for layouters + ImplGetSVData()->maAppData.mnDefaultLayoutBorder = -1; // Verify availability of the configured UI font, otherwise choose "Andale Sans UI" String aUserInterfaceFont; @@ -599,6 +601,7 @@ void Window::ImplInitWindowData( WindowType nType ) mpWindowImpl->mpDlgCtrlDownWindow = NULL; // window for dialog control mpWindowImpl->mpFirstDel = NULL; // Dtor notification list mpWindowImpl->mpUserData = NULL; // user data + mpWindowImpl->mpExtImpl = NULL; // extended implementation data mpWindowImpl->mpCursor = NULL; // cursor mpWindowImpl->mpControlFont = NULL; // font propertie mpWindowImpl->mpVCLXWindow = NULL; @@ -1129,6 +1132,8 @@ void Window::ImplCallResize() // #88419# Most classes don't call the base class in Resize() and Move(), // => Call ImpleResize/Move instead of Resize/Move directly... ImplCallEventListeners( VCLEVENT_WINDOW_RESIZE ); + + ImplExtResize(); } // ----------------------------------------------------------------------- @@ -4342,6 +4347,8 @@ namespace Window::~Window() { + ImplFreeExtWindowImpl(); + vcl::LazyDeletor<Window>::Undelete( this ); DBG_DTOR( Window, ImplDbgCheckWindow ); diff --git a/vcl/source/window/window4.cxx b/vcl/source/window/window4.cxx new file mode 100644 index 000000000000..577a573c2015 --- /dev/null +++ b/vcl/source/window/window4.cxx @@ -0,0 +1,224 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_vcl.hxx" + +#include "vcl/window.hxx" +#include "vcl/window.h" +#include "vcl/svdata.hxx" +#include "vcl/arrange.hxx" + +#include "com/sun/star/beans/PropertyValue.hpp" + +#include <map> +#include <vector> + +using namespace com::sun::star; + +namespace vcl +{ + struct ExtWindowImpl + { + ExtWindowImpl() + : mbOwnedByParent( false ) + {} + ~ExtWindowImpl() + {} + + boost::shared_ptr< WindowArranger > mxLayout; + bool mbOwnedByParent; + rtl::OUString maIdentifier; + }; +} + +void Window::ImplDeleteOwnedChildren() +{ + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + Window* pDeleteCandidate = pChild; + pChild = pChild->mpWindowImpl->mpNext; + vcl::ExtWindowImpl* pDelImpl = pDeleteCandidate->ImplGetExtWindowImpl(); + if( pDelImpl && pDelImpl->mbOwnedByParent ) + delete pDeleteCandidate; + } +} + +void Window::ImplFreeExtWindowImpl() +{ + ImplDeleteOwnedChildren(); + if( mpWindowImpl ) + { + delete mpWindowImpl->mpExtImpl; + mpWindowImpl->mpExtImpl = NULL; + } +} + +vcl::ExtWindowImpl* Window::ImplGetExtWindowImpl() const +{ + vcl::ExtWindowImpl* pImpl = NULL; + if( mpWindowImpl ) + { + if( ! mpWindowImpl->mpExtImpl && ! mpWindowImpl->mbInDtor ) + mpWindowImpl->mpExtImpl = new vcl::ExtWindowImpl(); + pImpl = mpWindowImpl->mpExtImpl; + } + return pImpl; +} + +void Window::ImplExtResize() +{ + if( mpWindowImpl && mpWindowImpl->mpExtImpl ) + { + if( mpWindowImpl->mpExtImpl->mxLayout.get() ) + mpWindowImpl->mpExtImpl->mxLayout->setManagedArea( Rectangle( Point( 0, 0 ), GetSizePixel() ) ); + } +} + +boost::shared_ptr< vcl::WindowArranger > Window::getLayout() +{ + boost::shared_ptr< vcl::WindowArranger > xRet; + vcl::ExtWindowImpl* pImpl = ImplGetExtWindowImpl(); + if( pImpl ) + { + if( ! pImpl->mxLayout.get() ) + { + pImpl->mxLayout.reset( new vcl::LabelColumn() ); + pImpl->mxLayout->setParentWindow( this ); + pImpl->mxLayout->setOuterBorder( -1 ); + } + xRet = pImpl->mxLayout; + } + + return xRet; +} + +void Window::addWindow( Window* i_pWin, bool i_bTakeOwnership ) +{ + vcl::ExtWindowImpl* pImpl = ImplGetExtWindowImpl(); + if( pImpl && i_pWin ) + { + vcl::ExtWindowImpl* pChildImpl = i_pWin->ImplGetExtWindowImpl(); + if( pChildImpl ) + { + i_pWin->SetParent( this ); + pChildImpl->mbOwnedByParent = i_bTakeOwnership; + } + } +} + +Window* Window::removeWindow( Window* i_pWin, Window* i_pNewParent ) +{ + Window* pRet = NULL; + if( i_pWin ) + { + vcl::ExtWindowImpl* pImpl = ImplGetExtWindowImpl(); + if( pImpl ) + { + vcl::ExtWindowImpl* pChildImpl = i_pWin->ImplGetExtWindowImpl(); + if( pChildImpl ) + { + if( ! i_pNewParent ) + pChildImpl->mbOwnedByParent = false; + i_pWin->SetParent( i_pNewParent ); + pRet = i_pWin; + } + } + } + return pRet; +} + +Window* Window::findWindow( const rtl::OUString& i_rIdentifier ) const +{ + if( getIdentifier() == i_rIdentifier ) + return const_cast<Window*>(this); + + Window* pChild = mpWindowImpl->mpFirstChild; + while ( pChild ) + { + Window* pResult = pChild->findWindow( i_rIdentifier ); + if( pResult ) + return pResult; + pChild = pChild->mpWindowImpl->mpNext; + } + + return NULL; +} + +const rtl::OUString& Window::getIdentifier() const +{ + static rtl::OUString aEmptyStr; + + return (mpWindowImpl && mpWindowImpl->mpExtImpl) ? mpWindowImpl->mpExtImpl->maIdentifier : aEmptyStr; +} + +void Window::setIdentifier( const rtl::OUString& i_rIdentifier ) +{ + vcl::ExtWindowImpl* pImpl = ImplGetExtWindowImpl(); + if( pImpl ) + pImpl->maIdentifier = i_rIdentifier; +} + +void Window::setProperties( const uno::Sequence< beans::PropertyValue >& i_rProps ) +{ + const beans::PropertyValue* pVals = i_rProps.getConstArray(); + for( sal_Int32 i = 0; i < i_rProps.getLength(); i++ ) + { + if( pVals[i].Name.equalsAscii( "Enabled" ) ) + { + sal_Bool bVal = sal_True; + if( pVals[i].Value >>= bVal ) + Enable( bVal ); + } + else if( pVals[i].Name.equalsAscii( "Visible" ) ) + { + sal_Bool bVal = sal_True; + if( pVals[i].Value >>= bVal ) + Show( bVal ); + } + else if( pVals[i].Name.equalsAscii( "Text" ) ) + { + rtl::OUString aText; + if( pVals[i].Value >>= aText ) + SetText( aText ); + } + } +} + +uno::Sequence< beans::PropertyValue > Window::getProperties() const +{ + uno::Sequence< beans::PropertyValue > aProps( 3 ); + aProps[0].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Enabled" ) ); + aProps[0].Value = uno::makeAny( sal_Bool( IsEnabled() ) ); + aProps[1].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Visible" ) ); + aProps[1].Value = uno::makeAny( sal_Bool( IsVisible() ) ); + aProps[2].Name = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Text" ) ); + aProps[2].Value = uno::makeAny( rtl::OUString( GetText() ) ); + + return aProps; +} + diff --git a/vcl/source/window/wpropset.cxx b/vcl/source/window/wpropset.cxx new file mode 100644 index 000000000000..4aaa3f987b77 --- /dev/null +++ b/vcl/source/window/wpropset.cxx @@ -0,0 +1,346 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_vcl.hxx" + +#include "vcl/wpropset.hxx" +#include "vcl/window.hxx" +#include "vcl/vclevent.hxx" +#include "vcl/svdata.hxx" + +#include "com/sun/star/lang/XMultiServiceFactory.hpp" +#include "com/sun/star/beans/PropertyValue.hpp" +#include "com/sun/star/beans/PropertyAttribute.hpp" +#include "com/sun/star/beans/XPropertySet.hpp" +#include "com/sun/star/beans/XPropertyContainer.hpp" +#include "com/sun/star/beans/XPropertyAccess.hpp" + +#include "cppuhelper/basemutex.hxx" +#include "cppuhelper/compbase1.hxx" + +#include <map> + +using namespace vcl; +using namespace com::sun::star; + +/* + +TODO: +- release solarmutex during outside UNO calls +- in ChildEventListener protect against reentry by using PostUserEvent + +*/ + +class vcl::WindowPropertySetListener : + public cppu::BaseMutex, + public cppu::WeakComponentImplHelper1< com::sun::star::beans::XPropertyChangeListener >, + private boost::noncopyable +{ + WindowPropertySet* mpParent; + bool mbSuspended; +public: + WindowPropertySetListener( WindowPropertySet* pParent ) + : cppu::WeakComponentImplHelper1< com::sun::star::beans::XPropertyChangeListener >( m_aMutex ) + , mpParent( pParent ) + , mbSuspended( false ) + {} + + virtual ~WindowPropertySetListener() + { + } + + using cppu::WeakComponentImplHelperBase::disposing; + virtual void SAL_CALL disposing( const lang::EventObject& ) throw() + { + } + + virtual void SAL_CALL propertyChange( const beans::PropertyChangeEvent& i_rEvent ) throw() + { + if( ! mbSuspended ) + mpParent->propertyChange( i_rEvent ); + } + + void suspend( bool i_bSuspended ) + { + mbSuspended = i_bSuspended; + } +}; + +class vcl::WindowPropertySetData +{ +public: + + struct PropertyMapEntry + { + Window* mpWindow; + boost::shared_ptr<WindowArranger> mpLayout; + uno::Sequence< beans::PropertyValue > maSavedValues; + + PropertyMapEntry( Window* i_pWindow = NULL, + const boost::shared_ptr<WindowArranger>& i_pLayout = boost::shared_ptr<WindowArranger>() ) + : mpWindow( i_pWindow ) + , mpLayout( i_pLayout ) + {} + + uno::Sequence< beans::PropertyValue > getProperties() const + { + if( mpWindow ) + return mpWindow->getProperties(); + else if( mpLayout.get() ) + return mpLayout->getProperties(); + return uno::Sequence< beans::PropertyValue >(); + } + + void setProperties( const uno::Sequence< beans::PropertyValue >& i_rProps ) const + { + if( mpWindow ) + mpWindow->setProperties( i_rProps ); + else if( mpLayout.get() ) + mpLayout->setProperties( i_rProps ); + } + }; + + Window* mpTopWindow; + bool mbOwner; + std::map< rtl::OUString, PropertyMapEntry > maProperties; + uno::Reference< beans::XPropertySet > mxPropSet; + uno::Reference< beans::XPropertyAccess > mxPropSetAccess; + uno::Reference< beans::XPropertyChangeListener > mxListener; + vcl::WindowPropertySetListener* mpListener; + + WindowPropertySetData() + : mpTopWindow( NULL ) + , mbOwner( false ) + , mpListener( NULL ) + {} + + ~WindowPropertySetData() + { + // release layouters, possibly interface properties before destroying + // the involved parent to be on the safe side + maProperties.clear(); + if( mbOwner ) + delete mpTopWindow; + } +}; + +static rtl::OUString getIdentifiedPropertyName( const rtl::OUString& i_rIdentifier, const rtl::OUString& i_rName ) +{ + rtl::OUStringBuffer aBuf( i_rIdentifier.getLength() + 1 + i_rName.getLength() ); + aBuf.append( i_rIdentifier ); + aBuf.append( sal_Unicode( '#' ) ); + aBuf.append( i_rName ); + return aBuf.makeStringAndClear(); +} + +static void spliceIdentifiedPropertyName( const rtl::OUString& i_rIdentifiedPropName, + rtl::OUString& o_rIdentifier, + rtl::OUString& o_rPropName ) +{ + sal_Int32 nIndex = 0; + o_rIdentifier = i_rIdentifiedPropName.getToken( 0, sal_Unicode( '#' ), nIndex ); + if( nIndex != -1 ) + o_rPropName = i_rIdentifiedPropName.copy( nIndex ); + else + o_rPropName = rtl::OUString(); +} + +WindowPropertySet::WindowPropertySet( Window* i_pTopWindow, bool i_bTakeOwnership ) +: mpImpl( new vcl::WindowPropertySetData ) +{ + mpImpl->mpTopWindow = i_pTopWindow; + mpImpl->mbOwner = i_bTakeOwnership; + + mpImpl->mpTopWindow->AddChildEventListener( LINK( this, WindowPropertySet, ChildEventListener ) ); + + mpImpl->mxPropSet = uno::Reference< beans::XPropertySet >( + ImplGetSVData()->maAppData.mxMSF->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.beans.PropertyBag" ) ) ), + uno::UNO_QUERY ); + OSL_ENSURE( mpImpl->mxPropSet.is(), "could not create instance of com.sun.star.beans.PropertyBag" ); + mpImpl->mxPropSetAccess = uno::Reference< beans::XPropertyAccess >( mpImpl->mxPropSet, uno::UNO_QUERY ); + OSL_ENSURE( mpImpl->mxPropSet.is(), "could not query XPropertyAccess interface" ); + if( ! mpImpl->mxPropSetAccess.is() ) + mpImpl->mxPropSet.clear(); + + addWindowToSet( i_pTopWindow ); + + setupProperties(); + + if( mpImpl->mxPropSet.is() ) + { + mpImpl->mxListener.set( mpImpl->mpListener = new WindowPropertySetListener( this ) ); + } +} + +WindowPropertySet::~WindowPropertySet() +{ + mpImpl->mpTopWindow->RemoveChildEventListener( LINK( this, WindowPropertySet, ChildEventListener ) ); + + delete mpImpl; + mpImpl = NULL; +} + +uno::Reference< beans::XPropertySet > WindowPropertySet::getPropertySet() const +{ + return mpImpl->mxPropSet; +} + +void WindowPropertySet::addLayoutToSet( const boost::shared_ptr< WindowArranger >& i_pLayout ) +{ + if( i_pLayout.get() ) + { + if( i_pLayout->getIdentifier().getLength() ) + { + WindowPropertySetData::PropertyMapEntry& rEntry = mpImpl->maProperties[ i_pLayout->getIdentifier() ]; + OSL_ENSURE( rEntry.mpWindow == 0 && rEntry.mpLayout.get() == 0, "inserted layout has duplicate name" ); + rEntry.mpWindow = NULL; + rEntry.mpLayout = i_pLayout; + rEntry.maSavedValues = i_pLayout->getProperties(); + } + // insert child layouts + size_t nChildren = i_pLayout->countElements(); + for( size_t i = 0; i < nChildren; i++ ) + addLayoutToSet( i_pLayout->getChild( i ) ); + } +} + +void WindowPropertySet::addWindowToSet( Window* i_pWindow ) +{ + if( i_pWindow->getIdentifier().getLength() ) // no name, no properties + { + WindowPropertySetData::PropertyMapEntry& rEntry = mpImpl->maProperties[ i_pWindow->getIdentifier() ]; + OSL_ENSURE( rEntry.mpWindow == 0 && rEntry.mpLayout.get() == 0, "inserted window has duplicate name" ); + rEntry.mpWindow = i_pWindow; + rEntry.mpLayout.reset(); + rEntry.maSavedValues = i_pWindow->getProperties(); + } + addLayoutToSet( i_pWindow->getLayout() ); + + Window* pWin = i_pWindow->GetWindow( WINDOW_FIRSTCHILD ); + while( pWin ) + { + addWindowToSet( pWin ); + pWin = pWin->GetWindow( WINDOW_NEXT ); + } +} + +void WindowPropertySet::setupProperties() +{ + uno::Reference< beans::XPropertyContainer > xCont( mpImpl->mxPropSet, uno::UNO_QUERY ); + OSL_ENSURE( xCont.is(), "could not get XPropertyContainer interface" ); + if( ! xCont.is() ) + return; + + for( std::map< rtl::OUString, WindowPropertySetData::PropertyMapEntry >::iterator it + = mpImpl->maProperties.begin(); it != mpImpl->maProperties.end(); ++it ) + { + uno::Sequence< beans::PropertyValue > aOutsideValues( it->second.maSavedValues ); + beans::PropertyValue* pVal = aOutsideValues.getArray(); + for( sal_Int32 i = 0; i < aOutsideValues.getLength(); i++ ) + { + pVal[i].Name = getIdentifiedPropertyName( it->first, pVal[i].Name ); + xCont->addProperty( pVal[i].Name, + beans::PropertyAttribute::BOUND | beans:: PropertyAttribute::CONSTRAINED, + pVal[i].Value + ); + } + } +} + +void WindowPropertySet::propertyChange( const beans::PropertyChangeEvent& i_rEvent ) +{ + rtl::OUString aIdentifier, aProperty; + spliceIdentifiedPropertyName( i_rEvent.PropertyName, aIdentifier, aProperty ); + std::map< rtl::OUString, WindowPropertySetData::PropertyMapEntry >::iterator it = + mpImpl->maProperties.find( aIdentifier ); + if( it != mpImpl->maProperties.end() ) + { + uno::Sequence< beans::PropertyValue > aSet( 1 ); + aSet[0].Name = aProperty; + aSet[0].Value = i_rEvent.NewValue; + it->second.setProperties( aSet ); + } +} + +IMPL_LINK( vcl::WindowPropertySet, ChildEventListener, VclWindowEvent*, pEvent ) +{ + // find window in our properties + std::map< rtl::OUString, WindowPropertySetData::PropertyMapEntry >::iterator it + = mpImpl->maProperties.find( pEvent->GetWindow()->getIdentifier() ); + if( it != mpImpl->maProperties.end() ) // this is valid, some unnamed child may have sent an event + { + ULONG nId = pEvent->GetId(); + // check if anything interesting happened + if( + // general windowy things + nId == VCLEVENT_WINDOW_SHOW || + nId == VCLEVENT_WINDOW_HIDE || + nId == VCLEVENT_WINDOW_ENABLED || + nId == VCLEVENT_WINDOW_DISABLED || + // button thingies + nId == VCLEVENT_BUTTON_CLICK || + nId == VCLEVENT_PUSHBUTTON_TOGGLE || + nId == VCLEVENT_RADIOBUTTON_TOGGLE || + nId == VCLEVENT_CHECKBOX_TOGGLE || + // listbox + nId == VCLEVENT_LISTBOX_SELECT || + // edit + nId == VCLEVENT_EDIT_MODIFY + ) + { + WindowPropertySetData::PropertyMapEntry& rEntry = it->second; + // collect changes + uno::Sequence< beans::PropertyValue > aNewProps( rEntry.getProperties() ); + uno::Sequence< beans::PropertyValue > aNewPropsOut( aNewProps ); + + // translate to identified properties + beans::PropertyValue* pValues = aNewPropsOut.getArray(); + for( sal_Int32 i = 0; i < aNewPropsOut.getLength(); i++ ) + pValues[i].Name = getIdentifiedPropertyName( it->first, pValues[i].Name ); + + // broadcast changes + bool bWasVeto = false; + mpImpl->mpListener->suspend( true ); + try + { + mpImpl->mxPropSetAccess->setPropertyValues( aNewPropsOut ); + } + catch( beans::PropertyVetoException& ) + { + bWasVeto = true; + } + mpImpl->mpListener->suspend( false ); + + if( ! bWasVeto ) // changes accepted ? + rEntry.maSavedValues = rEntry.getProperties(); + else // no, reset + rEntry.setProperties( rEntry.maSavedValues ); + } + } + + return 0; +} diff --git a/vcl/unx/source/gdi/salprnpsp.cxx b/vcl/unx/source/gdi/salprnpsp.cxx index 417704eb3b69..ece724d717cb 100644 --- a/vcl/unx/source/gdi/salprnpsp.cxx +++ b/vcl/unx/source/gdi/salprnpsp.cxx @@ -1187,14 +1187,12 @@ BOOL PspSalPrinter::StartJob( const String* i_pFileName, const String& i_rJobNam aContext.Version = vcl::PDFWriter::PDF_1_4; aContext.Tagged = false; aContext.EmbedStandardFonts = true; - aContext.Encrypt = false; aContext.DocumentLocale = Application::GetSettings().GetLocale(); // prepare doc info - vcl::PDFDocInfo aDocInfo; - aDocInfo.Title = i_rJobName; - aDocInfo.Creator = i_rAppName; - aDocInfo.Producer = i_rAppName; + aContext.DocumentInfo.Title = i_rJobName; + aContext.DocumentInfo.Creator = i_rAppName; + aContext.DocumentInfo.Producer = i_rAppName; // define how we handle metafiles in PDFWriter vcl::PDFWriter::PlayMetafileContext aMtfContext; @@ -1271,11 +1269,10 @@ BOOL PspSalPrinter::StartJob( const String* i_pFileName, const String& i_rJobNam #if defined __SUNPRO_CC #pragma disable_warn #endif - pWriter.reset( new vcl::PDFWriter( aContext ) ); + pWriter.reset( new vcl::PDFWriter( aContext, uno::Reference< beans::XMaterialHolder >() ) ); #if defined __SUNPRO_CC #pragma enable_warn #endif - pWriter->SetDocInfo( aDocInfo ); } pWriter->NewPage( TenMuToPt( aNewParm.maPageSize.Width() ), |