gfx/thebes/gfxPlatformGtk.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #define PANGO_ENABLE_BACKEND
     7 #define PANGO_ENABLE_ENGINE
     9 #include "gfxPlatformGtk.h"
    10 #include "prenv.h"
    12 #include "nsUnicharUtils.h"
    13 #include "nsUnicodeProperties.h"
    14 #include "gfx2DGlue.h"
    15 #include "gfxFontconfigUtils.h"
    16 #include "gfxPangoFonts.h"
    17 #include "gfxContext.h"
    18 #include "gfxUserFontSet.h"
    19 #include "gfxFT2FontBase.h"
    21 #include "mozilla/gfx/2D.h"
    23 #include "cairo.h"
    24 #include <gtk/gtk.h>
    26 #include "gfxImageSurface.h"
    27 #ifdef MOZ_X11
    28 #include <gdk/gdkx.h>
    29 #include "gfxXlibSurface.h"
    30 #include "cairo-xlib.h"
    31 #include "mozilla/Preferences.h"
    33 /* Undefine the Status from Xlib since it will conflict with system headers on OSX */
    34 #if defined(__APPLE__) && defined(Status)
    35 #undef Status
    36 #endif
    38 #endif /* MOZ_X11 */
    40 #include <fontconfig/fontconfig.h>
    42 #include "nsMathUtils.h"
    44 #define GDK_PIXMAP_SIZE_MAX 32767
    46 using namespace mozilla;
    47 using namespace mozilla::gfx;
    48 using namespace mozilla::unicode;
    50 gfxFontconfigUtils *gfxPlatformGtk::sFontconfigUtils = nullptr;
    52 #if (MOZ_WIDGET_GTK == 2)
    53 static cairo_user_data_key_t cairo_gdk_drawable_key;
    54 #endif
    56 #ifdef MOZ_X11
    57     bool gfxPlatformGtk::sUseXRender = true;
    58 #endif
    60 gfxPlatformGtk::gfxPlatformGtk()
    61 {
    62     if (!sFontconfigUtils)
    63         sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils();
    64 #ifdef MOZ_X11
    65     sUseXRender = mozilla::Preferences::GetBool("gfx.xrender.enabled");
    66 #endif
    68     uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
    69     uint32_t contentMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
    70     InitBackendPrefs(canvasMask, BackendType::CAIRO,
    71                      contentMask, BackendType::CAIRO);
    72 }
    74 gfxPlatformGtk::~gfxPlatformGtk()
    75 {
    76     gfxFontconfigUtils::Shutdown();
    77     sFontconfigUtils = nullptr;
    79     gfxPangoFontGroup::Shutdown();
    80 }
    82 already_AddRefed<gfxASurface>
    83 gfxPlatformGtk::CreateOffscreenSurface(const IntSize& size,
    84                                        gfxContentType contentType)
    85 {
    86     nsRefPtr<gfxASurface> newSurface;
    87     bool needsClear = true;
    88     gfxImageFormat imageFormat = OptimalFormatForContent(contentType);
    89 #ifdef MOZ_X11
    90     // XXX we really need a different interface here, something that passes
    91     // in more context, including the display and/or target surface type that
    92     // we should try to match
    93     GdkScreen *gdkScreen = gdk_screen_get_default();
    94     if (gdkScreen) {
    95         if (UseXRender()) {
    96             Screen *screen = gdk_x11_screen_get_xscreen(gdkScreen);
    97             XRenderPictFormat* xrenderFormat =
    98                 gfxXlibSurface::FindRenderFormat(DisplayOfScreen(screen),
    99                                                  imageFormat);
   101             if (xrenderFormat) {
   102                 newSurface = gfxXlibSurface::Create(screen, xrenderFormat,
   103                                                     ThebesIntSize(size));
   104             }
   105         } else {
   106             // We're not going to use XRender, so we don't need to
   107             // search for a render format
   108             newSurface = new gfxImageSurface(ThebesIntSize(size), imageFormat);
   109             // The gfxImageSurface ctor zeroes this for us, no need to
   110             // waste time clearing again
   111             needsClear = false;
   112         }
   113     }
   114 #endif
   116     if (!newSurface) {
   117         // We couldn't create a native surface for whatever reason;
   118         // e.g., no display, no RENDER, bad size, etc.
   119         // Fall back to image surface for the data.
   120         newSurface = new gfxImageSurface(ThebesIntSize(size), imageFormat);
   121     }
   123     if (newSurface->CairoStatus()) {
   124         newSurface = nullptr; // surface isn't valid for some reason
   125     }
   127     if (newSurface && needsClear) {
   128         gfxContext tmpCtx(newSurface);
   129         tmpCtx.SetOperator(gfxContext::OPERATOR_CLEAR);
   130         tmpCtx.Paint();
   131     }
   133     return newSurface.forget();
   134 }
   136 nsresult
   137 gfxPlatformGtk::GetFontList(nsIAtom *aLangGroup,
   138                             const nsACString& aGenericFamily,
   139                             nsTArray<nsString>& aListOfFonts)
   140 {
   141     return sFontconfigUtils->GetFontList(aLangGroup, aGenericFamily,
   142                                          aListOfFonts);
   143 }
   145 nsresult
   146 gfxPlatformGtk::UpdateFontList()
   147 {
   148     return sFontconfigUtils->UpdateFontList();
   149 }
   151 nsresult
   152 gfxPlatformGtk::ResolveFontName(const nsAString& aFontName,
   153                                 FontResolverCallback aCallback,
   154                                 void *aClosure,
   155                                 bool& aAborted)
   156 {
   157     return sFontconfigUtils->ResolveFontName(aFontName, aCallback,
   158                                              aClosure, aAborted);
   159 }
   161 nsresult
   162 gfxPlatformGtk::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
   163 {
   164     return sFontconfigUtils->GetStandardFamilyName(aFontName, aFamilyName);
   165 }
   167 gfxFontGroup *
   168 gfxPlatformGtk::CreateFontGroup(const nsAString &aFamilies,
   169                                 const gfxFontStyle *aStyle,
   170                                 gfxUserFontSet *aUserFontSet)
   171 {
   172     return new gfxPangoFontGroup(aFamilies, aStyle, aUserFontSet);
   173 }
   175 gfxFontEntry*
   176 gfxPlatformGtk::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
   177                                 const nsAString& aFontName)
   178 {
   179     return gfxPangoFontGroup::NewFontEntry(*aProxyEntry, aFontName);
   180 }
   182 gfxFontEntry* 
   183 gfxPlatformGtk::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry, 
   184                                  const uint8_t *aFontData, uint32_t aLength)
   185 {
   186     // passing ownership of the font data to the new font entry
   187     return gfxPangoFontGroup::NewFontEntry(*aProxyEntry,
   188                                            aFontData, aLength);
   189 }
   191 bool
   192 gfxPlatformGtk::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags)
   193 {
   194     // check for strange format flags
   195     NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
   196                  "strange font format hint set");
   198     // accept supported formats
   199     // Pango doesn't apply features from AAT TrueType extensions.
   200     // Assume that if this is the only SFNT format specified,
   201     // then AAT extensions are required for complex script support.
   202     if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_WOFF     |
   203                         gfxUserFontSet::FLAG_FORMAT_OPENTYPE | 
   204                         gfxUserFontSet::FLAG_FORMAT_TRUETYPE)) {
   205         return true;
   206     }
   208     // reject all other formats, known and unknown
   209     if (aFormatFlags != 0) {
   210         return false;
   211     }
   213     // no format hint set, need to look at data
   214     return true;
   215 }
   217 static int32_t sDPI = 0;
   219 int32_t
   220 gfxPlatformGtk::GetDPI()
   221 {
   222     if (!sDPI) {
   223         // Make sure init is run so we have a resolution
   224         GdkScreen *screen = gdk_screen_get_default();
   225         gtk_settings_get_for_screen(screen);
   226         sDPI = int32_t(round(gdk_screen_get_resolution(screen)));
   227         if (sDPI <= 0) {
   228             // Fall back to something sane
   229             sDPI = 96;
   230         }
   231     }
   232     return sDPI;
   233 }
   235 gfxImageFormat
   236 gfxPlatformGtk::GetOffscreenFormat()
   237 {
   238     // Make sure there is a screen
   239     GdkScreen *screen = gdk_screen_get_default();
   240     if (screen && gdk_visual_get_depth(gdk_visual_get_system()) == 16) {
   241         return gfxImageFormat::RGB16_565;
   242     }
   244     return gfxImageFormat::RGB24;
   245 }
   247 static int sDepth = 0;
   249 int
   250 gfxPlatformGtk::GetScreenDepth() const
   251 {
   252     if (!sDepth) {
   253         GdkScreen *screen = gdk_screen_get_default();
   254         if (screen) {
   255             sDepth = gdk_visual_get_depth(gdk_visual_get_system());
   256         } else {
   257             sDepth = 24;
   258         }
   260     }
   262     return sDepth;
   263 }
   265 bool
   266 gfxPlatformGtk::SupportsOffMainThreadCompositing()
   267 {
   268   // Nightly builds have OMTC support by default for Electrolysis testing.
   269 #if defined(MOZ_X11) && !defined(NIGHTLY_BUILD)
   270   return (PR_GetEnv("MOZ_USE_OMTC") != nullptr) ||
   271          (PR_GetEnv("MOZ_OMTC_ENABLED") != nullptr);
   272 #else
   273   return true;
   274 #endif
   275 }
   277 void
   278 gfxPlatformGtk::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
   279 {
   280     mem = nullptr;
   281     size = 0;
   283 #ifdef MOZ_X11
   284     const char EDID1_ATOM_NAME[] = "XFree86_DDC_EDID1_RAWDATA";
   285     const char ICC_PROFILE_ATOM_NAME[] = "_ICC_PROFILE";
   287     Atom edidAtom, iccAtom;
   288     Display *dpy = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
   289     // In xpcshell tests, we never initialize X and hence don't have a Display.
   290     // In this case, there's no output colour management to be done, so we just
   291     // return with nullptr.
   292     if (!dpy)
   293         return;
   295     Window root = gdk_x11_get_default_root_xwindow();
   297     Atom retAtom;
   298     int retFormat;
   299     unsigned long retLength, retAfter;
   300     unsigned char *retProperty ;
   302     iccAtom = XInternAtom(dpy, ICC_PROFILE_ATOM_NAME, TRUE);
   303     if (iccAtom) {
   304         // read once to get size, once for the data
   305         if (Success == XGetWindowProperty(dpy, root, iccAtom,
   306                                           0, INT_MAX /* length */,
   307                                           False, AnyPropertyType,
   308                                           &retAtom, &retFormat, &retLength,
   309                                           &retAfter, &retProperty)) {
   311             if (retLength > 0) {
   312                 void *buffer = malloc(retLength);
   313                 if (buffer) {
   314                     memcpy(buffer, retProperty, retLength);
   315                     mem = buffer;
   316                     size = retLength;
   317                 }
   318             }
   320             XFree(retProperty);
   321             if (size > 0) {
   322 #ifdef DEBUG_tor
   323                 fprintf(stderr,
   324                         "ICM profile read from %s successfully\n",
   325                         ICC_PROFILE_ATOM_NAME);
   326 #endif
   327                 return;
   328             }
   329         }
   330     }
   332     edidAtom = XInternAtom(dpy, EDID1_ATOM_NAME, TRUE);
   333     if (edidAtom) {
   334         if (Success == XGetWindowProperty(dpy, root, edidAtom, 0, 32,
   335                                           False, AnyPropertyType,
   336                                           &retAtom, &retFormat, &retLength,
   337                                           &retAfter, &retProperty)) {
   338             double gamma;
   339             qcms_CIE_xyY whitePoint;
   340             qcms_CIE_xyYTRIPLE primaries;
   342             if (retLength != 128) {
   343 #ifdef DEBUG_tor
   344                 fprintf(stderr, "Short EDID data\n");
   345 #endif
   346                 return;
   347             }
   349             // Format documented in "VESA E-EDID Implementation Guide"
   351             gamma = (100 + retProperty[0x17]) / 100.0;
   352             whitePoint.x = ((retProperty[0x21] << 2) |
   353                             (retProperty[0x1a] >> 2 & 3)) / 1024.0;
   354             whitePoint.y = ((retProperty[0x22] << 2) |
   355                             (retProperty[0x1a] >> 0 & 3)) / 1024.0;
   356             whitePoint.Y = 1.0;
   358             primaries.red.x = ((retProperty[0x1b] << 2) |
   359                                (retProperty[0x19] >> 6 & 3)) / 1024.0;
   360             primaries.red.y = ((retProperty[0x1c] << 2) |
   361                                (retProperty[0x19] >> 4 & 3)) / 1024.0;
   362             primaries.red.Y = 1.0;
   364             primaries.green.x = ((retProperty[0x1d] << 2) |
   365                                  (retProperty[0x19] >> 2 & 3)) / 1024.0;
   366             primaries.green.y = ((retProperty[0x1e] << 2) |
   367                                  (retProperty[0x19] >> 0 & 3)) / 1024.0;
   368             primaries.green.Y = 1.0;
   370             primaries.blue.x = ((retProperty[0x1f] << 2) |
   371                                (retProperty[0x1a] >> 6 & 3)) / 1024.0;
   372             primaries.blue.y = ((retProperty[0x20] << 2) |
   373                                (retProperty[0x1a] >> 4 & 3)) / 1024.0;
   374             primaries.blue.Y = 1.0;
   376             XFree(retProperty);
   378 #ifdef DEBUG_tor
   379             fprintf(stderr, "EDID gamma: %f\n", gamma);
   380             fprintf(stderr, "EDID whitepoint: %f %f %f\n",
   381                     whitePoint.x, whitePoint.y, whitePoint.Y);
   382             fprintf(stderr, "EDID primaries: [%f %f %f] [%f %f %f] [%f %f %f]\n",
   383                     primaries.Red.x, primaries.Red.y, primaries.Red.Y,
   384                     primaries.Green.x, primaries.Green.y, primaries.Green.Y,
   385                     primaries.Blue.x, primaries.Blue.y, primaries.Blue.Y);
   386 #endif
   388             qcms_data_create_rgb_with_gamma(whitePoint, primaries, gamma, &mem, &size);
   390 #ifdef DEBUG_tor
   391             if (size > 0) {
   392                 fprintf(stderr,
   393                         "ICM profile read from %s successfully\n",
   394                         EDID1_ATOM_NAME);
   395             }
   396 #endif
   397         }
   398     }
   399 #endif
   400 }
   403 #if (MOZ_WIDGET_GTK == 2)
   404 void
   405 gfxPlatformGtk::SetGdkDrawable(cairo_surface_t *target,
   406                                GdkDrawable *drawable)
   407 {
   408     if (cairo_surface_status(target))
   409         return;
   411     g_object_ref(drawable);
   413     cairo_surface_set_user_data (target,
   414                                  &cairo_gdk_drawable_key,
   415                                  drawable,
   416                                  g_object_unref);
   417 }
   419 GdkDrawable *
   420 gfxPlatformGtk::GetGdkDrawable(cairo_surface_t *target)
   421 {
   422     if (cairo_surface_status(target))
   423         return nullptr;
   425     GdkDrawable *result;
   427     result = (GdkDrawable*) cairo_surface_get_user_data (target,
   428                                                          &cairo_gdk_drawable_key);
   429     if (result)
   430         return result;
   432 #ifdef MOZ_X11
   433     if (cairo_surface_get_type(target) != CAIRO_SURFACE_TYPE_XLIB)
   434         return nullptr;
   436     // try looking it up in gdk's table
   437     result = (GdkDrawable*) gdk_xid_table_lookup(cairo_xlib_surface_get_drawable(target));
   438     if (result) {
   439         SetGdkDrawable(target, result);
   440         return result;
   441     }
   442 #endif
   444     return nullptr;
   445 }
   446 #endif
   448 TemporaryRef<ScaledFont>
   449 gfxPlatformGtk::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
   450 {
   451     return GetScaledFontForFontWithCairoSkia(aTarget, aFont);
   452 }

mercurial