gfx/thebes/gfxPlatformGtk.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/thebes/gfxPlatformGtk.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,452 @@
     1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     1.5 + * This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#define PANGO_ENABLE_BACKEND
    1.10 +#define PANGO_ENABLE_ENGINE
    1.11 +
    1.12 +#include "gfxPlatformGtk.h"
    1.13 +#include "prenv.h"
    1.14 +
    1.15 +#include "nsUnicharUtils.h"
    1.16 +#include "nsUnicodeProperties.h"
    1.17 +#include "gfx2DGlue.h"
    1.18 +#include "gfxFontconfigUtils.h"
    1.19 +#include "gfxPangoFonts.h"
    1.20 +#include "gfxContext.h"
    1.21 +#include "gfxUserFontSet.h"
    1.22 +#include "gfxFT2FontBase.h"
    1.23 +
    1.24 +#include "mozilla/gfx/2D.h"
    1.25 +
    1.26 +#include "cairo.h"
    1.27 +#include <gtk/gtk.h>
    1.28 +
    1.29 +#include "gfxImageSurface.h"
    1.30 +#ifdef MOZ_X11
    1.31 +#include <gdk/gdkx.h>
    1.32 +#include "gfxXlibSurface.h"
    1.33 +#include "cairo-xlib.h"
    1.34 +#include "mozilla/Preferences.h"
    1.35 +
    1.36 +/* Undefine the Status from Xlib since it will conflict with system headers on OSX */
    1.37 +#if defined(__APPLE__) && defined(Status)
    1.38 +#undef Status
    1.39 +#endif
    1.40 +
    1.41 +#endif /* MOZ_X11 */
    1.42 +
    1.43 +#include <fontconfig/fontconfig.h>
    1.44 +
    1.45 +#include "nsMathUtils.h"
    1.46 +
    1.47 +#define GDK_PIXMAP_SIZE_MAX 32767
    1.48 +
    1.49 +using namespace mozilla;
    1.50 +using namespace mozilla::gfx;
    1.51 +using namespace mozilla::unicode;
    1.52 +
    1.53 +gfxFontconfigUtils *gfxPlatformGtk::sFontconfigUtils = nullptr;
    1.54 +
    1.55 +#if (MOZ_WIDGET_GTK == 2)
    1.56 +static cairo_user_data_key_t cairo_gdk_drawable_key;
    1.57 +#endif
    1.58 +
    1.59 +#ifdef MOZ_X11
    1.60 +    bool gfxPlatformGtk::sUseXRender = true;
    1.61 +#endif
    1.62 +
    1.63 +gfxPlatformGtk::gfxPlatformGtk()
    1.64 +{
    1.65 +    if (!sFontconfigUtils)
    1.66 +        sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils();
    1.67 +#ifdef MOZ_X11
    1.68 +    sUseXRender = mozilla::Preferences::GetBool("gfx.xrender.enabled");
    1.69 +#endif
    1.70 +
    1.71 +    uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
    1.72 +    uint32_t contentMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
    1.73 +    InitBackendPrefs(canvasMask, BackendType::CAIRO,
    1.74 +                     contentMask, BackendType::CAIRO);
    1.75 +}
    1.76 +
    1.77 +gfxPlatformGtk::~gfxPlatformGtk()
    1.78 +{
    1.79 +    gfxFontconfigUtils::Shutdown();
    1.80 +    sFontconfigUtils = nullptr;
    1.81 +
    1.82 +    gfxPangoFontGroup::Shutdown();
    1.83 +}
    1.84 +
    1.85 +already_AddRefed<gfxASurface>
    1.86 +gfxPlatformGtk::CreateOffscreenSurface(const IntSize& size,
    1.87 +                                       gfxContentType contentType)
    1.88 +{
    1.89 +    nsRefPtr<gfxASurface> newSurface;
    1.90 +    bool needsClear = true;
    1.91 +    gfxImageFormat imageFormat = OptimalFormatForContent(contentType);
    1.92 +#ifdef MOZ_X11
    1.93 +    // XXX we really need a different interface here, something that passes
    1.94 +    // in more context, including the display and/or target surface type that
    1.95 +    // we should try to match
    1.96 +    GdkScreen *gdkScreen = gdk_screen_get_default();
    1.97 +    if (gdkScreen) {
    1.98 +        if (UseXRender()) {
    1.99 +            Screen *screen = gdk_x11_screen_get_xscreen(gdkScreen);
   1.100 +            XRenderPictFormat* xrenderFormat =
   1.101 +                gfxXlibSurface::FindRenderFormat(DisplayOfScreen(screen),
   1.102 +                                                 imageFormat);
   1.103 +
   1.104 +            if (xrenderFormat) {
   1.105 +                newSurface = gfxXlibSurface::Create(screen, xrenderFormat,
   1.106 +                                                    ThebesIntSize(size));
   1.107 +            }
   1.108 +        } else {
   1.109 +            // We're not going to use XRender, so we don't need to
   1.110 +            // search for a render format
   1.111 +            newSurface = new gfxImageSurface(ThebesIntSize(size), imageFormat);
   1.112 +            // The gfxImageSurface ctor zeroes this for us, no need to
   1.113 +            // waste time clearing again
   1.114 +            needsClear = false;
   1.115 +        }
   1.116 +    }
   1.117 +#endif
   1.118 +
   1.119 +    if (!newSurface) {
   1.120 +        // We couldn't create a native surface for whatever reason;
   1.121 +        // e.g., no display, no RENDER, bad size, etc.
   1.122 +        // Fall back to image surface for the data.
   1.123 +        newSurface = new gfxImageSurface(ThebesIntSize(size), imageFormat);
   1.124 +    }
   1.125 +
   1.126 +    if (newSurface->CairoStatus()) {
   1.127 +        newSurface = nullptr; // surface isn't valid for some reason
   1.128 +    }
   1.129 +
   1.130 +    if (newSurface && needsClear) {
   1.131 +        gfxContext tmpCtx(newSurface);
   1.132 +        tmpCtx.SetOperator(gfxContext::OPERATOR_CLEAR);
   1.133 +        tmpCtx.Paint();
   1.134 +    }
   1.135 +
   1.136 +    return newSurface.forget();
   1.137 +}
   1.138 +
   1.139 +nsresult
   1.140 +gfxPlatformGtk::GetFontList(nsIAtom *aLangGroup,
   1.141 +                            const nsACString& aGenericFamily,
   1.142 +                            nsTArray<nsString>& aListOfFonts)
   1.143 +{
   1.144 +    return sFontconfigUtils->GetFontList(aLangGroup, aGenericFamily,
   1.145 +                                         aListOfFonts);
   1.146 +}
   1.147 +
   1.148 +nsresult
   1.149 +gfxPlatformGtk::UpdateFontList()
   1.150 +{
   1.151 +    return sFontconfigUtils->UpdateFontList();
   1.152 +}
   1.153 +
   1.154 +nsresult
   1.155 +gfxPlatformGtk::ResolveFontName(const nsAString& aFontName,
   1.156 +                                FontResolverCallback aCallback,
   1.157 +                                void *aClosure,
   1.158 +                                bool& aAborted)
   1.159 +{
   1.160 +    return sFontconfigUtils->ResolveFontName(aFontName, aCallback,
   1.161 +                                             aClosure, aAborted);
   1.162 +}
   1.163 +
   1.164 +nsresult
   1.165 +gfxPlatformGtk::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
   1.166 +{
   1.167 +    return sFontconfigUtils->GetStandardFamilyName(aFontName, aFamilyName);
   1.168 +}
   1.169 +
   1.170 +gfxFontGroup *
   1.171 +gfxPlatformGtk::CreateFontGroup(const nsAString &aFamilies,
   1.172 +                                const gfxFontStyle *aStyle,
   1.173 +                                gfxUserFontSet *aUserFontSet)
   1.174 +{
   1.175 +    return new gfxPangoFontGroup(aFamilies, aStyle, aUserFontSet);
   1.176 +}
   1.177 +
   1.178 +gfxFontEntry*
   1.179 +gfxPlatformGtk::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
   1.180 +                                const nsAString& aFontName)
   1.181 +{
   1.182 +    return gfxPangoFontGroup::NewFontEntry(*aProxyEntry, aFontName);
   1.183 +}
   1.184 +
   1.185 +gfxFontEntry* 
   1.186 +gfxPlatformGtk::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, 
   1.187 +                                 const uint8_t *aFontData, uint32_t aLength)
   1.188 +{
   1.189 +    // passing ownership of the font data to the new font entry
   1.190 +    return gfxPangoFontGroup::NewFontEntry(*aProxyEntry,
   1.191 +                                           aFontData, aLength);
   1.192 +}
   1.193 +
   1.194 +bool
   1.195 +gfxPlatformGtk::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags)
   1.196 +{
   1.197 +    // check for strange format flags
   1.198 +    NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
   1.199 +                 "strange font format hint set");
   1.200 +
   1.201 +    // accept supported formats
   1.202 +    // Pango doesn't apply features from AAT TrueType extensions.
   1.203 +    // Assume that if this is the only SFNT format specified,
   1.204 +    // then AAT extensions are required for complex script support.
   1.205 +    if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_WOFF     |
   1.206 +                        gfxUserFontSet::FLAG_FORMAT_OPENTYPE | 
   1.207 +                        gfxUserFontSet::FLAG_FORMAT_TRUETYPE)) {
   1.208 +        return true;
   1.209 +    }
   1.210 +
   1.211 +    // reject all other formats, known and unknown
   1.212 +    if (aFormatFlags != 0) {
   1.213 +        return false;
   1.214 +    }
   1.215 +
   1.216 +    // no format hint set, need to look at data
   1.217 +    return true;
   1.218 +}
   1.219 +
   1.220 +static int32_t sDPI = 0;
   1.221 +
   1.222 +int32_t
   1.223 +gfxPlatformGtk::GetDPI()
   1.224 +{
   1.225 +    if (!sDPI) {
   1.226 +        // Make sure init is run so we have a resolution
   1.227 +        GdkScreen *screen = gdk_screen_get_default();
   1.228 +        gtk_settings_get_for_screen(screen);
   1.229 +        sDPI = int32_t(round(gdk_screen_get_resolution(screen)));
   1.230 +        if (sDPI <= 0) {
   1.231 +            // Fall back to something sane
   1.232 +            sDPI = 96;
   1.233 +        }
   1.234 +    }
   1.235 +    return sDPI;
   1.236 +}
   1.237 +
   1.238 +gfxImageFormat
   1.239 +gfxPlatformGtk::GetOffscreenFormat()
   1.240 +{
   1.241 +    // Make sure there is a screen
   1.242 +    GdkScreen *screen = gdk_screen_get_default();
   1.243 +    if (screen && gdk_visual_get_depth(gdk_visual_get_system()) == 16) {
   1.244 +        return gfxImageFormat::RGB16_565;
   1.245 +    }
   1.246 +
   1.247 +    return gfxImageFormat::RGB24;
   1.248 +}
   1.249 +
   1.250 +static int sDepth = 0;
   1.251 +
   1.252 +int
   1.253 +gfxPlatformGtk::GetScreenDepth() const
   1.254 +{
   1.255 +    if (!sDepth) {
   1.256 +        GdkScreen *screen = gdk_screen_get_default();
   1.257 +        if (screen) {
   1.258 +            sDepth = gdk_visual_get_depth(gdk_visual_get_system());
   1.259 +        } else {
   1.260 +            sDepth = 24;
   1.261 +        }
   1.262 +
   1.263 +    }
   1.264 +
   1.265 +    return sDepth;
   1.266 +}
   1.267 +
   1.268 +bool
   1.269 +gfxPlatformGtk::SupportsOffMainThreadCompositing()
   1.270 +{
   1.271 +  // Nightly builds have OMTC support by default for Electrolysis testing.
   1.272 +#if defined(MOZ_X11) && !defined(NIGHTLY_BUILD)
   1.273 +  return (PR_GetEnv("MOZ_USE_OMTC") != nullptr) ||
   1.274 +         (PR_GetEnv("MOZ_OMTC_ENABLED") != nullptr);
   1.275 +#else
   1.276 +  return true;
   1.277 +#endif
   1.278 +}
   1.279 +
   1.280 +void
   1.281 +gfxPlatformGtk::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
   1.282 +{
   1.283 +    mem = nullptr;
   1.284 +    size = 0;
   1.285 +
   1.286 +#ifdef MOZ_X11
   1.287 +    const char EDID1_ATOM_NAME[] = "XFree86_DDC_EDID1_RAWDATA";
   1.288 +    const char ICC_PROFILE_ATOM_NAME[] = "_ICC_PROFILE";
   1.289 +
   1.290 +    Atom edidAtom, iccAtom;
   1.291 +    Display *dpy = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
   1.292 +    // In xpcshell tests, we never initialize X and hence don't have a Display.
   1.293 +    // In this case, there's no output colour management to be done, so we just
   1.294 +    // return with nullptr.
   1.295 +    if (!dpy)
   1.296 +        return;
   1.297 + 
   1.298 +    Window root = gdk_x11_get_default_root_xwindow();
   1.299 +
   1.300 +    Atom retAtom;
   1.301 +    int retFormat;
   1.302 +    unsigned long retLength, retAfter;
   1.303 +    unsigned char *retProperty ;
   1.304 +
   1.305 +    iccAtom = XInternAtom(dpy, ICC_PROFILE_ATOM_NAME, TRUE);
   1.306 +    if (iccAtom) {
   1.307 +        // read once to get size, once for the data
   1.308 +        if (Success == XGetWindowProperty(dpy, root, iccAtom,
   1.309 +                                          0, INT_MAX /* length */,
   1.310 +                                          False, AnyPropertyType,
   1.311 +                                          &retAtom, &retFormat, &retLength,
   1.312 +                                          &retAfter, &retProperty)) {
   1.313 +
   1.314 +            if (retLength > 0) {
   1.315 +                void *buffer = malloc(retLength);
   1.316 +                if (buffer) {
   1.317 +                    memcpy(buffer, retProperty, retLength);
   1.318 +                    mem = buffer;
   1.319 +                    size = retLength;
   1.320 +                }
   1.321 +            }
   1.322 +
   1.323 +            XFree(retProperty);
   1.324 +            if (size > 0) {
   1.325 +#ifdef DEBUG_tor
   1.326 +                fprintf(stderr,
   1.327 +                        "ICM profile read from %s successfully\n",
   1.328 +                        ICC_PROFILE_ATOM_NAME);
   1.329 +#endif
   1.330 +                return;
   1.331 +            }
   1.332 +        }
   1.333 +    }
   1.334 +
   1.335 +    edidAtom = XInternAtom(dpy, EDID1_ATOM_NAME, TRUE);
   1.336 +    if (edidAtom) {
   1.337 +        if (Success == XGetWindowProperty(dpy, root, edidAtom, 0, 32,
   1.338 +                                          False, AnyPropertyType,
   1.339 +                                          &retAtom, &retFormat, &retLength,
   1.340 +                                          &retAfter, &retProperty)) {
   1.341 +            double gamma;
   1.342 +            qcms_CIE_xyY whitePoint;
   1.343 +            qcms_CIE_xyYTRIPLE primaries;
   1.344 +
   1.345 +            if (retLength != 128) {
   1.346 +#ifdef DEBUG_tor
   1.347 +                fprintf(stderr, "Short EDID data\n");
   1.348 +#endif
   1.349 +                return;
   1.350 +            }
   1.351 +
   1.352 +            // Format documented in "VESA E-EDID Implementation Guide"
   1.353 +
   1.354 +            gamma = (100 + retProperty[0x17]) / 100.0;
   1.355 +            whitePoint.x = ((retProperty[0x21] << 2) |
   1.356 +                            (retProperty[0x1a] >> 2 & 3)) / 1024.0;
   1.357 +            whitePoint.y = ((retProperty[0x22] << 2) |
   1.358 +                            (retProperty[0x1a] >> 0 & 3)) / 1024.0;
   1.359 +            whitePoint.Y = 1.0;
   1.360 +
   1.361 +            primaries.red.x = ((retProperty[0x1b] << 2) |
   1.362 +                               (retProperty[0x19] >> 6 & 3)) / 1024.0;
   1.363 +            primaries.red.y = ((retProperty[0x1c] << 2) |
   1.364 +                               (retProperty[0x19] >> 4 & 3)) / 1024.0;
   1.365 +            primaries.red.Y = 1.0;
   1.366 +
   1.367 +            primaries.green.x = ((retProperty[0x1d] << 2) |
   1.368 +                                 (retProperty[0x19] >> 2 & 3)) / 1024.0;
   1.369 +            primaries.green.y = ((retProperty[0x1e] << 2) |
   1.370 +                                 (retProperty[0x19] >> 0 & 3)) / 1024.0;
   1.371 +            primaries.green.Y = 1.0;
   1.372 +
   1.373 +            primaries.blue.x = ((retProperty[0x1f] << 2) |
   1.374 +                               (retProperty[0x1a] >> 6 & 3)) / 1024.0;
   1.375 +            primaries.blue.y = ((retProperty[0x20] << 2) |
   1.376 +                               (retProperty[0x1a] >> 4 & 3)) / 1024.0;
   1.377 +            primaries.blue.Y = 1.0;
   1.378 +
   1.379 +            XFree(retProperty);
   1.380 +
   1.381 +#ifdef DEBUG_tor
   1.382 +            fprintf(stderr, "EDID gamma: %f\n", gamma);
   1.383 +            fprintf(stderr, "EDID whitepoint: %f %f %f\n",
   1.384 +                    whitePoint.x, whitePoint.y, whitePoint.Y);
   1.385 +            fprintf(stderr, "EDID primaries: [%f %f %f] [%f %f %f] [%f %f %f]\n",
   1.386 +                    primaries.Red.x, primaries.Red.y, primaries.Red.Y,
   1.387 +                    primaries.Green.x, primaries.Green.y, primaries.Green.Y,
   1.388 +                    primaries.Blue.x, primaries.Blue.y, primaries.Blue.Y);
   1.389 +#endif
   1.390 +
   1.391 +            qcms_data_create_rgb_with_gamma(whitePoint, primaries, gamma, &mem, &size);
   1.392 +
   1.393 +#ifdef DEBUG_tor
   1.394 +            if (size > 0) {
   1.395 +                fprintf(stderr,
   1.396 +                        "ICM profile read from %s successfully\n",
   1.397 +                        EDID1_ATOM_NAME);
   1.398 +            }
   1.399 +#endif
   1.400 +        }
   1.401 +    }
   1.402 +#endif
   1.403 +}
   1.404 +
   1.405 +
   1.406 +#if (MOZ_WIDGET_GTK == 2)
   1.407 +void
   1.408 +gfxPlatformGtk::SetGdkDrawable(cairo_surface_t *target,
   1.409 +                               GdkDrawable *drawable)
   1.410 +{
   1.411 +    if (cairo_surface_status(target))
   1.412 +        return;
   1.413 +
   1.414 +    g_object_ref(drawable);
   1.415 +
   1.416 +    cairo_surface_set_user_data (target,
   1.417 +                                 &cairo_gdk_drawable_key,
   1.418 +                                 drawable,
   1.419 +                                 g_object_unref);
   1.420 +}
   1.421 +
   1.422 +GdkDrawable *
   1.423 +gfxPlatformGtk::GetGdkDrawable(cairo_surface_t *target)
   1.424 +{
   1.425 +    if (cairo_surface_status(target))
   1.426 +        return nullptr;
   1.427 +
   1.428 +    GdkDrawable *result;
   1.429 +
   1.430 +    result = (GdkDrawable*) cairo_surface_get_user_data (target,
   1.431 +                                                         &cairo_gdk_drawable_key);
   1.432 +    if (result)
   1.433 +        return result;
   1.434 +
   1.435 +#ifdef MOZ_X11
   1.436 +    if (cairo_surface_get_type(target) != CAIRO_SURFACE_TYPE_XLIB)
   1.437 +        return nullptr;
   1.438 +
   1.439 +    // try looking it up in gdk's table
   1.440 +    result = (GdkDrawable*) gdk_xid_table_lookup(cairo_xlib_surface_get_drawable(target));
   1.441 +    if (result) {
   1.442 +        SetGdkDrawable(target, result);
   1.443 +        return result;
   1.444 +    }
   1.445 +#endif
   1.446 +
   1.447 +    return nullptr;
   1.448 +}
   1.449 +#endif
   1.450 +
   1.451 +TemporaryRef<ScaledFont>
   1.452 +gfxPlatformGtk::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
   1.453 +{
   1.454 +    return GetScaledFontForFontWithCairoSkia(aTarget, aFont);
   1.455 +}

mercurial