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