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"
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"
20 #include "gfxFT2FontBase.h"
22 #include "mozilla/gfx/2D.h"
27 #include "gfxImageSurface.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)
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
;
58 bool gfxPlatformGtk::sUseXRender
= true;
61 gfxPlatformGtk::gfxPlatformGtk()
63 if (!sFontconfigUtils
)
64 sFontconfigUtils
= gfxFontconfigUtils::GetFontconfigUtils();
66 sUseXRender
= mozilla::Preferences::GetBool("gfx.xrender.enabled");
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
);
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();
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
),
105 newSurface
= gfxXlibSurface::Create(screen
, xrenderFormat
,
106 ThebesIntSize(size
));
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
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();
138 gfxPlatformGtk::GetFontList(nsIAtom
*aLangGroup
,
139 const nsACString
& aGenericFamily
,
140 nsTArray
<nsString
>& aListOfFonts
)
142 return sFontconfigUtils
->GetFontList(aLangGroup
, aGenericFamily
,
147 gfxPlatformGtk::UpdateFontList()
149 return sFontconfigUtils
->UpdateFontList();
153 gfxPlatformGtk::GetStandardFamilyName(const nsAString
& aFontName
, nsAString
& aFamilyName
)
155 return sFontconfigUtils
->GetStandardFamilyName(aFontName
, aFamilyName
);
159 gfxPlatformGtk::CreateFontGroup(const FontFamilyList
& aFontFamilyList
,
160 const gfxFontStyle
*aStyle
,
161 gfxUserFontSet
*aUserFontSet
)
163 return new gfxPangoFontGroup(aFontFamilyList
, aStyle
, aUserFontSet
);
167 gfxPlatformGtk::LookupLocalFont(const gfxProxyFontEntry
*aProxyEntry
,
168 const nsAString
& aFontName
)
170 return gfxPangoFontGroup::NewFontEntry(*aProxyEntry
, aFontName
);
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
,
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
)) {
199 // reject all other formats, known and unknown
200 if (aFormatFlags
!= 0) {
204 // no format hint set, need to look at data
208 static int32_t sDPI
= 0;
211 gfxPlatformGtk::GetDPI()
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
)));
219 // Fall back to something sane
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
244 GdkScreen
*screen
= gdk_screen_get_default();
246 sDepth
= gdk_visual_get_depth(gdk_visual_get_system());
257 gfxPlatformGtk::GetPlatformCMSOutputProfile(void *&mem
, size_t &size
)
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.
274 Window root
= gdk_x11_get_default_root_xwindow();
278 unsigned long retLength
, retAfter
;
279 unsigned char *retProperty
;
281 iccAtom
= XInternAtom(dpy
, ICC_PROFILE_ATOM_NAME
, TRUE
);
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
)) {
291 void *buffer
= malloc(retLength
);
293 memcpy(buffer
, retProperty
, retLength
);
303 "ICM profile read from %s successfully\n",
304 ICC_PROFILE_ATOM_NAME
);
311 edidAtom
= XInternAtom(dpy
, EDID1_ATOM_NAME
, TRUE
);
313 if (Success
== XGetWindowProperty(dpy
, root
, edidAtom
, 0, 32,
314 False
, AnyPropertyType
,
315 &retAtom
, &retFormat
, &retLength
,
316 &retAfter
, &retProperty
)) {
318 qcms_CIE_xyY whitePoint
;
319 qcms_CIE_xyYTRIPLE primaries
;
321 if (retLength
!= 128) {
323 fprintf(stderr
, "Short EDID data\n");
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;
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;
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
);
367 qcms_data_create_rgb_with_gamma(whitePoint
, primaries
, gamma
, &mem
, &size
);
372 "ICM profile read from %s successfully\n",
382 #if (MOZ_WIDGET_GTK == 2)
384 gfxPlatformGtk::SetGdkDrawable(cairo_surface_t
*target
,
385 GdkDrawable
*drawable
)
387 if (cairo_surface_status(target
))
390 g_object_ref(drawable
);
392 cairo_surface_set_user_data (target
,
393 &cairo_gdk_drawable_key
,
399 gfxPlatformGtk::GetGdkDrawable(cairo_surface_t
*target
)
401 if (cairo_surface_status(target
))
406 result
= (GdkDrawable
*) cairo_surface_get_user_data (target
,
407 &cairo_gdk_drawable_key
);
412 if (cairo_surface_get_type(target
) != CAIRO_SURFACE_TYPE_XLIB
)
415 // try looking it up in gdk's table
416 result
= (GdkDrawable
*) gdk_xid_table_lookup(cairo_xlib_surface_get_drawable(target
));
418 SetGdkDrawable(target
, result
);
427 TemporaryRef
<ScaledFont
>
428 gfxPlatformGtk::GetScaledFontForFont(DrawTarget
* aTarget
, gfxFont
*aFont
)
430 return GetScaledFontForFontWithCairoSkia(aTarget
, aFont
);