[Cocoa] Add SPI to disallow user-installed fonts
[WebKit-https.git] / Tools / WebKitTestRunner / InjectedBundle / cocoa / ActivateFontsCocoa.mm
1 /*
2  * Copyright (C) 2010-2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "ActivateFonts.h"
28
29 #import <CoreFoundation/CoreFoundation.h>
30 #import <CoreText/CTFontManager.h>
31 #import <WebKit/WKStringCF.h>
32 #import <wtf/NeverDestroyed.h>
33 #import <wtf/ObjcRuntimeExtras.h>
34 #import <wtf/RetainPtr.h>
35
36 #if USE(APPKIT)
37 #import <AppKit/AppKit.h>
38 #endif
39
40 @interface WKTRFontActivatorDummyClass : NSObject
41 @end
42
43 @implementation WKTRFontActivatorDummyClass
44 @end
45
46 namespace WTR {
47
48 static NSURL *resourcesDirectoryURL()
49 {
50     static NeverDestroyed<RetainPtr<NSURL *>> resourcesDirectory([[NSBundle bundleForClass:[WKTRFontActivatorDummyClass class]] resourceURL]);
51     return resourcesDirectory.get().get();
52 }
53
54 #if USE(APPKIT)
55
56 // Activating system copies of these fonts overrides any others that could be preferred, such as ones
57 // in /Library/Fonts/Microsoft, and which don't always have the same metrics.
58 // FIXME: Switch to a solution from <rdar://problem/19553550> once it's available.
59 static void activateSystemCoreWebFonts()
60 {
61     NSArray *coreWebFontNames = @[
62         @"Andale Mono",
63         @"Arial",
64         @"Arial Black",
65         @"Comic Sans MS",
66         @"Courier New",
67         @"Georgia",
68         @"Impact",
69         @"Times New Roman",
70         @"Trebuchet MS",
71         @"Verdana",
72         @"Webdings"
73     ];
74
75     NSArray *fontFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtURL:[NSURL fileURLWithPath:@"/Library/Fonts" isDirectory:YES]
76         includingPropertiesForKeys:@[NSURLFileResourceTypeKey, NSURLNameKey] options:0 error:0];
77
78     for (NSURL *fontURL in fontFiles) {
79         NSString *resourceType;
80         NSString *fileName;
81         if (![fontURL getResourceValue:&resourceType forKey:NSURLFileResourceTypeKey error:0]
82             || ![fontURL getResourceValue:&fileName forKey:NSURLNameKey error:0])
83             continue;
84         if (![resourceType isEqualToString:NSURLFileResourceTypeRegular])
85             continue;
86
87         // Activate all font variations, such as Arial Bold Italic.ttf. This algorithm is not 100% precise, as it
88         // also activates e.g. Arial Unicode, which is not a variation of Arial.
89         for (NSString *coreWebFontName in coreWebFontNames) {
90             if ([fileName hasPrefix:coreWebFontName]) {
91                 CTFontManagerRegisterFontsForURL((CFURLRef)fontURL, kCTFontManagerScopeProcess, 0);
92                 break;
93             }
94         }
95     }
96 }
97
98 #endif // USE(APPKIT)
99
100 void activateFonts()
101 {
102     static const char* fontFileNames[] = {
103         "AHEM____.TTF",
104         "WebKitWeightWatcher100.ttf",
105         "WebKitWeightWatcher200.ttf",
106         "WebKitWeightWatcher300.ttf",
107         "WebKitWeightWatcher400.ttf",
108         "WebKitWeightWatcher500.ttf",
109         "WebKitWeightWatcher600.ttf",
110         "WebKitWeightWatcher700.ttf",
111         "WebKitWeightWatcher800.ttf",
112         "WebKitWeightWatcher900.ttf",
113         "FontWithFeatures.otf",
114         "FontWithFeatures.ttf",
115         0
116     };
117
118     NSMutableArray *fontURLs = [NSMutableArray array];
119     for (unsigned i = 0; fontFileNames[i]; ++i) {
120         NSURL *fontURL = [resourcesDirectoryURL() URLByAppendingPathComponent:[NSString stringWithUTF8String:fontFileNames[i]]];
121         [fontURLs addObject:[fontURL absoluteURL]];
122     }
123
124     CFArrayRef errors = 0;
125     if (!CTFontManagerRegisterFontsForURLs((CFArrayRef)fontURLs, kCTFontManagerScopeProcess, &errors)) {
126         NSLog(@"Failed to activate fonts: %@", errors);
127         CFRelease(errors);
128         exit(1);
129     }
130
131 #if USE(APPKIT)
132     activateSystemCoreWebFonts();
133 #endif // USE(APPKIT)
134 }
135
136 void installFakeHelvetica(WKStringRef configuration)
137 {
138     RetainPtr<CFStringRef> configurationString = adoptCF(WKStringCopyCFString(kCFAllocatorDefault, configuration));
139     NSURL *resourceURL = [resourcesDirectoryURL() URLByAppendingPathComponent:[NSString stringWithFormat:@"FakeHelvetica-%@.ttf", configurationString.get()]];
140     CFErrorRef error = nullptr;
141     CTFontManagerRegisterFontsForURL(static_cast<CFURLRef>(resourceURL), kCTFontManagerScopeProcess, &error);
142 }
143
144 void uninstallFakeHelvetica()
145 {
146     NSFileManager *defaultManager = [NSFileManager defaultManager];
147     NSError *nsError = nil;
148     NSArray *urls = [defaultManager contentsOfDirectoryAtURL:resourcesDirectoryURL() includingPropertiesForKeys:@[NSURLNameKey] options:NSDirectoryEnumerationSkipsSubdirectoryDescendants | NSDirectoryEnumerationSkipsPackageDescendants | NSDirectoryEnumerationSkipsHiddenFiles error:&nsError];
149     ASSERT(urls && !nsError);
150     if (!urls || nsError)
151         return;
152     NSMutableArray *fontsToRemove = [NSMutableArray array];
153     for (NSURL *url in urls) {
154         if ([[url lastPathComponent] hasPrefix:@"FakeHelvetica"])
155             [fontsToRemove addObject:url];
156     }
157     CFArrayRef errors = nullptr;
158     CTFontManagerUnregisterFontsForURLs(static_cast<CFArrayRef>(fontsToRemove), kCTFontManagerScopeProcess, &errors);
159 }
160
161 }
162