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 +}