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.

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

mercurial