gecko-dev/gfx/thebes/gfxPlatformMac.cpp
Chris Martin 64e1fb7a45 Bug 1540776 - Have parent send color profile to child during launch r=aosmond,jld,jfkthame,florian
For Win32k lockdown, we need to remove the content processes' ability to
call GetICMProfileW(). Since it needs this to retrieve the output color
profile, a new synchronous call is added that allows it to request the
parent process to read this file on its behalf.

The contents of the file are now being cached as well, as this should help
ease some of the increased parent process I/O caused by the children not
being able to do this in their process anymore.

For performance reasons, during launch this information is passed directly
to the child through the SetXPCOMProcessAttributes call

Differential Revision: https://phabricator.services.mozilla.com/D66126

--HG--
extra : moz-landing-system : lando
2020-04-02 15:42:15 +00:00

612 lines
20 KiB
C++

/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "gfxPlatformMac.h"
#include "gfxQuartzSurface.h"
#include "mozilla/gfx/2D.h"
#include "gfxMacPlatformFontList.h"
#include "gfxMacFont.h"
#include "gfxCoreTextShaper.h"
#include "gfxTextRun.h"
#include "gfxUserFontSet.h"
#include "gfxConfig.h"
#include "nsTArray.h"
#include "mozilla/Preferences.h"
#include "mozilla/VsyncDispatcher.h"
#include "nsCocoaFeatures.h"
#include "nsUnicodeProperties.h"
#include "qcms.h"
#include "gfx2DGlue.h"
#include <dlfcn.h>
#include <CoreVideo/CoreVideo.h>
#include "mozilla/layers/CompositorBridgeParent.h"
#include "mozilla/layers/SurfacePool.h"
#include "VsyncSource.h"
using namespace mozilla;
using namespace mozilla::gfx;
using namespace mozilla::unicode;
using mozilla::dom::SystemFontListEntry;
// cribbed from CTFontManager.h
enum { kAutoActivationDisabled = 1 };
typedef uint32_t AutoActivationSetting;
// bug 567552 - disable auto-activation of fonts
static void DisableFontActivation() {
// get the main bundle identifier
CFBundleRef mainBundle = ::CFBundleGetMainBundle();
CFStringRef mainBundleID = nullptr;
if (mainBundle) {
mainBundleID = ::CFBundleGetIdentifier(mainBundle);
}
// bug 969388 and bug 922590 - mainBundlID as null is sometimes problematic
if (!mainBundleID) {
NS_WARNING("missing bundle ID, packaging set up incorrectly");
return;
}
// if possible, fetch CTFontManagerSetAutoActivationSetting
void (*CTFontManagerSetAutoActivationSettingPtr)(CFStringRef,
AutoActivationSetting);
CTFontManagerSetAutoActivationSettingPtr =
(void (*)(CFStringRef, AutoActivationSetting))dlsym(
RTLD_DEFAULT, "CTFontManagerSetAutoActivationSetting");
// bug 567552 - disable auto-activation of fonts
if (CTFontManagerSetAutoActivationSettingPtr) {
CTFontManagerSetAutoActivationSettingPtr(mainBundleID,
kAutoActivationDisabled);
}
}
gfxPlatformMac::gfxPlatformMac() {
DisableFontActivation();
mFontAntiAliasingThreshold = ReadAntiAliasingThreshold();
InitBackendPrefs(GetBackendPrefs());
if (nsCocoaFeatures::OnHighSierraOrLater()) {
mHasNativeColrFontSupport = true;
}
}
gfxPlatformMac::~gfxPlatformMac() { gfxCoreTextShaper::Shutdown(); }
BackendPrefsData gfxPlatformMac::GetBackendPrefs() const {
BackendPrefsData data;
data.mCanvasBitmask = BackendTypeBit(BackendType::SKIA);
data.mContentBitmask = BackendTypeBit(BackendType::SKIA);
data.mCanvasDefault = BackendType::SKIA;
data.mContentDefault = BackendType::SKIA;
return data;
}
bool gfxPlatformMac::UsesTiling() const {
// The non-tiling ContentClient requires CrossProcessSemaphore which
// isn't implemented for OSX.
return true;
}
bool gfxPlatformMac::ContentUsesTiling() const { return UsesTiling(); }
gfxPlatformFontList* gfxPlatformMac::CreatePlatformFontList() {
gfxPlatformFontList* list = new gfxMacPlatformFontList();
if (NS_SUCCEEDED(list->InitFontList())) {
return list;
}
gfxPlatformFontList::Shutdown();
return nullptr;
}
void gfxPlatformMac::ReadSystemFontList(
nsTArray<SystemFontListEntry>* aFontList) {
gfxMacPlatformFontList::PlatformFontList()->ReadSystemFontList(aFontList);
}
already_AddRefed<gfxASurface> gfxPlatformMac::CreateOffscreenSurface(
const IntSize& aSize, gfxImageFormat aFormat) {
if (!Factory::AllowedSurfaceSize(aSize)) {
return nullptr;
}
RefPtr<gfxASurface> newSurface = new gfxQuartzSurface(aSize, aFormat);
return newSurface.forget();
}
bool gfxPlatformMac::IsFontFormatSupported(uint32_t aFormatFlags) {
if (gfxPlatform::IsFontFormatSupported(aFormatFlags)) {
return true;
}
// If the generic method rejected the format hint, then check for any
// platform-specific format we know about.
if (aFormatFlags & gfxUserFontSet::FLAG_FORMAT_TRUETYPE_AAT) {
return true;
}
return false;
}
static const char kFontArialUnicodeMS[] = "Arial Unicode MS";
static const char kFontAppleBraille[] = "Apple Braille";
static const char kFontAppleColorEmoji[] = "Apple Color Emoji";
static const char kFontAppleSymbols[] = "Apple Symbols";
static const char kFontDevanagariSangamMN[] = "Devanagari Sangam MN";
static const char kFontEuphemiaUCAS[] = "Euphemia UCAS";
static const char kFontGeneva[] = "Geneva";
static const char kFontGeezaPro[] = "Geeza Pro";
static const char kFontGujaratiSangamMN[] = "Gujarati Sangam MN";
static const char kFontGurmukhiMN[] = "Gurmukhi MN";
static const char kFontHelvetica[] = "Helvetica";
static const char kFontHiraginoKakuGothic[] = "Hiragino Kaku Gothic ProN";
static const char kFontHiraginoSansGB[] = "Hiragino Sans GB";
static const char kFontKefa[] = "Kefa";
static const char kFontKhmerMN[] = "Khmer MN";
static const char kFontLaoMN[] = "Lao MN";
static const char kFontLucidaGrande[] = "Lucida Grande";
static const char kFontMenlo[] = "Menlo";
static const char kFontMicrosoftTaiLe[] = "Microsoft Tai Le";
static const char kFontMingLiUExtB[] = "MingLiU-ExtB";
static const char kFontMyanmarMN[] = "Myanmar MN";
static const char kFontNotoSansMongolian[] = "Noto Sans Mongolian";
static const char kFontPlantagenetCherokee[] = "Plantagenet Cherokee";
static const char kFontSimSunExtB[] = "SimSun-ExtB";
static const char kFontSongtiSC[] = "Songti SC";
static const char kFontSTHeiti[] = "STHeiti";
static const char kFontSTIXGeneral[] = "STIXGeneral";
static const char kFontTamilMN[] = "Tamil MN";
static const char kFontZapfDingbats[] = "Zapf Dingbats";
void gfxPlatformMac::GetCommonFallbackFonts(uint32_t aCh, uint32_t aNextCh,
Script aRunScript,
nsTArray<const char*>& aFontList) {
EmojiPresentation emoji = GetEmojiPresentation(aCh);
if (emoji != EmojiPresentation::TextOnly) {
if (aNextCh == kVariationSelector16 ||
(aNextCh != kVariationSelector15 &&
emoji == EmojiPresentation::EmojiDefault)) {
// if char is followed by VS16, try for a color emoji glyph
aFontList.AppendElement(kFontAppleColorEmoji);
}
}
aFontList.AppendElement(kFontLucidaGrande);
if (!IS_IN_BMP(aCh)) {
uint32_t p = aCh >> 16;
if (p == 1) {
aFontList.AppendElement(kFontAppleSymbols);
aFontList.AppendElement(kFontSTIXGeneral);
aFontList.AppendElement(kFontGeneva);
} else if (p == 2) {
// OSX installations with MS Office may have these fonts
aFontList.AppendElement(kFontMingLiUExtB);
aFontList.AppendElement(kFontSimSunExtB);
}
} else {
uint32_t b = (aCh >> 8) & 0xff;
switch (b) {
case 0x03:
case 0x05:
aFontList.AppendElement(kFontGeneva);
break;
case 0x07:
aFontList.AppendElement(kFontGeezaPro);
break;
case 0x09:
aFontList.AppendElement(kFontDevanagariSangamMN);
break;
case 0x0a:
aFontList.AppendElement(kFontGurmukhiMN);
aFontList.AppendElement(kFontGujaratiSangamMN);
break;
case 0x0b:
aFontList.AppendElement(kFontTamilMN);
break;
case 0x0e:
aFontList.AppendElement(kFontLaoMN);
break;
case 0x0f:
aFontList.AppendElement(kFontSongtiSC);
break;
case 0x10:
aFontList.AppendElement(kFontHelvetica);
aFontList.AppendElement(kFontMenlo);
aFontList.AppendElement(kFontMyanmarMN);
break;
case 0x13: // Cherokee
aFontList.AppendElement(kFontPlantagenetCherokee);
aFontList.AppendElement(kFontKefa);
break;
case 0x14: // Unified Canadian Aboriginal Syllabics
case 0x15:
case 0x16:
aFontList.AppendElement(kFontEuphemiaUCAS);
aFontList.AppendElement(kFontGeneva);
break;
case 0x18: // Mongolian, UCAS
aFontList.AppendElement(kFontNotoSansMongolian);
aFontList.AppendElement(kFontEuphemiaUCAS);
break;
case 0x19: // Khmer
aFontList.AppendElement(kFontKhmerMN);
aFontList.AppendElement(kFontMicrosoftTaiLe);
break;
case 0x1d:
case 0x1e:
aFontList.AppendElement(kFontGeneva);
break;
case 0x27: // For Dingbats block 2700-27BF, prefer Zapf Dingbats
aFontList.AppendElement(kFontZapfDingbats);
[[fallthrough]];
case 0x20: // Symbol ranges
case 0x21:
case 0x22:
case 0x23:
case 0x24:
case 0x25:
case 0x26:
case 0x29:
case 0x2a:
case 0x2b:
case 0x2e:
aFontList.AppendElement(kFontHiraginoKakuGothic);
aFontList.AppendElement(kFontAppleSymbols);
aFontList.AppendElement(kFontMenlo);
aFontList.AppendElement(kFontSTIXGeneral);
aFontList.AppendElement(kFontGeneva);
aFontList.AppendElement(kFontAppleColorEmoji);
break;
case 0x2c:
aFontList.AppendElement(kFontGeneva);
break;
case 0x2d:
aFontList.AppendElement(kFontKefa);
aFontList.AppendElement(kFontGeneva);
break;
case 0x28: // Braille
aFontList.AppendElement(kFontAppleBraille);
break;
case 0x31:
aFontList.AppendElement(kFontHiraginoSansGB);
break;
case 0x4d:
aFontList.AppendElement(kFontAppleSymbols);
break;
case 0xa0: // Yi
case 0xa1:
case 0xa2:
case 0xa3:
case 0xa4:
aFontList.AppendElement(kFontSTHeiti);
break;
case 0xa6:
case 0xa7:
aFontList.AppendElement(kFontGeneva);
aFontList.AppendElement(kFontAppleSymbols);
break;
case 0xab:
aFontList.AppendElement(kFontKefa);
break;
case 0xfc:
case 0xff:
aFontList.AppendElement(kFontAppleSymbols);
break;
default:
break;
}
}
// Arial Unicode MS has lots of glyphs for obscure, use it as a last resort
aFontList.AppendElement(kFontArialUnicodeMS);
}
/*static*/
void gfxPlatformMac::LookupSystemFont(
mozilla::LookAndFeel::FontID aSystemFontID, nsACString& aSystemFontName,
gfxFontStyle& aFontStyle) {
gfxMacPlatformFontList* pfl = gfxMacPlatformFontList::PlatformFontList();
return pfl->LookupSystemFont(aSystemFontID, aSystemFontName, aFontStyle);
}
uint32_t gfxPlatformMac::ReadAntiAliasingThreshold() {
uint32_t threshold = 0; // default == no threshold
// first read prefs flag to determine whether to use the setting or not
bool useAntiAliasingThreshold =
Preferences::GetBool("gfx.use_text_smoothing_setting", false);
// if the pref setting is disabled, return 0 which effectively disables this
// feature
if (!useAntiAliasingThreshold) return threshold;
// value set via Appearance pref panel, "Turn off text smoothing for font
// sizes xxx and smaller"
CFNumberRef prefValue = (CFNumberRef)CFPreferencesCopyAppValue(
CFSTR("AppleAntiAliasingThreshold"), kCFPreferencesCurrentApplication);
if (prefValue) {
if (!CFNumberGetValue(prefValue, kCFNumberIntType, &threshold)) {
threshold = 0;
}
CFRelease(prefValue);
}
return threshold;
}
bool gfxPlatformMac::AccelerateLayersByDefault() { return true; }
// This is the renderer output callback function, called on the vsync thread
static CVReturn VsyncCallback(CVDisplayLinkRef aDisplayLink,
const CVTimeStamp* aNow,
const CVTimeStamp* aOutputTime,
CVOptionFlags aFlagsIn, CVOptionFlags* aFlagsOut,
void* aDisplayLinkContext);
class OSXVsyncSource final : public VsyncSource {
public:
OSXVsyncSource() {}
Display& GetGlobalDisplay() override { return mGlobalDisplay; }
class OSXDisplay final : public VsyncSource::Display {
public:
OSXDisplay() : mDisplayLink(nullptr) {
MOZ_ASSERT(NS_IsMainThread());
mTimer = NS_NewTimer();
}
virtual ~OSXDisplay() { MOZ_ASSERT(NS_IsMainThread()); }
static void RetryEnableVsync(nsITimer* aTimer, void* aOsxDisplay) {
MOZ_ASSERT(NS_IsMainThread());
OSXDisplay* osxDisplay = static_cast<OSXDisplay*>(aOsxDisplay);
MOZ_ASSERT(osxDisplay);
osxDisplay->EnableVsync();
}
void EnableVsync() override {
MOZ_ASSERT(NS_IsMainThread());
if (IsVsyncEnabled()) {
return;
}
// Create a display link capable of being used with all active displays
// TODO: See if we need to create an active DisplayLink for each monitor
// in multi-monitor situations. According to the docs, it is compatible
// with all displays running on the computer But if we have different
// monitors at different display rates, we may hit issues.
CVReturn retval = CVDisplayLinkCreateWithActiveCGDisplays(&mDisplayLink);
// Workaround for bug 1201401: CVDisplayLinkCreateWithCGDisplays()
// (called by CVDisplayLinkCreateWithActiveCGDisplays()) sometimes
// creates a CVDisplayLinkRef with an uninitialized (nulled) internal
// pointer. If we continue to use this CVDisplayLinkRef, we will
// eventually crash in CVCGDisplayLink::getDisplayTimes(), where the
// internal pointer is dereferenced. Fortunately, when this happens
// another internal variable is also left uninitialized (zeroed),
// which is accessible via CVDisplayLinkGetCurrentCGDisplay(). In
// normal conditions the current display is never zero.
if ((retval == kCVReturnSuccess) &&
(CVDisplayLinkGetCurrentCGDisplay(mDisplayLink) == 0)) {
retval = kCVReturnInvalidDisplay;
}
if (retval != kCVReturnSuccess) {
NS_WARNING(
"Could not create a display link with all active displays. "
"Retrying");
CVDisplayLinkRelease(mDisplayLink);
mDisplayLink = nullptr;
// bug 1142708 - When coming back from sleep,
// or when changing displays, active displays may not be ready yet,
// even if listening for the kIOMessageSystemHasPoweredOn event
// from OS X sleep notifications.
// Active displays are those that are drawable.
// bug 1144638 - When changing display configurations and getting
// notifications from CGDisplayReconfigurationCallBack, the
// callback gets called twice for each active display
// so it's difficult to know when all displays are active.
// Instead, try again soon. The delay is arbitrary. 100ms chosen
// because on a late 2013 15" retina, it takes about that
// long to come back up from sleep.
uint32_t delay = 100;
mTimer->InitWithNamedFuncCallback(RetryEnableVsync, this, delay,
nsITimer::TYPE_ONE_SHOT,
"RetryEnableVsync");
return;
}
if (CVDisplayLinkSetOutputCallback(mDisplayLink, &VsyncCallback, this) !=
kCVReturnSuccess) {
NS_WARNING("Could not set displaylink output callback");
CVDisplayLinkRelease(mDisplayLink);
mDisplayLink = nullptr;
return;
}
mPreviousTimestamp = TimeStamp::Now();
if (CVDisplayLinkStart(mDisplayLink) != kCVReturnSuccess) {
NS_WARNING("Could not activate the display link");
CVDisplayLinkRelease(mDisplayLink);
mDisplayLink = nullptr;
}
CVTime vsyncRate =
CVDisplayLinkGetNominalOutputVideoRefreshPeriod(mDisplayLink);
if (vsyncRate.flags & kCVTimeIsIndefinite) {
NS_WARNING("Could not get vsync rate, setting to 60.");
mVsyncRate = TimeDuration::FromMilliseconds(1000.0 / 60.0);
} else {
int64_t timeValue = vsyncRate.timeValue;
int64_t timeScale = vsyncRate.timeScale;
const int milliseconds = 1000;
float rateInMs = ((double)timeValue / (double)timeScale) * milliseconds;
mVsyncRate = TimeDuration::FromMilliseconds(rateInMs);
}
}
void DisableVsync() override {
MOZ_ASSERT(NS_IsMainThread());
if (!IsVsyncEnabled()) {
return;
}
// Release the display link
if (mDisplayLink) {
CVDisplayLinkRelease(mDisplayLink);
mDisplayLink = nullptr;
}
}
bool IsVsyncEnabled() override {
MOZ_ASSERT(NS_IsMainThread());
return mDisplayLink != nullptr;
}
TimeDuration GetVsyncRate() override { return mVsyncRate; }
void Shutdown() override {
MOZ_ASSERT(NS_IsMainThread());
mTimer->Cancel();
mTimer = nullptr;
DisableVsync();
}
// The vsync timestamps given by the CVDisplayLinkCallback are
// in the future for the NEXT frame. Large parts of Gecko, such
// as animations assume a timestamp at either now or in the past.
// Normalize the timestamps given to the VsyncDispatchers to the vsync
// that just occured, not the vsync that is upcoming.
TimeStamp mPreviousTimestamp;
private:
// Manages the display link render thread
CVDisplayLinkRef mDisplayLink;
RefPtr<nsITimer> mTimer;
TimeDuration mVsyncRate;
}; // OSXDisplay
private:
virtual ~OSXVsyncSource() = default;
OSXDisplay mGlobalDisplay;
}; // OSXVsyncSource
static CVReturn VsyncCallback(CVDisplayLinkRef aDisplayLink,
const CVTimeStamp* aNow,
const CVTimeStamp* aOutputTime,
CVOptionFlags aFlagsIn, CVOptionFlags* aFlagsOut,
void* aDisplayLinkContext) {
// Executed on OS X hardware vsync thread
OSXVsyncSource::OSXDisplay* display =
(OSXVsyncSource::OSXDisplay*)aDisplayLinkContext;
int64_t nextVsyncTimestamp = aOutputTime->hostTime;
mozilla::TimeStamp nextVsync =
mozilla::TimeStamp::FromSystemTime(nextVsyncTimestamp);
mozilla::TimeStamp previousVsync = display->mPreviousTimestamp;
mozilla::TimeStamp now = TimeStamp::Now();
// Snow leopard sometimes sends vsync timestamps very far in the past.
// Normalize the vsync timestamps to now.
if (nextVsync <= previousVsync) {
nextVsync = now;
previousVsync = now;
} else if (now < previousVsync) {
// Bug 1158321 - The VsyncCallback can sometimes execute before the reported
// vsync time. In those cases, normalize the timestamp to Now() as sending
// timestamps in the future has undefined behavior. See the comment above
// OSXDisplay::mPreviousTimestamp
previousVsync = now;
}
display->mPreviousTimestamp = nextVsync;
display->NotifyVsync(previousVsync);
return kCVReturnSuccess;
}
already_AddRefed<mozilla::gfx::VsyncSource>
gfxPlatformMac::CreateHardwareVsyncSource() {
RefPtr<VsyncSource> osxVsyncSource = new OSXVsyncSource();
VsyncSource::Display& primaryDisplay = osxVsyncSource->GetGlobalDisplay();
primaryDisplay.EnableVsync();
if (!primaryDisplay.IsVsyncEnabled()) {
NS_WARNING(
"OS X Vsync source not enabled. Falling back to software vsync.");
return gfxPlatform::CreateHardwareVsyncSource();
}
primaryDisplay.DisableVsync();
return osxVsyncSource.forget();
}
nsTArray<uint8_t> gfxPlatformMac::GetPlatformCMSOutputProfileData() {
nsTArray<uint8_t> prefProfileData = GetPrefCMSOutputProfileData();
if (!prefProfileData.IsEmpty()) {
return prefProfileData;
}
CGColorSpaceRef cspace = ::CGDisplayCopyColorSpace(::CGMainDisplayID());
if (!cspace) {
cspace = ::CGColorSpaceCreateDeviceRGB();
}
if (!cspace) {
return nsTArray<uint8_t>();
}
CFDataRef iccp = ::CGColorSpaceCopyICCProfile(cspace);
::CFRelease(cspace);
if (!iccp) {
return nsTArray<uint8_t>();
}
// copy to external buffer
size_t size = static_cast<size_t>(::CFDataGetLength(iccp));
nsTArray<uint8_t> result;
if (size > 0) {
result.AppendElements(::CFDataGetBytePtr(iccp), size);
}
::CFRelease(iccp);
return result;
}
bool gfxPlatformMac::CheckVariationFontSupport() {
// We don't allow variation fonts to be enabled before 10.13,
// as although the Core Text APIs existed, they are known to be
// fairly buggy.
// (Note that Safari also requires 10.13 for variation-font support.)
return nsCocoaFeatures::OnHighSierraOrLater();
}
void gfxPlatformMac::InitPlatformGPUProcessPrefs() {
FeatureState& gpuProc = gfxConfig::GetFeature(Feature::GPU_PROCESS);
gpuProc.ForceDisable(FeatureStatus::Blocked,
"GPU process does not work on Mac",
NS_LITERAL_CSTRING("FEATURE_FAILURE_MAC_GPU_PROC"));
}