[macOS] Migrate off of CTFontCreateForCSS
authormmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 28 Feb 2017 20:40:14 +0000 (20:40 +0000)
committermmaxfield@apple.com <mmaxfield@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 28 Feb 2017 20:40:14 +0000 (20:40 +0000)
commitd432101fd64a443704070f6656efb3342c594a3e
treef857e51307b5243568725d70ce8a9d804021e3eb
parent5fe38848aee5174de93180327c87f18a15eb607a
[macOS] Migrate off of CTFontCreateForCSS
https://bugs.webkit.org/show_bug.cgi?id=168678

Reviewed by David Hyatt.

Source/WebCore:

This patch implements the Font Matching Algorithm detailed in
https://drafts.csswg.org/css-fonts-4/#font-matching-algorithm
Previously, this was implemented inside Core Text (via
CTFontCreateForCSS()), but that implementation does not understand
variation fonts. Therefore it should move to WebKit (along with
the general fact that CSS algorithms should be implemented in a
CSS engine, not the platform's text engine).

This implementation is not completely divorced from the platform,
however - Core Text exposes font weights on a [-1, 1] range, but
CSS operates on a [1, 999] range. In order to provide the mapping
to CSS weights, Core Text infrastructure is necessary. Therefore,
this new implementation of the matching algorithm is only used
on certain operating systems.

The new implementation of the algorithm is not bug-compatible with
the existing implementation; this patch does represent a behavior
change. However, I have reviewed the differences manually and
believe this algorithm to be a progression over the previous one
(except for one case with Helvetica Neue - see
LayoutTests/ChangeLog for more information about that).

This patch also represents a 27% performance progression on our
standard page load test (just measuring the performance of the font
matching algorithm, and nothing else). (Because font matching is
only a small part of the entire test, the overall progression is
much smaller.)

Tests: FontCacheTest.FontLookupFromFamilyName
       FontCacheTest.FontLookupFromPostScriptName

* platform/graphics/FontCache.h:
(WebCore::FontCache::createFontPlatformDataForTesting): Allow for
unit testing.
* platform/graphics/cocoa/FontCacheCoreText.cpp:
(WebCore::isSystemFont): Inlined.
(WebCore::FontDatabase::singleton): Cache results of Core Text
lookups.
(WebCore::FontDatabase::Range::Range): Because of variation fonts,
fonts' weights, widths, and slopes need to be represented as a range
instead of an individual value.
(WebCore::FontDatabase::Range::isValid):
(WebCore::FontDatabase::Range::expand):
(WebCore::FontDatabase::Range::includes):
(WebCore::FontDatabase::InstalledFont::InstalledFont): Represents a
Font Descriptor as well as some lookup information about it.
(WebCore::FontDatabase::InstalledFontCollection::InstalledFontCollection):
A collection of installed fonts.
(WebCore::FontDatabase::InstalledFontCollection::insertInstalledFont):
Cache minima and maxima.
(WebCore::FontDatabase::InstalledFontCollection::isEmpty):
(WebCore::FontDatabase::InstalledFontCollection::size):
(WebCore::FontDatabase::lookupFamilyName): Get all the fonts in
the family.
(WebCore::FontDatabase::lookupPostScriptName): Get the font with
the given PostScript name.
(WebCore::FontDatabase::clear):
(WebCore::FontDatabase::FontDatabase): Cache.
(WebCore::iterateActiveFontsWithReturn): The Font Matching Algorithm
works by starting with every font in the family, and the eliminating
items from the set iteratively. Instead of actually removing items
from a vector or linked list, we instead want to treat the collection
as immutable and keep a parallel side-table of which items have been
eliminated (in order to reduce copies and allocations). This makes
sense because most families only have a handful of fonts in them.
This function consults with the side-table to iterate only over the
fonts which have not been eliminated.
(WebCore::iterateActiveFonts): Ditto.
(WebCore::findClosestStretch):
(WebCore::filterStretch): Eliminate fonts based on their stretch
value.
(WebCore::findClosestStyle):
(WebCore::filterStyle): Eliminate fonts based on their style value.
(WebCore::findClosestWeight):
(WebCore::filterWeight): Eliminate fonts based on their weight value.
(WebCore::computeTargetWeight):
(WebCore::findClosestFont): If we have a set of fonts in a family,
select the font in the set which best matches the criteria.
(WebCore::platformFontLookupWithFamily): While findClosestFont()
function satisfies the spec's notion of the font matching algorithm,
WebKit actually claims to be able to look up fonts by their PostScript
name. Therefore, this function has a higher-level of logic to rectify
the confusion that results when the PostScript name doesn't agree with
the other CSS properties (like if you say "Helvetica-Bold" but also say
font-weight: 100).
* platform/spi/cocoa/CoreTextSPI.h: Add signature for system CSS
font weight support.

Tools:

Exhaustively test the font matching algorithm on Sierra.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/WebCore/FontCache.cpp: Added.
(TestWebKitAPI::FontCacheTest::SetUp):
(TestWebKitAPI::createPlatformFont):
(TestWebKitAPI::compareFonts):
(TestWebKitAPI::TEST_F):

LayoutTests:

Updating test results.

Note that there is a slight regression here with Helvetica Neue. In
particular, this family includes a Bold font with a weight of 700,
and a Condensed Black font with a weight of 900. Because we don't
currently have any notion of font-stretch, our model can only
distinguish between these fonts due to their differing weights, not
their widths. This means that requests for weights 800 or 900 will
match the Condensed Black font in accordance with the font matching
algorithm. This gives visually surprising results because weights
100-700 match regular-width fonts.

However, this regression is intentional and temporary - my next task
is to properly implement font-stretch, which will educate our model
on the difference between these two fonts. This will fix the regression
and allow the tests below to be reset to their original expected
results.

* platform/mac-elcapitan/fast/text/font-weights-expected.png: Copied from LayoutTests/platform/mac/fast/text/font-weights-expected.png.
* platform/mac-elcapitan/fast/text/font-weights-expected.txt: Copied from LayoutTests/platform/mac/fast/text/font-weights-expected.txt.
* platform/mac-elcapitan/fast/text/font-weights-zh-expected.png: Copied from LayoutTests/platform/mac/fast/text/font-weights-zh-expected.png.
* platform/mac-elcapitan/fast/text/font-weights-zh-expected.txt: Copied from LayoutTests/platform/mac/fast/text/font-weights-zh-expected.txt.
* platform/mac/fast/text/font-weights-expected.png:
* platform/mac/fast/text/font-weights-expected.txt:
* platform/mac/fast/text/font-weights-zh-expected.png:
* platform/mac/fast/text/font-weights-zh-expected.txt:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@213163 268f45cc-cd09-0410-ab3c-d52691b4dbfc
18 files changed:
LayoutTests/ChangeLog
LayoutTests/platform/mac-elcapitan/fast/text/font-weights-expected.png [new file with mode: 0644]
LayoutTests/platform/mac-elcapitan/fast/text/font-weights-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac-elcapitan/fast/text/font-weights-zh-expected.png [new file with mode: 0644]
LayoutTests/platform/mac-elcapitan/fast/text/font-weights-zh-expected.txt [new file with mode: 0644]
LayoutTests/platform/mac/fast/text/font-weights-expected.png
LayoutTests/platform/mac/fast/text/font-weights-expected.txt
LayoutTests/platform/mac/fast/text/font-weights-zh-expected.png
LayoutTests/platform/mac/fast/text/font-weights-zh-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/FontCache.h
Source/WebCore/platform/graphics/cocoa/FontCacheCoreText.cpp
Source/WebCore/platform/graphics/ios/FontCacheIOS.mm
Source/WebCore/platform/graphics/mac/FontCacheMac.mm
Source/WebCore/platform/spi/cocoa/CoreTextSPI.h
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/WebCore/FontCache.cpp [new file with mode: 0644]