gecko-dev/gfx/thebes/src/gfxPlatformGtk.cpp

400 lines
14 KiB
C++
Raw Normal View History

2005-11-29 20:29:45 +00:00
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Foundation code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
* Masayuki Nakano <masayuki@d-toybox.com>
2005-11-29 20:29:45 +00:00
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#define PANGO_ENABLE_BACKEND
#define PANGO_ENABLE_ENGINE
2005-11-29 20:29:45 +00:00
#include "gfxPlatformGtk.h"
#include "gfxFontconfigUtils.h"
#include "gfxPangoFonts.h"
2007-01-27 02:14:19 +00:00
#include "cairo.h"
2005-11-29 20:29:45 +00:00
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include "gfxImageSurface.h"
#include "gfxXlibSurface.h"
#include "gfxPangoFonts.h"
#include <pango/pangocairo.h>
2005-11-29 20:29:45 +00:00
#ifdef MOZ_ENABLE_GLITZ
#include "gfxGlitzSurface.h"
#include "glitz-glx.h"
#endif
#include <fontconfig/fontconfig.h>
#include "nsMathUtils.h"
#include "lcms.h"
PRInt32 gfxPlatformGtk::sDPI = -1;
gfxFontconfigUtils *gfxPlatformGtk::sFontconfigUtils = nsnull;
static cairo_user_data_key_t cairo_gdk_pixmap_key;
static void do_gdk_pixmap_unref (void *data)
{
GdkPixmap *pmap = (GdkPixmap*)data;
gdk_pixmap_unref (pmap);
}
2005-11-29 20:29:45 +00:00
gfxPlatformGtk::gfxPlatformGtk()
{
#ifdef MOZ_ENABLE_GLITZ
if (UseGlitz())
glitz_glx_init(NULL);
#endif
if (!sFontconfigUtils)
sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils();
InitDPI();
2005-11-29 20:29:45 +00:00
}
gfxPlatformGtk::~gfxPlatformGtk()
{
gfxFontconfigUtils::Shutdown();
sFontconfigUtils = nsnull;
gfxPangoFont::Shutdown();
#if 0
// It would be nice to do this (although it might need to be after
// the cairo shutdown that happens in ~gfxPlatform). It even looks
// idempotent. But it has fatal assertions that fire if stuff is
// leaked, and we hit them.
FcFini();
#endif
}
already_AddRefed<gfxASurface>
gfxPlatformGtk::CreateOffscreenSurface(const gfxIntSize& size,
2006-02-01 02:35:38 +00:00
gfxASurface::gfxImageFormat imageFormat)
2005-11-29 20:29:45 +00:00
{
nsRefPtr<gfxASurface> newSurface = nsnull;
2005-11-29 20:29:45 +00:00
int glitzf;
int xrenderFormatID;
2006-02-01 02:35:38 +00:00
switch (imageFormat) {
case gfxASurface::ImageFormatARGB32:
glitzf = 0; // GLITZ_STANDARD_ARGB32;
xrenderFormatID = PictStandardARGB32;
2006-02-01 02:35:38 +00:00
break;
case gfxASurface::ImageFormatRGB24:
glitzf = 1; // GLITZ_STANDARD_RGB24;
xrenderFormatID = PictStandardRGB24;
2006-02-01 02:35:38 +00:00
break;
case gfxASurface::ImageFormatA8:
glitzf = 2; // GLITZ_STANDARD_A8;
xrenderFormatID = PictStandardA8;
break;
2006-02-01 02:35:38 +00:00
case gfxASurface::ImageFormatA1:
glitzf = 3; // GLITZ_STANDARD_A1;
xrenderFormatID = PictStandardA1;
2006-02-01 02:35:38 +00:00
break;
default:
return nsnull;
}
// XXX we really need a different interface here, something that passes
// in more context, including the display and/or target surface type that
// we should try to match
Display* display = GDK_DISPLAY();
2006-02-01 02:35:38 +00:00
if (!UseGlitz()) {
GdkPixmap* pixmap = nsnull;
XRenderPictFormat* xrenderFormat =
XRenderFindStandardFormat(display, xrenderFormatID);
if (!xrenderFormat) {
// We don't have Render; see if we can just create a pixmap
// of the requested depth.
GdkVisual* vis;
if (imageFormat == gfxASurface::ImageFormatRGB24) {
vis = gdk_rgb_get_visual();
if (vis->type == GDK_VISUAL_TRUE_COLOR)
pixmap = gdk_pixmap_new(nsnull, size.width, size.height, vis->depth);
}
if (pixmap) {
gdk_drawable_set_colormap(GDK_DRAWABLE(pixmap), nsnull);
newSurface = new gfxXlibSurface(display,
GDK_PIXMAP_XID(GDK_DRAWABLE(pixmap)),
GDK_VISUAL_XVISUAL(vis),
size);
}
} else {
pixmap = gdk_pixmap_new(nsnull, size.width, size.height,
xrenderFormat->depth);
if (pixmap) {
gdk_drawable_set_colormap(GDK_DRAWABLE(pixmap), nsnull);
newSurface = new gfxXlibSurface(display,
GDK_PIXMAP_XID(GDK_DRAWABLE(pixmap)),
xrenderFormat,
size);
}
}
if (newSurface && newSurface->CairoStatus() == 0) {
// set up the surface to auto-unref the gdk pixmap when the surface
// is released
newSurface->SetData(&cairo_gdk_pixmap_key,
pixmap,
do_gdk_pixmap_unref);
} else {
// something went wrong with the surface creation. Ignore and let's fall back
// to image surfaces.
if (pixmap)
gdk_pixmap_unref(pixmap);
newSurface = nsnull;
}
if (!newSurface) {
// we couldn't create an xlib surface for whatever reason; fall back to
// image surface for the data.
newSurface = new gfxImageSurface(gfxIntSize(size.width, size.height), imageFormat);
}
2005-11-29 20:29:45 +00:00
} else {
#ifdef MOZ_ENABLE_GLITZ
2006-02-01 02:35:38 +00:00
glitz_drawable_format_t *gdformat = glitz_glx_find_pbuffer_format
(display,
2006-02-01 02:35:38 +00:00
gdk_x11_get_default_screen(),
0, NULL, 0);
glitz_drawable_t *gdraw =
glitz_glx_create_pbuffer_drawable(display,
DefaultScreen(display),
2006-02-01 02:35:38 +00:00
gdformat,
size.width,
size.height);
2006-02-01 02:35:38 +00:00
glitz_format_t *gformat =
glitz_find_standard_format(gdraw, (glitz_format_name_t)glitzf);
glitz_surface_t *gsurf =
glitz_surface_create(gdraw,
gformat,
size.width,
size.height,
2006-02-01 02:35:38 +00:00
0,
NULL);
glitz_surface_attach(gsurf, gdraw, GLITZ_DRAWABLE_BUFFER_FRONT_COLOR);
newSurface = new gfxGlitzSurface(gdraw, gsurf, PR_TRUE);
2005-11-29 20:29:45 +00:00
#endif
}
return newSurface.forget();
2005-11-29 20:29:45 +00:00
}
nsresult
gfxPlatformGtk::GetFontList(const nsACString& aLangGroup,
const nsACString& aGenericFamily,
nsStringArray& aListOfFonts)
{
return sFontconfigUtils->GetFontList(aLangGroup, aGenericFamily,
aListOfFonts);
}
nsresult
gfxPlatformGtk::UpdateFontList()
{
return sFontconfigUtils->UpdateFontList();
}
nsresult
gfxPlatformGtk::ResolveFontName(const nsAString& aFontName,
FontResolverCallback aCallback,
void *aClosure,
PRBool& aAborted)
{
return sFontconfigUtils->ResolveFontName(aFontName, aCallback,
aClosure, aAborted);
}
gfxFontGroup *
gfxPlatformGtk::CreateFontGroup(const nsAString &aFamilies,
const gfxFontStyle *aStyle)
{
return new gfxPangoFontGroup(aFamilies, aStyle);
}
/* static */
void
gfxPlatformGtk::InitDPI()
{
PangoContext *context = gdk_pango_context_get ();
sDPI = pango_cairo_context_get_resolution (context);
g_object_unref (context);
if (sDPI <= 0) {
// Fall back to something sane
sDPI = 96;
}
}
cmsHPROFILE
gfxPlatformGtk::GetPlatformCMSOutputProfile()
{
const char EDID1_ATOM_NAME[] = "XFree86_DDC_EDID1_RAWDATA";
const char ICC_PROFILE_ATOM_NAME[] = "_ICC_PROFILE";
Atom edidAtom, iccAtom;
Display *dpy = GDK_DISPLAY();
Window root = gdk_x11_get_default_root_xwindow();
Atom retAtom;
int retFormat;
unsigned long retLength, retAfter;
unsigned char *retProperty ;
iccAtom = XInternAtom(dpy, ICC_PROFILE_ATOM_NAME, TRUE);
if (iccAtom) {
// read once to get size, once for the data
if (Success == XGetWindowProperty(dpy, root, iccAtom,
0, 0 /* length */,
False, AnyPropertyType,
&retAtom, &retFormat, &retLength,
&retAfter, &retProperty)) {
XGetWindowProperty(dpy, root, iccAtom,
0, retLength,
False, AnyPropertyType,
&retAtom, &retFormat, &retLength,
&retAfter, &retProperty);
cmsHPROFILE profile =
cmsOpenProfileFromMem(retProperty, retLength);
XFree(retProperty);
if (profile) {
#ifdef DEBUG_tor
fprintf(stderr,
"ICM profile read from %s successfully\n",
ICC_PROFILE_ATOM_NAME);
#endif
return profile;
}
}
}
edidAtom = XInternAtom(dpy, EDID1_ATOM_NAME, TRUE);
if (edidAtom) {
if (Success == XGetWindowProperty(dpy, root, edidAtom, 0, 32,
False, AnyPropertyType,
&retAtom, &retFormat, &retLength,
&retAfter, &retProperty)) {
double gamma;
cmsCIExyY whitePoint;
cmsCIExyYTRIPLE primaries;
if (retLength != 128) {
#ifdef DEBUG_tor
fprintf(stderr, "Short EDID data\n");
#endif
return nsnull;
}
// Format documented in "VESA E-EDID Implementation Guide"
gamma = (100 + retProperty[0x17]) / 100.0;
whitePoint.x = ((retProperty[0x21] << 2) |
(retProperty[0x1a] >> 2 & 3)) / 1024.0;
whitePoint.y = ((retProperty[0x22] << 2) |
(retProperty[0x1a] >> 0 & 3)) / 1024.0;
whitePoint.Y = 1.0;
primaries.Red.x = ((retProperty[0x1b] << 2) |
(retProperty[0x19] >> 6 & 3)) / 1024.0;
primaries.Red.y = ((retProperty[0x1c] << 2) |
(retProperty[0x19] >> 4 & 3)) / 1024.0;
primaries.Red.Y = 1.0;
primaries.Green.x = ((retProperty[0x1d] << 2) |
(retProperty[0x19] >> 2 & 3)) / 1024.0;
primaries.Green.y = ((retProperty[0x1e] << 2) |
(retProperty[0x19] >> 0 & 3)) / 1024.0;
primaries.Green.Y = 1.0;
primaries.Blue.x = ((retProperty[0x1f] << 2) |
(retProperty[0x1a] >> 6 & 3)) / 1024.0;
primaries.Blue.y = ((retProperty[0x20] << 2) |
(retProperty[0x1a] >> 4 & 3)) / 1024.0;
primaries.Blue.Y = 1.0;
XFree(retProperty);
#ifdef DEBUG_tor
fprintf(stderr, "EDID gamma: %f\n", gamma);
fprintf(stderr, "EDID whitepoint: %f %f %f\n",
whitePoint.x, whitePoint.y, whitePoint.Y);
fprintf(stderr, "EDID primaries: [%f %f %f] [%f %f %f] [%f %f %f]\n",
primaries.Red.x, primaries.Red.y, primaries.Red.Y,
primaries.Green.x, primaries.Green.y, primaries.Green.Y,
primaries.Blue.x, primaries.Blue.y, primaries.Blue.Y);
#endif
LPGAMMATABLE gammaTable[3];
gammaTable[0] = gammaTable[1] = gammaTable[2] =
cmsBuildGamma(256, gamma);
if (!gammaTable[0])
return nsnull;
cmsHPROFILE profile =
cmsCreateRGBProfile(&whitePoint, &primaries, gammaTable);
cmsFreeGamma(gammaTable[0]);
#ifdef DEBUG_tor
if (profile) {
fprintf(stderr,
"ICM profile read from %s successfully\n",
EDID1_ATOM_NAME);
}
#endif
return profile;
}
}
return nsnull;
}