CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / widget / src / os2 / nsClipboard.cpp
blob0d57a1d0f9deb9766024c67dfb6feead27b65722
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
16 * The Original Code is the Mozilla OS/2 libraries.
18 * The Initial Developer of the Original Code is
19 * John Fairhurst, <john_fairhurst@iname.com>.
20 * Portions created by the Initial Developer are Copyright (C) 1999
21 * the Initial Developer. All Rights Reserved.
23 * Contributor(s):
24 * 2000/08/04 Henry Sobotka <sobotka@axess.com> Update from M7
25 * 2000/10/02 IBM Corp. Sync-up to M18 level
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
41 #include "nsXPCOM.h"
42 #include "nsISupportsPrimitives.h"
43 #include "nsCOMPtr.h"
44 #include "nsPrimitiveHelpers.h"
45 #include "nsXPIDLString.h"
46 #include "prmem.h"
47 #include "nsIObserverService.h"
48 #include "nsIServiceManager.h"
49 #include "nsOS2Uni.h"
50 #include "nsClipboard.h"
51 #include "mozilla/Services.h"
53 inline ULONG RegisterClipboardFormat(PCSZ pcszFormat)
55 ATOM atom = WinFindAtom(WinQuerySystemAtomTable(), pcszFormat);
56 if (!atom) {
57 atom = WinAddAtom(WinQuerySystemAtomTable(), pcszFormat);
59 return atom;
62 nsClipboard::nsClipboard() : nsBaseClipboard()
64 RegisterClipboardFormat(kTextMime);
65 RegisterClipboardFormat(kUnicodeMime);
66 RegisterClipboardFormat(kHTMLMime);
67 RegisterClipboardFormat(kAOLMailMime);
68 RegisterClipboardFormat(kPNGImageMime);
69 RegisterClipboardFormat(kJPEGImageMime);
70 RegisterClipboardFormat(kGIFImageMime);
71 RegisterClipboardFormat(kFileMime);
72 RegisterClipboardFormat(kURLMime);
73 RegisterClipboardFormat(kNativeImageMime);
74 RegisterClipboardFormat(kNativeHTMLMime);
76 // Register for a shutdown notification so that we can flush data
77 // to the OS clipboard.
78 nsCOMPtr<nsIObserverService> observerService =
79 mozilla::services::GetObserverService();
80 if (observerService)
81 observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
84 nsClipboard::~nsClipboard()
87 NS_IMPL_ISUPPORTS_INHERITED1(nsClipboard, nsBaseClipboard, nsIObserver)
89 nsresult nsClipboard::SetNativeClipboardData(PRInt32 aWhichClipboard)
91 if (aWhichClipboard != kGlobalClipboard)
92 return NS_ERROR_FAILURE;
94 return DoClipboardAction(Write);
97 nsresult nsClipboard::GetNativeClipboardData(nsITransferable *aTransferable, PRInt32 aWhichClipboard)
99 // make sure we have a good transferable
100 if (!aTransferable || aWhichClipboard != kGlobalClipboard)
101 return NS_ERROR_FAILURE;
103 nsITransferable *tmp = mTransferable;
104 mTransferable = aTransferable;
105 nsresult rc = DoClipboardAction(Read);
106 mTransferable = tmp;
107 return rc;
110 // Get some data from the clipboard
111 PRBool nsClipboard::GetClipboardData(const char *aFlavor)
113 ULONG ulFormatID = GetFormatID( aFlavor );
115 PRBool found = GetClipboardDataByID( ulFormatID, aFlavor );
117 if (!found)
119 if (!strcmp( aFlavor, kUnicodeMime ))
121 found = GetClipboardDataByID( CF_TEXT, aFlavor );
123 else if (strstr( aFlavor, "image/" ))
125 found = GetClipboardDataByID( CF_BITMAP, aFlavor );
129 return found;
132 PRBool nsClipboard::GetClipboardDataByID(ULONG ulFormatID, const char *aFlavor)
134 PVOID pDataMem;
135 PRUint32 NumOfBytes;
136 PRBool TempBufAllocated = PR_FALSE;
138 PVOID pClipboardData = reinterpret_cast<PVOID>(WinQueryClipbrdData( 0, ulFormatID ));
140 if (!pClipboardData)
141 return PR_FALSE;
143 if (strstr( aFlavor, "text/" )) // All text/.. flavors are null-terminated
145 pDataMem = pClipboardData;
147 if (ulFormatID == CF_TEXT) // CF_TEXT is one byte character set
149 PRUint32 NumOfChars = strlen( static_cast<char*>(pDataMem) );
150 NumOfBytes = NumOfChars;
152 if (!strcmp( aFlavor, kUnicodeMime )) // Asked for unicode, but only plain text available. Convert it!
154 nsAutoChar16Buffer buffer;
155 PRInt32 bufLength;
156 MultiByteToWideChar(0, static_cast<char*>(pDataMem), NumOfChars,
157 buffer, bufLength);
158 pDataMem = ToNewUnicode(nsDependentString(buffer.Elements()));
159 TempBufAllocated = PR_TRUE;
160 NumOfBytes = bufLength * sizeof(UniChar);
164 else // All other text/.. flavors are in unicode
166 PRUint32 NumOfChars = UniStrlen( static_cast<UniChar*>(pDataMem) );
167 NumOfBytes = NumOfChars * sizeof(UniChar);
168 PVOID pTempBuf = nsMemory::Alloc(NumOfBytes);
169 memcpy(pTempBuf, pDataMem, NumOfBytes);
170 pDataMem = pTempBuf;
171 TempBufAllocated = PR_TRUE;
174 // DOM wants LF only, so convert from CRLF
175 nsLinebreakHelpers::ConvertPlatformToDOMLinebreaks( aFlavor, &pDataMem, // pDataMem could be reallocated !!
176 reinterpret_cast<PRInt32*>(&NumOfBytes) ); // yuck
179 else // Assume rest of flavors are binary data
181 if (ulFormatID == CF_BITMAP)
183 if (!strcmp( aFlavor, kJPEGImageMime ))
185 // OS2TODO Convert bitmap to jpg
186 #ifdef DEBUG
187 printf( "nsClipboard:: No JPG found on clipboard; need to convert BMP\n");
188 #endif
190 else if (!strcmp( aFlavor, kGIFImageMime ))
192 // OS2TODO Convert bitmap to gif
193 #ifdef DEBUG
194 printf( "nsClipboard:: No GIF found on clipboard; need to convert BMP\n");
195 #endif
197 else if (!strcmp( aFlavor, kPNGImageMime ))
199 // OS2TODO Convert bitmap to png
200 #ifdef DEBUG
201 printf( "nsClipboard:: No PNG found on clipboard; need to convert BMP\n");
202 #endif
205 else
207 pDataMem = static_cast<PBYTE>(pClipboardData) + sizeof(PRUint32);
208 NumOfBytes = *(static_cast<PRUint32*>(pClipboardData));
212 nsCOMPtr<nsISupports> genericDataWrapper;
213 nsPrimitiveHelpers::CreatePrimitiveForData( aFlavor, pDataMem, NumOfBytes, getter_AddRefs(genericDataWrapper) );
214 #ifdef DEBUG
215 nsresult errCode =
216 #endif
217 mTransferable->SetTransferData( aFlavor, genericDataWrapper, NumOfBytes );
218 #ifdef DEBUG
219 if (errCode != NS_OK)
220 printf( "nsClipboard:: Error setting data into transferable\n" );
221 #endif
223 if (TempBufAllocated)
224 nsMemory::Free(pDataMem);
226 return PR_TRUE;
230 // Set some data onto the clipboard
231 void nsClipboard::SetClipboardData(const char *aFlavor)
233 void *pMozData = nsnull;
234 PRUint32 NumOfBytes = 0;
236 // Get the data from the transferable
237 nsCOMPtr<nsISupports> genericDataWrapper;
238 #ifdef DEBUG
239 nsresult errCode =
240 #endif
241 mTransferable->GetTransferData( aFlavor, getter_AddRefs(genericDataWrapper), &NumOfBytes );
242 #ifdef DEBUG
243 if (NS_FAILED(errCode)) printf( "nsClipboard:: Error getting data from transferable\n" );
244 #endif
245 if (NumOfBytes == 0) return;
246 nsPrimitiveHelpers::CreateDataFromPrimitive( aFlavor, genericDataWrapper, &pMozData, NumOfBytes );
248 /* If creating the data failed, just return */
249 if (!pMozData) {
250 return;
253 ULONG ulFormatID = GetFormatID( aFlavor );
255 if (strstr( aFlavor, "text/" )) // All text/.. flavors are null-terminated
257 if (ulFormatID == CF_TEXT) // CF_TEXT is one byte character set
259 char* pByteMem = nsnull;
261 if (DosAllocSharedMem( reinterpret_cast<PPVOID>(&pByteMem), nsnull, NumOfBytes + sizeof(char),
262 PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE ) == NO_ERROR)
264 memcpy( pByteMem, pMozData, NumOfBytes ); // Copy text string
265 pByteMem[NumOfBytes] = '\0'; // Append terminator
267 // With Warp4 copying more than 64K to the clipboard works well, but
268 // legacy apps cannot always handle it. So output an alarm to alert the
269 // user that there might be a problem.
270 if (strlen(pByteMem) > 0xFFFF) {
271 WinAlarm(HWND_DESKTOP, WA_ERROR);
273 WinSetClipbrdData(0, reinterpret_cast<ULONG>(pByteMem), ulFormatID, CFI_POINTER);
276 else // All other text/.. flavors are in unicode
278 UniChar* pUnicodeMem = nsnull;
279 PRUint32 NumOfChars = NumOfBytes / sizeof(UniChar);
281 if (DosAllocSharedMem( reinterpret_cast<PPVOID>(&pUnicodeMem), nsnull, NumOfBytes + sizeof(UniChar),
282 PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE ) == NO_ERROR)
284 memcpy( pUnicodeMem, pMozData, NumOfBytes ); // Copy text string
285 pUnicodeMem[NumOfChars] = L'\0'; // Append terminator
287 WinSetClipbrdData( 0, reinterpret_cast<ULONG>(pUnicodeMem), ulFormatID, CFI_POINTER );
290 // If the flavor is unicode, we also put it on the clipboard as CF_TEXT
291 // after conversion to locale charset.
293 if (!strcmp( aFlavor, kUnicodeMime ))
295 char* pByteMem = nsnull;
297 if (DosAllocSharedMem(reinterpret_cast<PPVOID>(&pByteMem), nsnull,
298 NumOfBytes + 1,
299 PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE ) == NO_ERROR)
301 PRUnichar* uchtemp = (PRUnichar*)pMozData;
302 for (PRUint32 i=0;i<NumOfChars;i++) {
303 switch (uchtemp[i]) {
304 case 0x2018:
305 case 0x2019:
306 uchtemp[i] = 0x0027;
307 break;
308 case 0x201C:
309 case 0x201D:
310 uchtemp[i] = 0x0022;
311 break;
312 case 0x2014:
313 uchtemp[i] = 0x002D;
314 break;
318 nsAutoCharBuffer buffer;
319 PRInt32 bufLength;
320 WideCharToMultiByte(0, static_cast<PRUnichar*>(pMozData),
321 NumOfBytes, buffer, bufLength);
322 memcpy(pByteMem, buffer.Elements(), NumOfBytes);
323 // With Warp4 copying more than 64K to the clipboard works well, but
324 // legacy apps cannot always handle it. So output an alarm to alert the
325 // user that there might be a problem.
326 if (strlen(pByteMem) > 0xFFFF) {
327 WinAlarm(HWND_DESKTOP, WA_ERROR);
329 WinSetClipbrdData(0, reinterpret_cast<ULONG>(pByteMem), CF_TEXT, CFI_POINTER);
334 else // Assume rest of flavors are binary data
336 PBYTE pBinaryMem = nsnull;
338 if (DosAllocSharedMem( reinterpret_cast<PPVOID>(&pBinaryMem), nsnull, NumOfBytes + sizeof(PRUint32),
339 PAG_WRITE | PAG_COMMIT | OBJ_GIVEABLE ) == NO_ERROR)
341 *(reinterpret_cast<PRUint32*>(pBinaryMem)) = NumOfBytes; // First DWORD contains data length
342 memcpy( pBinaryMem + sizeof(PRUint32), pMozData, NumOfBytes ); // Copy binary data
344 WinSetClipbrdData( 0, reinterpret_cast<ULONG>(pBinaryMem), ulFormatID, CFI_POINTER );
347 // If the flavor is image, we also put it on clipboard as CF_BITMAP
348 // after conversion to OS2 bitmap
350 if (strstr (aFlavor, "image/"))
352 // XXX OS2TODO Convert jpg, gif, png to bitmap
353 #ifdef DEBUG
354 printf( "nsClipboard:: Putting image on clipboard; should also convert to BMP\n" );
355 #endif
358 nsMemory::Free(pMozData);
361 // Go through the flavors in the transferable and either get or set them
362 nsresult nsClipboard::DoClipboardAction(ClipboardAction aAction)
364 nsresult rc = NS_ERROR_FAILURE;
366 if (WinOpenClipbrd(0/*hab*/)) {
368 if (aAction == Write)
369 WinEmptyClipbrd(0/*hab*/);
371 // Get the list of formats the transferable can handle
372 nsCOMPtr<nsISupportsArray> pFormats;
373 if(aAction == Read)
374 rc = mTransferable->FlavorsTransferableCanImport(getter_AddRefs(pFormats));
375 else
376 rc = mTransferable->FlavorsTransferableCanExport(getter_AddRefs(pFormats));
378 if (NS_FAILED(rc))
379 return NS_ERROR_FAILURE;
381 PRUint32 cFormats = 0;
382 pFormats->Count(&cFormats);
384 for (PRUint32 i = 0; i < cFormats; i++) {
386 nsCOMPtr<nsISupports> genericFlavor;
387 pFormats->GetElementAt(i, getter_AddRefs(genericFlavor));
388 nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
390 if (currentFlavor) {
391 nsXPIDLCString flavorStr;
392 currentFlavor->ToString(getter_Copies(flavorStr));
394 if (aAction == Read) {
395 if (GetClipboardData(flavorStr))
396 break;
398 else
399 SetClipboardData(flavorStr);
402 WinCloseClipbrd(0/*hab*/);
403 rc = NS_OK;
405 return rc;
408 // get the format ID for a given mimetype
409 ULONG nsClipboard::GetFormatID(const char *aMimeStr)
411 if (strcmp(aMimeStr, kTextMime) == 0)
412 return CF_TEXT;
414 return RegisterClipboardFormat(aMimeStr);
417 // nsIObserver
418 NS_IMETHODIMP
419 nsClipboard::Observe(nsISupports *aSubject, const char *aTopic,
420 const PRUnichar *aData)
422 // This will be called on shutdown.
424 // make sure we have a good transferable
425 if (!mTransferable)
426 return NS_ERROR_FAILURE;
428 if (WinOpenClipbrd(0/*hab*/)) {
429 WinEmptyClipbrd(0/*hab*/);
431 // get flavor list that includes all flavors that can be written (including ones
432 // obtained through conversion)
433 nsCOMPtr<nsISupportsArray> flavorList;
434 nsresult errCode = mTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList));
435 if (NS_FAILED(errCode))
436 return NS_ERROR_FAILURE;
438 // Walk through flavors and put data on to clipboard
439 PRUint32 i;
440 PRUint32 cnt;
441 flavorList->Count(&cnt);
442 for (i = 0; i < cnt; i++) {
443 nsCOMPtr<nsISupports> genericFlavor;
444 flavorList->GetElementAt(i, getter_AddRefs(genericFlavor));
445 nsCOMPtr<nsISupportsCString> currentFlavor(do_QueryInterface(genericFlavor));
446 if (currentFlavor) {
447 nsXPIDLCString flavorStr;
448 currentFlavor->ToString(getter_Copies(flavorStr));
449 SetClipboardData(flavorStr);
452 WinCloseClipbrd(0/*hab*/);
454 return NS_OK;
457 NS_IMETHODIMP nsClipboard::HasDataMatchingFlavors(const char** aFlavorList,
458 PRUint32 aLength,
459 PRInt32 aWhichClipboard,
460 PRBool *_retval)
462 *_retval = PR_FALSE;
463 if (aWhichClipboard != kGlobalClipboard || !aFlavorList)
464 return NS_OK;
466 for (PRUint32 i = 0; i < aLength; ++i) {
467 ULONG fmtInfo = 0;
468 ULONG format = GetFormatID(aFlavorList[i]);
470 if (WinQueryClipbrdFmtInfo(0/*hab*/, format, &fmtInfo)) {
471 *_retval = PR_TRUE;
472 break;
475 // if the client asked for unicode and it wasn't present, check if we have CF_TEXT.
476 if (!strcmp(aFlavorList[i], kUnicodeMime)) {
477 if (WinQueryClipbrdFmtInfo(0/*hab*/, CF_TEXT, &fmtInfo)) {
478 *_retval = PR_TRUE;
479 break;
483 // OS2TODO - Support for Images
484 // if the client asked for image/.. and it wasn't present, check if we have CF_BITMAP.
485 if (strstr(aFlavorList[i], "image/")) {
486 if (WinQueryClipbrdFmtInfo (0, CF_BITMAP, &fmtInfo)) {
487 #ifdef DEBUG
488 printf("nsClipboard:: Image present on clipboard; need to add BMP conversion!\n");
489 #endif
490 // *_retval = PR_TRUE;
491 // break;
495 return NS_OK;