diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2021-03-05 20:45:08 +0300 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2021-03-06 07:11:57 +0100 |
commit | 7b6c0e63e64eb2ad1e83bd744a0d20f78c7a6b84 (patch) | |
tree | cfdc6040e947f446ec9a61626ee2e1208a287919 /vcl | |
parent | d130bda377d00654267e8bfb75e61f34e8991150 (diff) |
tdf#140813: Use GetUpdatedClipboardFormats to enumerate clipboard formats
We really don't have to provide plain text formats other than Unicode, so
we may avoid checking CF_LOCALE data when initializing flavor list. Let's
pretend that any textual format in the clipboard is Unicode, and ensure
that we only actually access system clipboard when we paste.
Change-Id: Ife30f57605a42d59233bfcb97f8bc297b3ace463
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/112044
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/win/dtrans/DOTransferable.cxx | 110 | ||||
-rw-r--r-- | vcl/win/dtrans/DOTransferable.hxx | 19 | ||||
-rw-r--r-- | vcl/win/dtrans/DataFmtTransl.cxx | 4 | ||||
-rw-r--r-- | vcl/win/dtrans/DataFmtTransl.hxx | 2 | ||||
-rw-r--r-- | vcl/win/dtrans/FetcList.cxx | 5 | ||||
-rw-r--r-- | vcl/win/dtrans/WinClipboard.cxx | 36 | ||||
-rw-r--r-- | vcl/win/dtrans/WinClipboard.hxx | 6 | ||||
-rw-r--r-- | vcl/win/dtrans/XTDataObject.cxx | 6 | ||||
-rw-r--r-- | vcl/win/dtrans/target.cxx | 3 |
9 files changed, 113 insertions, 78 deletions
diff --git a/vcl/win/dtrans/DOTransferable.cxx b/vcl/win/dtrans/DOTransferable.cxx index 0c61ddcccc77..7a911a0fa567 100644 --- a/vcl/win/dtrans/DOTransferable.cxx +++ b/vcl/win/dtrans/DOTransferable.cxx @@ -25,6 +25,7 @@ #include "DOTransferable.hxx" #include "ImplHelper.hxx" #include "WinClip.hxx" +#include "WinClipboard.hxx" #include "DTransHelper.hxx" #include "TxtCnvtHlp.hxx" #include "MimeAttrib.hxx" @@ -208,19 +209,6 @@ bool cmpAllContentTypeParameter( } // end namespace -Reference< XTransferable > CDOTransferable::create( const Reference< XComponentContext >& rxContext, - IDataObjectPtr pIDataObject ) -{ - CDOTransferable* pTransf = new CDOTransferable(rxContext, pIDataObject); - Reference<XTransferable> refDOTransf(pTransf); - - pTransf->acquire(); - pTransf->initFlavorList(); - pTransf->release(); - - return refDOTransf; -} - CDOTransferable::CDOTransferable( const Reference< XComponentContext >& rxContext, IDataObjectPtr rDataObject ) : m_rDataObject( rDataObject ), @@ -229,6 +217,20 @@ CDOTransferable::CDOTransferable( m_bUnicodeRegistered( false ), m_TxtFormatOnClipboard( CF_INVALID ) { + initFlavorList(); +} + +CDOTransferable::CDOTransferable( + const Reference<XComponentContext>& rxContext, + const css::uno::Reference<css::datatransfer::clipboard::XClipboard>& xClipboard, + const std::vector<sal_uInt32>& rFormats) + : m_xClipboard(xClipboard) + , m_xContext(rxContext) + , m_DataFormatTranslator(rxContext) + , m_bUnicodeRegistered(false) + , m_TxtFormatOnClipboard(CF_INVALID) +{ + initFlavorListFromFormatList(rFormats); } Any SAL_CALL CDOTransferable::getTransferData( const DataFlavor& aFlavor ) @@ -312,6 +314,7 @@ sal_Bool SAL_CALL CDOTransferable::isDataFlavorSupported( const DataFlavor& aFla void CDOTransferable::initFlavorList( ) { + std::vector<sal_uInt32> aFormats; sal::systools::COMReference<IEnumFORMATETC> pEnumFormatEtc; HRESULT hr = m_rDataObject->EnumFormatEtc( DATADIR_GET, &pEnumFormatEtc ); if ( SUCCEEDED( hr ) ) @@ -321,39 +324,38 @@ void CDOTransferable::initFlavorList( ) FORMATETC fetc; while ( S_OK == pEnumFormatEtc->Next( 1, &fetc, nullptr ) ) { - // we use locales only to determine the - // charset if there is text on the cliboard - // we don't offer this format - if ( CF_LOCALE == fetc.cfFormat ) - continue; - - DataFlavor aFlavor = formatEtcToDataFlavor( fetc ); + aFormats.push_back(fetc.cfFormat); + // see MSDN IEnumFORMATETC + CoTaskMemFree( fetc.ptd ); + } + initFlavorListFromFormatList(aFormats); + } +} - // if text or oemtext is offered we also pretend to have unicode text - if ( CDataFormatTranslator::isOemOrAnsiTextFormat( fetc.cfFormat ) && - !m_bUnicodeRegistered ) +void CDOTransferable::initFlavorListFromFormatList(const std::vector<sal_uInt32>& rFormats) +{ + for (sal_uInt32 cfFormat : rFormats) + { + // we use locales only to determine the + // charset if there is text on the cliboard + // we don't offer this format + if (CF_LOCALE == cfFormat) + continue; + + // if text or oemtext is offered we pretend to have unicode text + if (CDataFormatTranslator::isTextFormat(cfFormat)) + { + if (!m_bUnicodeRegistered) { - addSupportedFlavor( aFlavor ); - - m_TxtFormatOnClipboard = fetc.cfFormat; + m_TxtFormatOnClipboard = cfFormat; m_bUnicodeRegistered = true; - // register unicode text as accompany format - aFlavor = formatEtcToDataFlavor( - CDataFormatTranslator::getFormatEtcForClipformat( CF_UNICODETEXT ) ); - addSupportedFlavor( aFlavor ); + // register unicode text as format + addSupportedFlavor(formatEtcToDataFlavor(CF_UNICODETEXT)); } - else if ( (CF_UNICODETEXT == fetc.cfFormat) && !m_bUnicodeRegistered ) - { - addSupportedFlavor( aFlavor ); - m_bUnicodeRegistered = true; - } - else - addSupportedFlavor( aFlavor ); - - // see MSDN IEnumFORMATETC - CoTaskMemFree( fetc.ptd ); } + else + addSupportedFlavor(formatEtcToDataFlavor(cfFormat)); } } @@ -370,18 +372,9 @@ void CDOTransferable::addSupportedFlavor( const DataFlavor& aFlavor ) } } -DataFlavor CDOTransferable::formatEtcToDataFlavor( const FORMATETC& aFormatEtc ) +DataFlavor CDOTransferable::formatEtcToDataFlavor(sal_uInt32 cfFormat) { - LCID lcid = 0; - - // for non-unicode text format we must provide a locale to get - // the character-set of the text, if there is no locale on the - // clipboard we assume the text is in a charset appropriate for - // the current thread locale - if ( (CF_TEXT == aFormatEtc.cfFormat) || (CF_OEMTEXT == aFormatEtc.cfFormat) ) - lcid = getLocaleFromClipboard( ); - - return m_DataFormatTranslator.getDataFlavorFromFormatEtc( aFormatEtc, lcid ); + return m_DataFormatTranslator.getDataFlavorFromFormatEtc(cfFormat); } // returns the current locale on clipboard; if there is no locale on @@ -411,6 +404,18 @@ LCID CDOTransferable::getLocaleFromClipboard( ) return lcid; } +void CDOTransferable::tryToGetIDataObjectIfAbsent() +{ + if (!m_rDataObject.is()) + { + auto xClipboard = m_xClipboard.get(); // holding the reference while we get the object + if (CWinClipboard* pWinClipboard = dynamic_cast<CWinClipboard*>(xClipboard.get())) + { + m_rDataObject = pWinClipboard->getIDataObject(); + } + } +} + // I think it's not necessary to call ReleaseStgMedium // in case of failures because nothing should have been // allocated etc. @@ -418,6 +423,9 @@ LCID CDOTransferable::getLocaleFromClipboard( ) CDOTransferable::ByteSequence_t CDOTransferable::getClipboardData( CFormatEtc& aFormatEtc ) { STGMEDIUM stgmedium; + tryToGetIDataObjectIfAbsent(); + if (!m_rDataObject.is()) // Maybe we are shutting down, and clipboard is already destroyed? + throw RuntimeException(); HRESULT hr = m_rDataObject->GetData( aFormatEtc, &stgmedium ); // in case of failure to get a WMF metafile handle, try to get a memory block diff --git a/vcl/win/dtrans/DOTransferable.hxx b/vcl/win/dtrans/DOTransferable.hxx index af2d2008cf37..0e652f9b6a0d 100644 --- a/vcl/win/dtrans/DOTransferable.hxx +++ b/vcl/win/dtrans/DOTransferable.hxx @@ -23,12 +23,16 @@ #include <cppuhelper/implbase.hxx> #include "DataFmtTransl.hxx" +#include <com/sun/star/datatransfer/clipboard/XClipboard.hpp> #include <com/sun/star/datatransfer/XMimeContentTypeFactory.hpp> #include <com/sun/star/datatransfer/XMimeContentType.hpp> #include <com/sun/star/datatransfer/XSystemTransferable.hpp> +#include <cppuhelper/weakref.hxx> #include <systools/win32/comtools.hxx> +#include <vector> + // forward class CFormatEtc; @@ -39,9 +43,6 @@ class CDOTransferable : public ::cppu::WeakImplHelper< public: typedef css::uno::Sequence< sal_Int8 > ByteSequence_t; - static css::uno::Reference< css::datatransfer::XTransferable > create( - const css::uno::Reference< css::uno::XComponentContext >& rxContext, IDataObjectPtr pIDataObject ); - // XTransferable virtual css::uno::Any SAL_CALL getTransferData( const css::datatransfer::DataFlavor& aFlavor ) override; @@ -54,18 +55,25 @@ public: virtual css::uno::Any SAL_CALL getData( const css::uno::Sequence<sal_Int8>& aProcessId ) override; -private: + explicit CDOTransferable( + const css::uno::Reference< css::uno::XComponentContext >& rxContext, + const css::uno::Reference<css::datatransfer::clipboard::XClipboard>& xClipboard, + const std::vector<sal_uInt32>& rFormats); + explicit CDOTransferable( const css::uno::Reference< css::uno::XComponentContext >& rxContext, IDataObjectPtr rDataObject ); +private: // some helper functions void initFlavorList( ); + void initFlavorListFromFormatList(const std::vector<sal_uInt32>& rFormats); void addSupportedFlavor( const css::datatransfer::DataFlavor& aFlavor ); - css::datatransfer::DataFlavor formatEtcToDataFlavor( const FORMATETC& aFormatEtc ); + css::datatransfer::DataFlavor formatEtcToDataFlavor(sal_uInt32 cfFormat); + void tryToGetIDataObjectIfAbsent(); ByteSequence_t getClipboardData( CFormatEtc& aFormatEtc ); OUString synthesizeUnicodeText( ); @@ -75,6 +83,7 @@ private: const css::datatransfer::DataFlavor& rhs ); private: + css::uno::WeakReference<css::datatransfer::clipboard::XClipboard> m_xClipboard; IDataObjectPtr m_rDataObject; css::uno::Sequence< css::datatransfer::DataFlavor > m_FlavorList; const css::uno::Reference< css::uno::XComponentContext > m_xContext; diff --git a/vcl/win/dtrans/DataFmtTransl.cxx b/vcl/win/dtrans/DataFmtTransl.cxx index f666f8c75401..5e2382213a0e 100644 --- a/vcl/win/dtrans/DataFmtTransl.cxx +++ b/vcl/win/dtrans/DataFmtTransl.cxx @@ -92,13 +92,13 @@ CFormatEtc CDataFormatTranslator::getFormatEtcFromDataFlavor( const DataFlavor& return sal::static_int_cast<CFormatEtc>(getFormatEtcForClipformat( sal::static_int_cast<CLIPFORMAT>(cf) )); } -DataFlavor CDataFormatTranslator::getDataFlavorFromFormatEtc( const FORMATETC& aFormatEtc, LCID lcid ) const +DataFlavor CDataFormatTranslator::getDataFlavorFromFormatEtc(sal_uInt32 cfFormat, LCID lcid) const { DataFlavor aFlavor; try { - CLIPFORMAT aClipformat = aFormatEtc.cfFormat; + CLIPFORMAT aClipformat = cfFormat; Any aAny; aAny <<= static_cast< sal_Int32 >( aClipformat ); diff --git a/vcl/win/dtrans/DataFmtTransl.hxx b/vcl/win/dtrans/DataFmtTransl.hxx index 3d748751b79c..e003f2538b2d 100644 --- a/vcl/win/dtrans/DataFmtTransl.hxx +++ b/vcl/win/dtrans/DataFmtTransl.hxx @@ -42,7 +42,7 @@ public: CFormatEtc getFormatEtcFromDataFlavor( const css::datatransfer::DataFlavor& aDataFlavor ) const; css::datatransfer::DataFlavor getDataFlavorFromFormatEtc( - const FORMATETC& aFormatEtc, LCID lcid = GetThreadLocale( ) ) const; + sal_uInt32 cfFormat, LCID lcid = GetThreadLocale()) const; static CFormatEtc getFormatEtcForClipformat( CLIPFORMAT cf ); static CFormatEtc getFormatEtcForClipformatName( const OUString& aClipFmtName ); diff --git a/vcl/win/dtrans/FetcList.cxx b/vcl/win/dtrans/FetcList.cxx index d8fc6a52548a..e9a1c0dac5f1 100644 --- a/vcl/win/dtrans/FetcList.cxx +++ b/vcl/win/dtrans/FetcList.cxx @@ -285,10 +285,7 @@ OUString CFormatRegistrar::getCharsetFromDataFlavor( const DataFlavor& aFlavor ) bool CFormatRegistrar::hasUnicodeFlavor( const Reference< XTransferable >& aXTransferable ) const { - CFormatEtc fetc( CF_UNICODETEXT ); - - DataFlavor aFlavor = - m_DataFormatTranslator.getDataFlavorFromFormatEtc( fetc ); + DataFlavor aFlavor = m_DataFormatTranslator.getDataFlavorFromFormatEtc(CF_UNICODETEXT); return aXTransferable->isDataFlavorSupported( aFlavor ); } diff --git a/vcl/win/dtrans/WinClipboard.cxx b/vcl/win/dtrans/WinClipboard.cxx index 6ed9e967d7e5..2100510b5d34 100644 --- a/vcl/win/dtrans/WinClipboard.cxx +++ b/vcl/win/dtrans/WinClipboard.cxx @@ -112,6 +112,32 @@ uno::Reference<datatransfer::XTransferable> SAL_CALL CWinClipboard::getContents( uno::Reference<datatransfer::XTransferable> rClipContent; + // get the current format list from clipboard + if (UINT nFormats; !GetUpdatedClipboardFormats(nullptr, 0, &nFormats) + && GetLastError() == ERROR_INSUFFICIENT_BUFFER) + { + std::vector<UINT> aUINTFormats(nFormats); + if (GetUpdatedClipboardFormats(aUINTFormats.data(), nFormats, &nFormats)) + { + std::vector<sal_uInt32> aFormats(aUINTFormats.begin(), aUINTFormats.end()); + rClipContent = new CDOTransferable(m_xContext, this, aFormats); + + osl::MutexGuard aGuard2(m_ClipContentMutex); + m_foreignContent = rClipContent; + } + } + + return rClipContent; +} + +IDataObjectPtr CWinClipboard::getIDataObject() +{ + osl::MutexGuard aGuard(m_aMutex); + + if (rBHelper.bDisposed) + throw lang::DisposedException("object is already disposed", + static_cast<XClipboardEx*>(this)); + // get the current dataobject from clipboard IDataObjectPtr pIDataObject; HRESULT hr = m_MtaOleClipboard.getClipboard(&pIDataObject); @@ -120,16 +146,10 @@ uno::Reference<datatransfer::XTransferable> SAL_CALL CWinClipboard::getContents( { // create an apartment neutral dataobject and initialize it with a // com smart pointer to the IDataObject from clipboard - IDataObjectPtr pIDo(new CAPNDataObject(pIDataObject)); - - // remember pIDo destroys itself due to the smart pointer - rClipContent = CDOTransferable::create(m_xContext, pIDo); - - osl::MutexGuard aGuard2(m_ClipContentMutex); - m_foreignContent = rClipContent; + pIDataObject = new CAPNDataObject(pIDataObject); } - return rClipContent; + return pIDataObject; } void SAL_CALL CWinClipboard::setContents( diff --git a/vcl/win/dtrans/WinClipboard.hxx b/vcl/win/dtrans/WinClipboard.hxx index 1b0a05a3450d..8e64029b9ae3 100644 --- a/vcl/win/dtrans/WinClipboard.hxx +++ b/vcl/win/dtrans/WinClipboard.hxx @@ -32,10 +32,10 @@ #include <com/sun/star/lang/XServiceInfo.hpp> #include <com/sun/star/uno/XComponentContext.hpp> #include <osl/conditn.hxx> +#include <systools/win32/comtools.hxx> #include "MtaOleClipb.hxx" - -class CXNotifyingDataObject; +#include "XNotifyingDataObject.hxx" // implements the XClipboard[Ex] ... interfaces // for the clipboard viewer mechanism we need a static callback function @@ -113,6 +113,8 @@ public: virtual OUString SAL_CALL getImplementationName() override; virtual sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override; virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + IDataObjectPtr getIDataObject(); }; /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/win/dtrans/XTDataObject.cxx b/vcl/win/dtrans/XTDataObject.cxx index 9300d2969997..adbed6bbec9f 100644 --- a/vcl/win/dtrans/XTDataObject.cxx +++ b/vcl/win/dtrans/XTDataObject.cxx @@ -636,10 +636,10 @@ DataFlavor CXTDataObject::formatEtcToDataFlavor( const FORMATETC& aFormatEtc ) c DataFlavor aFlavor; if ( m_FormatRegistrar.hasSynthesizedLocale( ) ) - aFlavor = - m_DataFormatTranslator.getDataFlavorFromFormatEtc( aFormatEtc, CFormatRegistrar::getSynthesizedLocale( ) ); + aFlavor = m_DataFormatTranslator.getDataFlavorFromFormatEtc( + aFormatEtc.cfFormat, CFormatRegistrar::getSynthesizedLocale()); else - aFlavor = m_DataFormatTranslator.getDataFlavorFromFormatEtc( aFormatEtc ); + aFlavor = m_DataFormatTranslator.getDataFlavorFromFormatEtc(aFormatEtc.cfFormat); if ( !aFlavor.MimeType.getLength( ) ) throw UnsupportedFlavorException( ); diff --git a/vcl/win/dtrans/target.cxx b/vcl/win/dtrans/target.cxx index 2492c8a3cc94..32cf95ffa647 100644 --- a/vcl/win/dtrans/target.cxx +++ b/vcl/win/dtrans/target.cxx @@ -333,8 +333,7 @@ HRESULT DropTarget::DragEnter( IDataObject *pDataObj, else { // Convert the IDataObject to a XTransferable - m_currentData= CDOTransferable::create( - m_xContext, IDataObjectPtr(pDataObj)); + m_currentData = new CDOTransferable(m_xContext, IDataObjectPtr(pDataObj)); } //<-- TRA |