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>
diff --git a/vcl/win/dtrans/DOTransferable.cxx b/vcl/win/dtrans/DOTransferable.cxx
index 0c61ddc..7a911a0 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 @@
} // 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 @@
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 @@
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 @@
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 );
// if text or oemtext is offered we also pretend to have unicode text
if ( CDataFormatTranslator::isOemOrAnsiTextFormat( fetc.cfFormat ) &&
!m_bUnicodeRegistered )
{
addSupportedFlavor( aFlavor );
m_TxtFormatOnClipboard = fetc.cfFormat;
m_bUnicodeRegistered = true;
// register unicode text as accompany format
aFlavor = formatEtcToDataFlavor(
CDataFormatTranslator::getFormatEtcForClipformat( CF_UNICODETEXT ) );
addSupportedFlavor( aFlavor );
}
else if ( (CF_UNICODETEXT == fetc.cfFormat) && !m_bUnicodeRegistered )
{
addSupportedFlavor( aFlavor );
m_bUnicodeRegistered = true;
}
else
addSupportedFlavor( aFlavor );
aFormats.push_back(fetc.cfFormat);
// see MSDN IEnumFORMATETC
CoTaskMemFree( fetc.ptd );
}
initFlavorListFromFormatList(aFormats);
}
}
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)
{
m_TxtFormatOnClipboard = cfFormat;
m_bUnicodeRegistered = true;
// register unicode text as format
addSupportedFlavor(formatEtcToDataFlavor(CF_UNICODETEXT));
}
}
else
addSupportedFlavor(formatEtcToDataFlavor(cfFormat));
}
}
@@ -370,18 +372,9 @@
}
}
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 @@
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 @@
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 af2d200..0e652f9 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 @@
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 @@
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 @@
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 f666f8c..5e23822 100644
--- a/vcl/win/dtrans/DataFmtTransl.cxx
+++ b/vcl/win/dtrans/DataFmtTransl.cxx
@@ -92,13 +92,13 @@
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 3d74875..e003f25 100644
--- a/vcl/win/dtrans/DataFmtTransl.hxx
+++ b/vcl/win/dtrans/DataFmtTransl.hxx
@@ -42,7 +42,7 @@
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 d8fc6a5..e9a1c0d 100644
--- a/vcl/win/dtrans/FetcList.cxx
+++ b/vcl/win/dtrans/FetcList.cxx
@@ -285,10 +285,7 @@
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 6ed9e96..2100510 100644
--- a/vcl/win/dtrans/WinClipboard.cxx
+++ b/vcl/win/dtrans/WinClipboard.cxx
@@ -112,6 +112,32 @@
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 @@
{
// 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 1b0a05a..8e64029 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 @@
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 9300d29..adbed6b 100644
--- a/vcl/win/dtrans/XTDataObject.cxx
+++ b/vcl/win/dtrans/XTDataObject.cxx
@@ -636,10 +636,10 @@
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 2492c8a..32cf95f 100644
--- a/vcl/win/dtrans/target.cxx
+++ b/vcl/win/dtrans/target.cxx
@@ -333,8 +333,7 @@
else
{
// Convert the IDataObject to a XTransferable
m_currentData= CDOTransferable::create(
m_xContext, IDataObjectPtr(pDataObj));
m_currentData = new CDOTransferable(m_xContext, IDataObjectPtr(pDataObj));
}
//<-- TRA