summaryrefslogtreecommitdiffstats
path: root/vcl/ios
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--vcl/ios/DataFlavorMapping.cxx571
-rw-r--r--vcl/ios/DataFlavorMapping.hxx127
-rw-r--r--vcl/ios/HtmlFmtFlt.cxx172
-rw-r--r--vcl/ios/HtmlFmtFlt.hxx41
-rw-r--r--vcl/ios/clipboard.cxx185
-rw-r--r--vcl/ios/clipboard.hxx111
-rw-r--r--vcl/ios/dummies.cxx138
-rw-r--r--vcl/ios/iOSTransferable.cxx186
-rw-r--r--vcl/ios/iOSTransferable.hxx73
-rw-r--r--vcl/ios/iosinst.cxx197
10 files changed, 1801 insertions, 0 deletions
diff --git a/vcl/ios/DataFlavorMapping.cxx b/vcl/ios/DataFlavorMapping.cxx
new file mode 100644
index 000000000..88b0e6199
--- /dev/null
+++ b/vcl/ios/DataFlavorMapping.cxx
@@ -0,0 +1,571 @@
+/* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include "DataFlavorMapping.hxx"
+#include "HtmlFmtFlt.hxx"
+#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
+#include <com/sun/star/datatransfer/XMimeContentType.hpp>
+#include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+#include <osl/endian.h>
+
+#include <cassert>
+#include <cstring>
+
+#include <premac.h>
+#include <UIKit/UIKit.h>
+#include <MobileCoreServices/MobileCoreServices.h>
+#include <postmac.h>
+
+using namespace css::datatransfer;
+using namespace css::uno;
+using namespace css::lang;
+using namespace cppu;
+
+namespace
+{
+/* Determine whether or not a DataFlavor is valid.
+ */
+bool isValidFlavor(const DataFlavor& aFlavor)
+{
+ size_t len = aFlavor.MimeType.getLength();
+ Type dtype = aFlavor.DataType;
+ return ((len > 0)
+ && ((dtype == cppu::UnoType<Sequence<sal_Int8>>::get())
+ || (dtype == cppu::UnoType<OUString>::get())));
+}
+
+OUString NSStringToOUString(const NSString* cfString)
+{
+ assert(cfString && "Invalid parameter");
+
+ const char* utf8Str = [cfString UTF8String];
+ unsigned int len = rtl_str_getLength(utf8Str);
+
+ return OUString(utf8Str, len, RTL_TEXTENCODING_UTF8);
+}
+
+NSString* OUStringToNSString(const OUString& ustring)
+{
+ OString utf8Str = OUStringToOString(ustring, RTL_TEXTENCODING_UTF8);
+ return [NSString stringWithCString:utf8Str.getStr() encoding:NSUTF8StringEncoding];
+}
+
+NSString* PBTYPE_PLAINTEXT = (__bridge NSString*)kUTTypePlainText;
+// Nope. See commented-out use below.
+// NSString* PBTYPE_UTF8PLAINTEXT = (__bridge NSString*)kUTTypeUTF8PlainText;
+NSString* PBTYPE_RTF = (__bridge NSString*)kUTTypeRTF;
+NSString* PBTYPE_PNG = (__bridge NSString*)kUTTypePNG;
+NSString* PBTYPE_JPEG = (__bridge NSString*)kUTTypeJPEG;
+NSString* PBTYPE_HTML = (__bridge NSString*)kUTTypeHTML;
+NSString* PBTYPE_PDF = (__bridge NSString*)kUTTypePDF;
+NSString* PBTYPE_SESX
+ = @"application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
+NSString* PBTYPE_SLSDX = @"application/"
+ @"x-openoffice-linksrcdescriptor-xml;windows_formatname=\"Star Link "
+ @"Source Descriptor (XML)\"";
+NSString* PBTYPE_LSX
+ = @"application/x-openoffice-link-source-xml;windows_formatname=\"Star Link Source (XML)\"";
+NSString* PBTYPE_EOX = @"application/x-openoffice-embedded-obj-xml;windows_formatname=\"Star "
+ @"Embedded Object (XML)\"";
+NSString* PBTYPE_SVXB
+ = @"application/x-openoffice-svbx;windows_formatname=\"SVXB (StarView Bitmap/Animation)\"";
+NSString* PBTYPE_GDIMF = @"application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"";
+NSString* PBTYPE_SODX = @"application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star "
+ @"Object Descriptor (XML)\"";
+NSString* PBTYPE_DUMMY_INTERNAL = @"application/x-openoffice-internal";
+
+const char* FLAVOR_SESX
+ = "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"";
+const char* FLAVOR_SLSDX = "application/"
+ "x-openoffice-linksrcdescriptor-xml;windows_formatname=\"Star Link "
+ "Source Descriptor (XML)\"";
+const char* FLAVOR_LSX
+ = "application/x-openoffice-link-source-xml;windows_formatname=\"Star Link Source (XML)\"";
+const char* FLAVOR_EOX
+ = "application/x-openoffice-embedded-obj-xml;windows_formatname=\"Star Embedded Object (XML)\"";
+const char* FLAVOR_SVXB
+ = "application/x-openoffice-svbx;windows_formatname=\"SVXB (StarView Bitmap/Animation)\"";
+const char* FLAVOR_GDIMF
+ = "application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"";
+const char* FLAVOR_SODX = "application/x-openoffice-objectdescriptor-xml;windows_formatname=\"Star "
+ "Object Descriptor (XML)\"";
+const char* FLAVOR_DUMMY_INTERNAL = "application/x-openoffice-internal";
+
+struct FlavorMap
+{
+ NSString* SystemFlavor;
+ const char* OOoFlavor;
+ const char* HumanPresentableName;
+ bool DataTypeOUString; // sequence<byte> otherwise
+};
+
+static const FlavorMap flavorMap[]
+ = { { PBTYPE_PLAINTEXT, "text/plain;charset=utf-16", "Unicode Text (UTF-16)", true },
+ // Nope. The LO code does not understand text/plain in UTF-8. Which is a shame.
+ // PBTYPE_UTF8PLAINTEXT, "text/plain;charset=utf-8", "Unicode Text (UTF-8)", false },
+ { PBTYPE_RTF, "text/rtf", "Rich Text Format", false },
+ { PBTYPE_PNG, "image/png", "Portable Network Graphics", false },
+ { PBTYPE_JPEG, "image/jpeg", "JPEG", false },
+ { PBTYPE_HTML, "text/html", "Plain HTML", false },
+ { PBTYPE_PDF, "application/pdf", "PDF File", false },
+ { PBTYPE_SESX, FLAVOR_SESX, "Star Embed Source (XML)", false },
+ { PBTYPE_SLSDX, FLAVOR_SLSDX, "Star Link Source Descriptor (XML)", false },
+ { PBTYPE_LSX, FLAVOR_LSX, "Star Link Source (XML)", false },
+ { PBTYPE_EOX, FLAVOR_EOX, "Star Embedded Object (XML)", false },
+ { PBTYPE_SVXB, FLAVOR_SVXB, "SVXB (StarView Bitmap/Animation", false },
+ { PBTYPE_GDIMF, FLAVOR_GDIMF, "GDIMetaFile", false },
+ { PBTYPE_SODX, FLAVOR_SODX, "Star Object Descriptor (XML)", false },
+ { PBTYPE_DUMMY_INTERNAL, FLAVOR_DUMMY_INTERNAL, "internal data", false } };
+
+#define SIZE_FLAVOR_MAP (sizeof(flavorMap) / sizeof(FlavorMap))
+
+inline bool isByteSequenceType(const Type& theType)
+{
+ return (theType == cppu::UnoType<Sequence<sal_Int8>>::get());
+}
+
+inline bool isOUStringType(const Type& theType)
+{
+ return (theType == cppu::UnoType<OUString>::get());
+}
+
+} // unnamed namespace
+
+/* A base class for other data provider.
+ */
+class DataProviderBaseImpl : public DataProvider
+{
+public:
+ DataProviderBaseImpl(const Any& data);
+ DataProviderBaseImpl(id data);
+ virtual ~DataProviderBaseImpl() override;
+
+protected:
+ Any mData;
+ //NSData* mSystemData;
+ id mSystemData;
+};
+
+DataProviderBaseImpl::DataProviderBaseImpl(const Any& data)
+ : mData(data)
+ , mSystemData(nil)
+{
+}
+
+DataProviderBaseImpl::DataProviderBaseImpl(id data)
+ : mSystemData(data)
+{
+ [mSystemData retain];
+}
+
+DataProviderBaseImpl::~DataProviderBaseImpl()
+{
+ if (mSystemData)
+ {
+ [mSystemData release];
+ }
+}
+
+class UniDataProvider : public DataProviderBaseImpl
+{
+public:
+ UniDataProvider(const Any& data);
+ UniDataProvider(NSData* data);
+
+ NSData* getSystemData() override;
+ Any getOOoData() override;
+};
+
+UniDataProvider::UniDataProvider(const Any& data)
+ : DataProviderBaseImpl(data)
+{
+}
+
+UniDataProvider::UniDataProvider(NSData* data)
+ : DataProviderBaseImpl(data)
+{
+}
+
+NSData* UniDataProvider::getSystemData()
+{
+ OUString ustr;
+ mData >>= ustr;
+
+ OString strUtf8;
+ ustr.convertToString(&strUtf8, RTL_TEXTENCODING_UTF8, OUSTRING_TO_OSTRING_CVTFLAGS);
+
+ return [NSData dataWithBytes:strUtf8.getStr() length:strUtf8.getLength()];
+}
+
+Any UniDataProvider::getOOoData()
+{
+ Any oOOData;
+
+ if (mSystemData)
+ {
+ oOOData <<= OUString(static_cast<const char*>([mSystemData bytes]), [mSystemData length],
+ RTL_TEXTENCODING_UTF8);
+ }
+ else
+ {
+ oOOData = mData;
+ }
+
+ return oOOData;
+}
+
+class ByteSequenceDataProvider : public DataProviderBaseImpl
+{
+public:
+ ByteSequenceDataProvider(const Any& data);
+ ByteSequenceDataProvider(NSData* data);
+
+ NSData* getSystemData() override;
+ Any getOOoData() override;
+};
+
+ByteSequenceDataProvider::ByteSequenceDataProvider(const Any& data)
+ : DataProviderBaseImpl(data)
+{
+}
+
+ByteSequenceDataProvider::ByteSequenceDataProvider(NSData* data)
+ : DataProviderBaseImpl(data)
+{
+}
+
+NSData* ByteSequenceDataProvider::getSystemData()
+{
+ Sequence<sal_Int8> rawData;
+ mData >>= rawData;
+
+ return [NSData dataWithBytes:rawData.getArray() length:rawData.getLength()];
+}
+
+Any ByteSequenceDataProvider::getOOoData()
+{
+ Any oOOData;
+
+ if (mSystemData)
+ {
+ unsigned int flavorDataLength = [mSystemData length];
+ Sequence<sal_Int8> byteSequence;
+ byteSequence.realloc(flavorDataLength);
+ memcpy(byteSequence.getArray(), [mSystemData bytes], flavorDataLength);
+ oOOData <<= byteSequence;
+ }
+ else
+ {
+ oOOData = mData;
+ }
+
+ return oOOData;
+}
+
+class HTMLFormatDataProvider : public DataProviderBaseImpl
+{
+public:
+ HTMLFormatDataProvider(NSData* data);
+
+ NSData* getSystemData() override;
+ Any getOOoData() override;
+};
+
+HTMLFormatDataProvider::HTMLFormatDataProvider(NSData* data)
+ : DataProviderBaseImpl(data)
+{
+}
+
+NSData* HTMLFormatDataProvider::getSystemData()
+{
+ Sequence<sal_Int8> textHtmlData;
+ mData >>= textHtmlData;
+
+ Sequence<sal_Int8> htmlFormatData = TextHtmlToHTMLFormat(textHtmlData);
+
+ return [NSData dataWithBytes:htmlFormatData.getArray() length:htmlFormatData.getLength()];
+}
+
+Any HTMLFormatDataProvider::getOOoData()
+{
+ Any oOOData;
+
+ if (mSystemData)
+ {
+ unsigned int flavorDataLength = [mSystemData length];
+ Sequence<sal_Int8> unkHtmlData;
+
+ unkHtmlData.realloc(flavorDataLength);
+ memcpy(unkHtmlData.getArray(), [mSystemData bytes], flavorDataLength);
+
+ Sequence<sal_Int8>* pPlainHtml = &unkHtmlData;
+ Sequence<sal_Int8> plainHtml;
+
+ if (isHTMLFormat(unkHtmlData))
+ {
+ plainHtml = HTMLFormatToTextHtml(unkHtmlData);
+ pPlainHtml = &plainHtml;
+ }
+
+ oOOData <<= *pPlainHtml;
+ }
+ else
+ {
+ oOOData = mData;
+ }
+
+ return oOOData;
+}
+
+DataFlavorMapper::DataFlavorMapper()
+{
+ Reference<XComponentContext> xContext = comphelper::getProcessComponentContext();
+ mrXMimeCntFactory = MimeContentTypeFactory::create(xContext);
+}
+
+DataFlavorMapper::~DataFlavorMapper()
+{
+ // release potential NSStrings
+ for (OfficeOnlyTypes::iterator it = maOfficeOnlyTypes.begin(); it != maOfficeOnlyTypes.end();
+ ++it)
+ {
+ [it->second release];
+ it->second = nil;
+ }
+}
+
+DataFlavor DataFlavorMapper::systemToOpenOfficeFlavor(const NSString* systemDataFlavor) const
+{
+ DataFlavor oOOFlavor;
+
+ for (size_t i = 0; i < SIZE_FLAVOR_MAP; i++)
+ {
+ if ([systemDataFlavor
+ caseInsensitiveCompare:const_cast<NSString*>(flavorMap[i].SystemFlavor)]
+ == NSOrderedSame)
+ {
+ oOOFlavor.MimeType = OUString::createFromAscii(flavorMap[i].OOoFlavor);
+ oOOFlavor.HumanPresentableName
+ = OUString::createFromAscii(flavorMap[i].HumanPresentableName);
+ oOOFlavor.DataType = flavorMap[i].DataTypeOUString
+ ? cppu::UnoType<OUString>::get()
+ : cppu::UnoType<Sequence<sal_Int8>>::get();
+ return oOOFlavor;
+ }
+ } // for
+
+ // look if this might be an internal type; if it comes in here it must have
+ // been through openOfficeToSystemFlavor before, so it should then be in the map
+ OUString aTryFlavor(NSStringToOUString(systemDataFlavor));
+ if (maOfficeOnlyTypes.find(aTryFlavor) != maOfficeOnlyTypes.end())
+ {
+ oOOFlavor.MimeType = aTryFlavor;
+ oOOFlavor.HumanPresentableName.clear();
+ oOOFlavor.DataType = cppu::UnoType<Sequence<sal_Int8>>::get();
+ }
+
+ return oOOFlavor;
+}
+
+NSString* DataFlavorMapper::openOfficeToSystemFlavor(const DataFlavor& oOOFlavor,
+ bool& rbInternal) const
+{
+ NSString* sysFlavor = nullptr;
+ rbInternal = false;
+
+ for (size_t i = 0; i < SIZE_FLAVOR_MAP; ++i)
+ {
+ if (oOOFlavor.MimeType.startsWith(OUString::createFromAscii(flavorMap[i].OOoFlavor)))
+ {
+ sysFlavor = flavorMap[i].SystemFlavor;
+ }
+ }
+
+ if (!sysFlavor)
+ {
+ // For some reason, if we allow text/html, we get an OSL_ENSURE failure in xmloff that
+ // apparently is a symptom of something being seriously wrong:
+ // xmloff/source/transform/OOo2Oasis.cxx:1925: duplicate doc handler
+ // Because is then followed a bit later by an assertion failure:
+ // Assertion failed: (!m_pFirst && !m_pLast && "There are still indices registered"), function ~SwIndexReg, file [...]/sw/source/core/bastyp/index.cxx, line 226
+
+ if (oOOFlavor.MimeType == "text/html")
+ return nil;
+
+ rbInternal = true;
+ OfficeOnlyTypes::const_iterator it = maOfficeOnlyTypes.find(oOOFlavor.MimeType);
+
+ if (it == maOfficeOnlyTypes.end())
+ sysFlavor = maOfficeOnlyTypes[oOOFlavor.MimeType]
+ = OUStringToNSString(oOOFlavor.MimeType);
+ else
+ sysFlavor = it->second;
+ }
+
+ return sysFlavor;
+}
+
+NSString* DataFlavorMapper::openOfficeImageToSystemFlavor(UIPasteboard* pPasteboard)
+{
+ if ([pPasteboard containsPasteboardTypes:@[ PBTYPE_PNG ]])
+ return PBTYPE_PNG;
+ else if ([pPasteboard containsPasteboardTypes:@[ PBTYPE_JPEG ]])
+ return PBTYPE_JPEG;
+ else if ([pPasteboard containsPasteboardTypes:@[ PBTYPE_PDF ]])
+ return PBTYPE_PDF;
+ return @"";
+}
+
+DataProviderPtr_t
+DataFlavorMapper::getDataProvider(const NSString* systemFlavor,
+ Reference<XTransferable> const& rTransferable) const
+{
+ DataProviderPtr_t dp;
+
+ try
+ {
+ DataFlavor oOOFlavor = systemToOpenOfficeFlavor(systemFlavor);
+
+ Any data = rTransferable->getTransferData(oOOFlavor);
+
+ if (isByteSequenceType(data.getValueType()))
+ {
+ dp = DataProviderPtr_t(new ByteSequenceDataProvider(data));
+ }
+ else // Must be OUString type
+ {
+ SAL_WARN_IF(!isOUStringType(data.getValueType()), "vcl", "must be OUString type");
+ dp = DataProviderPtr_t(new UniDataProvider(data));
+ }
+ }
+ catch (UnsupportedFlavorException&)
+ {
+ // Somebody violates the contract of the clipboard
+ // interface @see XTransferable
+ }
+
+ return dp;
+}
+
+DataProviderPtr_t DataFlavorMapper::getDataProvider(const NSString* systemFlavor,
+ NSData* systemData)
+{
+ DataProviderPtr_t dp;
+
+ if ([systemFlavor caseInsensitiveCompare:PBTYPE_PLAINTEXT] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new UniDataProvider(systemData));
+ }
+ else if ([systemFlavor caseInsensitiveCompare:PBTYPE_HTML] == NSOrderedSame)
+ {
+ dp = DataProviderPtr_t(new HTMLFormatDataProvider(systemData));
+ }
+ else
+ {
+ dp = DataProviderPtr_t(new ByteSequenceDataProvider(systemData));
+ }
+
+ return dp;
+}
+
+bool DataFlavorMapper::isValidMimeContentType(const OUString& contentType) const
+{
+ bool result = true;
+
+ try
+ {
+ Reference<XMimeContentType> xCntType(mrXMimeCntFactory->createMimeContentType(contentType));
+ }
+ catch (IllegalArgumentException&)
+ {
+ result = false;
+ }
+
+ return result;
+}
+
+NSArray* DataFlavorMapper::flavorSequenceToTypesArray(
+ const css::uno::Sequence<css::datatransfer::DataFlavor>& flavors) const
+{
+ const sal_uInt32 nFlavors = flavors.getLength();
+ NSMutableArray* array = [[NSMutableArray alloc] initWithCapacity:1];
+
+ bool bNeedDummyInternalFlavor(false);
+
+ for (sal_uInt32 i = 0; i < nFlavors; i++)
+ {
+ if (flavors[i].MimeType.startsWith("image/bmp"))
+ {
+ [array addObject:PBTYPE_PNG];
+ }
+ else
+ {
+ const NSString* str = openOfficeToSystemFlavor(flavors[i], bNeedDummyInternalFlavor);
+
+ if (str != nil)
+ {
+ [str retain];
+ [array addObject:str];
+ }
+ }
+ }
+
+ // #i89462# #i90747#
+ // in case no system flavor was found to report
+ // report at least one so D&D between OOo targets works
+ if ([array count] == 0 || bNeedDummyInternalFlavor)
+ {
+ [array addObject:PBTYPE_DUMMY_INTERNAL];
+ }
+
+ return [array autorelease];
+}
+
+css::uno::Sequence<css::datatransfer::DataFlavor>
+DataFlavorMapper::typesArrayToFlavorSequence(NSArray* types) const
+{
+ int nFormats = [types count];
+ Sequence<DataFlavor> flavors;
+
+ for (int i = 0; i < nFormats; i++)
+ {
+ NSString* sysFormat = [types objectAtIndex:i];
+ DataFlavor oOOFlavor = systemToOpenOfficeFlavor(sysFormat);
+
+ if (isValidFlavor(oOOFlavor))
+ {
+ flavors.realloc(flavors.getLength() + 1);
+ flavors[flavors.getLength() - 1] = oOOFlavor;
+ SAL_INFO("vcl.ios.clipboard",
+ "Mapped " << [sysFormat UTF8String] << " to " << oOOFlavor.MimeType);
+ }
+ }
+
+ return flavors;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/ios/DataFlavorMapping.hxx b/vcl/ios/DataFlavorMapping.hxx
new file mode 100644
index 000000000..7e527dc09
--- /dev/null
+++ b/vcl/ios/DataFlavorMapping.hxx
@@ -0,0 +1,127 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_VCL_IOS_DATAFLAVORMAPPING_HXX
+#define INCLUDED_VCL_IOS_DATAFLAVORMAPPING_HXX
+
+#include <com/sun/star/datatransfer/DataFlavor.hpp>
+#include <com/sun/star/datatransfer/XMimeContentTypeFactory.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+
+#include <premac.h>
+#import <UIKit/UIKit.h>
+#include <postmac.h>
+
+#include <memory>
+#include <unordered_map>
+
+/* An interface to get the clipboard data in either
+ system or OOo format.
+ */
+class DataProvider
+{
+public:
+ virtual ~DataProvider(){};
+
+ /* Get the clipboard data in the system format.
+ The caller has to retain/release the returned
+ CFDataRef on demand.
+ */
+ virtual NSData* getSystemData() = 0;
+
+ /* Get the clipboard data in OOo format.
+ */
+ virtual css::uno::Any getOOoData() = 0;
+};
+
+typedef std::unique_ptr<DataProvider> DataProviderPtr_t;
+
+class DataFlavorMapper
+{
+public:
+ /* Initialize a DataFavorMapper instance. Throws a RuntimeException in case the XMimeContentTypeFactory service
+ cannot be created.
+ */
+ DataFlavorMapper();
+ ~DataFlavorMapper();
+
+ /* Map a system data flavor to an OpenOffice data flavor.
+ Return an empty string if there is not suitable
+ mapping from a system data flavor to an OpenOffice data
+ flavor.
+ */
+ css::datatransfer::DataFlavor systemToOpenOfficeFlavor(const NSString* systemDataFlavor) const;
+
+ /* Map an OpenOffice data flavor to a system data flavor.
+ If there is no suitable mapping available NULL will
+ be returned.
+ */
+ NSString* openOfficeToSystemFlavor(const css::datatransfer::DataFlavor& oooDataFlavor,
+ bool& rbInternal) const;
+
+ /* Select the best available image data type
+ If there is no suitable mapping available NULL will
+ be returned.
+ */
+ static NSString* openOfficeImageToSystemFlavor(UIPasteboard* pPasteboard);
+
+ /* Get a data provider which is able to provide the data 'rTransferable' offers in a format that can
+ be put on to the system clipboard.
+ */
+ DataProviderPtr_t getDataProvider(
+ const NSString* systemFlavor,
+ const css::uno::Reference<css::datatransfer::XTransferable>& rTransferable) const;
+
+ /* Get a data provider which is able to provide 'systemData' in the OOo expected format.
+ */
+ static DataProviderPtr_t getDataProvider(const NSString* systemFlavor, NSArray* systemData);
+
+ /* Get a data provider which is able to provide 'systemData' in the OOo expected format.
+ */
+ static DataProviderPtr_t getDataProvider(const NSString* systemFlavor, NSData* systemData);
+
+ /* Translate a sequence of DataFlavors into a NSArray of system types.
+ Only those DataFlavors for which a suitable mapping to a system
+ type exist will be contained in the returned types array.
+ */
+ NSArray* flavorSequenceToTypesArray(
+ const css::uno::Sequence<css::datatransfer::DataFlavor>& flavors) const;
+
+ /* Translate a NSArray of system types into a sequence of DataFlavors.
+ Only those types for which a suitable mapping to a DataFlavor
+ exist will be contained in the new DataFlavor Sequence.
+ */
+ css::uno::Sequence<css::datatransfer::DataFlavor>
+ typesArrayToFlavorSequence(NSArray* types) const;
+
+private:
+ /* Determines if the provided Mime content type is valid.
+ */
+ bool isValidMimeContentType(const OUString& contentType) const;
+
+private:
+ css::uno::Reference<css::datatransfer::XMimeContentTypeFactory> mrXMimeCntFactory;
+ typedef std::unordered_map<OUString, NSString*> OfficeOnlyTypes;
+ mutable OfficeOnlyTypes maOfficeOnlyTypes;
+};
+
+#endif // INCLUDED_VCL_IOS_DATAFLAVORMAPPING_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/ios/HtmlFmtFlt.cxx b/vcl/ios/HtmlFmtFlt.cxx
new file mode 100644
index 000000000..4f90ced3b
--- /dev/null
+++ b/vcl/ios/HtmlFmtFlt.cxx
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "HtmlFmtFlt.hxx"
+
+#include <rtl/string.h>
+#include <osl/diagnose.h>
+
+#include <string>
+#include <sstream>
+#include <vector>
+#include <iomanip>
+#include <cassert>
+
+using namespace com::sun::star::uno;
+
+// converts the openoffice text/html clipboard format to the HTML Format
+// well known under MS Windows
+// the MS HTML Format has a header before the real html data
+
+// Version:1.0 Version number of the clipboard. Starting is 0.9
+// StartHTML: Byte count from the beginning of the clipboard to the start
+// of the context, or -1 if no context
+// EndHTML: Byte count from the beginning of the clipboard to the end
+// of the context, or -1 if no context
+// StartFragment: Byte count from the beginning of the clipboard to the
+// start of the fragment
+// EndFragment: Byte count from the beginning of the clipboard to the
+// end of the fragment
+// StartSelection: Byte count from the beginning of the clipboard to the
+// start of the selection
+// EndSelection: Byte count from the beginning of the clipboard to the
+// end of the selection
+
+// StartSelection and EndSelection are optional
+// The fragment should be preceded and followed by the HTML comments
+// <!--StartFragment--> and <!--EndFragment--> (no space between !-- and the
+// text
+
+namespace
+{
+std::string GetHtmlFormatHeader(size_t startHtml, size_t endHtml, size_t startFragment,
+ size_t endFragment)
+{
+ std::ostringstream htmlHeader;
+ htmlHeader << "Version:1.0" << '\r' << '\n';
+ htmlHeader << "StartHTML:" << std::setw(10) << std::setfill('0') << std::dec << startHtml
+ << '\r' << '\n';
+ htmlHeader << "EndHTML:" << std::setw(10) << std::setfill('0') << std::dec << endHtml << '\r'
+ << '\n';
+ htmlHeader << "StartFragment:" << std::setw(10) << std::setfill('0') << std::dec
+ << startFragment << '\r' << '\n';
+ htmlHeader << "EndFragment:" << std::setw(10) << std::setfill('0') << std::dec << endFragment
+ << '\r' << '\n';
+ return htmlHeader.str();
+}
+}
+
+// the office always writes the start and end html tag in upper cases and
+// without spaces both tags don't allow parameters
+const std::string TAG_HTML = std::string("<html>");
+const std::string TAG_END_HTML = std::string("</html>");
+
+// The body tag may have parameters so we need to search for the
+// closing '>' manually e.g. <BODY param> #92840#
+const std::string TAG_BODY = std::string("<body");
+const std::string TAG_END_BODY = std::string("</body");
+
+Sequence<sal_Int8> SAL_CALL TextHtmlToHTMLFormat(Sequence<sal_Int8> const& aTextHtml)
+{
+ OSL_ASSERT(aTextHtml.getLength() > 0);
+
+ if (aTextHtml.getLength() <= 0)
+ return Sequence<sal_Int8>();
+
+ // fill the buffer with dummy values to calc the exact length
+ std::string dummyHtmlHeader = GetHtmlFormatHeader(0, 0, 0, 0);
+ size_t lHtmlFormatHeader = dummyHtmlHeader.length();
+
+ std::string textHtml(reinterpret_cast<const char*>(aTextHtml.getConstArray()),
+ reinterpret_cast<const char*>(aTextHtml.getConstArray())
+ + aTextHtml.getLength());
+
+ std::string::size_type nStartHtml = textHtml.find(TAG_HTML) + lHtmlFormatHeader
+ - 1; // we start one before '<HTML>' Word 2000 does also so
+ std::string::size_type nEndHtml = textHtml.find(TAG_END_HTML) + lHtmlFormatHeader
+ + TAG_END_HTML.length()
+ + 1; // our SOffice 5.2 wants 2 behind </HTML>?
+
+ // The body tag may have parameters so we need to search for the
+ // closing '>' manually e.g. <BODY param> #92840#
+ std::string::size_type nStartFragment
+ = textHtml.find(">", textHtml.find(TAG_BODY)) + lHtmlFormatHeader + 1;
+ std::string::size_type nEndFragment = textHtml.find(TAG_END_BODY) + lHtmlFormatHeader;
+
+ std::string htmlFormat
+ = GetHtmlFormatHeader(nStartHtml, nEndHtml, nStartFragment, nEndFragment);
+ htmlFormat += textHtml;
+
+ Sequence<sal_Int8> byteSequence(htmlFormat.length() + 1); // space the trailing '\0'
+ memset(byteSequence.getArray(), 0, byteSequence.getLength());
+
+ memcpy(static_cast<void*>(byteSequence.getArray()),
+ static_cast<const void*>(htmlFormat.c_str()), htmlFormat.length());
+
+ return byteSequence;
+}
+
+const char* const HtmlStartTag = "<html";
+
+Sequence<sal_Int8> HTMLFormatToTextHtml(const Sequence<sal_Int8>& aHTMLFormat)
+{
+ assert(isHTMLFormat(aHTMLFormat) && "No HTML Format provided");
+
+ Sequence<sal_Int8>& nonconstHTMLFormatRef = const_cast<Sequence<sal_Int8>&>(aHTMLFormat);
+ char* dataStart = reinterpret_cast<char*>(nonconstHTMLFormatRef.getArray());
+ char* dataEnd = dataStart + nonconstHTMLFormatRef.getLength() - 1;
+ const char* htmlStartTag = strcasestr(dataStart, HtmlStartTag);
+
+ assert(htmlStartTag && "Seems to be no HTML at all");
+
+ // It doesn't seem to be HTML? Well then simply return what has been
+ // provided in non-debug builds
+ if (htmlStartTag == nullptr)
+ {
+ return aHTMLFormat;
+ }
+
+ sal_Int32 len = dataEnd - htmlStartTag;
+ Sequence<sal_Int8> plainHtmlData(len);
+
+ memcpy(static_cast<void*>(plainHtmlData.getArray()), htmlStartTag, len);
+
+ return plainHtmlData;
+}
+
+/* A simple format detection. We are just comparing the first few bytes
+ of the provided byte sequence to see whether or not it is the MS
+ Office Html format. If it shows that this is not reliable enough we
+ can improve this
+*/
+const char HtmlFormatStart[] = "Version:";
+int const HtmlFormatStartLen = (sizeof(HtmlFormatStart) - 1);
+
+bool isHTMLFormat(const Sequence<sal_Int8>& aHtmlSequence)
+{
+ if (aHtmlSequence.getLength() < HtmlFormatStartLen)
+ return false;
+
+ return rtl_str_compareIgnoreAsciiCase_WithLength(
+ HtmlFormatStart, HtmlFormatStartLen,
+ reinterpret_cast<const char*>(aHtmlSequence.getConstArray()), HtmlFormatStartLen)
+ == 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/ios/HtmlFmtFlt.hxx b/vcl/ios/HtmlFmtFlt.hxx
new file mode 100644
index 000000000..b11b19857
--- /dev/null
+++ b/vcl/ios/HtmlFmtFlt.hxx
@@ -0,0 +1,41 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_VCL_OSX_HTMLFMTFLT_HXX
+#define INCLUDED_VCL_OSX_HTMLFMTFLT_HXX
+
+#include <com/sun/star/uno/Sequence.hxx>
+
+/* Transform plain HTML into the format expected by MS Office.
+ */
+css::uno::Sequence<sal_Int8> TextHtmlToHTMLFormat(css::uno::Sequence<sal_Int8> const& aTextHtml);
+
+/* Transform the MS Office HTML format into plain HTML.
+ */
+css::uno::Sequence<sal_Int8> HTMLFormatToTextHtml(const css::uno::Sequence<sal_Int8>& aHTMLFormat);
+
+/* Detects whether the given byte sequence contains the MS Office Html format.
+
+ @returns True if the MS Office Html format will be detected False otherwise.
+ */
+bool isHTMLFormat(const css::uno::Sequence<sal_Int8>& aHtmlSequence);
+
+#endif // INCLUDED_VCL_OSX_HTMLFMTFLT_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/ios/clipboard.cxx b/vcl/ios/clipboard.cxx
new file mode 100644
index 000000000..b60cda1be
--- /dev/null
+++ b/vcl/ios/clipboard.cxx
@@ -0,0 +1,185 @@
+/* -*- Mode: ObjC; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "ios/iosinst.hxx"
+
+#include "clipboard.hxx"
+
+#include "DataFlavorMapping.hxx"
+#include "iOSTransferable.hxx"
+#include <com/sun/star/datatransfer/MimeContentTypeFactory.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <comphelper/processfactory.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+iOSClipboard::iOSClipboard()
+ : WeakComponentImplHelper<XSystemClipboard, XServiceInfo>(m_aMutex)
+{
+ auto xContext = comphelper::getProcessComponentContext();
+
+ mrXMimeCntFactory = css::datatransfer::MimeContentTypeFactory::create(xContext);
+
+ mpDataFlavorMapper.reset(new DataFlavorMapper());
+
+ mPasteboard = [UIPasteboard generalPasteboard];
+ assert(mPasteboard != nil);
+}
+
+iOSClipboard::~iOSClipboard() {}
+
+css::uno::Reference<css::datatransfer::XTransferable> SAL_CALL iOSClipboard::getContents()
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ return css::uno::Reference<css::datatransfer::XTransferable>(
+ new iOSTransferable(mrXMimeCntFactory, mpDataFlavorMapper, mPasteboard));
+}
+
+void SAL_CALL iOSClipboard::setContents(
+ const css::uno::Reference<css::datatransfer::XTransferable>& xTransferable,
+ const css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner>& /*xClipboardOwner*/)
+{
+ NSArray* types = xTransferable.is() ? mpDataFlavorMapper->flavorSequenceToTypesArray(
+ xTransferable->getTransferDataFlavors())
+ : [NSArray array];
+
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+
+ NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithCapacity:1];
+ NSArray* array = @[ dict ];
+
+ for (sal_uInt32 i = 0; i < [types count]; ++i)
+ {
+ DataProviderPtr_t dp = mpDataFlavorMapper->getDataProvider(types[i], xTransferable);
+
+ if (dp.get() != nullptr)
+ {
+ NSData* pBoardData = (NSData*)dp->getSystemData();
+ dict[types[i]] = pBoardData;
+ }
+ }
+ [mPasteboard setItems:array options:@{}];
+
+ // We don't keep a copy of the clipboard contents around in-process, so fire the lost clipboard
+ // ownership event right away.
+ // fireLostClipboardOwnershipEvent(xClipboardOwner, xTransferable);
+
+ // fireClipboardChangedEvent(xTransferable);
+}
+
+OUString SAL_CALL iOSClipboard::getName() { return OUString(); }
+
+sal_Int8 SAL_CALL iOSClipboard::getRenderingCapabilities() { return 0; }
+
+void SAL_CALL iOSClipboard::addClipboardListener(
+ const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ if (!listener.is())
+ throw css::lang::IllegalArgumentException(
+ "empty reference", static_cast<css::datatransfer::clipboard::XClipboardEx*>(this), 1);
+
+ mClipboardListeners.push_back(listener);
+}
+
+void SAL_CALL iOSClipboard::removeClipboardListener(
+ const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener)
+{
+ osl::MutexGuard aGuard(m_aMutex);
+
+ if (!listener.is())
+ throw css::lang::IllegalArgumentException(
+ "empty reference", static_cast<css::datatransfer::clipboard::XClipboardEx*>(this), 1);
+
+ mClipboardListeners.remove(listener);
+}
+
+void iOSClipboard::fireClipboardChangedEvent(
+ css::uno::Reference<css::datatransfer::XTransferable> xNewContents)
+{
+ osl::ClearableMutexGuard aGuard(m_aMutex);
+
+ std::list<css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>> listeners(
+ mClipboardListeners);
+ css::datatransfer::clipboard::ClipboardEvent aEvent;
+
+ if (!listeners.empty())
+ {
+ aEvent = css::datatransfer::clipboard::ClipboardEvent(static_cast<OWeakObject*>(this),
+ xNewContents);
+ }
+
+ aGuard.clear();
+
+ while (!listeners.empty())
+ {
+ if (listeners.front().is())
+ {
+ try
+ {
+ listeners.front()->changedContents(aEvent);
+ }
+ catch (const css::uno::RuntimeException&)
+ {
+ }
+ }
+ listeners.pop_front();
+ }
+}
+
+void iOSClipboard::fireLostClipboardOwnershipEvent(
+ css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> const& oldOwner,
+ css::uno::Reference<css::datatransfer::XTransferable> const& oldContent)
+{
+ assert(oldOwner.is());
+
+ try
+ {
+ oldOwner->lostOwnership(static_cast<css::datatransfer::clipboard::XClipboardEx*>(this),
+ oldContent);
+ }
+ catch (const css::uno::RuntimeException&)
+ {
+ }
+}
+
+OUString SAL_CALL iOSClipboard::getImplementationName()
+{
+ return OUString("com.sun.star.datatransfer.clipboard.iOSClipboard");
+}
+
+sal_Bool SAL_CALL iOSClipboard::supportsService(const OUString& ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence<OUString> SAL_CALL iOSClipboard::getSupportedServiceNames()
+{
+ return { OUString("com.sun.star.datatransfer.clipboard.SystemClipboard") };
+}
+
+css::uno::Reference<css::uno::XInterface>
+IosSalInstance::CreateClipboard(const css::uno::Sequence<css::uno::Any>&)
+{
+ return css::uno::Reference<css::uno::XInterface>(
+ static_cast<cppu::OWeakObject*>(new iOSClipboard()));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/ios/clipboard.hxx b/vcl/ios/clipboard.hxx
new file mode 100644
index 000000000..144e9c3ac
--- /dev/null
+++ b/vcl/ios/clipboard.hxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_VCL_IOS_CLIPBOARD_HXX
+#define INCLUDED_VCL_IOS_CLIPBOARD_HXX
+
+#include "DataFlavorMapping.hxx"
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+#include <cppuhelper/compbase.hxx>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardOwner.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardListener.hpp>
+#include <com/sun/star/datatransfer/clipboard/XClipboardNotifier.hpp>
+#include <com/sun/star/datatransfer/clipboard/XSystemClipboard.hpp>
+#include <com/sun/star/datatransfer/XMimeContentTypeFactory.hpp>
+#include <com/sun/star/datatransfer/clipboard/XFlushableClipboard.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+
+#include <list>
+
+#include <premac.h>
+#import <UIKit/UIKit.h>
+#include <postmac.h>
+
+class iOSClipboard
+ : public ::cppu::BaseMutex,
+ public ::cppu::WeakComponentImplHelper<css::datatransfer::clipboard::XSystemClipboard,
+ css::lang::XServiceInfo>
+{
+public:
+ iOSClipboard();
+
+ virtual ~iOSClipboard() override;
+ iOSClipboard(const iOSClipboard&) = delete;
+ iOSClipboard& operator=(const iOSClipboard&) = delete;
+
+ // XClipboard
+
+ css::uno::Reference<css::datatransfer::XTransferable> SAL_CALL getContents() override;
+
+ void SAL_CALL setContents(
+ const css::uno::Reference<css::datatransfer::XTransferable>& xTransferable,
+ const css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner>& xClipboardOwner)
+ override;
+
+ OUString SAL_CALL getName() override;
+
+ // XClipboardEx
+
+ sal_Int8 SAL_CALL getRenderingCapabilities() override;
+
+ // XClipboardNotifier
+
+ void SAL_CALL addClipboardListener(
+ const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener)
+ override;
+
+ void SAL_CALL removeClipboardListener(
+ const css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>& listener)
+ override;
+
+ // XServiceInfo
+
+ OUString SAL_CALL getImplementationName() override;
+
+ sal_Bool SAL_CALL supportsService(const OUString& ServiceName) override;
+
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+private:
+ /* Notify the current clipboard owner that he is no longer the clipboard owner. */
+ void fireLostClipboardOwnershipEvent(
+ css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> const& oldOwner,
+ css::uno::Reference<css::datatransfer::XTransferable> const& oldContent);
+
+ /* Notify all registered XClipboardListener that the clipboard content has changed. */
+ void
+ fireClipboardChangedEvent(css::uno::Reference<css::datatransfer::XTransferable> xNewContents);
+
+private:
+ css::uno::Reference<css::datatransfer::XMimeContentTypeFactory> mrXMimeCntFactory;
+ std::list<css::uno::Reference<css::datatransfer::clipboard::XClipboardListener>>
+ mClipboardListeners;
+ css::uno::Reference<css::datatransfer::clipboard::XClipboardOwner> mXClipboardOwner;
+ std::shared_ptr<DataFlavorMapper> mpDataFlavorMapper;
+ UIPasteboard* mPasteboard;
+};
+
+#endif // INCLUDED_VCL_IOS_CLIPBOARD_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/ios/dummies.cxx b/vcl/ios/dummies.cxx
new file mode 100644
index 000000000..d62609dc9
--- /dev/null
+++ b/vcl/ios/dummies.cxx
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <vcl/svapp.hxx>
+#include "salprn.hxx"
+#include "quartz/salgdi.h"
+#include "headless/svpinst.hxx"
+#include "unx/fontmanager.hxx"
+#include "unx/gendata.hxx"
+
+class FreetypeManager
+{
+};
+
+std::unique_ptr<SalPrinter> SvpSalInstance::CreatePrinter( SalInfoPrinter* /* pInfoPrinter */ )
+{
+ return nullptr;
+}
+
+OUString SvpSalInstance::GetDefaultPrinter()
+{
+ return OUString();
+}
+
+std::unique_ptr<GenPspGraphics> SvpSalInstance::CreatePrintGraphics()
+{
+ return nullptr;
+}
+
+void SvpSalInstance::PostPrintersChanged()
+{
+}
+
+SalInfoPrinter* SvpSalInstance::CreateInfoPrinter( SalPrinterQueueInfo* /* pQueueInfo */,
+ ImplJobSetup* /* pJobSetup */ )
+{
+ return NULL;
+}
+
+void SvpSalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+void SvpSalInstance::GetPrinterQueueInfo( ImplPrnQueueList* /* pList */ )
+{
+}
+
+void SvpSalInstance::GetPrinterQueueState( SalPrinterQueueInfo* /* pInfo */ )
+{
+}
+
+std::unique_ptr<SalPrinter> SalGenericInstance::CreatePrinter( SalInfoPrinter* /* pInfoPrinter */ )
+{
+ return nullptr;
+}
+
+OUString SalGenericInstance::GetDefaultPrinter()
+{
+ return OUString();
+}
+
+void SalGenericInstance::PostPrintersChanged()
+{
+}
+
+SalInfoPrinter* SalGenericInstance::CreateInfoPrinter( SalPrinterQueueInfo* /* pQueueInfo */,
+ ImplJobSetup* /* pJobSetup */ )
+{
+ return NULL;
+}
+
+void SalGenericInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
+{
+ delete pPrinter;
+}
+
+void SalGenericInstance::GetPrinterQueueInfo( ImplPrnQueueList* /* pList */ )
+{
+}
+
+void SalGenericInstance::GetPrinterQueueState( SalPrinterQueueInfo* /* pInfo */ )
+{
+}
+
+void SalGenericInstance::updatePrinterUpdate()
+{
+}
+
+void SalGenericInstance::jobStartedPrinterUpdate()
+{
+}
+
+void SalGenericInstance::jobEndedPrinterUpdate()
+{
+}
+
+bool AquaSalGraphics::drawEPS( long, long, long, long, void*, sal_uInt32 )
+{
+ return false;
+}
+
+using namespace psp;
+
+GenericUnixSalData::GenericUnixSalData(GenericUnixSalDataType const t, SalInstance *const pInstance)
+ : m_eType(t)
+ , m_pDisplay(nullptr)
+ , m_pFreetypeManager(new FreetypeManager)
+ , m_pPrintFontManager(nullptr)
+{
+ m_pInstance = pInstance;
+ SetSalData(this);
+}
+
+GenericUnixSalData::~GenericUnixSalData()
+{
+}
+
+PrintFontManager::~PrintFontManager()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/ios/iOSTransferable.cxx b/vcl/ios/iOSTransferable.cxx
new file mode 100644
index 000000000..9ec27867f
--- /dev/null
+++ b/vcl/ios/iOSTransferable.cxx
@@ -0,0 +1,186 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/datatransfer/UnsupportedFlavorException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <sal/log.hxx>
+#include <sal/types.h>
+#include <osl/diagnose.h>
+
+#include "iOSTransferable.hxx"
+
+#include "DataFlavorMapping.hxx"
+
+using namespace std;
+using namespace osl;
+using namespace cppu;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::datatransfer;
+using namespace com::sun::star::lang;
+
+namespace
+{
+bool isValidFlavor(const DataFlavor& aFlavor)
+{
+ size_t len = aFlavor.MimeType.getLength();
+ Type dtype = aFlavor.DataType;
+ return ((len > 0)
+ && ((dtype == cppu::UnoType<Sequence<sal_Int8>>::get())
+ || (dtype == cppu::UnoType<OUString>::get())));
+}
+
+bool cmpAllContentTypeParameter(const Reference<XMimeContentType>& xLhs,
+ const Reference<XMimeContentType>& xRhs)
+{
+ Sequence<OUString> xLhsFlavors = xLhs->getParameters();
+ Sequence<OUString> xRhsFlavors = xRhs->getParameters();
+
+ // Stop here if the number of parameters is different already
+ if (xLhsFlavors.getLength() != xRhsFlavors.getLength())
+ return false;
+
+ try
+ {
+ OUString pLhs;
+ OUString pRhs;
+
+ for (sal_Int32 i = 0; i < xLhsFlavors.getLength(); i++)
+ {
+ pLhs = xLhs->getParameterValue(xLhsFlavors[i]);
+ pRhs = xRhs->getParameterValue(xLhsFlavors[i]);
+
+ if (!pLhs.equalsIgnoreAsciiCase(pRhs))
+ {
+ return false;
+ }
+ }
+ }
+ catch (IllegalArgumentException&)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+} // unnamed namespace
+
+iOSTransferable::iOSTransferable(const Reference<XMimeContentTypeFactory>& rXMimeCntFactory,
+ std::shared_ptr<DataFlavorMapper> pDataFlavorMapper,
+ UIPasteboard* pasteboard)
+ : mrXMimeCntFactory(rXMimeCntFactory)
+ , mDataFlavorMapper(pDataFlavorMapper)
+ , mPasteboard(pasteboard)
+{
+ [mPasteboard retain];
+
+ initClipboardItemList();
+}
+
+iOSTransferable::~iOSTransferable() { [mPasteboard release]; }
+
+Any SAL_CALL iOSTransferable::getTransferData(const DataFlavor& aFlavor)
+{
+ if (!isValidFlavor(aFlavor) || !isDataFlavorSupported(aFlavor))
+ {
+ throw UnsupportedFlavorException("Unsupported data flavor",
+ static_cast<XTransferable*>(this));
+ }
+
+ bool bInternal(false);
+ NSString* sysFormat = (aFlavor.MimeType.startsWith("image/png"))
+ ? DataFlavorMapper::openOfficeImageToSystemFlavor(mPasteboard)
+ : mDataFlavorMapper->openOfficeToSystemFlavor(aFlavor, bInternal);
+ DataProviderPtr_t dp;
+
+ NSData* sysData = [mPasteboard dataForPasteboardType:sysFormat];
+ dp = DataFlavorMapper::getDataProvider(sysFormat, sysData);
+
+ if (dp.get() == nullptr)
+ {
+ throw UnsupportedFlavorException("Unsupported data flavor",
+ static_cast<XTransferable*>(this));
+ }
+
+ return dp->getOOoData();
+}
+
+Sequence<DataFlavor> SAL_CALL iOSTransferable::getTransferDataFlavors() { return mFlavorList; }
+
+sal_Bool SAL_CALL iOSTransferable::isDataFlavorSupported(const DataFlavor& aFlavor)
+{
+ for (sal_Int32 i = 0; i < mFlavorList.getLength(); i++)
+ if (compareDataFlavors(aFlavor, mFlavorList[i]))
+ return true;
+
+ return false;
+}
+
+void iOSTransferable::initClipboardItemList()
+{
+ NSArray* pboardFormats = [mPasteboard pasteboardTypes];
+
+ if (pboardFormats == nullptr)
+ {
+ throw RuntimeException("Cannot get clipboard data", static_cast<XTransferable*>(this));
+ }
+
+#ifdef SAL_LOG_INFO
+ NSString* types = @"";
+ for (unsigned i = 0; i < [pboardFormats count]; i++)
+ {
+ if ([types length] > 0)
+ types = [types stringByAppendingString:@", "];
+ types = [types stringByAppendingString:[pboardFormats objectAtIndex:i]];
+ }
+ SAL_INFO("vcl.ios.clipboard", "Types on clipboard: " << [types UTF8String]);
+#endif
+
+ mFlavorList = mDataFlavorMapper->typesArrayToFlavorSequence(pboardFormats);
+}
+
+/* Compares two DataFlavors. Returns true if both DataFlavor have the same media type
+ and the number of parameter and all parameter values do match otherwise false
+ is returned.
+ */
+bool iOSTransferable::compareDataFlavors(const DataFlavor& lhs, const DataFlavor& rhs)
+{
+ try
+ {
+ Reference<XMimeContentType> xLhs(mrXMimeCntFactory->createMimeContentType(lhs.MimeType));
+ Reference<XMimeContentType> xRhs(mrXMimeCntFactory->createMimeContentType(rhs.MimeType));
+
+ if (!xLhs->getFullMediaType().equalsIgnoreAsciiCase(xRhs->getFullMediaType())
+ || !cmpAllContentTypeParameter(xLhs, xRhs))
+ {
+ return false;
+ }
+ }
+ catch (IllegalArgumentException&)
+ {
+ OSL_FAIL("Invalid content type detected");
+ return false;
+ }
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/ios/iOSTransferable.hxx b/vcl/ios/iOSTransferable.hxx
new file mode 100644
index 000000000..5c685dba8
--- /dev/null
+++ b/vcl/ios/iOSTransferable.hxx
@@ -0,0 +1,73 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef INCLUDED_VCL_IOS_IOSTRANSFERABLE_HXX
+#define INCLUDED_VCL_IOS_IOSTRANSFERABLE_HXX
+
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/datatransfer/XMimeContentTypeFactory.hpp>
+#include <com/sun/star/datatransfer/XMimeContentType.hpp>
+
+#include "DataFlavorMapping.hxx"
+
+#include <premac.h>
+#import <UIKit/UIKit.h>
+#include <postmac.h>
+
+#include <memory>
+#include <vector>
+
+class iOSTransferable : public ::cppu::WeakImplHelper<css::datatransfer::XTransferable>
+{
+public:
+ explicit iOSTransferable(
+ css::uno::Reference<css::datatransfer::XMimeContentTypeFactory> const& rXMimeCntFactory,
+ std::shared_ptr<DataFlavorMapper> pDataFlavorMapper, UIPasteboard* pasteboard);
+
+ virtual ~iOSTransferable() override;
+ iOSTransferable(const iOSTransferable&) = delete;
+ iOSTransferable& operator=(const iOSTransferable&) = delete;
+
+ // XTransferable
+
+ virtual css::uno::Any SAL_CALL
+ getTransferData(const css::datatransfer::DataFlavor& aFlavor) override;
+
+ css::uno::Sequence<css::datatransfer::DataFlavor> SAL_CALL getTransferDataFlavors() override;
+
+ sal_Bool SAL_CALL isDataFlavorSupported(const css::datatransfer::DataFlavor& aFlavor) override;
+
+ // Helper functions not part of the XTransferable interface
+
+ void initClipboardItemList();
+
+ bool compareDataFlavors(const css::datatransfer::DataFlavor& lhs,
+ const css::datatransfer::DataFlavor& rhs);
+
+private:
+ css::uno::Sequence<css::datatransfer::DataFlavor> mFlavorList;
+ css::uno::Reference<css::datatransfer::XMimeContentTypeFactory> mrXMimeCntFactory;
+ std::shared_ptr<DataFlavorMapper> mDataFlavorMapper;
+ UIPasteboard* mPasteboard;
+};
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/ios/iosinst.cxx b/vcl/ios/iosinst.cxx
new file mode 100644
index 000000000..65963ef9c
--- /dev/null
+++ b/vcl/ios/iosinst.cxx
@@ -0,0 +1,197 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <premac.h>
+#include <UIKit/UIKit.h>
+#include <postmac.h>
+
+#include "ios/iosinst.hxx"
+#include "headless/svpdummies.hxx"
+#include "unx/gendata.hxx"
+#include "quartz/utils.h"
+#include <vcl/layout.hxx>
+#include <vcl/settings.hxx>
+
+// Totally wrong of course but doesn't seem to harm much in the iOS app.
+static int viewWidth = 1, viewHeight = 1;
+
+class IosSalData : public GenericUnixSalData
+{
+public:
+ explicit IosSalData(SalInstance *pInstance)
+ : GenericUnixSalData(SAL_DATA_IOS, pInstance)
+ {
+ }
+ virtual void ErrorTrapPush() {}
+ virtual bool ErrorTrapPop( bool ) { return false; }
+};
+
+void IosSalInstance::GetWorkArea( tools::Rectangle& rRect )
+{
+ rRect = tools::Rectangle( Point( 0, 0 ),
+ Size( viewWidth, viewHeight ) );
+}
+
+IosSalInstance *IosSalInstance::getInstance()
+{
+ if (!ImplGetSVData())
+ return NULL;
+ IosSalData *pData = static_cast<IosSalData *>(ImplGetSVData()->mpSalData);
+ if (!pData)
+ return NULL;
+ return static_cast<IosSalInstance *>(pData->m_pInstance);
+}
+
+IosSalInstance::IosSalInstance( std::unique_ptr<SalYieldMutex> pMutex )
+ : SvpSalInstance( std::move(pMutex) )
+{
+}
+
+IosSalInstance::~IosSalInstance()
+{
+}
+
+class IosSalSystem : public SvpSalSystem {
+public:
+ IosSalSystem() : SvpSalSystem() {}
+ virtual ~IosSalSystem() {}
+ virtual int ShowNativeDialog( const OUString& rTitle,
+ const OUString& rMessage,
+ const std::vector< OUString >& rButtons );
+};
+
+SalSystem *IosSalInstance::CreateSalSystem()
+{
+ return new IosSalSystem();
+}
+
+class IosSalFrame : public SvpSalFrame
+{
+public:
+ IosSalFrame( IosSalInstance *pInstance,
+ SalFrame *pParent,
+ SalFrameStyleFlags nSalFrameStyle)
+ : SvpSalFrame( pInstance, pParent, nSalFrameStyle )
+ {
+ if (pParent == NULL && viewWidth > 1 && viewHeight > 1)
+ SetPosSize(0, 0, viewWidth, viewHeight, SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT);
+ }
+
+ virtual void GetWorkArea( tools::Rectangle& rRect ) override
+ {
+ IosSalInstance::getInstance()->GetWorkArea( rRect );
+ }
+
+ virtual void ShowFullScreen( bool, sal_Int32 ) override
+ {
+ SetPosSize( 0, 0, viewWidth, viewHeight,
+ SAL_FRAME_POSSIZE_WIDTH | SAL_FRAME_POSSIZE_HEIGHT );
+ }
+
+ virtual void UpdateSettings( AllSettings &rSettings ) override
+ {
+ // Clobber the UI fonts
+ vcl::Font aFont( "Helvetica", Size( 0, 10 ) );
+
+ StyleSettings aStyleSet = rSettings.GetStyleSettings();
+ aStyleSet.SetAppFont( aFont );
+ aStyleSet.SetHelpFont( aFont );
+ aStyleSet.SetMenuFont( aFont );
+ aStyleSet.SetToolFont( aFont );
+ aStyleSet.SetLabelFont( aFont );
+ aStyleSet.SetRadioCheckFont( aFont );
+ aStyleSet.SetPushButtonFont( aFont );
+ aStyleSet.SetFieldFont( aFont );
+ aStyleSet.SetIconFont( aFont );
+ aStyleSet.SetTabFont( aFont );
+ aStyleSet.SetGroupFont( aFont );
+
+ Color aBackgroundColor( 0xff, 0xff, 0xff );
+ aStyleSet.BatchSetBackgrounds( aBackgroundColor, false );
+ aStyleSet.SetMenuColor( aBackgroundColor );
+ aStyleSet.SetMenuBarColor( aBackgroundColor );
+ aStyleSet.SetDialogColor( aBackgroundColor );
+
+ rSettings.SetStyleSettings( aStyleSet );
+ }
+};
+
+SalFrame *IosSalInstance::CreateChildFrame( SystemParentData* pParent, SalFrameStyleFlags nStyle )
+{
+ pParent = NULL;
+ return new IosSalFrame( this, NULL, nStyle );
+}
+
+SalFrame *IosSalInstance::CreateFrame( SalFrame* pParent, SalFrameStyleFlags nStyle )
+{
+ return new IosSalFrame( this, pParent, nStyle );
+}
+
+void SalAbort( const OUString& rErrorText, bool bDumpCore )
+{
+ (void) bDumpCore;
+
+ NSLog(@"SalAbort: %s", OUStringToOString(rErrorText, osl_getThreadTextEncoding()).getStr() );
+}
+
+const OUString& SalGetDesktopEnvironment()
+{
+ static OUString aEnv( "iOS" );
+ return aEnv;
+}
+
+SalData::SalData() :
+ m_pInstance( 0 ),
+ mpFontList( 0 ),
+ mxRGBSpace( CGColorSpaceCreateDeviceRGB() ),
+ mxGraySpace( CGColorSpaceCreateDeviceGray() )
+{
+}
+
+SalData::~SalData()
+{
+}
+
+// This is our main entry point:
+SalInstance *CreateSalInstance()
+{
+ IosSalInstance* pInstance = new IosSalInstance( std::make_unique<SvpSalYieldMutex>() );
+ new IosSalData( pInstance );
+ pInstance->AcquireYieldMutex();
+ return pInstance;
+}
+
+void DestroySalInstance( SalInstance *pInst )
+{
+ pInst->ReleaseYieldMutexAll();
+ delete pInst;
+}
+
+int IosSalSystem::ShowNativeDialog( const OUString& rTitle,
+ const OUString& rMessage,
+ const std::vector< OUString >& rButtons )
+{
+ (void)rButtons;
+
+ NSLog(@"%@: %@", CreateNSString(rTitle), CreateNSString(rMessage));
+
+ return 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */