Bug 460926 A11y hierachy is broken on Ubuntu 8.10 (GNOME 2.24), r=Evan.Yan sr=roc
[wine-gecko.git] / gfx / thebes / src / gfxPlatformGtk.cpp
blob5c3d869c6d5bedce45db5a04319ceb8854522852
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Foundation code.
17 * The Initial Developer of the Original Code is Mozilla Foundation.
18 * Portions created by the Initial Developer are Copyright (C) 2005
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
22 * Vladimir Vukicevic <vladimir@pobox.com>
23 * Masayuki Nakano <masayuki@d-toybox.com>
24 * Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #ifdef MOZ_PANGO
41 #define PANGO_ENABLE_BACKEND
42 #define PANGO_ENABLE_ENGINE
43 #endif
45 #include "gfxPlatformGtk.h"
47 #include "gfxFontconfigUtils.h"
48 #ifdef MOZ_PANGO
49 #include "gfxPangoFonts.h"
50 #include "gfxContext.h"
51 #include "gfxUserFontSet.h"
52 #else
53 #include <ft2build.h>
54 #include FT_FREETYPE_H
55 #include "gfxFT2Fonts.h"
56 #endif
58 #include "cairo.h"
59 #include <gtk/gtk.h>
61 #include "gfxImageSurface.h"
62 #ifdef MOZ_X11
63 #include <gdk/gdkx.h>
64 #include "gfxXlibSurface.h"
65 #include "cairo-xlib.h"
66 #endif /* MOZ_X11 */
68 #ifdef MOZ_DFB
69 #include "gfxDirectFBSurface.h"
70 #endif
72 #ifdef MOZ_DFB
73 #include "gfxDirectFBSurface.h"
74 #endif
76 #include <fontconfig/fontconfig.h>
78 #include "nsMathUtils.h"
80 #include "lcms.h"
82 #define GDK_PIXMAP_SIZE_MAX 32767
84 #ifndef MOZ_PANGO
85 #include <ft2build.h>
86 #include FT_FREETYPE_H
87 #endif
89 double gfxPlatformGtk::sDPI = -1.0;
90 gfxFontconfigUtils *gfxPlatformGtk::sFontconfigUtils = nsnull;
92 #ifndef MOZ_PANGO
93 typedef nsDataHashtable<nsStringHashKey, nsRefPtr<FontFamily> > FontTable;
94 static FontTable *gPlatformFonts = NULL;
95 static FontTable *gPlatformFontAliases = NULL;
96 static FT_Library gPlatformFTLibrary = NULL;
97 #endif
99 static cairo_user_data_key_t cairo_gdk_drawable_key;
100 static void do_gdk_drawable_unref (void *data)
102 GdkDrawable *d = (GdkDrawable*) data;
103 g_object_unref (d);
106 gfxPlatformGtk::gfxPlatformGtk()
108 if (!sFontconfigUtils)
109 sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils();
111 #ifndef MOZ_PANGO
112 FT_Init_FreeType(&gPlatformFTLibrary);
114 gPlatformFonts = new FontTable();
115 gPlatformFonts->Init(100);
116 gPlatformFontAliases = new FontTable();
117 gPlatformFontAliases->Init(100);
118 UpdateFontList();
119 #endif
121 InitDPI();
124 gfxPlatformGtk::~gfxPlatformGtk()
126 gfxFontconfigUtils::Shutdown();
127 sFontconfigUtils = nsnull;
129 #ifdef MOZ_PANGO
130 gfxPangoFontGroup::Shutdown();
131 #else
132 delete gPlatformFonts;
133 gPlatformFonts = NULL;
134 delete gPlatformFontAliases;
135 gPlatformFontAliases = NULL;
137 FT_Done_FreeType(gPlatformFTLibrary);
138 gPlatformFTLibrary = NULL;
139 #endif
141 #if 0
142 // It would be nice to do this (although it might need to be after
143 // the cairo shutdown that happens in ~gfxPlatform). It even looks
144 // idempotent. But it has fatal assertions that fire if stuff is
145 // leaked, and we hit them.
146 FcFini();
147 #endif
150 already_AddRefed<gfxASurface>
151 gfxPlatformGtk::CreateOffscreenSurface(const gfxIntSize& size,
152 gfxASurface::gfxImageFormat imageFormat)
154 nsRefPtr<gfxASurface> newSurface = nsnull;
155 PRBool sizeOk = PR_TRUE;
157 if (size.width >= GDK_PIXMAP_SIZE_MAX ||
158 size.height >= GDK_PIXMAP_SIZE_MAX)
159 sizeOk = PR_FALSE;
161 #ifdef MOZ_X11
162 int glitzf;
163 int xrenderFormatID;
164 switch (imageFormat) {
165 case gfxASurface::ImageFormatARGB32:
166 glitzf = 0; // GLITZ_STANDARD_ARGB32;
167 xrenderFormatID = PictStandardARGB32;
168 break;
169 case gfxASurface::ImageFormatRGB24:
170 glitzf = 1; // GLITZ_STANDARD_RGB24;
171 xrenderFormatID = PictStandardRGB24;
172 break;
173 case gfxASurface::ImageFormatA8:
174 glitzf = 2; // GLITZ_STANDARD_A8;
175 xrenderFormatID = PictStandardA8;
176 break;
177 case gfxASurface::ImageFormatA1:
178 glitzf = 3; // GLITZ_STANDARD_A1;
179 xrenderFormatID = PictStandardA1;
180 break;
181 default:
182 return nsnull;
185 // XXX we really need a different interface here, something that passes
186 // in more context, including the display and/or target surface type that
187 // we should try to match
188 Display* display = GDK_DISPLAY();
189 if (!display)
190 return nsnull;
192 GdkPixmap* pixmap = nsnull;
193 XRenderPictFormat* xrenderFormat =
194 XRenderFindStandardFormat(display, xrenderFormatID);
196 if (xrenderFormat && sizeOk) {
197 pixmap = gdk_pixmap_new(nsnull, size.width, size.height,
198 xrenderFormat->depth);
200 if (pixmap) {
201 gdk_drawable_set_colormap(GDK_DRAWABLE(pixmap), nsnull);
202 newSurface = new gfxXlibSurface(display,
203 GDK_PIXMAP_XID(GDK_DRAWABLE(pixmap)),
204 xrenderFormat,
205 size);
208 if (newSurface && newSurface->CairoStatus() == 0) {
209 // set up the surface to auto-unref the gdk pixmap when
210 // the surface is released
211 SetGdkDrawable(newSurface, GDK_DRAWABLE(pixmap));
212 } else {
213 // something went wrong with the surface creation.
214 // Ignore and let's fall back to image surfaces.
215 newSurface = nsnull;
218 // always unref; SetGdkDrawable takes its own ref
219 if (pixmap)
220 g_object_unref(pixmap);
222 #endif
224 #ifdef MOZ_DFB
225 if (sizeOk)
226 newSurface = new gfxDirectFBSurface(size, imageFormat);
227 #endif
230 if (!newSurface) {
231 // We couldn't create a native surface for whatever reason;
232 // e.g., no RENDER, bad size, etc.
233 // Fall back to image surface for the data.
234 newSurface = new gfxImageSurface(gfxIntSize(size.width, size.height), imageFormat);
237 if (newSurface) {
238 gfxContext tmpCtx(newSurface);
239 tmpCtx.SetOperator(gfxContext::OPERATOR_CLEAR);
240 tmpCtx.Paint();
243 return newSurface.forget();
246 #ifdef MOZ_PANGO
248 nsresult
249 gfxPlatformGtk::GetFontList(const nsACString& aLangGroup,
250 const nsACString& aGenericFamily,
251 nsStringArray& aListOfFonts)
253 return sFontconfigUtils->GetFontList(aLangGroup, aGenericFamily,
254 aListOfFonts);
257 nsresult
258 gfxPlatformGtk::UpdateFontList()
260 return sFontconfigUtils->UpdateFontList();
263 nsresult
264 gfxPlatformGtk::ResolveFontName(const nsAString& aFontName,
265 FontResolverCallback aCallback,
266 void *aClosure,
267 PRBool& aAborted)
269 return sFontconfigUtils->ResolveFontName(aFontName, aCallback,
270 aClosure, aAborted);
273 nsresult
274 gfxPlatformGtk::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
276 return sFontconfigUtils->GetStandardFamilyName(aFontName, aFamilyName);
279 gfxFontGroup *
280 gfxPlatformGtk::CreateFontGroup(const nsAString &aFamilies,
281 const gfxFontStyle *aStyle,
282 gfxUserFontSet *aUserFontSet)
284 return new gfxPangoFontGroup(aFamilies, aStyle, aUserFontSet);
287 gfxFontEntry*
288 gfxPlatformGtk::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
289 nsISupports *aLoader,
290 const PRUint8 *aFontData, PRUint32 aLength)
292 // Just being consistent with other platforms.
293 // This will mean that only fonts in SFNT formats will be accepted.
294 if (!gfxFontUtils::ValidateSFNTHeaders(aFontData, aLength))
295 return nsnull;
297 return gfxPangoFontGroup::NewFontEntry(*aProxyEntry, aLoader,
298 aFontData, aLength);
301 PRBool
302 gfxPlatformGtk::IsFontFormatSupported(nsIURI *aFontURI, PRUint32 aFormatFlags)
304 // reject based on format flags
305 if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_EOT | gfxUserFontSet::FLAG_FORMAT_SVG)) {
306 return PR_FALSE;
309 // Pango doesn't apply features from AAT TrueType extensions.
310 // Assume that if this is the only SFNT format specified,
311 // then AAT extensions are required for complex script support.
312 if ((aFormatFlags & gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT)
313 && !(aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_OPENTYPE | gfxUserFontSet::FLAG_FORMAT_TRUETYPE))) {
314 return PR_FALSE;
317 // otherwise, return true
318 return PR_TRUE;
321 #else
323 nsresult
324 gfxPlatformGtk::GetFontList(const nsACString& aLangGroup,
325 const nsACString& aGenericFamily,
326 nsStringArray& aListOfFonts)
328 return sFontconfigUtils->GetFontList(aLangGroup, aGenericFamily,
329 aListOfFonts);
332 nsresult
333 gfxPlatformGtk::UpdateFontList()
335 FcPattern *pat = NULL;
336 FcObjectSet *os = NULL;
337 FcFontSet *fs = NULL;
338 PRInt32 result = -1;
340 pat = FcPatternCreate();
341 os = FcObjectSetBuild(FC_FAMILY, FC_FILE, FC_INDEX, FC_WEIGHT, FC_SLANT, FC_WIDTH, NULL);
343 fs = FcFontList(NULL, pat, os);
346 for (int i = 0; i < fs->nfont; i++) {
347 char *str;
349 if (FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch)
350 continue;
352 //printf("Family: %s\n", str);
354 nsAutoString name(NS_ConvertUTF8toUTF16(nsDependentCString(str)).get());
355 nsAutoString key(name);
356 /* FIXME DFB */
357 //ToLowerCase(key);
358 nsRefPtr<FontFamily> ff;
359 if (!gPlatformFonts->Get(key, &ff)) {
360 ff = new FontFamily(name);
361 gPlatformFonts->Put(key, ff);
364 nsRefPtr<FontEntry> fe = new FontEntry(ff->mName);
365 ff->mFaces.AppendElement(fe);
367 if (FcPatternGetString(fs->fonts[i], FC_FILE, 0, (FcChar8 **) &str) == FcResultMatch) {
368 fe->mFilename = nsDependentCString(str);
369 //printf(" - file: %s\n", str);
372 int x;
373 if (FcPatternGetInteger(fs->fonts[i], FC_INDEX, 0, &x) == FcResultMatch) {
374 //printf(" - index: %d\n", x);
375 fe->mFTFontIndex = x;
376 } else {
377 fe->mFTFontIndex = 0;
380 fe->mWeight = gfxFontconfigUtils::GetThebesWeight(fs->fonts[i]);
381 //printf(" - weight: %d\n", fe->mWeight);
383 fe->mItalic = PR_FALSE;
384 if (FcPatternGetInteger(fs->fonts[i], FC_SLANT, 0, &x) == FcResultMatch) {
385 switch (x) {
386 case FC_SLANT_ITALIC:
387 case FC_SLANT_OBLIQUE:
388 fe->mItalic = PR_TRUE;
390 //printf(" - slant: %d\n", x);
393 //if (FcPatternGetInteger(fs->fonts[i], FC_WIDTH, 0, &x) == FcResultMatch)
394 //printf(" - width: %d\n", x);
395 // XXX deal with font-stretch stuff later
398 if (pat)
399 FcPatternDestroy(pat);
400 if (os)
401 FcObjectSetDestroy(os);
402 if (fs)
403 FcFontSetDestroy(fs);
405 return sFontconfigUtils->UpdateFontList();
408 nsresult
409 gfxPlatformGtk::ResolveFontName(const nsAString& aFontName,
410 FontResolverCallback aCallback,
411 void *aClosure,
412 PRBool& aAborted)
415 nsAutoString name(aFontName);
416 /* FIXME: DFB */
417 //ToLowerCase(name);
419 nsRefPtr<FontFamily> ff;
420 if (gPlatformFonts->Get(name, &ff) ||
421 gPlatformFontAliases->Get(name, &ff)) {
422 aAborted = !(*aCallback)(ff->mName, aClosure);
423 return NS_OK;
426 nsCAutoString utf8Name = NS_ConvertUTF16toUTF8(aFontName);
428 FcPattern *npat = FcPatternCreate();
429 FcPatternAddString(npat, FC_FAMILY, (FcChar8*)utf8Name.get());
430 FcObjectSet *nos = FcObjectSetBuild(FC_FAMILY, NULL);
431 FcFontSet *nfs = FcFontList(NULL, npat, nos);
433 for (int k = 0; k < nfs->nfont; k++) {
434 FcChar8 *str;
435 if (FcPatternGetString(nfs->fonts[k], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch)
436 continue;
437 nsAutoString altName = NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast<char*>(str)));
438 /* FIXME: DFB */
439 //ToLowerCase(altName);
440 if (gPlatformFonts->Get(altName, &ff)) {
441 //printf("Adding alias: %s -> %s\n", utf8Name.get(), str);
442 gPlatformFontAliases->Put(name, ff);
443 aAborted = !(*aCallback)(NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast<char*>(str))), aClosure);
444 goto DONE;
448 FcPatternDestroy(npat);
449 FcObjectSetDestroy(nos);
450 FcFontSetDestroy(nfs);
453 npat = FcPatternCreate();
454 FcPatternAddString(npat, FC_FAMILY, (FcChar8*)utf8Name.get());
455 FcPatternDel(npat, FC_LANG);
456 FcConfigSubstitute(NULL, npat, FcMatchPattern);
457 FcDefaultSubstitute(npat);
459 nos = FcObjectSetBuild(FC_FAMILY, NULL);
460 nfs = FcFontList(NULL, npat, nos);
462 FcResult fresult;
464 FcPattern *match = FcFontMatch(NULL, npat, &fresult);
465 if (match)
466 FcFontSetAdd(nfs, match);
468 for (int k = 0; k < nfs->nfont; k++) {
469 FcChar8 *str;
470 if (FcPatternGetString(nfs->fonts[k], FC_FAMILY, 0, (FcChar8 **) &str) != FcResultMatch)
471 continue;
472 nsAutoString altName = NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast<char*>(str)));
473 /* FIXME: DFB */
474 //ToLowerCase(altName);
475 if (gPlatformFonts->Get(altName, &ff)) {
476 //printf("Adding alias: %s -> %s\n", utf8Name.get(), str);
477 gPlatformFontAliases->Put(name, ff);
478 aAborted = !(*aCallback)(NS_ConvertUTF8toUTF16(nsDependentCString(reinterpret_cast<char*>(str))), aClosure);
479 goto DONE;
483 DONE:
484 FcPatternDestroy(npat);
485 FcObjectSetDestroy(nos);
486 FcFontSetDestroy(nfs);
488 return NS_OK;
491 nsresult
492 gfxPlatformGtk::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
494 return sFontconfigUtils->GetStandardFamilyName(aFontName, aFamilyName);
497 gfxFontGroup *
498 gfxPlatformGtk::CreateFontGroup(const nsAString &aFamilies,
499 const gfxFontStyle *aStyle)
501 return new gfxFT2FontGroup(aFamilies, aStyle);
504 #endif
507 /* static */
508 void
509 gfxPlatformGtk::InitDPI()
511 sDPI = gdk_screen_get_resolution(gdk_screen_get_default());
513 if (sDPI <= 0.0) {
514 // Fall back to something sane
515 sDPI = 96.0;
519 cmsHPROFILE
520 gfxPlatformGtk::GetPlatformCMSOutputProfile()
522 #ifdef MOZ_X11
523 const char EDID1_ATOM_NAME[] = "XFree86_DDC_EDID1_RAWDATA";
524 const char ICC_PROFILE_ATOM_NAME[] = "_ICC_PROFILE";
526 Atom edidAtom, iccAtom;
527 Display *dpy = GDK_DISPLAY();
528 Window root = gdk_x11_get_default_root_xwindow();
530 Atom retAtom;
531 int retFormat;
532 unsigned long retLength, retAfter;
533 unsigned char *retProperty ;
535 iccAtom = XInternAtom(dpy, ICC_PROFILE_ATOM_NAME, TRUE);
536 if (iccAtom) {
537 // read once to get size, once for the data
538 if (Success == XGetWindowProperty(dpy, root, iccAtom,
539 0, 0 /* length */,
540 False, AnyPropertyType,
541 &retAtom, &retFormat, &retLength,
542 &retAfter, &retProperty)) {
543 XGetWindowProperty(dpy, root, iccAtom,
544 0, retLength,
545 False, AnyPropertyType,
546 &retAtom, &retFormat, &retLength,
547 &retAfter, &retProperty);
549 cmsHPROFILE profile =
550 cmsOpenProfileFromMem(retProperty, retLength);
552 XFree(retProperty);
554 if (profile) {
555 #ifdef DEBUG_tor
556 fprintf(stderr,
557 "ICM profile read from %s successfully\n",
558 ICC_PROFILE_ATOM_NAME);
559 #endif
560 return profile;
565 edidAtom = XInternAtom(dpy, EDID1_ATOM_NAME, TRUE);
566 if (edidAtom) {
567 if (Success == XGetWindowProperty(dpy, root, edidAtom, 0, 32,
568 False, AnyPropertyType,
569 &retAtom, &retFormat, &retLength,
570 &retAfter, &retProperty)) {
571 double gamma;
572 cmsCIExyY whitePoint;
573 cmsCIExyYTRIPLE primaries;
575 if (retLength != 128) {
576 #ifdef DEBUG_tor
577 fprintf(stderr, "Short EDID data\n");
578 #endif
579 return nsnull;
582 // Format documented in "VESA E-EDID Implementation Guide"
584 gamma = (100 + retProperty[0x17]) / 100.0;
585 whitePoint.x = ((retProperty[0x21] << 2) |
586 (retProperty[0x1a] >> 2 & 3)) / 1024.0;
587 whitePoint.y = ((retProperty[0x22] << 2) |
588 (retProperty[0x1a] >> 0 & 3)) / 1024.0;
589 whitePoint.Y = 1.0;
591 primaries.Red.x = ((retProperty[0x1b] << 2) |
592 (retProperty[0x19] >> 6 & 3)) / 1024.0;
593 primaries.Red.y = ((retProperty[0x1c] << 2) |
594 (retProperty[0x19] >> 4 & 3)) / 1024.0;
595 primaries.Red.Y = 1.0;
597 primaries.Green.x = ((retProperty[0x1d] << 2) |
598 (retProperty[0x19] >> 2 & 3)) / 1024.0;
599 primaries.Green.y = ((retProperty[0x1e] << 2) |
600 (retProperty[0x19] >> 0 & 3)) / 1024.0;
601 primaries.Green.Y = 1.0;
603 primaries.Blue.x = ((retProperty[0x1f] << 2) |
604 (retProperty[0x1a] >> 6 & 3)) / 1024.0;
605 primaries.Blue.y = ((retProperty[0x20] << 2) |
606 (retProperty[0x1a] >> 4 & 3)) / 1024.0;
607 primaries.Blue.Y = 1.0;
609 XFree(retProperty);
611 #ifdef DEBUG_tor
612 fprintf(stderr, "EDID gamma: %f\n", gamma);
613 fprintf(stderr, "EDID whitepoint: %f %f %f\n",
614 whitePoint.x, whitePoint.y, whitePoint.Y);
615 fprintf(stderr, "EDID primaries: [%f %f %f] [%f %f %f] [%f %f %f]\n",
616 primaries.Red.x, primaries.Red.y, primaries.Red.Y,
617 primaries.Green.x, primaries.Green.y, primaries.Green.Y,
618 primaries.Blue.x, primaries.Blue.y, primaries.Blue.Y);
619 #endif
621 LPGAMMATABLE gammaTable[3];
622 gammaTable[0] = gammaTable[1] = gammaTable[2] =
623 cmsBuildGamma(256, gamma);
625 if (!gammaTable[0])
626 return nsnull;
628 cmsHPROFILE profile =
629 cmsCreateRGBProfile(&whitePoint, &primaries, gammaTable);
631 cmsFreeGamma(gammaTable[0]);
633 #ifdef DEBUG_tor
634 if (profile) {
635 fprintf(stderr,
636 "ICM profile read from %s successfully\n",
637 EDID1_ATOM_NAME);
639 #endif
641 return profile;
644 #endif
646 return nsnull;
650 #ifndef MOZ_PANGO
651 FT_Library
652 gfxPlatformGtk::GetFTLibrary()
654 return gPlatformFTLibrary;
657 FontFamily *
658 gfxPlatformGtk::FindFontFamily(const nsAString& aName)
660 nsAutoString name(aName);
661 /* FIXME: DFB */
662 //ToLowerCase(name);
664 nsRefPtr<FontFamily> ff;
665 if (!gPlatformFonts->Get(name, &ff)) {
666 return nsnull;
668 return ff.get();
671 FontEntry *
672 gfxPlatformGtk::FindFontEntry(const nsAString& aName, const gfxFontStyle& aFontStyle)
674 nsRefPtr<FontFamily> ff = FindFontFamily(aName);
675 if (!ff)
676 return nsnull;
678 return ff->FindFontEntry(aFontStyle);
680 #endif
683 void
684 gfxPlatformGtk::SetGdkDrawable(gfxASurface *target,
685 GdkDrawable *drawable)
687 if (target->CairoStatus())
688 return;
690 gdk_drawable_ref(drawable);
692 cairo_surface_set_user_data (target->CairoSurface(),
693 &cairo_gdk_drawable_key,
694 drawable,
695 do_gdk_drawable_unref);
698 #ifdef MOZ_X11
699 // Look for an existing Colormap that is known to be associated with visual.
700 static GdkColormap *
701 LookupGdkColormapForVisual(const Screen* screen, const Visual* visual)
703 Display* dpy = DisplayOfScreen(screen);
704 GdkDisplay* gdkDpy = gdk_x11_lookup_xdisplay(dpy);
705 if (!gdkDpy)
706 return NULL;
708 // I wish there were a gdk_x11_display_lookup_screen.
709 gint screen_num = 0;
710 for (int s = 0; s < ScreenCount(dpy); ++s) {
711 if (ScreenOfDisplay(dpy, s) == screen) {
712 screen_num = s;
713 break;
716 GdkScreen* gdkScreen = gdk_display_get_screen(gdkDpy, screen_num);
718 // Common case: the display's default colormap
719 if (visual ==
720 GDK_VISUAL_XVISUAL(gdk_screen_get_system_visual(gdkScreen)))
721 return gdk_screen_get_system_colormap(gdkScreen);
723 // widget/src/gtk2/mozcontainer.c uses gdk_rgb_get_colormap()
724 // which is inherited by child widgets, so this is the visual
725 // expected when drawing directly to widget surfaces or surfaces
726 // created using cairo_surface_create_similar with
727 // CAIRO_CONTENT_COLOR.
728 // gdk_screen_get_rgb_colormap is the generalization of
729 // gdk_rgb_get_colormap for any screen.
730 if (visual ==
731 GDK_VISUAL_XVISUAL(gdk_screen_get_rgb_visual(gdkScreen)))
732 return gdk_screen_get_rgb_colormap(gdkScreen);
734 // This is the visual expected on displays with the Composite
735 // extension enabled when the surface has been created using
736 // cairo_surface_create_similar with CAIRO_CONTENT_COLOR_ALPHA,
737 // as happens with non-unit opacity.
738 if (visual ==
739 GDK_VISUAL_XVISUAL(gdk_screen_get_rgba_visual(gdkScreen)))
740 return gdk_screen_get_rgba_colormap(gdkScreen);
742 return NULL;
744 #endif
746 GdkDrawable *
747 gfxPlatformGtk::GetGdkDrawable(gfxASurface *target)
749 if (target->CairoStatus())
750 return nsnull;
752 GdkDrawable *result;
754 result = (GdkDrawable*) cairo_surface_get_user_data (target->CairoSurface(),
755 &cairo_gdk_drawable_key);
756 if (result)
757 return result;
759 #ifdef MOZ_X11
760 if (target->GetType() == gfxASurface::SurfaceTypeXlib) {
761 gfxXlibSurface *xs = (gfxXlibSurface*) target;
763 // try looking it up in gdk's table
764 result = (GdkDrawable*) gdk_xid_table_lookup(xs->XDrawable());
765 if (result) {
766 SetGdkDrawable(target, result);
767 return result;
770 // If all else fails, try doing a foreign_new
771 // but don't bother if we can't get a colormap.
772 // Without a colormap GDK won't know how to draw.
773 Screen *screen = cairo_xlib_surface_get_screen(xs->CairoSurface());
774 Visual *visual = cairo_xlib_surface_get_visual(xs->CairoSurface());
775 GdkColormap *cmap = LookupGdkColormapForVisual(screen, visual);
776 if (cmap == None)
777 return nsnull;
779 result = (GdkDrawable*) gdk_pixmap_foreign_new_for_display
780 (gdk_display_get_default(), xs->XDrawable());
781 if (result) {
782 gdk_drawable_set_colormap(result, cmap);
784 SetGdkDrawable(target, result);
785 // Release our ref. The object is held by target. Caller will
786 // only need to ref if it wants to keep the drawable longer than
787 // target.
788 g_object_unref(result);
789 return result;
792 #endif
794 return nsnull;