Bumping manifests a=b2g-bump
[gecko.git] / gfx / thebes / gfxPlatformGtk.cpp
blobd984036eb3aa292a4d8a33e3c424e96a844c4c7f
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 "gfxUtils.h"
20 #include "gfxFT2FontBase.h"
22 #include "mozilla/gfx/2D.h"
24 #include "cairo.h"
25 #include <gtk/gtk.h>
27 #include "gfxImageSurface.h"
28 #ifdef MOZ_X11
29 #include <gdk/gdkx.h>
30 #include "gfxXlibSurface.h"
31 #include "cairo-xlib.h"
32 #include "mozilla/Preferences.h"
34 /* Undefine the Status from Xlib since it will conflict with system headers on OSX */
35 #if defined(__APPLE__) && defined(Status)
36 #undef Status
37 #endif
39 #endif /* MOZ_X11 */
41 #include <fontconfig/fontconfig.h>
43 #include "nsMathUtils.h"
45 #define GDK_PIXMAP_SIZE_MAX 32767
47 using namespace mozilla;
48 using namespace mozilla::gfx;
49 using namespace mozilla::unicode;
51 gfxFontconfigUtils *gfxPlatformGtk::sFontconfigUtils = nullptr;
53 #if (MOZ_WIDGET_GTK == 2)
54 static cairo_user_data_key_t cairo_gdk_drawable_key;
55 #endif
57 #ifdef MOZ_X11
58 bool gfxPlatformGtk::sUseXRender = true;
59 #endif
61 gfxPlatformGtk::gfxPlatformGtk()
63 if (!sFontconfigUtils)
64 sFontconfigUtils = gfxFontconfigUtils::GetFontconfigUtils();
65 #ifdef MOZ_X11
66 sUseXRender = mozilla::Preferences::GetBool("gfx.xrender.enabled");
67 #endif
69 uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
70 uint32_t contentMask = BackendTypeBit(BackendType::CAIRO) | BackendTypeBit(BackendType::SKIA);
71 InitBackendPrefs(canvasMask, BackendType::CAIRO,
72 contentMask, BackendType::CAIRO);
75 gfxPlatformGtk::~gfxPlatformGtk()
77 gfxFontconfigUtils::Shutdown();
78 sFontconfigUtils = nullptr;
80 gfxPangoFontGroup::Shutdown();
83 already_AddRefed<gfxASurface>
84 gfxPlatformGtk::CreateOffscreenSurface(const IntSize& size,
85 gfxContentType contentType)
87 nsRefPtr<gfxASurface> newSurface;
88 bool needsClear = true;
89 gfxImageFormat imageFormat = OptimalFormatForContent(contentType);
90 #ifdef MOZ_X11
91 // XXX we really need a different interface here, something that passes
92 // in more context, including the display and/or target surface type that
93 // we should try to match
94 GdkScreen *gdkScreen = gdk_screen_get_default();
95 if (gdkScreen) {
96 // When forcing Thebes Layers to use image surfaces for content,
97 // force creation of gfxImageSurface surfaces.
98 if (UseXRender() && !UseImageOffscreenSurfaces()) {
99 Screen *screen = gdk_x11_screen_get_xscreen(gdkScreen);
100 XRenderPictFormat* xrenderFormat =
101 gfxXlibSurface::FindRenderFormat(DisplayOfScreen(screen),
102 imageFormat);
104 if (xrenderFormat) {
105 newSurface = gfxXlibSurface::Create(screen, xrenderFormat,
106 ThebesIntSize(size));
108 } else {
109 // We're not going to use XRender, so we don't need to
110 // search for a render format
111 newSurface = new gfxImageSurface(ThebesIntSize(size), imageFormat);
112 // The gfxImageSurface ctor zeroes this for us, no need to
113 // waste time clearing again
114 needsClear = false;
117 #endif
119 if (!newSurface) {
120 // We couldn't create a native surface for whatever reason;
121 // e.g., no display, no RENDER, bad size, etc.
122 // Fall back to image surface for the data.
123 newSurface = new gfxImageSurface(ThebesIntSize(size), imageFormat);
126 if (newSurface->CairoStatus()) {
127 newSurface = nullptr; // surface isn't valid for some reason
130 if (newSurface && needsClear) {
131 gfxUtils::ClearThebesSurface(newSurface);
134 return newSurface.forget();
137 nsresult
138 gfxPlatformGtk::GetFontList(nsIAtom *aLangGroup,
139 const nsACString& aGenericFamily,
140 nsTArray<nsString>& aListOfFonts)
142 return sFontconfigUtils->GetFontList(aLangGroup, aGenericFamily,
143 aListOfFonts);
146 nsresult
147 gfxPlatformGtk::UpdateFontList()
149 return sFontconfigUtils->UpdateFontList();
152 nsresult
153 gfxPlatformGtk::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
155 return sFontconfigUtils->GetStandardFamilyName(aFontName, aFamilyName);
158 gfxFontGroup *
159 gfxPlatformGtk::CreateFontGroup(const FontFamilyList& aFontFamilyList,
160 const gfxFontStyle *aStyle,
161 gfxUserFontSet *aUserFontSet)
163 return new gfxPangoFontGroup(aFontFamilyList, aStyle, aUserFontSet);
166 gfxFontEntry*
167 gfxPlatformGtk::LookupLocalFont(const gfxProxyFontEntry *aProxyEntry,
168 const nsAString& aFontName)
170 return gfxPangoFontGroup::NewFontEntry(*aProxyEntry, aFontName);
173 gfxFontEntry*
174 gfxPlatformGtk::MakePlatformFont(const gfxProxyFontEntry *aProxyEntry,
175 const uint8_t *aFontData, uint32_t aLength)
177 // passing ownership of the font data to the new font entry
178 return gfxPangoFontGroup::NewFontEntry(*aProxyEntry,
179 aFontData, aLength);
182 bool
183 gfxPlatformGtk::IsFontFormatSupported(nsIURI *aFontURI, uint32_t aFormatFlags)
185 // check for strange format flags
186 NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
187 "strange font format hint set");
189 // accept supported formats
190 // Pango doesn't apply features from AAT TrueType extensions.
191 // Assume that if this is the only SFNT format specified,
192 // then AAT extensions are required for complex script support.
193 if (aFormatFlags & (gfxUserFontSet::FLAG_FORMAT_WOFF |
194 gfxUserFontSet::FLAG_FORMAT_OPENTYPE |
195 gfxUserFontSet::FLAG_FORMAT_TRUETYPE)) {
196 return true;
199 // reject all other formats, known and unknown
200 if (aFormatFlags != 0) {
201 return false;
204 // no format hint set, need to look at data
205 return true;
208 static int32_t sDPI = 0;
210 int32_t
211 gfxPlatformGtk::GetDPI()
213 if (!sDPI) {
214 // Make sure init is run so we have a resolution
215 GdkScreen *screen = gdk_screen_get_default();
216 gtk_settings_get_for_screen(screen);
217 sDPI = int32_t(round(gdk_screen_get_resolution(screen)));
218 if (sDPI <= 0) {
219 // Fall back to something sane
220 sDPI = 96;
223 return sDPI;
226 gfxImageFormat
227 gfxPlatformGtk::GetOffscreenFormat()
229 // Make sure there is a screen
230 GdkScreen *screen = gdk_screen_get_default();
231 if (screen && gdk_visual_get_depth(gdk_visual_get_system()) == 16) {
232 return gfxImageFormat::RGB16_565;
235 return gfxImageFormat::RGB24;
238 static int sDepth = 0;
241 gfxPlatformGtk::GetScreenDepth() const
243 if (!sDepth) {
244 GdkScreen *screen = gdk_screen_get_default();
245 if (screen) {
246 sDepth = gdk_visual_get_depth(gdk_visual_get_system());
247 } else {
248 sDepth = 24;
253 return sDepth;
256 void
257 gfxPlatformGtk::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
259 mem = nullptr;
260 size = 0;
262 #ifdef MOZ_X11
263 const char EDID1_ATOM_NAME[] = "XFree86_DDC_EDID1_RAWDATA";
264 const char ICC_PROFILE_ATOM_NAME[] = "_ICC_PROFILE";
266 Atom edidAtom, iccAtom;
267 Display *dpy = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
268 // In xpcshell tests, we never initialize X and hence don't have a Display.
269 // In this case, there's no output colour management to be done, so we just
270 // return with nullptr.
271 if (!dpy)
272 return;
274 Window root = gdk_x11_get_default_root_xwindow();
276 Atom retAtom;
277 int retFormat;
278 unsigned long retLength, retAfter;
279 unsigned char *retProperty ;
281 iccAtom = XInternAtom(dpy, ICC_PROFILE_ATOM_NAME, TRUE);
282 if (iccAtom) {
283 // read once to get size, once for the data
284 if (Success == XGetWindowProperty(dpy, root, iccAtom,
285 0, INT_MAX /* length */,
286 False, AnyPropertyType,
287 &retAtom, &retFormat, &retLength,
288 &retAfter, &retProperty)) {
290 if (retLength > 0) {
291 void *buffer = malloc(retLength);
292 if (buffer) {
293 memcpy(buffer, retProperty, retLength);
294 mem = buffer;
295 size = retLength;
299 XFree(retProperty);
300 if (size > 0) {
301 #ifdef DEBUG_tor
302 fprintf(stderr,
303 "ICM profile read from %s successfully\n",
304 ICC_PROFILE_ATOM_NAME);
305 #endif
306 return;
311 edidAtom = XInternAtom(dpy, EDID1_ATOM_NAME, TRUE);
312 if (edidAtom) {
313 if (Success == XGetWindowProperty(dpy, root, edidAtom, 0, 32,
314 False, AnyPropertyType,
315 &retAtom, &retFormat, &retLength,
316 &retAfter, &retProperty)) {
317 double gamma;
318 qcms_CIE_xyY whitePoint;
319 qcms_CIE_xyYTRIPLE primaries;
321 if (retLength != 128) {
322 #ifdef DEBUG_tor
323 fprintf(stderr, "Short EDID data\n");
324 #endif
325 return;
328 // Format documented in "VESA E-EDID Implementation Guide"
330 gamma = (100 + retProperty[0x17]) / 100.0;
331 whitePoint.x = ((retProperty[0x21] << 2) |
332 (retProperty[0x1a] >> 2 & 3)) / 1024.0;
333 whitePoint.y = ((retProperty[0x22] << 2) |
334 (retProperty[0x1a] >> 0 & 3)) / 1024.0;
335 whitePoint.Y = 1.0;
337 primaries.red.x = ((retProperty[0x1b] << 2) |
338 (retProperty[0x19] >> 6 & 3)) / 1024.0;
339 primaries.red.y = ((retProperty[0x1c] << 2) |
340 (retProperty[0x19] >> 4 & 3)) / 1024.0;
341 primaries.red.Y = 1.0;
343 primaries.green.x = ((retProperty[0x1d] << 2) |
344 (retProperty[0x19] >> 2 & 3)) / 1024.0;
345 primaries.green.y = ((retProperty[0x1e] << 2) |
346 (retProperty[0x19] >> 0 & 3)) / 1024.0;
347 primaries.green.Y = 1.0;
349 primaries.blue.x = ((retProperty[0x1f] << 2) |
350 (retProperty[0x1a] >> 6 & 3)) / 1024.0;
351 primaries.blue.y = ((retProperty[0x20] << 2) |
352 (retProperty[0x1a] >> 4 & 3)) / 1024.0;
353 primaries.blue.Y = 1.0;
355 XFree(retProperty);
357 #ifdef DEBUG_tor
358 fprintf(stderr, "EDID gamma: %f\n", gamma);
359 fprintf(stderr, "EDID whitepoint: %f %f %f\n",
360 whitePoint.x, whitePoint.y, whitePoint.Y);
361 fprintf(stderr, "EDID primaries: [%f %f %f] [%f %f %f] [%f %f %f]\n",
362 primaries.Red.x, primaries.Red.y, primaries.Red.Y,
363 primaries.Green.x, primaries.Green.y, primaries.Green.Y,
364 primaries.Blue.x, primaries.Blue.y, primaries.Blue.Y);
365 #endif
367 qcms_data_create_rgb_with_gamma(whitePoint, primaries, gamma, &mem, &size);
369 #ifdef DEBUG_tor
370 if (size > 0) {
371 fprintf(stderr,
372 "ICM profile read from %s successfully\n",
373 EDID1_ATOM_NAME);
375 #endif
378 #endif
382 #if (MOZ_WIDGET_GTK == 2)
383 void
384 gfxPlatformGtk::SetGdkDrawable(cairo_surface_t *target,
385 GdkDrawable *drawable)
387 if (cairo_surface_status(target))
388 return;
390 g_object_ref(drawable);
392 cairo_surface_set_user_data (target,
393 &cairo_gdk_drawable_key,
394 drawable,
395 g_object_unref);
398 GdkDrawable *
399 gfxPlatformGtk::GetGdkDrawable(cairo_surface_t *target)
401 if (cairo_surface_status(target))
402 return nullptr;
404 GdkDrawable *result;
406 result = (GdkDrawable*) cairo_surface_get_user_data (target,
407 &cairo_gdk_drawable_key);
408 if (result)
409 return result;
411 #ifdef MOZ_X11
412 if (cairo_surface_get_type(target) != CAIRO_SURFACE_TYPE_XLIB)
413 return nullptr;
415 // try looking it up in gdk's table
416 result = (GdkDrawable*) gdk_xid_table_lookup(cairo_xlib_surface_get_drawable(target));
417 if (result) {
418 SetGdkDrawable(target, result);
419 return result;
421 #endif
423 return nullptr;
425 #endif
427 TemporaryRef<ScaledFont>
428 gfxPlatformGtk::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
430 return GetScaledFontForFontWithCairoSkia(aTarget, aFont);