]> code.ossystems Code Review - openembedded-core.git/blob
db9e1479904eb7dde76c28074748e9e138125dd2
[openembedded-core.git] /
1 From fb41f028badb4dfddfc47fb2a1a68c1aa90dcef5 Mon Sep 17 00:00:00 2001
2 From: Robert Bragg <robert@linux.intel.com>
3 Date: Fri, 8 May 2009 13:57:22 +0100
4 Subject: [PATCH] Adds initial Gtk clipboard support to moz-headless
5
6 If build with MOZ_X11 enabled then this now builds the clipboard code taken
7 from the gtk2 backend.  This doesn't provide any embedding API yet to expose
8 the clipboard.
9 ---
10  widget/src/headless/Makefile.in         |    6 +
11  widget/src/headless/nsClipboard.cpp     |  948 +++++++++++++++++++++++++++++++
12  widget/src/headless/nsClipboard.h       |   93 +++
13  widget/src/headless/nsIImageToPixbuf.h  |   62 ++
14  widget/src/headless/nsImageToPixbuf.cpp |  196 +++++++
15  widget/src/headless/nsImageToPixbuf.h   |   71 +++
16  widget/src/headless/nsWidgetFactory.cpp |   18 +
17  7 files changed, 1394 insertions(+), 0 deletions(-)
18  create mode 100644 widget/src/headless/nsClipboard.cpp
19  create mode 100644 widget/src/headless/nsClipboard.h
20  create mode 100644 widget/src/headless/nsIImageToPixbuf.h
21  create mode 100644 widget/src/headless/nsImageToPixbuf.cpp
22  create mode 100644 widget/src/headless/nsImageToPixbuf.h
23
24 Index: offscreen/widget/src/headless/Makefile.in
25 ===================================================================
26 --- offscreen.orig/widget/src/headless/Makefile.in      2009-05-16 18:23:25.000000000 +0100
27 +++ offscreen/widget/src/headless/Makefile.in   2009-06-12 14:14:05.000000000 +0100
28 @@ -95,6 +95,12 @@
29                 nsScreenManagerHeadless.cpp \
30                 $(NULL)
31  
32 +ifdef MOZ_X11
33 +CPPSRCS +=      nsClipboard.cpp \
34 +               nsImageToPixbuf.cpp \
35 +                $(NULL)
36 +endif
37 +
38  # build our subdirs, too
39  SHARED_LIBRARY_LIBS = ../xpwidgets/libxpwidgets_s.a
40  
41 Index: offscreen/widget/src/headless/nsClipboard.cpp
42 ===================================================================
43 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
44 +++ offscreen/widget/src/headless/nsClipboard.cpp       2009-06-12 14:14:05.000000000 +0100
45 @@ -0,0 +1,948 @@
46 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
47 +/* vim:expandtab:shiftwidth=4:tabstop=4:
48 + */
49 +/* ***** BEGIN LICENSE BLOCK *****
50 + * Version: MPL 1.1/GPL 2.0/LGPL 2.1
51 + *
52 + * The contents of this file are subject to the Mozilla Public License Version
53 + * 1.1 (the "License"); you may not use this file except in compliance with
54 + * the License. You may obtain a copy of the License at
55 + * http://www.mozilla.org/MPL/
56 + *
57 + * Software distributed under the License is distributed on an "AS IS" basis,
58 + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
59 + * for the specific language governing rights and limitations under the
60 + * License.
61 + *
62 + * The Original Code is mozilla.org code.
63 + *
64 + * The Initial Developer of the Original Code is Christopher Blizzard
65 + * <blizzard@mozilla.org>.  Portions created by the Initial Developer
66 + * are Copyright (C) 2001 the Initial Developer. All Rights Reserved.
67 + *
68 + * Contributor(s):
69 + *
70 + * Alternatively, the contents of this file may be used under the terms of
71 + * either the GNU General Public License Version 2 or later (the "GPL"), or
72 + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
73 + * in which case the provisions of the GPL or the LGPL are applicable instead
74 + * of those above. If you wish to allow use of your version of this file only
75 + * under the terms of either the GPL or the LGPL, and not to allow others to
76 + * use your version of this file under the terms of the MPL, indicate your
77 + * decision by deleting the provisions above and replace them with the notice
78 + * and other provisions required by the GPL or the LGPL. If you do not delete
79 + * the provisions above, a recipient may use your version of this file under
80 + * the terms of any one of the MPL, the GPL or the LGPL.
81 + *
82 + * ***** END LICENSE BLOCK ***** */
83 +
84 +#include "nsClipboard.h"
85 +#include "nsSupportsPrimitives.h"
86 +#include "nsString.h"
87 +#include "nsReadableUtils.h"
88 +#include "nsXPIDLString.h"
89 +#include "nsPrimitiveHelpers.h"
90 +#include "nsICharsetConverterManager.h"
91 +#include "nsIServiceManager.h"
92 +#include "nsIImage.h"
93 +#include "nsImageToPixbuf.h"
94 +#include "nsStringStream.h"
95 +
96 +#include <gtk/gtk.h>
97 +
98 +// For manipulation of the X event queue
99 +#include <X11/Xlib.h>
100 +#include <gdk/gdkx.h>
101 +#include <sys/time.h>
102 +#include <sys/types.h>
103 +#include <unistd.h>
104 +
105 +#ifdef POLL_WITH_XCONNECTIONNUMBER
106 +#include <poll.h>
107 +#endif
108 +
109 +// Callback when someone asks us for the selection
110 +void
111 +invisible_selection_get_cb (GtkWidget          *aWidget,
112 +                            GtkSelectionData   *aSelectionData,
113 +                            guint               aTime,
114 +                            guint               aInfo,
115 +                            nsClipboard        *aClipboard);
116 +
117 +gboolean
118 +selection_clear_event_cb   (GtkWidget          *aWidget,
119 +                            GdkEventSelection  *aEvent,
120 +                            nsClipboard        *aClipboard);
121 +
122 +static void
123 +ConvertHTMLtoUCS2          (guchar             *data,
124 +                            PRInt32             dataLength,
125 +                            PRUnichar         **unicodeData,
126 +                            PRInt32            &outUnicodeLen);
127 +
128 +static void
129 +GetHTMLCharset             (guchar * data, PRInt32 dataLength, nsCString& str);
130 +
131 +
132 +// Our own versions of gtk_clipboard_wait_for_contents and
133 +// gtk_clipboard_wait_for_text, which don't run the event loop while
134 +// waiting for the data.  This prevents a lot of problems related to
135 +// dispatching events at unexpected times.
136 +
137 +static GtkSelectionData *
138 +wait_for_contents          (GtkClipboard *clipboard, GdkAtom target);
139 +
140 +static gchar *
141 +wait_for_text              (GtkClipboard *clipboard);
142 +
143 +static Bool
144 +checkEventProc(Display *display, XEvent *event, XPointer arg);
145 +
146 +struct retrieval_context
147 +{
148 +    PRBool   completed;
149 +    void    *data;
150 +
151 +    retrieval_context() : completed(PR_FALSE), data(nsnull) { }
152 +};
153 +
154 +static void
155 +wait_for_retrieval(GtkClipboard *clipboard, retrieval_context *transferData);
156 +
157 +static void
158 +clipboard_contents_received(GtkClipboard     *clipboard,
159 +                            GtkSelectionData *selection_data,
160 +                            gpointer          data);
161 +
162 +static void
163 +clipboard_text_received(GtkClipboard *clipboard,
164 +                        const gchar  *text,
165 +                        gpointer      data);
166 +
167 +nsClipboard::nsClipboard()
168 +{
169 +    mWidget = nsnull;
170 +}
171 +
172 +nsClipboard::~nsClipboard()
173 +{
174 +    if (mWidget)
175 +        gtk_widget_destroy(mWidget);
176 +}
177 +
178 +NS_IMPL_ISUPPORTS1(nsClipboard, nsIClipboard)
179 +
180 +nsresult
181 +nsClipboard::Init(void)
182 +{
183 +    mWidget = gtk_invisible_new();
184 +    if (!mWidget)
185 +        return NS_ERROR_FAILURE;
186 +
187 +    g_signal_connect(G_OBJECT(mWidget), "selection_get",
188 +                     G_CALLBACK(invisible_selection_get_cb), this);
189 +
190 +    g_signal_connect(G_OBJECT(mWidget), "selection_clear_event",
191 +                     G_CALLBACK(selection_clear_event_cb), this);
192 +
193 +    // XXX make sure to set up the selection_clear event
194 +
195 +    return NS_OK;
196 +}
197 +
198 +NS_IMETHODIMP
199 +nsClipboard::SetData(nsITransferable *aTransferable,
200 +                     nsIClipboardOwner *aOwner, PRInt32 aWhichClipboard)
201 +{
202 +    // See if we can short cut
203 +    if ((aWhichClipboard == kGlobalClipboard &&
204 +         aTransferable == mGlobalTransferable.get() &&
205 +         aOwner == mGlobalOwner.get()) ||
206 +        (aWhichClipboard == kSelectionClipboard &&
207 +         aTransferable == mSelectionTransferable.get() &&
208 +         aOwner == mSelectionOwner.get())) {
209 +        return NS_OK;
210 +    }
211 +
212 +    nsresult rv;
213 +    if (!mPrivacyHandler) {
214 +        rv = NS_NewClipboardPrivacyHandler(getter_AddRefs(mPrivacyHandler));
215 +        NS_ENSURE_SUCCESS(rv, rv);
216 +    }
217 +    rv = mPrivacyHandler->PrepareDataForClipboard(aTransferable);
218 +    NS_ENSURE_SUCCESS(rv, rv);
219 +
220 +    // Clear out the clipboard in order to set the new data
221 +    EmptyClipboard(aWhichClipboard);
222 +
223 +    if (aWhichClipboard == kSelectionClipboard) {
224 +        mSelectionOwner = aOwner;
225 +        mSelectionTransferable = aTransferable;
226 +    }
227 +    else {
228 +        mGlobalOwner = aOwner;
229 +        mGlobalTransferable = aTransferable;
230 +    }
231 +
232 +    // Which selection are we about to claim, CLIPBOARD or PRIMARY?
233 +    GdkAtom selectionAtom = GetSelectionAtom(aWhichClipboard);
234 +
235 +    // Make ourselves the owner.  If we fail to, return.
236 +    if (!gtk_selection_owner_set(mWidget, selectionAtom, GDK_CURRENT_TIME))
237 +        return NS_ERROR_FAILURE;
238 +
239 +    // Clear the old selection target list.
240 +    gtk_selection_clear_targets(mWidget, selectionAtom);
241 +
242 +    // Get the types of supported flavors
243 +    nsCOMPtr<nsISupportsArray> flavors;
244 +
245 +    rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavors));
246 +    if (!flavors || NS_FAILED(rv))
247 +        return NS_ERROR_FAILURE;
248 +
249 +    // Add all the flavors to this widget's supported type.
250 +    PRUint32 count;
251 +    flavors->Count(&count);
252 +    for (PRUint32 i=0; i < count; i++) {
253 +        nsCOMPtr<nsISupports> tastesLike;
254 +        flavors->GetElementAt(i, getter_AddRefs(tastesLike));
255 +        nsCOMPtr<nsISupportsCString> flavor = do_QueryInterface(tastesLike);
256 +
257 +        if (flavor) {
258 +            nsXPIDLCString flavorStr;
259 +            flavor->ToString(getter_Copies(flavorStr));
260 +
261 +            // special case text/unicode since we can handle all of
262 +            // the string types
263 +            if (!strcmp(flavorStr, kUnicodeMime)) {
264 +                AddTarget(gdk_atom_intern("UTF8_STRING", FALSE),
265 +                          selectionAtom);
266 +                AddTarget(gdk_atom_intern("COMPOUND_TEXT", FALSE),
267 +                          selectionAtom);
268 +                AddTarget(gdk_atom_intern("TEXT", FALSE), selectionAtom);
269 +                AddTarget(GDK_SELECTION_TYPE_STRING, selectionAtom);
270 +                // next loop iteration
271 +                continue;
272 +            }
273 +
274 +            // very special case for this one. since our selection mechanism doesn't work for images,
275 +            // we must use GTK's clipboard utility functions
276 +            if (!strcmp(flavorStr, kNativeImageMime) || !strcmp(flavorStr, kPNGImageMime) ||
277 +                !strcmp(flavorStr, kJPEGImageMime) || !strcmp(flavorStr, kGIFImageMime)) {
278 +                nsCOMPtr<nsISupports> item;
279 +                PRUint32 len;
280 +                rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(item), &len);
281 +                nsCOMPtr<nsISupportsInterfacePointer> ptrPrimitive(do_QueryInterface(item));
282 +                if (!ptrPrimitive)
283 +                    continue;
284 +
285 +                nsCOMPtr<nsISupports> primitiveData;
286 +                ptrPrimitive->GetData(getter_AddRefs(primitiveData));
287 +                nsCOMPtr<nsIImage> image(do_QueryInterface(primitiveData));
288 +                if (!image) // Not getting an image for an image mime type!?
289 +                    continue;
290 +
291 +                if (NS_FAILED(image->LockImagePixels(PR_FALSE)))
292 +                    continue;
293 +                GdkPixbuf* pixbuf = nsImageToPixbuf::ImageToPixbuf(image);
294 +                if (!pixbuf) {
295 +                    image->UnlockImagePixels(PR_FALSE);
296 +                    continue;
297 +                }
298 +
299 +                GtkClipboard *aClipboard = gtk_clipboard_get(GetSelectionAtom(aWhichClipboard));
300 +                gtk_clipboard_set_image(aClipboard, pixbuf);
301 +                g_object_unref(pixbuf);
302 +                image->UnlockImagePixels(PR_FALSE);
303 +                continue;
304 +            }
305 +
306 +            // Add this to our list of valid targets
307 +            GdkAtom atom = gdk_atom_intern(flavorStr, FALSE);
308 +            AddTarget(atom, selectionAtom);
309 +        }
310 +    }
311 +
312 +    return NS_OK;
313 +}
314 +
315 +NS_IMETHODIMP
316 +nsClipboard::GetData(nsITransferable *aTransferable, PRInt32 aWhichClipboard)
317 +{
318 +    if (!aTransferable)
319 +        return NS_ERROR_FAILURE;
320 +
321 +    GtkClipboard *clipboard;
322 +    clipboard = gtk_clipboard_get(GetSelectionAtom(aWhichClipboard));
323 +
324 +    guchar        *data = NULL;
325 +    gint           length = 0;
326 +    PRBool         foundData = PR_FALSE;
327 +    nsCAutoString  foundFlavor;
328 +
329 +    // Get a list of flavors this transferable can import
330 +    nsCOMPtr<nsISupportsArray> flavors;
331 +    nsresult rv;
332 +    rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavors));
333 +    if (!flavors || NS_FAILED(rv))
334 +        return NS_ERROR_FAILURE;
335 +
336 +    PRUint32 count;
337 +    flavors->Count(&count);
338 +    for (PRUint32 i=0; i < count; i++) {
339 +        nsCOMPtr<nsISupports> genericFlavor;
340 +        flavors->GetElementAt(i, getter_AddRefs(genericFlavor));
341 +
342 +        nsCOMPtr<nsISupportsCString> currentFlavor;
343 +        currentFlavor = do_QueryInterface(genericFlavor);
344 +
345 +        if (currentFlavor) {
346 +            nsXPIDLCString flavorStr;
347 +            currentFlavor->ToString(getter_Copies(flavorStr));
348 +
349 +            // Special case text/unicode since we can convert any
350 +            // string into text/unicode
351 +            if (!strcmp(flavorStr, kUnicodeMime)) {
352 +                gchar* new_text = wait_for_text(clipboard);
353 +                if (new_text) {
354 +                    // Convert utf-8 into our unicode format.
355 +                    NS_ConvertUTF8toUTF16 ucs2string(new_text);
356 +                    data = (guchar *)ToNewUnicode(ucs2string);
357 +                    length = ucs2string.Length() * 2;
358 +                    g_free(new_text);
359 +                    foundData = PR_TRUE;
360 +                    foundFlavor = kUnicodeMime;
361 +                    break;
362 +                }
363 +                // If the type was text/unicode and we couldn't get
364 +                // text off the clipboard, run the next loop
365 +                // iteration.
366 +                continue;
367 +            }
368 +
369 +            // For images, we must wrap the data in an nsIInputStream then return instead of break,
370 +            // because that code below won't help us.
371 +            if (!strcmp(flavorStr, kJPEGImageMime) || !strcmp(flavorStr, kPNGImageMime) || !strcmp(flavorStr, kGIFImageMime)) {
372 +                GdkAtom atom;
373 +                if (!strcmp(flavorStr, kJPEGImageMime)) // This is image/jpg, but X only understands image/jpeg
374 +                    atom = gdk_atom_intern("image/jpeg", FALSE);
375 +                else
376 +                    atom = gdk_atom_intern(flavorStr, FALSE);
377 +
378 +                GtkSelectionData *selectionData = wait_for_contents(clipboard, atom);
379 +                if (!selectionData)
380 +                    continue;
381 +
382 +                nsCOMPtr<nsIInputStream> byteStream;
383 +                NS_NewByteInputStream(getter_AddRefs(byteStream), (const char*)selectionData->data,
384 +                                      selectionData->length, NS_ASSIGNMENT_COPY);
385 +                aTransferable->SetTransferData(flavorStr, byteStream, sizeof(nsIInputStream*));
386 +                gtk_selection_data_free(selectionData);
387 +                return NS_OK;
388 +            }
389 +
390 +            // Get the atom for this type and try to request it off
391 +            // the clipboard.
392 +            GdkAtom atom = gdk_atom_intern(flavorStr, FALSE);
393 +            GtkSelectionData *selectionData;
394 +            selectionData = wait_for_contents(clipboard, atom);
395 +            if (selectionData) {
396 +                length = selectionData->length;
397 +                // Special case text/html since we can convert into UCS2
398 +                if (!strcmp(flavorStr, kHTMLMime)) {
399 +                    PRUnichar* htmlBody= nsnull;
400 +                    PRInt32 htmlBodyLen = 0;
401 +                    // Convert text/html into our unicode format
402 +                    ConvertHTMLtoUCS2((guchar *)selectionData->data, length,
403 +                                      &htmlBody, htmlBodyLen);
404 +                    if (!htmlBodyLen)
405 +                        break;
406 +                    data = (guchar *)htmlBody;
407 +                    length = htmlBodyLen * 2;
408 +                } else {
409 +                    data = (guchar *)nsMemory::Alloc(length);
410 +                    if (!data)
411 +                        break;
412 +                    memcpy(data, selectionData->data, length);
413 +                }
414 +                foundData = PR_TRUE;
415 +                foundFlavor = flavorStr;
416 +                break;
417 +            }
418 +        }
419 +    }
420 +
421 +    if (foundData) {
422 +        nsCOMPtr<nsISupports> wrapper;
423 +        nsPrimitiveHelpers::CreatePrimitiveForData(foundFlavor.get(),
424 +                                                   data, length,
425 +                                                   getter_AddRefs(wrapper));
426 +        aTransferable->SetTransferData(foundFlavor.get(),
427 +                                       wrapper, length);
428 +    }
429 +
430 +    if (data)
431 +        nsMemory::Free(data);
432 +
433 +    return NS_OK;
434 +}
435 +
436 +NS_IMETHODIMP
437 +nsClipboard::EmptyClipboard(PRInt32 aWhichClipboard)
438 +{
439 +    if (aWhichClipboard == kSelectionClipboard) {
440 +        if (mSelectionOwner) {
441 +            mSelectionOwner->LosingOwnership(mSelectionTransferable);
442 +            mSelectionOwner = nsnull;
443 +        }
444 +        mSelectionTransferable = nsnull;
445 +    }
446 +    else {
447 +        if (mGlobalOwner) {
448 +            mGlobalOwner->LosingOwnership(mGlobalTransferable);
449 +            mGlobalOwner = nsnull;
450 +        }
451 +        mGlobalTransferable = nsnull;
452 +    }
453 +
454 +    return NS_OK;
455 +}
456 +
457 +NS_IMETHODIMP
458 +nsClipboard::HasDataMatchingFlavors(const char** aFlavorList, PRUint32 aLength,
459 +                                    PRInt32 aWhichClipboard, PRBool *_retval)
460 +{
461 +    if (!aFlavorList || !_retval)
462 +        return NS_ERROR_NULL_POINTER;
463 +
464 +    *_retval = PR_FALSE;
465 +
466 +    GtkSelectionData *selection_data =
467 +        GetTargets(GetSelectionAtom(aWhichClipboard));
468 +    if (!selection_data)
469 +        return NS_OK;
470 +
471 +    gint n_targets = 0;
472 +    GdkAtom *targets = NULL;
473 +
474 +    if (!gtk_selection_data_get_targets(selection_data, 
475 +                                        &targets, &n_targets) ||
476 +        !n_targets)
477 +        return NS_OK;
478 +
479 +    // Walk through the provided types and try to match it to a
480 +    // provided type.
481 +    for (PRUint32 i = 0; i < aLength && !*_retval; i++) {
482 +        // We special case text/unicode here.
483 +        if (!strcmp(aFlavorList[i], kUnicodeMime) && 
484 +            gtk_selection_data_targets_include_text(selection_data)) {
485 +            *_retval = PR_TRUE;
486 +            break;
487 +        }
488 +
489 +        for (PRInt32 j = 0; j < n_targets; j++) {
490 +            gchar *atom_name = gdk_atom_name(targets[j]);
491 +            if (!strcmp(atom_name, aFlavorList[i]))
492 +                *_retval = PR_TRUE;
493 +
494 +            // X clipboard wants image/jpeg, not image/jpg
495 +            if (!strcmp(aFlavorList[i], kJPEGImageMime) && !strcmp(atom_name, "image/jpeg"))
496 +                *_retval = PR_TRUE;
497 +
498 +            g_free(atom_name);
499 +
500 +            if (*_retval)
501 +                break;
502 +        }
503 +    }
504 +    gtk_selection_data_free(selection_data);
505 +    g_free(targets);
506 +
507 +    return NS_OK;
508 +}
509 +
510 +NS_IMETHODIMP
511 +nsClipboard::SupportsSelectionClipboard(PRBool *_retval)
512 +{
513 +    *_retval = PR_TRUE; // yeah, unix supports the selection clipboard
514 +    return NS_OK;
515 +}
516 +
517 +/* static */
518 +GdkAtom
519 +nsClipboard::GetSelectionAtom(PRInt32 aWhichClipboard)
520 +{
521 +    if (aWhichClipboard == kGlobalClipboard)
522 +        return GDK_SELECTION_CLIPBOARD;
523 +
524 +    return GDK_SELECTION_PRIMARY;
525 +}
526 +
527 +/* static */
528 +GtkSelectionData *
529 +nsClipboard::GetTargets(GdkAtom aWhichClipboard)
530 +{
531 +    GtkClipboard *clipboard = gtk_clipboard_get(aWhichClipboard);
532 +    return wait_for_contents(clipboard, gdk_atom_intern("TARGETS", FALSE));
533 +}
534 +
535 +nsITransferable *
536 +nsClipboard::GetTransferable(PRInt32 aWhichClipboard)
537 +{
538 +    nsITransferable *retval;
539 +
540 +    if (aWhichClipboard == kSelectionClipboard)
541 +        retval = mSelectionTransferable.get();
542 +    else
543 +        retval = mGlobalTransferable.get();
544 +        
545 +    return retval;
546 +}
547 +
548 +void
549 +nsClipboard::AddTarget(GdkAtom aName, GdkAtom aClipboard)
550 +{
551 +    gtk_selection_add_target(mWidget, aClipboard, aName, 0);
552 +}
553 +
554 +void
555 +nsClipboard::SelectionGetEvent (GtkWidget        *aWidget,
556 +                                GtkSelectionData *aSelectionData,
557 +                                guint             aTime)
558 +{
559 +    // Someone has asked us to hand them something.  The first thing
560 +    // that we want to do is see if that something includes text.  If
561 +    // it does, try to give it text/unicode after converting it to
562 +    // utf-8.
563 +
564 +    PRInt32 whichClipboard;
565 +
566 +    // which clipboard?
567 +    if (aSelectionData->selection == GDK_SELECTION_PRIMARY)
568 +        whichClipboard = kSelectionClipboard;
569 +    else if (aSelectionData->selection == GDK_SELECTION_CLIPBOARD)
570 +        whichClipboard = kGlobalClipboard;
571 +    else
572 +        return; // THAT AIN'T NO CLIPBOARD I EVER HEARD OF
573 +
574 +    nsCOMPtr<nsITransferable> trans = GetTransferable(whichClipboard);
575 +    
576 +    nsresult rv;
577 +    nsCOMPtr<nsISupports> item;
578 +    PRUint32 len;
579 +
580 +    // Check to see if the selection data includes any of the string
581 +    // types that we support.
582 +    if (aSelectionData->target == gdk_atom_intern ("STRING", FALSE) ||
583 +        aSelectionData->target == gdk_atom_intern ("TEXT", FALSE) ||
584 +        aSelectionData->target == gdk_atom_intern ("COMPOUND_TEXT", FALSE) ||
585 +        aSelectionData->target == gdk_atom_intern ("UTF8_STRING", FALSE)) {
586 +        // Try to convert our internal type into a text string.  Get
587 +        // the transferable for this clipboard and try to get the
588 +        // text/unicode type for it.
589 +        rv = trans->GetTransferData("text/unicode", getter_AddRefs(item),
590 +                                    &len);
591 +        if (!item || NS_FAILED(rv))
592 +            return;
593 +        
594 +        nsCOMPtr<nsISupportsString> wideString;
595 +        wideString = do_QueryInterface(item);
596 +        if (!wideString)
597 +            return;
598 +
599 +        nsAutoString ucs2string;
600 +        wideString->GetData(ucs2string);
601 +        char *utf8string = ToNewUTF8String(ucs2string);
602 +        if (!utf8string)
603 +            return;
604 +        
605 +        gtk_selection_data_set_text (aSelectionData, utf8string,
606 +                                     strlen(utf8string));
607 +
608 +        nsMemory::Free(utf8string);
609 +        return;
610 +    }
611 +
612 +    // Try to match up the selection data target to something our
613 +    // transferable provides.
614 +    gchar *target_name = gdk_atom_name(aSelectionData->target);
615 +    if (!target_name)
616 +        return;
617 +
618 +    rv = trans->GetTransferData(target_name, getter_AddRefs(item), &len);
619 +    // nothing found?
620 +    if (!item || NS_FAILED(rv)) {
621 +        g_free(target_name);
622 +        return;
623 +    }
624 +
625 +    void *primitive_data = nsnull;
626 +    nsPrimitiveHelpers::CreateDataFromPrimitive(target_name, item,
627 +                                                &primitive_data, len);
628 +
629 +    if (primitive_data) {
630 +        // Check to see if the selection data is text/html
631 +        if (aSelectionData->target == gdk_atom_intern (kHTMLMime, FALSE)) {
632 +            /*
633 +             * "text/html" can be encoded UCS2. It is recommended that
634 +             * documents transmitted as UCS2 always begin with a ZERO-WIDTH
635 +             * NON-BREAKING SPACE character (hexadecimal FEFF, also called
636 +             * Byte Order Mark (BOM)). Adding BOM can help other app to
637 +             * detect mozilla use UCS2 encoding when copy-paste.
638 +             */
639 +            guchar *buffer = (guchar *)
640 +                    nsMemory::Alloc((len * sizeof(guchar)) + sizeof(PRUnichar));
641 +            if (!buffer)
642 +                return;
643 +            PRUnichar prefix = 0xFEFF;
644 +            memcpy(buffer, &prefix, sizeof(prefix));
645 +            memcpy(buffer + sizeof(prefix), primitive_data, len);
646 +            nsMemory::Free((guchar *)primitive_data);
647 +            primitive_data = (guchar *)buffer;
648 +            len += sizeof(prefix);
649 +        }
650 +  
651 +        gtk_selection_data_set(aSelectionData, aSelectionData->target,
652 +                               8, /* 8 bits in a unit */
653 +                               (const guchar *)primitive_data, len);
654 +        nsMemory::Free(primitive_data);
655 +    }
656 +
657 +    g_free(target_name);
658 +                           
659 +}
660 +
661 +void
662 +nsClipboard::SelectionClearEvent (GtkWidget         *aWidget,
663 +                                  GdkEventSelection *aEvent)
664 +{
665 +    PRInt32 whichClipboard;
666 +
667 +    // which clipboard?
668 +    if (aEvent->selection == GDK_SELECTION_PRIMARY)
669 +        whichClipboard = kSelectionClipboard;
670 +    else if (aEvent->selection == GDK_SELECTION_CLIPBOARD)
671 +        whichClipboard = kGlobalClipboard;
672 +    else
673 +        return; // THAT AIN'T NO CLIPBOARD I EVER HEARD OF
674 +
675 +    EmptyClipboard(whichClipboard);
676 +}
677 +
678 +void
679 +invisible_selection_get_cb (GtkWidget          *aWidget,
680 +                            GtkSelectionData   *aSelectionData,
681 +                            guint               aTime,
682 +                            guint               aInfo,
683 +                            nsClipboard        *aClipboard)
684 +{
685 +    aClipboard->SelectionGetEvent(aWidget, aSelectionData, aTime);
686 +}
687 +
688 +gboolean
689 +selection_clear_event_cb   (GtkWidget          *aWidget,
690 +                            GdkEventSelection  *aEvent,
691 +                            nsClipboard        *aClipboard)
692 +{
693 +    aClipboard->SelectionClearEvent(aWidget, aEvent);
694 +    return TRUE;
695 +}
696 +
697 +/*
698 + * when copy-paste, mozilla wants data encoded using UCS2,
699 + * other app such as StarOffice use "text/html"(RFC2854).
700 + * This function convert data(got from GTK clipboard)
701 + * to data mozilla wanted.
702 + *
703 + * data from GTK clipboard can be 3 forms:
704 + *  1. From current mozilla
705 + *     "text/html", charset = utf-16
706 + *  2. From old version mozilla or mozilla-based app
707 + *     content("body" only), charset = utf-16
708 + *  3. From other app who use "text/html" when copy-paste
709 + *     "text/html", has "charset" info
710 + *
711 + * data      : got from GTK clipboard
712 + * dataLength: got from GTK clipboard
713 + * body      : pass to Mozilla
714 + * bodyLength: pass to Mozilla
715 + */
716 +void ConvertHTMLtoUCS2(guchar * data, PRInt32 dataLength,
717 +                       PRUnichar** unicodeData, PRInt32& outUnicodeLen)
718 +{
719 +    nsCAutoString charset;
720 +    GetHTMLCharset(data, dataLength, charset);// get charset of HTML
721 +    if (charset.EqualsLiteral("UTF-16")) {//current mozilla
722 +        outUnicodeLen = (dataLength / 2) - 1;
723 +        *unicodeData = reinterpret_cast<PRUnichar*>
724 +                                       (nsMemory::Alloc((outUnicodeLen + sizeof('\0')) *
725 +                       sizeof(PRUnichar)));
726 +        if (*unicodeData) {
727 +            memcpy(*unicodeData, data + sizeof(PRUnichar),
728 +                   outUnicodeLen * sizeof(PRUnichar));
729 +            (*unicodeData)[outUnicodeLen] = '\0';
730 +        }
731 +    } else if (charset.EqualsLiteral("UNKNOWN")) {
732 +        outUnicodeLen = 0;
733 +        return;
734 +    } else {
735 +        // app which use "text/html" to copy&paste
736 +        nsCOMPtr<nsIUnicodeDecoder> decoder;
737 +        nsresult rv;
738 +        // get the decoder
739 +        nsCOMPtr<nsICharsetConverterManager> ccm =
740 +            do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
741 +        if (NS_FAILED(rv)) {
742 +#ifdef DEBUG_CLIPBOARD
743 +            g_print("        can't get CHARSET CONVERTER MANAGER service\n");
744 +#endif
745 +            outUnicodeLen = 0;
746 +            return;
747 +        }
748 +        rv = ccm->GetUnicodeDecoder(charset.get(), getter_AddRefs(decoder));
749 +        if (NS_FAILED(rv)) {
750 +#ifdef DEBUG_CLIPBOARD
751 +            g_print("        get unicode decoder error\n");
752 +#endif
753 +            outUnicodeLen = 0;
754 +            return;
755 +        }
756 +        // converting
757 +        decoder->GetMaxLength((const char *)data, dataLength, &outUnicodeLen);
758 +        // |outUnicodeLen| is number of chars
759 +        if (outUnicodeLen) {
760 +            *unicodeData = reinterpret_cast<PRUnichar*>
761 +                                           (nsMemory::Alloc((outUnicodeLen + sizeof('\0')) *
762 +                           sizeof(PRUnichar)));
763 +            if (*unicodeData) {
764 +                PRInt32 numberTmp = dataLength;
765 +                decoder->Convert((const char *)data, &numberTmp,
766 +                                 *unicodeData, &outUnicodeLen);
767 +#ifdef DEBUG_CLIPBOARD
768 +                if (numberTmp != dataLength)
769 +                    printf("didn't consume all the bytes\n");
770 +#endif
771 +                // null terminate. Convert() doesn't do it for us
772 +                (*unicodeData)[outUnicodeLen] = '\0';
773 +            }
774 +        } // if valid length
775 +    }
776 +}
777 +
778 +/*
779 + * get "charset" information from clipboard data
780 + * return value can be:
781 + *  1. "UTF-16":      mozilla or "text/html" with "charset=utf-16"
782 + *  2. "UNKNOWN":     mozilla can't detect what encode it use
783 + *  3. other:         "text/html" with other charset than utf-16
784 + */
785 +void GetHTMLCharset(guchar * data, PRInt32 dataLength, nsCString& str)
786 +{
787 +    // if detect "FFFE" or "FEFF", assume UTF-16
788 +    PRUnichar* beginChar =  (PRUnichar*)data;
789 +    if ((beginChar[0] == 0xFFFE) || (beginChar[0] == 0xFEFF)) {
790 +        str.AssignLiteral("UTF-16");
791 +        return;
792 +    }
793 +    // no "FFFE" and "FEFF", assume ASCII first to find "charset" info
794 +    const nsDependentCString htmlStr((const char *)data, dataLength);
795 +    nsACString::const_iterator start, end;
796 +    htmlStr.BeginReading(start);
797 +    htmlStr.EndReading(end);
798 +    nsACString::const_iterator valueStart(start), valueEnd(start);
799 +
800 +    if (CaseInsensitiveFindInReadable(
801 +        NS_LITERAL_CSTRING("CONTENT=\"text/html;"),
802 +        start, end)) {
803 +        start = end;
804 +        htmlStr.EndReading(end);
805 +
806 +        if (CaseInsensitiveFindInReadable(
807 +            NS_LITERAL_CSTRING("charset="),
808 +            start, end)) {
809 +            valueStart = end;
810 +            start = end;
811 +            htmlStr.EndReading(end);
812 +          
813 +            if (FindCharInReadable('"', start, end))
814 +                valueEnd = start;
815 +        }
816 +    }
817 +    // find "charset" in HTML
818 +    if (valueStart != valueEnd) {
819 +        str = Substring(valueStart, valueEnd);
820 +        ToUpperCase(str);
821 +#ifdef DEBUG_CLIPBOARD
822 +        printf("Charset of HTML = %s\n", charsetUpperStr.get());
823 +#endif
824 +        return;
825 +    }
826 +    str.AssignLiteral("UNKNOWN");
827 +}
828 +
829 +static void
830 +DispatchSelectionNotifyEvent(GtkWidget *widget, XEvent *xevent)
831 +{
832 +    GdkEvent event;
833 +    event.selection.type = GDK_SELECTION_NOTIFY;
834 +    event.selection.window = widget->window;
835 +    event.selection.selection = gdk_x11_xatom_to_atom(xevent->xselection.selection);
836 +    event.selection.target = gdk_x11_xatom_to_atom(xevent->xselection.target);
837 +    event.selection.property = gdk_x11_xatom_to_atom(xevent->xselection.property);
838 +    event.selection.time = xevent->xselection.time;
839 +
840 +    gtk_widget_event(widget, &event);
841 +}
842 +
843 +static void
844 +DispatchPropertyNotifyEvent(GtkWidget *widget, XEvent *xevent)
845 +{
846 +    if (((GdkWindowObject *) widget->window)->event_mask & GDK_PROPERTY_CHANGE_MASK) {
847 +        GdkEvent event;
848 +        event.property.type = GDK_PROPERTY_NOTIFY;
849 +        event.property.window = widget->window;
850 +        event.property.atom = gdk_x11_xatom_to_atom(xevent->xproperty.atom);
851 +        event.property.time = xevent->xproperty.time;
852 +        event.property.state = xevent->xproperty.state;
853 +
854 +        gtk_widget_event(widget, &event);
855 +    }
856 +}
857 +
858 +struct checkEventContext
859 +{
860 +    GtkWidget *cbWidget;
861 +    Atom       selAtom;
862 +};
863 +
864 +static Bool
865 +checkEventProc(Display *display, XEvent *event, XPointer arg)
866 +{
867 +    checkEventContext *context = (checkEventContext *) arg;
868 +
869 +    if (event->xany.type == SelectionNotify ||
870 +        (event->xany.type == PropertyNotify &&
871 +         event->xproperty.atom == context->selAtom)) {
872 +
873 +        GdkWindow *cbWindow = gdk_window_lookup(event->xany.window);
874 +        if (cbWindow) {
875 +            GtkWidget *cbWidget = NULL;
876 +            gdk_window_get_user_data(cbWindow, (gpointer *)&cbWidget);
877 +            if (cbWidget && GTK_IS_WIDGET(cbWidget)) {
878 +                context->cbWidget = cbWidget;
879 +                return True;
880 +            }
881 +        }
882 +    }
883 +
884 +    return False;
885 +}
886 +
887 +// Idle timeout for receiving selection and property notify events (microsec)
888 +static const int kClipboardTimeout = 500000;
889 +
890 +static void
891 +wait_for_retrieval(GtkClipboard *clipboard, retrieval_context *r_context)
892 +{
893 +    if (r_context->completed)  // the request completed synchronously
894 +        return;
895 +
896 +    Display *xDisplay = GDK_DISPLAY();
897 +    checkEventContext context;
898 +    context.cbWidget = NULL;
899 +    context.selAtom = gdk_x11_atom_to_xatom(gdk_atom_intern("GDK_SELECTION",
900 +                                                            FALSE));
901 +
902 +    // Send X events which are relevant to the ongoing selection retrieval
903 +    // to the clipboard widget.  Wait until either the operation completes, or
904 +    // we hit our timeout.  All other X events remain queued.
905 +
906 +    int select_result;
907 +
908 +#ifdef POLL_WITH_XCONNECTIONNUMBER
909 +    struct pollfd fds[1];
910 +    fds[0].fd = XConnectionNumber(xDisplay);
911 +    fds[0].events = POLLIN;
912 +#else
913 +    int cnumber = ConnectionNumber(xDisplay);
914 +    fd_set select_set;
915 +    FD_ZERO(&select_set);
916 +    FD_SET(cnumber, &select_set);
917 +    ++cnumber;
918 +    struct timeval tv;
919 +#endif
920 +
921 +    do {
922 +        XEvent xevent;
923 +
924 +        while (XCheckIfEvent(xDisplay, &xevent, checkEventProc,
925 +                             (XPointer) &context)) {
926 +
927 +            if (xevent.xany.type == SelectionNotify)
928 +                DispatchSelectionNotifyEvent(context.cbWidget, &xevent);
929 +            else
930 +                DispatchPropertyNotifyEvent(context.cbWidget, &xevent);
931 +
932 +            if (r_context->completed)
933 +                return;
934 +        }
935 +
936 +#ifdef POLL_WITH_XCONNECTIONNUMBER
937 +        select_result = poll(fds, 1, kClipboardTimeout / 1000);
938 +#else
939 +        tv.tv_sec = 0;
940 +        tv.tv_usec = kClipboardTimeout;
941 +        select_result = select(cnumber, &select_set, NULL, NULL, &tv);
942 +#endif
943 +    } while (select_result == 1);
944 +
945 +#ifdef DEBUG_CLIPBOARD
946 +    printf("exceeded clipboard timeout\n");
947 +#endif
948 +}
949 +
950 +static void
951 +clipboard_contents_received(GtkClipboard     *clipboard,
952 +                            GtkSelectionData *selection_data,
953 +                            gpointer          data)
954 +{
955 +    retrieval_context *context = static_cast<retrieval_context *>(data);
956 +    context->completed = PR_TRUE;
957 +
958 +    if (selection_data->length >= 0)
959 +        context->data = gtk_selection_data_copy(selection_data);
960 +}
961 +
962 +
963 +static GtkSelectionData *
964 +wait_for_contents(GtkClipboard *clipboard, GdkAtom target)
965 +{
966 +    retrieval_context context;
967 +    gtk_clipboard_request_contents(clipboard, target,
968 +                                   clipboard_contents_received,
969 +                                   &context);
970 +
971 +    wait_for_retrieval(clipboard, &context);
972 +    return static_cast<GtkSelectionData *>(context.data);
973 +}
974 +
975 +static void
976 +clipboard_text_received(GtkClipboard *clipboard,
977 +                        const gchar  *text,
978 +                        gpointer      data)
979 +{
980 +    retrieval_context *context = static_cast<retrieval_context *>(data);
981 +    context->completed = PR_TRUE;
982 +    context->data = g_strdup(text);
983 +}
984 +
985 +static gchar *
986 +wait_for_text(GtkClipboard *clipboard)
987 +{
988 +    retrieval_context context;
989 +    gtk_clipboard_request_text(clipboard, clipboard_text_received, &context);
990 +
991 +    wait_for_retrieval(clipboard, &context);
992 +    return static_cast<gchar *>(context.data);
993 +}
994 Index: offscreen/widget/src/headless/nsClipboard.h
995 ===================================================================
996 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
997 +++ offscreen/widget/src/headless/nsClipboard.h 2009-06-12 14:14:05.000000000 +0100
998 @@ -0,0 +1,93 @@
999 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
1000 +/* vim:expandtab:shiftwidth=4:tabstop=4:
1001 + */
1002 +/* ***** BEGIN LICENSE BLOCK *****
1003 + * Version: MPL 1.1/GPL 2.0/LGPL 2.1
1004 + *
1005 + * The contents of this file are subject to the Mozilla Public License Version
1006 + * 1.1 (the "License"); you may not use this file except in compliance with
1007 + * the License. You may obtain a copy of the License at
1008 + * http://www.mozilla.org/MPL/
1009 + *
1010 + * Software distributed under the License is distributed on an "AS IS" basis,
1011 + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1012 + * for the specific language governing rights and limitations under the
1013 + * License.
1014 + *
1015 + * The Original Code is mozilla.org code.
1016 + *
1017 + * The Initial Developer of the Original Code is Christopher Blizzard
1018 + * <blizzard@mozilla.org>.  Portions created by the Initial Developer
1019 + * are Copyright (C) 2001 the Initial Developer. All Rights Reserved.
1020 + *
1021 + * Contributor(s):
1022 + *
1023 + * Alternatively, the contents of this file may be used under the terms of
1024 + * either the GNU General Public License Version 2 or later (the "GPL"), or
1025 + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
1026 + * in which case the provisions of the GPL or the LGPL are applicable instead
1027 + * of those above. If you wish to allow use of your version of this file only
1028 + * under the terms of either the GPL or the LGPL, and not to allow others to
1029 + * use your version of this file under the terms of the MPL, indicate your
1030 + * decision by deleting the provisions above and replace them with the notice
1031 + * and other provisions required by the GPL or the LGPL. If you do not delete
1032 + * the provisions above, a recipient may use your version of this file under
1033 + * the terms of any one of the MPL, the GPL or the LGPL.
1034 + *
1035 + * ***** END LICENSE BLOCK ***** */
1036 +
1037 +#ifndef __nsClipboard_h_
1038 +#define __nsClipboard_h_
1039 +
1040 +#include "nsIClipboard.h"
1041 +#include "nsClipboardPrivacyHandler.h"
1042 +#include "nsAutoPtr.h"
1043 +#include <gtk/gtk.h>
1044 +
1045 +class nsClipboard : public nsIClipboard
1046 +{
1047 +public:
1048 +    nsClipboard();
1049 +    virtual ~nsClipboard();
1050 +    
1051 +    NS_DECL_ISUPPORTS
1052 +    
1053 +    NS_DECL_NSICLIPBOARD
1054 +
1055 +    // Make sure we are initialized, called from the factory
1056 +    // constructor
1057 +    nsresult  Init                (void);
1058 +    // Someone requested the selection from the hidden widget
1059 +    void      SelectionGetEvent   (GtkWidget         *aWidget,
1060 +                                   GtkSelectionData  *aSelectionData,
1061 +                                   guint              aTime);
1062 +    void      SelectionClearEvent (GtkWidget         *aWidget,
1063 +                                   GdkEventSelection *aEvent);
1064 +
1065 +
1066 +private:
1067 +    // Utility methods
1068 +    static GdkAtom               GetSelectionAtom (PRInt32 aWhichClipboard);
1069 +    static GtkSelectionData     *GetTargets       (GdkAtom aWhichClipboard);
1070 +
1071 +    // Get our hands on the correct transferable, given a specific
1072 +    // clipboard
1073 +    nsITransferable             *GetTransferable  (PRInt32 aWhichClipboard);
1074 +
1075 +    // Add a target type to the hidden widget
1076 +    void                         AddTarget        (GdkAtom aName,
1077 +                                                   GdkAtom aClipboard);
1078 +
1079 +    // The hidden widget where we do all of our operations
1080 +    GtkWidget                   *mWidget;
1081 +    // Hang on to our owners and transferables so we can transfer data
1082 +    // when asked.
1083 +    nsCOMPtr<nsIClipboardOwner>  mSelectionOwner;
1084 +    nsCOMPtr<nsIClipboardOwner>  mGlobalOwner;
1085 +    nsCOMPtr<nsITransferable>    mSelectionTransferable;
1086 +    nsCOMPtr<nsITransferable>    mGlobalTransferable;
1087 +    nsRefPtr<nsClipboardPrivacyHandler> mPrivacyHandler;
1088 +
1089 +};
1090 +
1091 +#endif /* __nsClipboard_h_ */
1092 Index: offscreen/widget/src/headless/nsIImageToPixbuf.h
1093 ===================================================================
1094 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
1095 +++ offscreen/widget/src/headless/nsIImageToPixbuf.h    2009-06-12 14:14:05.000000000 +0100
1096 @@ -0,0 +1,62 @@
1097 +/* ***** BEGIN LICENSE BLOCK *****
1098 + * Version: MPL 1.1/GPL 2.0/LGPL 2.1
1099 + *
1100 + * The contents of this file are subject to the Mozilla Public License Version
1101 + * 1.1 (the "License"); you may not use this file except in compliance with
1102 + * the License. You may obtain a copy of the License at
1103 + * http://www.mozilla.org/MPL/
1104 + *
1105 + * Software distributed under the License is distributed on an "AS IS" basis,
1106 + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1107 + * for the specific language governing rights and limitations under the
1108 + * License.
1109 + *
1110 + * The Original Code is mozilla.org widget code.
1111 + *
1112 + * The Initial Developer of the Original Code is
1113 + * Christian Biesinger <cbiesinger@web.de>.
1114 + * Portions created by the Initial Developer are Copyright (C) 2006
1115 + * the Initial Developer. All Rights Reserved.
1116 + *
1117 + * Contributor(s):
1118 + *
1119 + * Alternatively, the contents of this file may be used under the terms of
1120 + * either the GNU General Public License Version 2 or later (the "GPL"), or
1121 + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
1122 + * in which case the provisions of the GPL or the LGPL are applicable instead
1123 + * of those above. If you wish to allow use of your version of this file only
1124 + * under the terms of either the GPL or the LGPL, and not to allow others to
1125 + * use your version of this file under the terms of the MPL, indicate your
1126 + * decision by deleting the provisions above and replace them with the notice
1127 + * and other provisions required by the GPL or the LGPL. If you do not delete
1128 + * the provisions above, a recipient may use your version of this file under
1129 + * the terms of any one of the MPL, the GPL or the LGPL.
1130 + *
1131 + * ***** END LICENSE BLOCK ***** */
1132 +
1133 +#ifndef NSIIMAGETOPIXBUF_H_
1134 +#define NSIIMAGETOPIXBUF_H_
1135 +
1136 +#include "nsISupports.h"
1137 +
1138 +// dfa4ac93-83f2-4ab8-9b2a-0ff7022aebe2
1139 +#define NSIIMAGETOPIXBUF_IID \
1140 +{ 0xdfa4ac93, 0x83f2, 0x4ab8, \
1141 +  { 0x9b, 0x2a, 0x0f, 0xf7, 0x02, 0x2a, 0xeb, 0xe2 } }
1142 +
1143 +class nsIImage;
1144 +typedef struct _GdkPixbuf GdkPixbuf;
1145 +
1146 +/**
1147 + * An interface that allows converting an nsIImage to a GdkPixbuf*.
1148 + */
1149 +class nsIImageToPixbuf : public nsISupports {
1150 +    public:
1151 +        NS_DECLARE_STATIC_IID_ACCESSOR(NSIIMAGETOPIXBUF_IID)
1152 +
1153 +        NS_IMETHOD_(GdkPixbuf*) ConvertImageToPixbuf(nsIImage* aImage) = 0;
1154 +};
1155 +
1156 +NS_DEFINE_STATIC_IID_ACCESSOR(nsIImageToPixbuf, NSIIMAGETOPIXBUF_IID)
1157 +
1158 +#endif
1159 Index: offscreen/widget/src/headless/nsImageToPixbuf.cpp
1160 ===================================================================
1161 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
1162 +++ offscreen/widget/src/headless/nsImageToPixbuf.cpp   2009-06-12 14:14:05.000000000 +0100
1163 @@ -0,0 +1,196 @@
1164 +/* vim:set sw=4 sts=4 et cin: */
1165 +/* ***** BEGIN LICENSE BLOCK *****
1166 + * Version: MPL 1.1/GPL 2.0/LGPL 2.1
1167 + *
1168 + * The contents of this file are subject to the Mozilla Public License Version
1169 + * 1.1 (the "License"); you may not use this file except in compliance with
1170 + * the License. You may obtain a copy of the License at
1171 + * http://www.mozilla.org/MPL/
1172 + *
1173 + * Software distributed under the License is distributed on an "AS IS" basis,
1174 + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1175 + * for the specific language governing rights and limitations under the
1176 + * License.
1177 + *
1178 + * The Original Code is mozilla.org widget code.
1179 + *
1180 + * The Initial Developer of the Original Code is
1181 + * Christian Biesinger <cbiesinger@web.de>.
1182 + * Portions created by the Initial Developer are Copyright (C) 2006
1183 + * the Initial Developer. All Rights Reserved.
1184 + *
1185 + * Contributor(s):
1186 + *
1187 + * Alternatively, the contents of this file may be used under the terms of
1188 + * either the GNU General Public License Version 2 or later (the "GPL"), or
1189 + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
1190 + * in which case the provisions of the GPL or the LGPL are applicable instead
1191 + * of those above. If you wish to allow use of your version of this file only
1192 + * under the terms of either the GPL or the LGPL, and not to allow others to
1193 + * use your version of this file under the terms of the MPL, indicate your
1194 + * decision by deleting the provisions above and replace them with the notice
1195 + * and other provisions required by the GPL or the LGPL. If you do not delete
1196 + * the provisions above, a recipient may use your version of this file under
1197 + * the terms of any one of the MPL, the GPL or the LGPL.
1198 + *
1199 + * ***** END LICENSE BLOCK ***** */
1200 +
1201 +#include <gdk-pixbuf/gdk-pixbuf.h>
1202 +
1203 +#include "gfxASurface.h"
1204 +#include "gfxImageSurface.h"
1205 +#include "gfxContext.h"
1206 +
1207 +#include "nsIImage.h"
1208 +
1209 +#include "nsAutoPtr.h"
1210 +
1211 +#include "nsImageToPixbuf.h"
1212 +
1213 +NS_IMPL_ISUPPORTS1(nsImageToPixbuf, nsIImageToPixbuf)
1214 +
1215 +inline unsigned char
1216 +unpremultiply (unsigned char color,
1217 +               unsigned char alpha)
1218 +{
1219 +    if (alpha == 0)
1220 +        return 0;
1221 +    // plus alpha/2 to round instead of truncate
1222 +    return (color * 255 + alpha / 2) / alpha;
1223 +}
1224 +
1225 +NS_IMETHODIMP_(GdkPixbuf*)
1226 +nsImageToPixbuf::ConvertImageToPixbuf(nsIImage* aImage)
1227 +{
1228 +    return ImageToPixbuf(aImage);
1229 +}
1230 +
1231 +GdkPixbuf*
1232 +nsImageToPixbuf::ImageToPixbuf(nsIImage* aImage)
1233 +{
1234 +    PRInt32 width = aImage->GetWidth(),
1235 +            height = aImage->GetHeight();
1236 +
1237 +    nsRefPtr<gfxPattern> pattern;
1238 +    aImage->GetPattern(getter_AddRefs(pattern));
1239 +
1240 +    return PatternToPixbuf(pattern, width, height);
1241 +}
1242 +
1243 +GdkPixbuf*
1244 +nsImageToPixbuf::ImgSurfaceToPixbuf(gfxImageSurface* aImgSurface, PRInt32 aWidth, PRInt32 aHeight)
1245 +{
1246 +    GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, PR_TRUE, 8,
1247 +                                       aWidth, aHeight);
1248 +    if (!pixbuf)
1249 +        return nsnull;
1250 +
1251 +    PRUint32 rowstride = gdk_pixbuf_get_rowstride (pixbuf);
1252 +    guchar* pixels = gdk_pixbuf_get_pixels (pixbuf);
1253 +
1254 +    long cairoStride = aImgSurface->Stride();
1255 +    unsigned char* cairoData = aImgSurface->Data();
1256 +
1257 +    gfxASurface::gfxImageFormat format = aImgSurface->Format();
1258 +
1259 +    for (PRInt32 row = 0; row < aHeight; ++row) {
1260 +        for (PRInt32 col = 0; col < aWidth; ++col) {
1261 +            guchar* pixel = pixels + row * rowstride + 4 * col;
1262 +
1263 +            PRUint32* cairoPixel = reinterpret_cast<PRUint32*>
1264 +                                                   ((cairoData + row * cairoStride + 4 * col));
1265 +
1266 +            if (format == gfxASurface::ImageFormatARGB32) {
1267 +                const PRUint8 a = (*cairoPixel >> 24) & 0xFF;
1268 +                const PRUint8 r = unpremultiply((*cairoPixel >> 16) & 0xFF, a);
1269 +                const PRUint8 g = unpremultiply((*cairoPixel >>  8) & 0xFF, a);
1270 +                const PRUint8 b = unpremultiply((*cairoPixel >>  0) & 0xFF, a);
1271 +
1272 +                *pixel++ = r;
1273 +                *pixel++ = g;
1274 +                *pixel++ = b;
1275 +                *pixel++ = a;
1276 +            } else {
1277 +                NS_ASSERTION(format == gfxASurface::ImageFormatRGB24,
1278 +                             "unexpected format");
1279 +                const PRUint8 r = (*cairoPixel >> 16) & 0xFF;
1280 +                const PRUint8 g = (*cairoPixel >>  8) & 0xFF;
1281 +                const PRUint8 b = (*cairoPixel >>  0) & 0xFF;
1282 +
1283 +                *pixel++ = r;
1284 +                *pixel++ = g;
1285 +                *pixel++ = b;
1286 +                *pixel++ = 0xFF; // A
1287 +            }
1288 +        }
1289 +    }
1290 +
1291 +    return pixbuf;
1292 +}
1293 +
1294 +GdkPixbuf*
1295 +nsImageToPixbuf::SurfaceToPixbuf(gfxASurface* aSurface, PRInt32 aWidth, PRInt32 aHeight)
1296 +{
1297 +    if (aSurface->CairoStatus()) {
1298 +        NS_ERROR("invalid surface");
1299 +        return nsnull;
1300 +    }
1301 +
1302 +    nsRefPtr<gfxImageSurface> imgSurface;
1303 +    if (aSurface->GetType() == gfxASurface::SurfaceTypeImage) {
1304 +        imgSurface = static_cast<gfxImageSurface*>
1305 +                                (static_cast<gfxASurface*>(aSurface));
1306 +    } else {
1307 +        imgSurface = new gfxImageSurface(gfxIntSize(aWidth, aHeight),
1308 +                                        gfxImageSurface::ImageFormatARGB32);
1309 +                                       
1310 +        if (!imgSurface)
1311 +            return nsnull;
1312 +
1313 +        nsRefPtr<gfxContext> context = new gfxContext(imgSurface);
1314 +        if (!context)
1315 +            return nsnull;
1316 +
1317 +        context->SetOperator(gfxContext::OPERATOR_SOURCE);
1318 +        context->SetSource(aSurface);
1319 +        context->Paint();
1320 +    }
1321 +
1322 +    return ImgSurfaceToPixbuf(imgSurface, aWidth, aHeight);
1323 +}
1324 +  
1325 +GdkPixbuf*
1326 +nsImageToPixbuf::PatternToPixbuf(gfxPattern* aPattern, PRInt32 aWidth, PRInt32 aHeight)
1327 +{
1328 +    if (aPattern->CairoStatus()) {
1329 +        NS_ERROR("invalid pattern");
1330 +        return nsnull;
1331 +    }
1332 +
1333 +    nsRefPtr<gfxImageSurface> imgSurface;
1334 +    if (aPattern->GetType() == gfxPattern::PATTERN_SURFACE) {
1335 +        nsRefPtr<gfxASurface> surface = aPattern->GetSurface();
1336 +        if (surface->GetType() == gfxASurface::SurfaceTypeImage) {
1337 +            imgSurface = static_cast<gfxImageSurface*>
1338 +                                    (static_cast<gfxASurface*>(surface.get()));
1339 +        }
1340 +    } 
1341 +    
1342 +    if (!imgSurface) {
1343 +        imgSurface = new gfxImageSurface(gfxIntSize(aWidth, aHeight),
1344 +                                        gfxImageSurface::ImageFormatARGB32);
1345 +                                       
1346 +        if (!imgSurface)
1347 +            return nsnull;
1348 +
1349 +        nsRefPtr<gfxContext> context = new gfxContext(imgSurface);
1350 +        if (!context)
1351 +            return nsnull;
1352 +
1353 +        context->SetOperator(gfxContext::OPERATOR_SOURCE);
1354 +        context->SetPattern(aPattern);
1355 +        context->Paint();
1356 +    }
1357 +
1358 +    return ImgSurfaceToPixbuf(imgSurface, aWidth, aHeight);
1359 +}
1360 Index: offscreen/widget/src/headless/nsImageToPixbuf.h
1361 ===================================================================
1362 --- /dev/null   1970-01-01 00:00:00.000000000 +0000
1363 +++ offscreen/widget/src/headless/nsImageToPixbuf.h     2009-06-12 14:14:05.000000000 +0100
1364 @@ -0,0 +1,71 @@
1365 +/* vim:set sw=4 sts=4 et cin: */
1366 +/* ***** BEGIN LICENSE BLOCK *****
1367 + * Version: MPL 1.1/GPL 2.0/LGPL 2.1
1368 + *
1369 + * The contents of this file are subject to the Mozilla Public License Version
1370 + * 1.1 (the "License"); you may not use this file except in compliance with
1371 + * the License. You may obtain a copy of the License at
1372 + * http://www.mozilla.org/MPL/
1373 + *
1374 + * Software distributed under the License is distributed on an "AS IS" basis,
1375 + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
1376 + * for the specific language governing rights and limitations under the
1377 + * License.
1378 + *
1379 + * The Original Code is mozilla.org widget code.
1380 + *
1381 + * The Initial Developer of the Original Code is
1382 + * Christian Biesinger <cbiesinger@web.de>.
1383 + * Portions created by the Initial Developer are Copyright (C) 2006
1384 + * the Initial Developer. All Rights Reserved.
1385 + *
1386 + * Contributor(s):
1387 + *
1388 + * Alternatively, the contents of this file may be used under the terms of
1389 + * either the GNU General Public License Version 2 or later (the "GPL"), or
1390 + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
1391 + * in which case the provisions of the GPL or the LGPL are applicable instead
1392 + * of those above. If you wish to allow use of your version of this file only
1393 + * under the terms of either the GPL or the LGPL, and not to allow others to
1394 + * use your version of this file under the terms of the MPL, indicate your
1395 + * decision by deleting the provisions above and replace them with the notice
1396 + * and other provisions required by the GPL or the LGPL. If you do not delete
1397 + * the provisions above, a recipient may use your version of this file under
1398 + * the terms of any one of the MPL, the GPL or the LGPL.
1399 + *
1400 + * ***** END LICENSE BLOCK ***** */
1401 +
1402 +#ifndef NSIMAGETOPIXBUF_H_
1403 +#define NSIMAGETOPIXBUF_H_
1404 +
1405 +#include "nsIImageToPixbuf.h"
1406 +
1407 +class gfxASurface;
1408 +class gfxPattern;
1409 +class gfxImageSurface;
1410 +
1411 +class nsImageToPixbuf : public nsIImageToPixbuf {
1412 +    public:
1413 +        NS_DECL_ISUPPORTS
1414 +        NS_IMETHOD_(GdkPixbuf*) ConvertImageToPixbuf(nsIImage* aImage);
1415 +
1416 +        // Friendlier version of ConvertImageToPixbuf for callers inside of
1417 +        // widget
1418 +        static GdkPixbuf* ImageToPixbuf(nsIImage* aImage);
1419 +        static GdkPixbuf* SurfaceToPixbuf(gfxASurface* aSurface,
1420 +                                          PRInt32 aWidth, PRInt32 aHeight);
1421 +        static GdkPixbuf* PatternToPixbuf(gfxPattern* aPattern,
1422 +                                          PRInt32 aWidth, PRInt32 aHeight);
1423 +    private:
1424 +        static GdkPixbuf* ImgSurfaceToPixbuf(gfxImageSurface* aImgSurface,
1425 +                                             PRInt32 aWidth, PRInt32 aHeight);
1426 +        ~nsImageToPixbuf() {}
1427 +};
1428 +
1429 +
1430 +// fc2389b8-c650-4093-9e42-b05e5f0685b7
1431 +#define NS_IMAGE_TO_PIXBUF_CID \
1432 +{ 0xfc2389b8, 0xc650, 0x4093, \
1433 +  { 0x9e, 0x42, 0xb0, 0x5e, 0x5f, 0x06, 0x85, 0xb7 } }
1434 +
1435 +#endif
1436 Index: offscreen/widget/src/headless/nsWidgetFactory.cpp
1437 ===================================================================
1438 --- offscreen.orig/widget/src/headless/nsWidgetFactory.cpp      2009-06-12 14:08:56.000000000 +0100
1439 +++ offscreen/widget/src/headless/nsWidgetFactory.cpp   2009-06-12 14:15:24.000000000 +0100
1440 @@ -46,6 +46,10 @@
1441  #include "nsWindow.h"
1442  #include "nsTransferable.h"
1443  #include "nsHTMLFormatConverter.h"
1444 +#ifdef MOZ_X11
1445 +#include "nsClipboardHelper.h"
1446 +#include "nsClipboard.h"
1447 +#endif
1448  #include "nsSound.h"
1449  #include "nsBidiKeyboard.h"
1450  #include "nsScreenManagerHeadless.h"
1451 @@ -66,6 +70,10 @@
1452  NS_GENERIC_FACTORY_CONSTRUCTOR(nsTransferable)
1453  NS_GENERIC_FACTORY_CONSTRUCTOR(nsBidiKeyboard)
1454  NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLFormatConverter)
1455 +#ifdef MOZ_X11
1456 +NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardHelper)
1457 +NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsClipboard, Init)
1458 +#endif
1459  NS_GENERIC_FACTORY_CONSTRUCTOR(nsSound)
1460  NS_GENERIC_FACTORY_CONSTRUCTOR(nsScreenManagerHeadless)
1461  //NS_GENERIC_FACTORY_CONSTRUCTOR(nsImageToPixbuf)
1462 @@ -142,6 +150,16 @@
1463      NS_TRANSFERABLE_CID,
1464      "@mozilla.org/widget/transferable;1",
1465      nsTransferableConstructor },
1466 +#ifdef MOZ_X11
1467 +  { "Gtk Clipboard",
1468 +    NS_CLIPBOARD_CID,
1469 +    "@mozilla.org/widget/clipboard;1",
1470 +    nsClipboardConstructor },
1471 +  { "Clipboard Helper",
1472 +    NS_CLIPBOARDHELPER_CID,
1473 +    "@mozilla.org/widget/clipboardhelper;1",
1474 +    nsClipboardHelperConstructor },
1475 +#endif
1476    { "HTML Format Converter",
1477      NS_HTMLFORMATCONVERTER_CID,
1478      "@mozilla.org/widget/htmlformatconverter;1",