Move nsIDocShellTreeItem::childOffset to nsDocShell and remove all uses except internally by nsDocShell (it should be removed eventually).
b=376562 r=Olli.Pettay sr=bzbarsky
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1999-2000
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Stuart Parmenter <pavlov@netscape.com>
* Mike Pinkerton <pinkerton@netscape.com>
* Dan Rosen <dr@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsClipboard.h"
#include <Pt.h>
#include "nsCOMPtr.h"
#include "nsCRT.h"
#include "nsISupportsArray.h"
#include "nsISupportsPrimitives.h"
#include "nsReadableUtils.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsWidgetsCID.h"
#include "nsXPIDLString.h"
#include "nsReadableUtils.h"
#include "nsPrimitiveHelpers.h"
#include "nsTextFormatter.h"
#include "nsIServiceManager.h"
#include "nsICharsetConverterManager.h"
#include "prtime.h"
#include "prthread.h"
// unicode conversion
#include "nsIPlatformCharset.h"
#include "nsICharsetConverterManager.h"
//#define DEBUG_CLIPBOARD
// Define this to enable the obsolete X cut buffer mechanism
// In general, a bad idea (see http://www.jwz.org/doc/x-cut-and-paste.html)
// but it might have its uses for backwards compatibility.
NS_IMPL_ISUPPORTS1(nsClipboard, nsIClipboard)
#define Ph_CLIPBOARD_TYPE_MOZ_BOOKMARK "BOOK"
#define Ph_CLIPBOARD_TYPE_IMAGE "IMAG"
#define Ph_CLIPBOARD_TYPE_HTML "HTML"
//-------------------------------------------------------------------------
//
// nsClipboard constructor
//
//-------------------------------------------------------------------------
nsClipboard::nsClipboard()
{
#ifdef DEBUG_CLIPBOARD
printf("nsClipboard::nsClipboard()\n");
#endif /* DEBUG_CLIPBOARD */
mIgnoreEmptyNotification = PR_FALSE;
mGlobalTransferable = nsnull;
mSelectionTransferable = nsnull;
mGlobalOwner = nsnull;
mSelectionOwner = nsnull;
mInputGroup = 1;
}
//-------------------------------------------------------------------------
//
// nsClipboard destructor
//
//-------------------------------------------------------------------------
nsClipboard::~nsClipboard()
{
#ifdef DEBUG_CLIPBOARD
printf("nsClipboard::~nsClipboard()\n");
#endif /* DEBUG_CLIPBOARD */
}
/**
* Sets the transferable object
*
*/
NS_IMETHODIMP nsClipboard::SetData(nsITransferable * aTransferable,
nsIClipboardOwner * anOwner,
PRInt32 aWhichClipboard)
{
if (aWhichClipboard == kSelectionClipboard)
return (NS_ERROR_FAILURE);
if ((aTransferable == mGlobalTransferable.get() && anOwner == mGlobalOwner.get() &&
aWhichClipboard == kGlobalClipboard ) || (aTransferable == mSelectionTransferable.get() &&
anOwner == mSelectionOwner.get() && aWhichClipboard == kSelectionClipboard))
{
return NS_OK;
}
EmptyClipboard(aWhichClipboard);
switch (aWhichClipboard)
{
case kSelectionClipboard:
mSelectionOwner = anOwner;
mSelectionTransferable = aTransferable;
break;
case kGlobalClipboard:
mGlobalOwner = anOwner;
mGlobalTransferable = aTransferable;
break;
}
return SetNativeClipboardData(aWhichClipboard);
}
/**
* Gets the transferable object
*
*/
NS_IMETHODIMP nsClipboard::GetData(nsITransferable * aTransferable, PRInt32 aWhichClipboard)
{
if (aWhichClipboard == kSelectionClipboard)
return (NS_ERROR_FAILURE);
if (nsnull != aTransferable)
return GetNativeClipboardData(aTransferable, aWhichClipboard);
else
{
#ifdef DEBUG_CLIPBOARD
printf(" nsClipboard::GetData(), aTransferable is NULL.\n");
#endif
}
return NS_ERROR_FAILURE;
}
/**
*
*
*/
NS_IMETHODIMP nsClipboard::EmptyClipboard(PRInt32 aWhichClipboard)
{
if (mIgnoreEmptyNotification)
return NS_OK;
if (aWhichClipboard == kSelectionClipboard)
return (NS_ERROR_FAILURE);
switch(aWhichClipboard)
{
case kSelectionClipboard:
return NS_ERROR_FAILURE;
if (mSelectionOwner)
{
mSelectionOwner->LosingOwnership(mSelectionTransferable);
mSelectionOwner = nsnull;
}
mSelectionTransferable = nsnull;
break;
case kGlobalClipboard:
if (mGlobalOwner)
{
mGlobalOwner->LosingOwnership(mGlobalTransferable);
mGlobalOwner = nsnull;
}
mGlobalTransferable = nsnull;
break;
}
return NS_OK;
}
NS_IMETHODIMP nsClipboard::SupportsSelectionClipboard(PRBool *_retval)
{
NS_ENSURE_ARG_POINTER(_retval);
*_retval = PR_FALSE; // we support the selection clipboard on unix.
return NS_ERROR_FAILURE;
}
//-------------------------------------------------------------------------
NS_IMETHODIMP nsClipboard::SetNativeClipboardData(PRInt32 aWhichClipboard)
{
mIgnoreEmptyNotification = PR_TRUE;
if (aWhichClipboard == kSelectionClipboard)
return (NS_ERROR_FAILURE);
#ifdef DEBUG_CLIPBOARD
printf(" nsClipboard::SetNativeClipboardData(%i)\n", aWhichClipboard);
#endif /* DEBUG_CLIPBOARD */
nsCOMPtr<nsITransferable> transferable(GetTransferable(aWhichClipboard));
// make sure we have a good transferable
if (nsnull == transferable)
{
#ifdef DEBUG_CLIPBOARD
printf("nsClipboard::SetNativeClipboardData(): no transferable!\n");
#endif
return NS_ERROR_FAILURE;
}
// get flavor list that includes all flavors that can be written (including ones
// obtained through conversion)
nsCOMPtr<nsISupportsArray> flavorList;
nsresult errCode = transferable->FlavorsTransferableCanExport ( getter_AddRefs(flavorList) );
if ( NS_FAILED(errCode) )
return NS_ERROR_FAILURE;
PRUint32 cnt, index = 0;
flavorList->Count(&cnt);
PhClipHeader *cliphdr = (PhClipHeader *) calloc( cnt, sizeof( PhClipHeader ));
if( !cliphdr ) return NS_ERROR_FAILURE;
for ( PRUint32 k=0; k<cnt; ++k )
{
void *data = nsnull;
PRUint32 dataLen;
nsCOMPtr<nsISupports> genericFlavor;
flavorList->GetElementAt ( k, getter_AddRefs(genericFlavor) );
nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) );
if ( currentFlavor )
{
nsXPIDLCString flavorStr;
currentFlavor->ToString(getter_Copies(flavorStr));
nsresult err = GetFormat( flavorStr, cliphdr[index].type );
if( err != NS_OK )
continue;
// Get data out of transferable.
nsCOMPtr<nsISupports> genericDataWrapper;
transferable->GetTransferData( flavorStr, getter_AddRefs(genericDataWrapper), &dataLen );
nsPrimitiveHelpers::CreateDataFromPrimitive ( flavorStr, genericDataWrapper, &data, dataLen );
if( !strcmp(cliphdr[index].type, Ph_CLIPBOARD_TYPE_TEXT) ||
!strcmp(cliphdr[index].type, Ph_CLIPBOARD_TYPE_HTML) ||
!strcmp(cliphdr[index].type, Ph_CLIPBOARD_TYPE_MOZ_BOOKMARK) )
{
PRUnichar* castedUnicode = NS_REINTERPRET_CAST(PRUnichar*, data);
char *utf8String = ToNewUTF8String(nsDependentString(castedUnicode, dataLen/2));
nsMemory::Free(NS_REINTERPRET_CAST(char*, data));
if( !strcmp(cliphdr[index].type, Ph_CLIPBOARD_TYPE_TEXT) )
{
/* we have to create a null terminated string, because
PhClipboardCopyString does that and some other applications
rely on the null terminated thing
*/
PRInt32 len = strlen(utf8String);
char *temp = ( char * ) nsMemory::Alloc( len + 1 );
memcpy( temp, utf8String, len );
temp[len] = 0;
nsMemory::Free(NS_REINTERPRET_CAST(char*, utf8String));
cliphdr[index].length = len+1;
cliphdr[index].data = temp;
}
else {
cliphdr[index].length = strlen(utf8String);
cliphdr[index].data = utf8String;
}
}
index++;
}
}
PhClipboardCopy( mInputGroup, index, cliphdr );
for( PRUint32 k=0; k<index; k++)
nsMemory::Free(NS_REINTERPRET_CAST(char*, cliphdr[k].data));
free( cliphdr );
mIgnoreEmptyNotification = PR_FALSE;
return NS_OK;
}
//-------------------------------------------------------------------------
//
// The blocking Paste routine
//
//-------------------------------------------------------------------------
NS_IMETHODIMP
nsClipboard::GetNativeClipboardData(nsITransferable * aTransferable,
PRInt32 aWhichClipboard)
{
if (aWhichClipboard == kSelectionClipboard)
return (NS_ERROR_FAILURE);
#ifdef DEBUG_CLIPBOARD
printf("nsClipboard::GetNativeClipboardData(%i)\n", aWhichClipboard);
#endif /* DEBUG_CLIPBOARD */
// make sure we have a good transferable
if (nsnull == aTransferable)
{
#ifdef DEBUG_CLIPBOARD
printf(" GetNativeClipboardData: Transferable is null!\n");
#endif
return NS_ERROR_FAILURE;
}
// get flavor list that includes all acceptable flavors (including ones obtained through
// conversion)
nsCOMPtr<nsISupportsArray> flavorList;
nsresult errCode = aTransferable->FlavorsTransferableCanImport ( getter_AddRefs(flavorList) );
if ( NS_FAILED(errCode) )
return NS_ERROR_FAILURE;
// Walk through flavors and see which flavor matches the one being pasted:
PRUint32 cnt;
flavorList->Count(&cnt);
nsCAutoString foundFlavor;
if (cnt > 0)
{
void *clipPtr;
PhClipHeader *cliphdr;
char *data = nsnull, type[8];
PRUint32 dataLen;
clipPtr = PhClipboardPasteStart( mInputGroup );
if(!clipPtr) return NS_ERROR_FAILURE;
/*
Look at the timestamps of the data in the clipboard and eliminate the flavours if they are not synchronized.
We can have a HTML flavour from a previous copy and a TEXT flavour from a more recent copy from another application
( from instance from ped or pterm ). The HTML flavour and TEXT flavour are desynchronized and we have
to use only the most recent one */
unsigned long *dont_use_flavour = ( unsigned long * ) calloc( cnt, sizeof( unsigned long ) );
if( !dont_use_flavour ) {
PhClipboardPasteFinish( clipPtr );
return NS_ERROR_FAILURE;
}
unsigned long max_time = 0;
PRUint32 i;
for ( i = 0; i < cnt; ++i )
{
nsCOMPtr<nsISupports> genericFlavor;
flavorList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) );
if ( currentFlavor )
{
nsXPIDLCString flavorStr;
currentFlavor->ToString ( getter_Copies(flavorStr) );
nsresult err = GetFormat( flavorStr, type );
if (err != NS_OK)
continue;
dont_use_flavour[i] = GetFlavourTimestamp( type );
if( dont_use_flavour[i] > max_time ) max_time = dont_use_flavour[i];
}
}
for ( i = 0; i < cnt; ++i )
{
if( abs( dont_use_flavour[i] - max_time ) >= 4 )
dont_use_flavour[i] = 1; /* this flavour is desynchronized */
else dont_use_flavour[i] = 0; /* this flavour is ok */
}
for ( i = 0; i < cnt; ++i )
{
if( dont_use_flavour[i] ) continue; /* this flavour is desynchronized */
nsCOMPtr<nsISupports> genericFlavor;
flavorList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) );
if ( currentFlavor )
{
nsXPIDLCString flavorStr;
currentFlavor->ToString ( getter_Copies(flavorStr) );
nsresult err = GetFormat( flavorStr, type );
if (err != NS_OK)
continue;
cliphdr = PhClipboardPasteType( clipPtr, type );
if (cliphdr)
{
data = (char*)cliphdr->data;
if( !strcmp(type, Ph_CLIPBOARD_TYPE_TEXT) )
/* for the Ph_CLIPBOARD_TYPE_TEXT, we null terminate the data, since PhClipboardCopyString() does that */
dataLen = cliphdr->length - 1;
else dataLen = cliphdr->length;
if( !strcmp(type, Ph_CLIPBOARD_TYPE_TEXT) ||
!strcmp(type, Ph_CLIPBOARD_TYPE_HTML) ||
!strcmp(type, Ph_CLIPBOARD_TYPE_MOZ_BOOKMARK) )
{
nsresult rv;
PRInt32 outUnicodeLen;
PRUnichar *unicodeData = nsnull;
// get the decoder
nsCOMPtr<nsIUnicodeDecoder> decoder;
nsCOMPtr<nsICharsetConverterManager> ccm = do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
rv = ccm->GetUnicodeDecoderRaw("UTF-8", getter_AddRefs(decoder));
if( NS_SUCCEEDED(rv) )
{
decoder->GetMaxLength(data, dataLen, &outUnicodeLen); // |outUnicodeLen| is number of chars
if (outUnicodeLen) {
unicodeData = NS_REINTERPRET_CAST(PRUnichar*, nsMemory::Alloc((outUnicodeLen + 1) * sizeof(PRUnichar)));
if ( unicodeData ) {
PRInt32 numberTmp = dataLen;
rv = decoder->Convert(data, &numberTmp, unicodeData, &outUnicodeLen);
#ifdef DEBUG_CLIPBOARD
if (numberTmp != dataLen)
printf("didn't consume all the bytes\n");
#endif
(unicodeData)[outUnicodeLen] = '\0'; // null terminate. Convert() doesn't do it for us
}
} // if valid length
data = NS_REINTERPRET_CAST(char*,unicodeData);
dataLen = outUnicodeLen * 2;
nsCOMPtr<nsISupports> genericDataWrapper;
nsPrimitiveHelpers::CreatePrimitiveForData( flavorStr, data, dataLen, getter_AddRefs(genericDataWrapper) );
aTransferable->SetTransferData( flavorStr, genericDataWrapper, dataLen );
/* free the allocated memory */
nsMemory::Free( unicodeData );
break;
}
}
}
}
}
free( dont_use_flavour );
PhClipboardPasteFinish( clipPtr );
}
return NS_OK;
}
NS_IMETHODIMP
nsClipboard::HasDataMatchingFlavors(nsISupportsArray* aFlavorList,
PRInt32 aWhichClipboard,
PRBool * outResult)
{
if (aWhichClipboard == kSelectionClipboard)
return (NS_ERROR_FAILURE);
// XXX this doesn't work right. need to fix it.
// Note to implementor...(from pink the clipboard bitch).
//
// If a client asks for unicode, first check if unicode is present. If not, then
// check for plain text. If it's there, say "yes" as we will do the conversion
// in GetNativeClipboardData(). From this point on, no client will
// ever ask for text/plain explicitly. If they do, you must ASSERT!
#ifdef DEBUG_CLIPBOARD
printf(" nsClipboard::HasDataMatchingFlavors()\n {\n");
#endif
nsresult res = NS_OK;
* outResult = PR_FALSE;
// Walk through flavors and see which flavor matches the one being pasted:
PRUint32 cnt;
aFlavorList->Count(&cnt);
nsCAutoString foundFlavor;
if (cnt > 0) {
void *clipPtr;
char type[8];
PhClipHeader *cliphdr;
clipPtr = PhClipboardPasteStart( 1 );
if(nsnull == clipPtr)
return res;
for ( PRUint32 i = 0; i < cnt; ++i ) {
nsCOMPtr<nsISupports> genericFlavor;
aFlavorList->GetElementAt ( i, getter_AddRefs(genericFlavor) );
nsCOMPtr<nsISupportsCString> currentFlavor ( do_QueryInterface(genericFlavor) );
if ( currentFlavor ) {
nsXPIDLCString flavorStr;
currentFlavor->ToString ( getter_Copies(flavorStr) );
nsresult err = GetFormat( flavorStr, type );
if (err != NS_OK) continue;
cliphdr = PhClipboardPasteType( clipPtr, type );
if (cliphdr)
{
res = NS_OK;
*outResult = PR_TRUE;
break;
}
}
}
PhClipboardPasteFinish( clipPtr );
}
return res;
}
nsresult nsClipboard::GetFormat(const char* aMimeStr, char *format )
{
nsDependentCString mimeStr(aMimeStr);
int ret = NS_OK;
if( mimeStr.Equals(kUnicodeMime) || mimeStr.Equals(kTextMime) )
strcpy( format, Ph_CLIPBOARD_TYPE_TEXT );
else if( mimeStr.Equals(kHTMLMime) )
strcpy( format, Ph_CLIPBOARD_TYPE_HTML );
else if (mimeStr.Equals("moz/bookmarkclipboarditem"))
strcpy( format, Ph_CLIPBOARD_TYPE_MOZ_BOOKMARK );
else ret = NS_ERROR_FAILURE;
return ret;
}
/* inline */
nsITransferable *nsClipboard::GetTransferable(PRInt32 aWhichClipboard)
{
nsITransferable *transferable = nsnull;
switch (aWhichClipboard)
{
case kGlobalClipboard:
transferable = mGlobalTransferable;
break;
case kSelectionClipboard:
break;
}
return transferable;
}
unsigned long nsClipboard::GetFlavourTimestamp( char *type)
{
char fname[512];
extern struct _Ph_ctrl *_Ph_;
strcpy( fname, "/var/clipboard/" );
if( access( fname, X_OK ) != 0 )
return 0;
struct stat buf;
if( fstat( _Ph_->fd, &buf ) != 0 )
return 0;
if(gethostname(&fname[strlen(fname)],PATH_MAX-40)!=0)
strcpy(&fname[strlen(fname)],"localhost");
sprintf( &fname[strlen(fname)], "/%08x/%d.%s",buf.st_uid, mInputGroup, type );
struct stat st;
if( stat( fname, &st ) != 0 )
return 0;
return st.st_mtime;
}