LCOV - code coverage report
Current view: top level - gfx/thebes - gfxPlatformGtk.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 116 326 35.6 %
Date: 2017-07-14 16:53:18 Functions: 14 41 34.1 %
Legend: Lines: hit not hit

          Line data    Source code
       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/. */
       5             : 
       6             : #define PANGO_ENABLE_BACKEND
       7             : #define PANGO_ENABLE_ENGINE
       8             : 
       9             : #include "gfxPlatformGtk.h"
      10             : #include "prenv.h"
      11             : 
      12             : #include "nsUnicharUtils.h"
      13             : #include "nsUnicodeProperties.h"
      14             : #include "gfx2DGlue.h"
      15             : #include "gfxFcPlatformFontList.h"
      16             : #include "gfxFontconfigUtils.h"
      17             : #include "gfxFontconfigFonts.h"
      18             : #include "gfxConfig.h"
      19             : #include "gfxContext.h"
      20             : #include "gfxUserFontSet.h"
      21             : #include "gfxUtils.h"
      22             : #include "gfxFT2FontBase.h"
      23             : #include "gfxPrefs.h"
      24             : #include "VsyncSource.h"
      25             : #include "mozilla/Atomics.h"
      26             : #include "mozilla/Monitor.h"
      27             : #include "base/task.h"
      28             : #include "base/thread.h"
      29             : #include "base/message_loop.h"
      30             : #include "mozilla/gfx/Logging.h"
      31             : 
      32             : #include "mozilla/gfx/2D.h"
      33             : 
      34             : #include "cairo.h"
      35             : #include <gtk/gtk.h>
      36             : 
      37             : #include "gfxImageSurface.h"
      38             : #ifdef MOZ_X11
      39             : #include <gdk/gdkx.h>
      40             : #include "gfxXlibSurface.h"
      41             : #include "cairo-xlib.h"
      42             : #include "mozilla/Preferences.h"
      43             : #include "mozilla/X11Util.h"
      44             : 
      45             : #ifdef GL_PROVIDER_GLX
      46             : #include "GLContextProvider.h"
      47             : #include "GLContextGLX.h"
      48             : #include "GLXLibrary.h"
      49             : #endif
      50             : 
      51             : /* Undefine the Status from Xlib since it will conflict with system headers on OSX */
      52             : #if defined(__APPLE__) && defined(Status)
      53             : #undef Status
      54             : #endif
      55             : 
      56             : #endif /* MOZ_X11 */
      57             : 
      58             : #include <fontconfig/fontconfig.h>
      59             : 
      60             : #include "nsMathUtils.h"
      61             : 
      62             : #define GDK_PIXMAP_SIZE_MAX 32767
      63             : 
      64             : #define GFX_PREF_MAX_GENERIC_SUBSTITUTIONS "gfx.font_rendering.fontconfig.max_generic_substitutions"
      65             : 
      66             : using namespace mozilla;
      67             : using namespace mozilla::gfx;
      68             : using namespace mozilla::unicode;
      69             : 
      70             : #if (MOZ_WIDGET_GTK == 2)
      71             : static cairo_user_data_key_t cairo_gdk_drawable_key;
      72             : #endif
      73             : 
      74           3 : gfxPlatformGtk::gfxPlatformGtk()
      75             : {
      76           3 :     if (!gfxPlatform::IsHeadless()) {
      77           3 :         gtk_init(nullptr, nullptr);
      78             :     }
      79             : 
      80           3 :     mMaxGenericSubstitutions = UNINITIALIZED_VALUE;
      81             : 
      82             : #ifdef MOZ_X11
      83           3 :     if (!gfxPlatform::IsHeadless() && XRE_IsParentProcess()) {
      84           2 :       if (GDK_IS_X11_DISPLAY(gdk_display_get_default()) &&
      85           1 :           mozilla::Preferences::GetBool("gfx.xrender.enabled"))
      86             :       {
      87           0 :           gfxVars::SetUseXRender(true);
      88             :       }
      89             :     }
      90             : #endif
      91             : 
      92           3 :     uint32_t canvasMask = BackendTypeBit(BackendType::CAIRO);
      93           3 :     uint32_t contentMask = BackendTypeBit(BackendType::CAIRO);
      94             : #ifdef USE_SKIA
      95           3 :     canvasMask |= BackendTypeBit(BackendType::SKIA);
      96           3 :     contentMask |= BackendTypeBit(BackendType::SKIA);
      97             : #endif
      98           3 :     InitBackendPrefs(canvasMask, BackendType::CAIRO,
      99           3 :                      contentMask, BackendType::CAIRO);
     100             : 
     101             : #ifdef MOZ_X11
     102           3 :     if (gfxPlatform::IsHeadless() && GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
     103           0 :       mCompositorDisplay = XOpenDisplay(nullptr);
     104           0 :       MOZ_ASSERT(mCompositorDisplay, "Failed to create compositor display!");
     105             :     } else {
     106           3 :       mCompositorDisplay = nullptr;
     107             :     }
     108             : #endif // MOZ_X11
     109           3 : }
     110             : 
     111           0 : gfxPlatformGtk::~gfxPlatformGtk()
     112             : {
     113             : #ifdef MOZ_X11
     114           0 :     if (mCompositorDisplay) {
     115           0 :       XCloseDisplay(mCompositorDisplay);
     116             :     }
     117             : #endif // MOZ_X11
     118           0 : }
     119             : 
     120             : void
     121          24 : gfxPlatformGtk::FlushContentDrawing()
     122             : {
     123          24 :     if (gfxVars::UseXRender()) {
     124           0 :         XFlush(DefaultXDisplay());
     125             :     }
     126          24 : }
     127             : 
     128             : already_AddRefed<gfxASurface>
     129           3 : gfxPlatformGtk::CreateOffscreenSurface(const IntSize& aSize,
     130             :                                        gfxImageFormat aFormat)
     131             : {
     132           3 :     if (!Factory::AllowedSurfaceSize(aSize)) {
     133           0 :         return nullptr;
     134             :     }
     135             : 
     136           6 :     RefPtr<gfxASurface> newSurface;
     137           3 :     bool needsClear = true;
     138             : #ifdef MOZ_X11
     139             :     // XXX we really need a different interface here, something that passes
     140             :     // in more context, including the display and/or target surface type that
     141             :     // we should try to match
     142           3 :     GdkScreen *gdkScreen = gdk_screen_get_default();
     143           3 :     if (gdkScreen) {
     144             :         // When forcing PaintedLayers to use image surfaces for content,
     145             :         // force creation of gfxImageSurface surfaces.
     146           3 :         if (gfxVars::UseXRender() && !UseImageOffscreenSurfaces()) {
     147           0 :             Screen *screen = gdk_x11_screen_get_xscreen(gdkScreen);
     148             :             XRenderPictFormat* xrenderFormat =
     149           0 :                 gfxXlibSurface::FindRenderFormat(DisplayOfScreen(screen),
     150           0 :                                                  aFormat);
     151             : 
     152           0 :             if (xrenderFormat) {
     153           0 :                 newSurface = gfxXlibSurface::Create(screen, xrenderFormat,
     154           0 :                                                     aSize);
     155             :             }
     156             :         } else {
     157             :             // We're not going to use XRender, so we don't need to
     158             :             // search for a render format
     159           3 :             newSurface = new gfxImageSurface(aSize, aFormat);
     160             :             // The gfxImageSurface ctor zeroes this for us, no need to
     161             :             // waste time clearing again
     162           3 :             needsClear = false;
     163             :         }
     164             :     }
     165             : #endif
     166             : 
     167           3 :     if (!newSurface) {
     168             :         // We couldn't create a native surface for whatever reason;
     169             :         // e.g., no display, no RENDER, bad size, etc.
     170             :         // Fall back to image surface for the data.
     171           0 :         newSurface = new gfxImageSurface(aSize, aFormat);
     172             :     }
     173             : 
     174           3 :     if (newSurface->CairoStatus()) {
     175           0 :         newSurface = nullptr; // surface isn't valid for some reason
     176             :     }
     177             : 
     178           3 :     if (newSurface && needsClear) {
     179           0 :         gfxUtils::ClearThebesSurface(newSurface);
     180             :     }
     181             : 
     182           3 :     return newSurface.forget();
     183             : }
     184             : 
     185             : nsresult
     186           0 : gfxPlatformGtk::GetFontList(nsIAtom *aLangGroup,
     187             :                             const nsACString& aGenericFamily,
     188             :                             nsTArray<nsString>& aListOfFonts)
     189             : {
     190           0 :     gfxPlatformFontList::PlatformFontList()->GetFontList(aLangGroup,
     191             :                                                          aGenericFamily,
     192           0 :                                                          aListOfFonts);
     193           0 :     return NS_OK;
     194             : }
     195             : 
     196             : nsresult
     197           0 : gfxPlatformGtk::UpdateFontList()
     198             : {
     199           0 :     gfxPlatformFontList::PlatformFontList()->UpdateFontList();
     200           0 :     return NS_OK;
     201             : }
     202             : 
     203             : // xxx - this is ubuntu centric, need to go through other distros and flesh
     204             : // out a more general list
     205             : static const char kFontDejaVuSans[] = "DejaVu Sans";
     206             : static const char kFontDejaVuSerif[] = "DejaVu Serif";
     207             : static const char kFontEmojiOneMozilla[] = "EmojiOne Mozilla";
     208             : static const char kFontFreeSans[] = "FreeSans";
     209             : static const char kFontFreeSerif[] = "FreeSerif";
     210             : static const char kFontTakaoPGothic[] = "TakaoPGothic";
     211             : static const char kFontDroidSansFallback[] = "Droid Sans Fallback";
     212             : static const char kFontWenQuanYiMicroHei[] = "WenQuanYi Micro Hei";
     213             : static const char kFontNanumGothic[] = "NanumGothic";
     214             : 
     215             : void
     216           0 : gfxPlatformGtk::GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
     217             :                                        Script aRunScript,
     218             :                                        nsTArray<const char*>& aFontList)
     219             : {
     220           0 :     if (aNextCh == 0xfe0fu) {
     221             :       // if char is followed by VS16, try for a color emoji glyph
     222           0 :       aFontList.AppendElement(kFontEmojiOneMozilla);
     223             :     }
     224             : 
     225           0 :     aFontList.AppendElement(kFontDejaVuSerif);
     226           0 :     aFontList.AppendElement(kFontFreeSerif);
     227           0 :     aFontList.AppendElement(kFontDejaVuSans);
     228           0 :     aFontList.AppendElement(kFontFreeSans);
     229             : 
     230           0 :     if (!IS_IN_BMP(aCh)) {
     231           0 :         uint32_t p = aCh >> 16;
     232           0 :         if (p == 1) { // try color emoji font, unless VS15 (text style) present
     233           0 :             if (aNextCh != 0xfe0fu && aNextCh != 0xfe0eu) {
     234           0 :                 aFontList.AppendElement(kFontEmojiOneMozilla);
     235             :             }
     236             :         }
     237             :     }
     238             : 
     239             :     // add fonts for CJK ranges
     240             :     // xxx - this isn't really correct, should use the same CJK font ordering
     241             :     // as the pref font code
     242           0 :     if (aCh >= 0x3000 &&
     243           0 :         ((aCh < 0xe000) ||
     244           0 :          (aCh >= 0xf900 && aCh < 0xfff0) ||
     245           0 :          ((aCh >> 16) == 2))) {
     246           0 :         aFontList.AppendElement(kFontTakaoPGothic);
     247           0 :         aFontList.AppendElement(kFontDroidSansFallback);
     248           0 :         aFontList.AppendElement(kFontWenQuanYiMicroHei);
     249           0 :         aFontList.AppendElement(kFontNanumGothic);
     250             :     }
     251           0 : }
     252             : 
     253             : gfxPlatformFontList*
     254           3 : gfxPlatformGtk::CreatePlatformFontList()
     255             : {
     256           3 :     gfxPlatformFontList* list = new gfxFcPlatformFontList();
     257           3 :     if (NS_SUCCEEDED(list->InitFontList())) {
     258           3 :         return list;
     259             :     }
     260           0 :     gfxPlatformFontList::Shutdown();
     261           0 :     return nullptr;
     262             : }
     263             : 
     264             : nsresult
     265           0 : gfxPlatformGtk::GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName)
     266             : {
     267           0 :     gfxPlatformFontList::PlatformFontList()->
     268           0 :         GetStandardFamilyName(aFontName, aFamilyName);
     269           0 :     return NS_OK;
     270             : }
     271             : 
     272             : gfxFontGroup *
     273           6 : gfxPlatformGtk::CreateFontGroup(const FontFamilyList& aFontFamilyList,
     274             :                                 const gfxFontStyle* aStyle,
     275             :                                 gfxTextPerfMetrics* aTextPerf,
     276             :                                 gfxUserFontSet* aUserFontSet,
     277             :                                 gfxFloat aDevToCssSize)
     278             : {
     279             :     return new gfxFontGroup(aFontFamilyList, aStyle, aTextPerf,
     280           6 :                             aUserFontSet, aDevToCssSize);
     281             : }
     282             : 
     283             : gfxFontEntry*
     284           0 : gfxPlatformGtk::LookupLocalFont(const nsAString& aFontName,
     285             :                                 uint16_t aWeight,
     286             :                                 int16_t aStretch,
     287             :                                 uint8_t aStyle)
     288             : {
     289           0 :     gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
     290           0 :     return pfl->LookupLocalFont(aFontName, aWeight, aStretch,
     291           0 :                                 aStyle);
     292             : }
     293             : 
     294             : gfxFontEntry*
     295           0 : gfxPlatformGtk::MakePlatformFont(const nsAString& aFontName,
     296             :                                  uint16_t aWeight,
     297             :                                  int16_t aStretch,
     298             :                                  uint8_t aStyle,
     299             :                                  const uint8_t* aFontData,
     300             :                                  uint32_t aLength)
     301             : {
     302           0 :     gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
     303           0 :     return pfl->MakePlatformFont(aFontName, aWeight, aStretch,
     304           0 :                                  aStyle, aFontData, aLength);
     305             : }
     306             : 
     307             : FT_Library
     308           3 : gfxPlatformGtk::GetFTLibrary()
     309             : {
     310           3 :     return gfxFcPlatformFontList::GetFTLibrary();
     311             : }
     312             : 
     313             : bool
     314           0 : gfxPlatformGtk::IsFontFormatSupported(uint32_t aFormatFlags)
     315             : {
     316             :     // check for strange format flags
     317           0 :     NS_ASSERTION(!(aFormatFlags & gfxUserFontSet::FLAG_FORMAT_NOT_USED),
     318             :                  "strange font format hint set");
     319             : 
     320             :     // accept supported formats
     321             :     // Pango doesn't apply features from AAT TrueType extensions.
     322             :     // Assume that if this is the only SFNT format specified,
     323             :     // then AAT extensions are required for complex script support.
     324           0 :     if (aFormatFlags & gfxUserFontSet::FLAG_FORMATS_COMMON) {
     325           0 :         return true;
     326             :     }
     327             : 
     328             :     // reject all other formats, known and unknown
     329           0 :     if (aFormatFlags != 0) {
     330           0 :         return false;
     331             :     }
     332             : 
     333             :     // no format hint set, need to look at data
     334           0 :     return true;
     335             : }
     336             : 
     337             : static int32_t sDPI = 0;
     338             : 
     339             : int32_t
     340          53 : gfxPlatformGtk::GetDPI()
     341             : {
     342          53 :     if (!sDPI) {
     343             :         // Make sure init is run so we have a resolution
     344           1 :         GdkScreen *screen = gdk_screen_get_default();
     345           1 :         gtk_settings_get_for_screen(screen);
     346           1 :         sDPI = int32_t(round(gdk_screen_get_resolution(screen)));
     347           1 :         if (sDPI <= 0) {
     348             :             // Fall back to something sane
     349           0 :             sDPI = 96;
     350             :         }
     351             :     }
     352          53 :     return sDPI;
     353             : }
     354             : 
     355             : double
     356          51 : gfxPlatformGtk::GetDPIScale()
     357             : {
     358             :     // Integer scale factors work well with GTK window scaling, image scaling,
     359             :     // and pixel alignment, but there is a range where 1 is too small and 2 is
     360             :     // too big.  An additional step of 1.5 is added because this is common
     361             :     // scale on WINNT and at this ratio the advantages of larger rendering
     362             :     // outweigh the disadvantages from scaling and pixel mis-alignment.
     363          51 :     int32_t dpi = GetDPI();
     364          51 :     if (dpi < 132) {
     365          51 :         return 1.0;
     366             :     }
     367           0 :     if (dpi < 168) {
     368           0 :         return 1.5;
     369             :     }
     370           0 :     return round(dpi/96.0);
     371             : 
     372             : }
     373             : 
     374             : bool
     375          22 : gfxPlatformGtk::UseImageOffscreenSurfaces()
     376             : {
     377          22 :     return GetDefaultContentBackend() != mozilla::gfx::BackendType::CAIRO ||
     378          22 :            gfxPrefs::UseImageOffscreenSurfaces();
     379             : }
     380             : 
     381             : gfxImageFormat
     382           4 : gfxPlatformGtk::GetOffscreenFormat()
     383             : {
     384             :     // Make sure there is a screen
     385           4 :     GdkScreen *screen = gdk_screen_get_default();
     386           4 :     if (screen && gdk_visual_get_depth(gdk_visual_get_system()) == 16) {
     387           0 :         return SurfaceFormat::R5G6B5_UINT16;
     388             :     }
     389             : 
     390           4 :     return SurfaceFormat::X8R8G8B8_UINT32;
     391             : }
     392             : 
     393           0 : void gfxPlatformGtk::FontsPrefsChanged(const char *aPref)
     394             : {
     395             :     // only checking for generic substitions, pass other changes up
     396           0 :     if (strcmp(GFX_PREF_MAX_GENERIC_SUBSTITUTIONS, aPref)) {
     397           0 :         gfxPlatform::FontsPrefsChanged(aPref);
     398           0 :         return;
     399             :     }
     400             : 
     401           0 :     mMaxGenericSubstitutions = UNINITIALIZED_VALUE;
     402           0 :     gfxFcPlatformFontList* pfl = gfxFcPlatformFontList::PlatformFontList();
     403           0 :     pfl->ClearGenericMappings();
     404           0 :     FlushFontAndWordCaches();
     405             : }
     406             : 
     407           5 : uint32_t gfxPlatformGtk::MaxGenericSubstitions()
     408             : {
     409           5 :     if (mMaxGenericSubstitutions == UNINITIALIZED_VALUE) {
     410           3 :         mMaxGenericSubstitutions =
     411           3 :             Preferences::GetInt(GFX_PREF_MAX_GENERIC_SUBSTITUTIONS, 3);
     412           3 :         if (mMaxGenericSubstitutions < 0) {
     413           0 :             mMaxGenericSubstitutions = 3;
     414             :         }
     415             :     }
     416             : 
     417           5 :     return uint32_t(mMaxGenericSubstitutions);
     418             : }
     419             : 
     420             : void
     421           3 : gfxPlatformGtk::GetPlatformCMSOutputProfile(void *&mem, size_t &size)
     422             : {
     423           3 :     mem = nullptr;
     424           3 :     size = 0;
     425             : 
     426             : #ifdef MOZ_X11
     427           3 :     GdkDisplay *display = gdk_display_get_default();
     428           3 :     if (!GDK_IS_X11_DISPLAY(display))
     429           0 :         return;
     430             : 
     431           3 :     const char EDID1_ATOM_NAME[] = "XFree86_DDC_EDID1_RAWDATA";
     432           3 :     const char ICC_PROFILE_ATOM_NAME[] = "_ICC_PROFILE";
     433             : 
     434             :     Atom edidAtom, iccAtom;
     435           3 :     Display *dpy = GDK_DISPLAY_XDISPLAY(display);
     436             :     // In xpcshell tests, we never initialize X and hence don't have a Display.
     437             :     // In this case, there's no output colour management to be done, so we just
     438             :     // return with nullptr.
     439           3 :     if (!dpy)
     440           0 :         return;
     441             : 
     442           3 :     Window root = gdk_x11_get_default_root_xwindow();
     443             : 
     444             :     Atom retAtom;
     445             :     int retFormat;
     446             :     unsigned long retLength, retAfter;
     447             :     unsigned char *retProperty ;
     448             : 
     449           3 :     iccAtom = XInternAtom(dpy, ICC_PROFILE_ATOM_NAME, TRUE);
     450           3 :     if (iccAtom) {
     451             :         // read once to get size, once for the data
     452           3 :         if (Success == XGetWindowProperty(dpy, root, iccAtom,
     453             :                                           0, INT_MAX /* length */,
     454             :                                           False, AnyPropertyType,
     455             :                                           &retAtom, &retFormat, &retLength,
     456             :                                           &retAfter, &retProperty)) {
     457             : 
     458           3 :             if (retLength > 0) {
     459           0 :                 void *buffer = malloc(retLength);
     460           0 :                 if (buffer) {
     461           0 :                     memcpy(buffer, retProperty, retLength);
     462           0 :                     mem = buffer;
     463           0 :                     size = retLength;
     464             :                 }
     465             :             }
     466             : 
     467           3 :             XFree(retProperty);
     468           3 :             if (size > 0) {
     469             : #ifdef DEBUG_tor
     470             :                 fprintf(stderr,
     471             :                         "ICM profile read from %s successfully\n",
     472             :                         ICC_PROFILE_ATOM_NAME);
     473             : #endif
     474           0 :                 return;
     475             :             }
     476             :         }
     477             :     }
     478             : 
     479           3 :     edidAtom = XInternAtom(dpy, EDID1_ATOM_NAME, TRUE);
     480           3 :     if (edidAtom) {
     481           3 :         if (Success == XGetWindowProperty(dpy, root, edidAtom, 0, 32,
     482             :                                           False, AnyPropertyType,
     483             :                                           &retAtom, &retFormat, &retLength,
     484             :                                           &retAfter, &retProperty)) {
     485             :             double gamma;
     486             :             qcms_CIE_xyY whitePoint;
     487             :             qcms_CIE_xyYTRIPLE primaries;
     488             : 
     489           3 :             if (retLength != 128) {
     490             : #ifdef DEBUG_tor
     491             :                 fprintf(stderr, "Short EDID data\n");
     492             : #endif
     493           0 :                 return;
     494             :             }
     495             : 
     496             :             // Format documented in "VESA E-EDID Implementation Guide"
     497             : 
     498           3 :             gamma = (100 + retProperty[0x17]) / 100.0;
     499           9 :             whitePoint.x = ((retProperty[0x21] << 2) |
     500           6 :                             (retProperty[0x1a] >> 2 & 3)) / 1024.0;
     501           9 :             whitePoint.y = ((retProperty[0x22] << 2) |
     502           6 :                             (retProperty[0x1a] >> 0 & 3)) / 1024.0;
     503           3 :             whitePoint.Y = 1.0;
     504             : 
     505           9 :             primaries.red.x = ((retProperty[0x1b] << 2) |
     506           6 :                                (retProperty[0x19] >> 6 & 3)) / 1024.0;
     507           9 :             primaries.red.y = ((retProperty[0x1c] << 2) |
     508           6 :                                (retProperty[0x19] >> 4 & 3)) / 1024.0;
     509           3 :             primaries.red.Y = 1.0;
     510             : 
     511           9 :             primaries.green.x = ((retProperty[0x1d] << 2) |
     512           6 :                                  (retProperty[0x19] >> 2 & 3)) / 1024.0;
     513           9 :             primaries.green.y = ((retProperty[0x1e] << 2) |
     514           6 :                                  (retProperty[0x19] >> 0 & 3)) / 1024.0;
     515           3 :             primaries.green.Y = 1.0;
     516             : 
     517           9 :             primaries.blue.x = ((retProperty[0x1f] << 2) |
     518           6 :                                (retProperty[0x1a] >> 6 & 3)) / 1024.0;
     519           9 :             primaries.blue.y = ((retProperty[0x20] << 2) |
     520           6 :                                (retProperty[0x1a] >> 4 & 3)) / 1024.0;
     521           3 :             primaries.blue.Y = 1.0;
     522             : 
     523           3 :             XFree(retProperty);
     524             : 
     525             : #ifdef DEBUG_tor
     526             :             fprintf(stderr, "EDID gamma: %f\n", gamma);
     527             :             fprintf(stderr, "EDID whitepoint: %f %f %f\n",
     528             :                     whitePoint.x, whitePoint.y, whitePoint.Y);
     529             :             fprintf(stderr, "EDID primaries: [%f %f %f] [%f %f %f] [%f %f %f]\n",
     530             :                     primaries.Red.x, primaries.Red.y, primaries.Red.Y,
     531             :                     primaries.Green.x, primaries.Green.y, primaries.Green.Y,
     532             :                     primaries.Blue.x, primaries.Blue.y, primaries.Blue.Y);
     533             : #endif
     534             : 
     535           3 :             qcms_data_create_rgb_with_gamma(whitePoint, primaries, gamma, &mem, &size);
     536             : 
     537             : #ifdef DEBUG_tor
     538             :             if (size > 0) {
     539             :                 fprintf(stderr,
     540             :                         "ICM profile read from %s successfully\n",
     541             :                         EDID1_ATOM_NAME);
     542             :             }
     543             : #endif
     544             :         }
     545             :     }
     546             : #endif
     547             : }
     548             : 
     549             : 
     550             : #if (MOZ_WIDGET_GTK == 2)
     551             : void
     552             : gfxPlatformGtk::SetGdkDrawable(cairo_surface_t *target,
     553             :                                GdkDrawable *drawable)
     554             : {
     555             :     if (cairo_surface_status(target))
     556             :         return;
     557             : 
     558             :     g_object_ref(drawable);
     559             : 
     560             :     cairo_surface_set_user_data (target,
     561             :                                  &cairo_gdk_drawable_key,
     562             :                                  drawable,
     563             :                                  g_object_unref);
     564             : }
     565             : 
     566             : GdkDrawable *
     567             : gfxPlatformGtk::GetGdkDrawable(cairo_surface_t *target)
     568             : {
     569             :     if (cairo_surface_status(target))
     570             :         return nullptr;
     571             : 
     572             :     GdkDrawable *result;
     573             : 
     574             :     result = (GdkDrawable*) cairo_surface_get_user_data (target,
     575             :                                                          &cairo_gdk_drawable_key);
     576             :     if (result)
     577             :         return result;
     578             : 
     579             : #ifdef MOZ_X11
     580             :     if (cairo_surface_get_type(target) != CAIRO_SURFACE_TYPE_XLIB)
     581             :         return nullptr;
     582             : 
     583             :     // try looking it up in gdk's table
     584             :     result = (GdkDrawable*) gdk_xid_table_lookup(cairo_xlib_surface_get_drawable(target));
     585             :     if (result) {
     586             :         SetGdkDrawable(target, result);
     587             :         return result;
     588             :     }
     589             : #endif
     590             : 
     591             :     return nullptr;
     592             : }
     593             : #endif
     594             : 
     595             : already_AddRefed<ScaledFont>
     596          21 : gfxPlatformGtk::GetScaledFontForFont(DrawTarget* aTarget, gfxFont *aFont)
     597             : {
     598          21 :   if (aFont->GetType() == gfxFont::FONT_TYPE_FONTCONFIG) {
     599          21 :       gfxFontconfigFontBase* fcFont = static_cast<gfxFontconfigFontBase*>(aFont);
     600             :       return Factory::CreateScaledFontForFontconfigFont(
     601          21 :               fcFont->GetCairoScaledFont(),
     602          21 :               fcFont->GetPattern(),
     603             :               fcFont->GetUnscaledFont(),
     604          63 :               fcFont->GetAdjustedSize());
     605             :   }
     606           0 :   return GetScaledFontForFontWithCairoSkia(aTarget, aFont);
     607             : }
     608             : 
     609             : #ifdef GL_PROVIDER_GLX
     610             : 
     611             : class GLXVsyncSource final : public VsyncSource
     612             : {
     613             : public:
     614           0 :   GLXVsyncSource()
     615           0 :   {
     616           0 :     MOZ_ASSERT(NS_IsMainThread());
     617           0 :     mGlobalDisplay = new GLXDisplay();
     618           0 :   }
     619             : 
     620           0 :   virtual ~GLXVsyncSource()
     621           0 :   {
     622           0 :     MOZ_ASSERT(NS_IsMainThread());
     623           0 :   }
     624             : 
     625           0 :   virtual Display& GetGlobalDisplay() override
     626             :   {
     627           0 :     return *mGlobalDisplay;
     628             :   }
     629             : 
     630             :   class GLXDisplay final : public VsyncSource::Display
     631             :   {
     632           0 :   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GLXDisplay)
     633             : 
     634             :   public:
     635           0 :     GLXDisplay() : mGLContext(nullptr)
     636             :                  , mXDisplay(nullptr)
     637             :                  , mSetupLock("GLXVsyncSetupLock")
     638             :                  , mVsyncThread("GLXVsyncThread")
     639             :                  , mVsyncTask(nullptr)
     640             :                  , mVsyncEnabledLock("GLXVsyncEnabledLock")
     641           0 :                  , mVsyncEnabled(false)
     642             :     {
     643           0 :     }
     644             : 
     645             :     // Sets up the display's GL context on a worker thread.
     646             :     // Required as GLContexts may only be used by the creating thread.
     647             :     // Returns true if setup was a success.
     648           0 :     bool Setup()
     649             :     {
     650           0 :       MonitorAutoLock lock(mSetupLock);
     651           0 :       MOZ_ASSERT(NS_IsMainThread());
     652           0 :       if (!mVsyncThread.Start())
     653           0 :         return false;
     654             : 
     655             :       RefPtr<Runnable> vsyncSetup =
     656           0 :         NewRunnableMethod("GLXVsyncSource::GLXDisplay::SetupGLContext",
     657             :                           this,
     658           0 :                           &GLXDisplay::SetupGLContext);
     659           0 :       mVsyncThread.message_loop()->PostTask(vsyncSetup.forget());
     660             :       // Wait until the setup has completed.
     661           0 :       lock.Wait();
     662           0 :       return mGLContext != nullptr;
     663             :     }
     664             : 
     665             :     // Called on the Vsync thread to setup the GL context.
     666           0 :     void SetupGLContext()
     667             :     {
     668           0 :         MonitorAutoLock lock(mSetupLock);
     669           0 :         MOZ_ASSERT(!NS_IsMainThread());
     670           0 :         MOZ_ASSERT(!mGLContext, "GLContext already setup!");
     671             : 
     672             :         // Create video sync timer on a separate Display to prevent locking the
     673             :         // main thread X display.
     674           0 :         mXDisplay = XOpenDisplay(nullptr);
     675           0 :         if (!mXDisplay) {
     676           0 :           lock.NotifyAll();
     677           0 :           return;
     678             :         }
     679             : 
     680             :         // Most compositors wait for vsync events on the root window.
     681           0 :         Window root = DefaultRootWindow(mXDisplay);
     682           0 :         int screen = DefaultScreen(mXDisplay);
     683             : 
     684           0 :         ScopedXFree<GLXFBConfig> cfgs;
     685             :         GLXFBConfig config;
     686             :         int visid;
     687           0 :         bool forWebRender = false;
     688           0 :         if (!gl::GLContextGLX::FindFBConfigForWindow(mXDisplay, screen, root,
     689             :                                                      &cfgs, &config, &visid,
     690             :                                                      forWebRender)) {
     691           0 :           lock.NotifyAll();
     692           0 :           return;
     693             :         }
     694             : 
     695           0 :         mGLContext = gl::GLContextGLX::CreateGLContext(gl::CreateContextFlags::NONE,
     696           0 :                                                        gl::SurfaceCaps::Any(), false,
     697             :                                                        mXDisplay, root, config, false,
     698           0 :                                                        nullptr);
     699             : 
     700           0 :         if (!mGLContext) {
     701           0 :           lock.NotifyAll();
     702           0 :           return;
     703             :         }
     704             : 
     705           0 :         mGLContext->MakeCurrent();
     706             : 
     707             :         // Test that SGI_video_sync lets us get the counter.
     708           0 :         unsigned int syncCounter = 0;
     709           0 :         if (gl::sGLXLibrary.fGetVideoSync(&syncCounter) != 0) {
     710           0 :           mGLContext = nullptr;
     711             :         }
     712             : 
     713           0 :         lock.NotifyAll();
     714             :     }
     715             : 
     716           0 :     virtual void EnableVsync() override
     717             :     {
     718           0 :       MOZ_ASSERT(NS_IsMainThread());
     719           0 :       MOZ_ASSERT(mGLContext, "GLContext not setup!");
     720             : 
     721           0 :       MonitorAutoLock lock(mVsyncEnabledLock);
     722           0 :       if (mVsyncEnabled) {
     723           0 :         return;
     724             :       }
     725           0 :       mVsyncEnabled = true;
     726             : 
     727             :       // If the task has not nulled itself out, it hasn't yet realized
     728             :       // that vsync was disabled earlier, so continue its execution.
     729           0 :       if (!mVsyncTask) {
     730           0 :         mVsyncTask = NewRunnableMethod(
     731           0 :           "GLXVsyncSource::GLXDisplay::RunVsync", this, &GLXDisplay::RunVsync);
     732           0 :         RefPtr<Runnable> addrefedTask = mVsyncTask;
     733           0 :         mVsyncThread.message_loop()->PostTask(addrefedTask.forget());
     734             :       }
     735             :     }
     736             : 
     737           0 :     virtual void DisableVsync() override
     738             :     {
     739           0 :       MonitorAutoLock lock(mVsyncEnabledLock);
     740           0 :       mVsyncEnabled = false;
     741           0 :     }
     742             : 
     743           0 :     virtual bool IsVsyncEnabled() override
     744             :     {
     745           0 :       MonitorAutoLock lock(mVsyncEnabledLock);
     746           0 :       return mVsyncEnabled;
     747             :     }
     748             : 
     749           0 :     virtual void Shutdown() override
     750             :     {
     751           0 :       MOZ_ASSERT(NS_IsMainThread());
     752           0 :       DisableVsync();
     753             : 
     754             :       // Cleanup thread-specific resources before shutting down.
     755           0 :       RefPtr<Runnable> shutdownTask = NewRunnableMethod(
     756           0 :         "GLXVsyncSource::GLXDisplay::Cleanup", this, &GLXDisplay::Cleanup);
     757           0 :       mVsyncThread.message_loop()->PostTask(shutdownTask.forget());
     758             : 
     759             :       // Stop, waiting for the cleanup task to finish execution.
     760           0 :       mVsyncThread.Stop();
     761           0 :     }
     762             : 
     763             :   private:
     764           0 :     virtual ~GLXDisplay()
     765           0 :     {
     766           0 :     }
     767             : 
     768           0 :     void RunVsync()
     769             :     {
     770           0 :       MOZ_ASSERT(!NS_IsMainThread());
     771             : 
     772           0 :       mGLContext->MakeCurrent();
     773             : 
     774           0 :       unsigned int syncCounter = 0;
     775           0 :       gl::sGLXLibrary.fGetVideoSync(&syncCounter);
     776             :       for (;;) {
     777             :         {
     778           0 :           MonitorAutoLock lock(mVsyncEnabledLock);
     779           0 :           if (!mVsyncEnabled) {
     780           0 :             mVsyncTask = nullptr;
     781           0 :             return;
     782             :           }
     783             :         }
     784             : 
     785           0 :         TimeStamp lastVsync = TimeStamp::Now();
     786           0 :         bool useSoftware = false;
     787             : 
     788             :         // Wait until the video sync counter reaches the next value by waiting
     789             :         // until the parity of the counter value changes.
     790           0 :         unsigned int nextSync = syncCounter + 1;
     791             :         int status;
     792           0 :         if ((status = gl::sGLXLibrary.fWaitVideoSync(2, nextSync % 2, &syncCounter)) != 0) {
     793           0 :           gfxWarningOnce() << "glXWaitVideoSync returned " << status;
     794           0 :           useSoftware = true;
     795             :         }
     796             : 
     797           0 :         if (syncCounter == (nextSync - 1)) {
     798           0 :           gfxWarningOnce() << "glXWaitVideoSync failed to increment the sync counter.";
     799           0 :           useSoftware = true;
     800             :         }
     801             : 
     802           0 :         if (useSoftware) {
     803             :           double remaining = (1000.f / 60.f) -
     804           0 :             (TimeStamp::Now() - lastVsync).ToMilliseconds();
     805           0 :           if (remaining > 0) {
     806           0 :             PlatformThread::Sleep(remaining);
     807             :           }
     808             :         }
     809             : 
     810           0 :         lastVsync = TimeStamp::Now();
     811           0 :         NotifyVsync(lastVsync);
     812           0 :       }
     813             :     }
     814             : 
     815           0 :     void Cleanup() {
     816           0 :       MOZ_ASSERT(!NS_IsMainThread());
     817             : 
     818           0 :       mGLContext = nullptr;
     819           0 :       XCloseDisplay(mXDisplay);
     820           0 :     }
     821             : 
     822             :     // Owned by the vsync thread.
     823             :     RefPtr<gl::GLContextGLX> mGLContext;
     824             :     _XDisplay* mXDisplay;
     825             :     Monitor mSetupLock;
     826             :     base::Thread mVsyncThread;
     827             :     RefPtr<Runnable> mVsyncTask;
     828             :     Monitor mVsyncEnabledLock;
     829             :     bool mVsyncEnabled;
     830             :   };
     831             : private:
     832             :   // We need a refcounted VsyncSource::Display to use chromium IPC runnables.
     833             :   RefPtr<GLXDisplay> mGlobalDisplay;
     834             : };
     835             : 
     836             : already_AddRefed<gfx::VsyncSource>
     837           1 : gfxPlatformGtk::CreateHardwareVsyncSource()
     838             : {
     839             :   // Only use GLX vsync when the OpenGL compositor is being used.
     840             :   // The extra cost of initializing a GLX context while blocking the main
     841             :   // thread is not worth it when using basic composition.
     842           1 :   if (gfxConfig::IsEnabled(Feature::HW_COMPOSITING)) {
     843           0 :     if (gl::sGLXLibrary.SupportsVideoSync()) {
     844           0 :       RefPtr<VsyncSource> vsyncSource = new GLXVsyncSource();
     845           0 :       VsyncSource::Display& display = vsyncSource->GetGlobalDisplay();
     846           0 :       if (!static_cast<GLXVsyncSource::GLXDisplay&>(display).Setup()) {
     847           0 :         NS_WARNING("Failed to setup GLContext, falling back to software vsync.");
     848           0 :         return gfxPlatform::CreateHardwareVsyncSource();
     849             :       }
     850           0 :       return vsyncSource.forget();
     851             :     }
     852           0 :     NS_WARNING("SGI_video_sync unsupported. Falling back to software vsync.");
     853             :   }
     854           1 :   return gfxPlatform::CreateHardwareVsyncSource();
     855             : }
     856             : 
     857             : #endif

Generated by: LCOV version 1.13